Compare commits

..

41 Commits

Author SHA1 Message Date
qiaozp
9317bb1cab Refactor: addon cache mechanism and code architecture (#2956)
* Refactor: fix addon cache and code

Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>

* basic trim

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* Fix list OSS bucket addon's meta

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* rename listAddonMeta func

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix enable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* rename and trim cache func call

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* remove same source code, use Registry to implement Source interface. Keep the compatibility of DeployTo fields.

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* complete github reader

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix read from github, fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* reviewable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* header

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* rename function, restore test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* try CI

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* sort out functions name. add detail test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* filter directory without metadata.yaml in oss

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* add GitHub reader unit test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* clean up

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* reviewable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* header

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* add cache arg

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* change field name

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* build swagger

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* some json tag, revert cache logic

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

Co-authored-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
2021-12-21 09:31:37 +08:00
barnettZQG
2543b7b510 Fix: can not find target name in pod list (#2936)
* Fix: can not find target name in pod list

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>

* Fix: set create time for init trait

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-20 18:51:21 +08:00
qiaozp
7ef8cea7ce Chore: remove addons stored in configmap (#2951)
Signed-off-by: qiaozp <chivalry.pp@gmail.com>
2021-12-20 17:21:03 +08:00
wyike
ae06ddacac Feat: addon compability code for 1.1 (#2961)
Signed-off-by: wangyike <wangyike_wyk@163.com>
2021-12-20 14:34:45 +08:00
Somefive
db189f7527 Fix: optimize resourcetracker upgrade (#2959)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-20 13:05:53 +08:00
Tianxin Dong
9599e2da9d Docs: update some outdated content in workflow doc (#2962)
Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-12-20 11:35:22 +08:00
Tianxin Dong
6c4b7699b9 Fix: nit fix for workflow (#2957)
Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-12-20 11:00:07 +08:00
Tianxin Dong
add5d40bfc Feat: add init secret demo (#2955)
Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-12-18 14:31:18 +08:00
Somefive
2f7b20d8b8 Fix: amend fix for log sanitize (#2953)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-18 10:16:36 +08:00
Tianxin Dong
b85be11324 Feat: add workflow stability mechanism doc (#2960)
Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-12-18 10:11:38 +08:00
Zheng Xi Zhou
d11d171be8 Fix: enable Observability in runtime clusters (#2886)
* Fix: enable Observability in runtime clusters

Enabled add-on observability in runtime clusters. In each cluster, a sub-domain
will be allocated to the cluste

Signed-off-by: Zheng Xi Zhou <zzxwill@gmail.com>


* Fix:add workflow step definition and ut

Added a new workflow step definition `apply-application-in-parallel`,
and added more unit tests
2021-12-17 23:04:54 +08:00
Somefive
cb0e88d590 Fix: nil pointer aliyun sdk (#2954)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-17 15:15:23 +08:00
Tianxin Dong
f0d95c566f Fix: fix notification definition to show better (#2952)
Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-12-17 01:09:56 +08:00
Somefive
0a2a41046c Fix: ack dashboard url (#2932)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-16 21:25:43 +08:00
yangsoon
b57db36dd3 Fix: velaql compatible with v1.2.0-beta version (#2946)
Signed-off-by: yangsoon <yangsoonlx@gmail.com>
2021-12-16 21:15:07 +08:00
Tianxin Dong
f5e04a5575 Fix: fix apiserver snake case (#2944)
Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-12-16 21:14:25 +08:00
Somefive
4e91e3ab8d Fix: workflow step definition for ui (#2948)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-16 21:10:09 +08:00
Somefive
478d134778 Feat: upgrade cluster-gateway (#2941)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-16 21:06:02 +08:00
Somefive
5f2085b470 Feat: support parallel apply in deploy2env (#2938)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-16 21:05:23 +08:00
Somefive
416fc45999 Fix: security alert (#2945)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-16 21:03:54 +08:00
Jian.Li
133a89be3f Fix: deprecate CRD discovery for CUE import in Definition to prevent memory leak and OOM crash (#2925)
* Pause test case

Signed-off-by: Jian.Li <lj176172@alibaba-inc.com>

* fix lint

Signed-off-by: Jian.Li <lj176172@alibaba-inc.com>

* diable discover the open api of the CRD

Signed-off-by: Jian.Li <lj176172@alibaba-inc.com>

* fix definition test cases

Signed-off-by: Jian.Li <lj176172@alibaba-inc.com>
2021-12-16 17:53:15 +08:00
yangsoon
3b1f097807 Fix: change catlog helm repo path to https://charts.kubevela.net/example (#2942)
Signed-off-by: yangsoon <yangsoonlx@gmail.com>
2021-12-16 15:17:00 +08:00
wyike
e49dec5a3a Feat(cli): app status more info (#2937)
* Feat(cli): app status more info

Signed-off-by: wangyike <wangyike_wyk@163.com>

* more info

Signed-off-by: wangyike <wangyike_wyk@163.com>

* fix: delete invisible check

Signed-off-by: wangyike <wangyike_wyk@163.com>
2021-12-16 11:12:06 +08:00
Somefive
f15d748251 Feat: add cluster alias to dt (#2929)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-15 16:33:45 +08:00
barnettZQG
e17f6b931a Feat: support specified existing namespace while creating a project (#2931)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-15 14:42:18 +08:00
Somefive
a3bf61fa4f Feat: set multicluster enabled by default (#2930)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-15 12:11:28 +08:00
Tianxin Dong
655c2615e1 Feat: add workflow reconciling backoff time and failed limit times (#2881)
* Feat: add workflow failed after retries

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* Feat: add workflow reconcile backoff time

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* fix lint

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* make reviewable

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* resolve some comments

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* add tests

* fix rebase

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* fix test

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* fix status

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* fix requeue time interval

* resolve comments

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* change time to pointer

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* fix pointer test

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* fix test

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* change time to cm

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

* resolve comments and add e2e test

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
2021-12-15 11:33:33 +08:00
Somefive
4dc213469a Feat: add compatibility code for new rt (#2920)
Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-14 21:27:47 +08:00
yangsoon
03d79db919 Fix: fix sync-api CI (#2923)
Signed-off-by: yangsoon <yangsoonlx@gmail.com>
2021-12-14 17:25:24 +08:00
qiaozp
0fc65eb787 Feat: add mock server (#2911)
* add mock server

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* use mock server

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* reviewable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* reviewable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* complate terraform-alibaba addon

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* move to test dir

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* complete terraform

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* add back oss

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* remove useless readme

Signed-off-by: qiaozp <chivalry.pp@gmail.com>
2021-12-14 14:52:10 +08:00
yangsoon
6d536a84d7 Feat: refactor velaql provider with new ResourceTracker architecture (#2915)
* Feat: refactor velaql with new ResourceTracker architecture

Signed-off-by: yangsoon <yangsoonlx@gmail.com>

* Feat: concurrently request the pod created by helm

Signed-off-by: yangsoon <yangsoonlx@gmail.com>
2021-12-14 13:09:40 +08:00
wyike
f5f5ff514f Feat: cli manage addon registry and apiserver addon status return app status info (#2910)
* Fix: cli add addon registry

add more detail info for addon workflow info

Signed-off-by: wangyike <wangyike_wyk@163.com>

* fix: set app status in addon status directly

Signed-off-by: wangyike <wangyike_wyk@163.com>

* add e2e test

Signed-off-by: wangyike <wangyike_wyk@163.com>
2021-12-13 19:47:32 +08:00
qiaozp
a67b7e90d0 Feat: add path argument to addon oss source (#2907)
* add path

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* pending test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* reviewable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* reviewable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* license

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* keep compatible

Signed-off-by: qiaozp <chivalry.pp@gmail.com>
2021-12-13 19:43:15 +08:00
Somefive
a89bb69a62 Fix: add design docs for ResourceTracker (#2909)
* Fix: enhance rt logic and add docs

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Fix: test conflict

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-13 19:41:42 +08:00
Min Kim
c5c664f316 pin ocm images version to v0.5.0 (#2900)
Signed-off-by: yue9944882 <291271447@qq.com>
2021-12-13 17:57:45 +08:00
qiaozp
53006b4137 Fix: move addon api to pkg/addon (#2905)
* move addon api to pkg/addon

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* reviewable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* license

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* reviewable

Signed-off-by: qiaozp <chivalry.pp@gmail.com>
2021-12-13 17:47:53 +08:00
barnettZQG
f47ae0e498 Feat: support automatically creating scaler trait for webservice component (#2908)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-10 15:04:31 +08:00
Somefive
b622cbdb7f Feat: ResourceTracker new architecture (#2849)
* Feat: new rt

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>

* Fix: add publish version

Signed-off-by: Yin Da <yd219913@alibaba-inc.com>
2021-12-10 15:00:03 +08:00
qiaozp
94f32a317d Feat: support addon definition in cue format (#2896)
* move def func to pkg

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* split def schema render

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* render CUE definition

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* add test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* add test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>

* fix test

Signed-off-by: qiaozp <chivalry.pp@gmail.com>
2021-12-09 20:31:19 +08:00
Min Kim
b483840987 honor existing cluster-gateway installation if exists (#2904)
Signed-off-by: yue9944882 <291271447@qq.com>
2021-12-09 15:59:16 +08:00
Jian.Li
3e81fdf008 remove InsecureSkipVerify (#2903)
Signed-off-by: Jian.Li <lj176172@alibaba-inc.com>
2021-12-09 09:20:49 +08:00
363 changed files with 10534 additions and 25580 deletions

1
.gitignore vendored
View File

@@ -41,6 +41,7 @@ references/cmd/cli/fake/source.go
references/cmd/cli/fake/chart_source.go
charts/vela-core/crds/_.yaml
.test_vela
tmp/
.vela/

View File

@@ -53,7 +53,7 @@ test: vet lint staticcheck unit-test-core
@$(OK) unit-tests pass
unit-test-core:
go test -coverprofile=coverage.txt $(shell go list ./pkg/... ./cmd/... | grep -v apiserver)
go test -coverprofile=coverage.txt $(shell go list ./pkg/... ./cmd/... ./apis/... | grep -v apiserver)
go test $(shell go list ./references/... | grep -v apiserver)
unit-test-apiserver:
go test -coverprofile=coverage.txt $(shell go list ./pkg/... ./cmd/... | grep -E 'apiserver|velaql')
@@ -154,8 +154,9 @@ docker-push:
e2e-setup-core:
sh ./hack/e2e/modify_charts.sh
helm upgrade --install --create-namespace --namespace vela-system --set image.pullPolicy=IfNotPresent --set image.repository=vela-core-test --set applicationRevisionLimit=5 --set dependCheckWait=10s --set image.tag=$(GIT_COMMIT) --set multicluster.enabled=true --wait kubevela ./charts/vela-core
helm upgrade --install --create-namespace --namespace vela-system --set image.pullPolicy=IfNotPresent --set image.repository=vela-core-test --set applicationRevisionLimit=5 --set dependCheckWait=10s --set image.tag=$(GIT_COMMIT) --wait kubevela ./charts/vela-core
kubectl wait --for=condition=Available deployment/kubevela-vela-core -n vela-system --timeout=180s
go run ./e2e/addon/mock &
setup-runtime-e2e-cluster:
helm upgrade --install --create-namespace --namespace vela-system --kubeconfig=$(RUNTIME_CLUSTER_CONFIG) --set image.pullPolicy=IfNotPresent --set image.repository=vela-runtime-rollout-test --set image.tag=$(GIT_COMMIT) --wait vela-rollout ./runtime/rollout/charts
@@ -165,7 +166,9 @@ e2e-setup:
sh ./hack/e2e/modify_charts.sh
helm upgrade --install --create-namespace --namespace vela-system --set image.pullPolicy=IfNotPresent --set image.repository=vela-core-test --set applicationRevisionLimit=5 --set dependCheckWait=10s --set image.tag=$(GIT_COMMIT) --wait kubevela ./charts/vela-core
helm upgrade --install --create-namespace --namespace oam-runtime-system --set image.pullPolicy=IfNotPresent --set image.repository=vela-core-test --set dependCheckWait=10s --set image.tag=$(GIT_COMMIT) --wait oam-runtime ./charts/oam-runtime
go run ./e2e/addon/mock &
bin/vela addon enable fluxcd
bin/vela addon enable terraform
bin/vela addon enable terraform-alibaba ALICLOUD_ACCESS_KEY=xxx ALICLOUD_SECRET_KEY=yyy ALICLOUD_REGION=cn-beijing
ginkgo version
ginkgo -v -r e2e/setup
@@ -183,6 +186,7 @@ e2e-api-test:
ginkgo -v -r e2e/application
e2e-apiserver-test: build-swagger
go run ./e2e/addon/mock &
go test -v -coverpkg=./... -coverprofile=/tmp/e2e_apiserver_test.out ./test/e2e-apiserver-test
@$(OK) tests pass
@@ -282,7 +286,7 @@ core-uninstall: manifests
kubectl delete -f charts/vela-core/crds/
# Generate manifests e.g. CRD, RBAC etc.
manifests: installcue kustomize addon
manifests: installcue kustomize
go generate $(foreach t,pkg apis,./$(t)/...)
# TODO(yangsoon): kustomize will merge all CRD into a whole file, it may not work if we want patch more than one CRD in this way
$(KUSTOMIZE) build config/crd -o config/crd/base/core.oam.dev_applications.yaml
@@ -374,6 +378,3 @@ check-license-header:
def-install:
./hack/utils/installdefinition.sh
# generate addons to auto-gen and charts
addon:
go run ./vela-templates/gen_addons.go

View File

@@ -21,6 +21,7 @@ import (
"errors"
"github.com/oam-dev/terraform-controller/api/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -28,6 +29,7 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/pkg/oam"
)
// Kube defines the encapsulation in raw Kubernetes resource format
@@ -191,12 +193,16 @@ const (
ApplicationRunning ApplicationPhase = "running"
// ApplicationUnhealthy means the app finished rendering and applied result to the cluster, but still unhealthy
ApplicationUnhealthy ApplicationPhase = "unhealthy"
// ApplicationDeleting means application is being deleted
ApplicationDeleting ApplicationPhase = "deleting"
)
// WorkflowState is a string that mark the workflow state
type WorkflowState string
const (
// WorkflowStateInitializing means the workflow is in initial state
WorkflowStateInitializing WorkflowState = "initializing"
// WorkflowStateTerminated means workflow is terminated manually, and it won't be started unless the spec changed.
WorkflowStateTerminated WorkflowState = "terminated"
// WorkflowStateSuspended means workflow is suspended manually, and it can be resumed.
@@ -293,6 +299,7 @@ type AppStatus struct {
// Services record the status of the application services
Services []ApplicationComponentStatus `json:"services,omitempty"`
// Deprecated
// ResourceTracker record the status of the ResourceTracker
ResourceTracker *corev1.ObjectReference `json:"resourceTracker,omitempty"`
@@ -322,6 +329,7 @@ type PolicyStatus struct {
type WorkflowStatus struct {
AppRevision string `json:"appRevision,omitempty"`
Mode WorkflowMode `json:"mode"`
Message string `json:"message,omitempty"`
Suspend bool `json:"suspend"`
Terminated bool `json:"terminated"`
@@ -346,7 +354,7 @@ type WorkflowStepPhase string
const (
// WorkflowStepPhaseSucceeded will make the controller run the next step.
WorkflowStepPhaseSucceeded WorkflowStepPhase = "succeeded"
// WorkflowStepPhaseFailed will make the controller stop the workflow and report error in `message`.
// WorkflowStepPhaseFailed will report error in `message`.
WorkflowStepPhaseFailed WorkflowStepPhase = "failed"
// WorkflowStepPhaseStopped will make the controller stop the workflow.
WorkflowStepPhaseStopped WorkflowStepPhase = "stopped"
@@ -476,6 +484,48 @@ const (
WorkflowResourceCreator ResourceCreatorRole = "workflow"
)
// OAMObjectReference defines the object reference for an oam resource
type OAMObjectReference struct {
Component string `json:"component,omitempty"`
Trait string `json:"trait,omitempty"`
Env string `json:"env,omitempty"`
}
// Equal check if two references are equal
func (in OAMObjectReference) Equal(r OAMObjectReference) bool {
return in.Component == r.Component && in.Trait == r.Trait && in.Env == r.Env
}
// AddLabelsToObject add labels to object if properties are not empty
func (in OAMObjectReference) AddLabelsToObject(obj client.Object) {
labels := obj.GetLabels()
if labels == nil {
labels = map[string]string{}
}
if in.Component != "" {
labels[oam.LabelAppComponent] = in.Component
}
if in.Trait != "" {
labels[oam.TraitTypeLabel] = in.Trait
}
if in.Env != "" {
labels[oam.LabelAppEnv] = in.Env
}
obj.SetLabels(labels)
}
// NewOAMObjectReferenceFromObject create OAMObjectReference from object
func NewOAMObjectReferenceFromObject(obj client.Object) OAMObjectReference {
if labels := obj.GetLabels(); labels != nil {
return OAMObjectReference{
Component: labels[oam.LabelAppComponent],
Trait: labels[oam.TraitTypeLabel],
Env: labels[oam.LabelAppEnv],
}
}
return OAMObjectReference{}
}
// ClusterObjectReference defines the object reference with cluster.
type ClusterObjectReference struct {
Cluster string `json:"cluster,omitempty"`

View File

@@ -0,0 +1,60 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package common
import (
"testing"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func TestOAMObjectReference(t *testing.T) {
r := require.New(t)
o1 := OAMObjectReference{
Component: "component",
Trait: "trait",
Env: "env",
}
obj := &unstructured.Unstructured{}
o2 := NewOAMObjectReferenceFromObject(obj)
r.False(o2.Equal(o1))
o1.AddLabelsToObject(obj)
r.Equal(3, len(obj.GetLabels()))
o3 := NewOAMObjectReferenceFromObject(obj)
r.True(o1.Equal(o3))
o3.Component = "comp"
r.False(o3.Equal(o1))
r.True(o1.Equal(*o1.DeepCopy()))
o4 := OAMObjectReference{}
o1.DeepCopyInto(&o4)
r.True(o4.Equal(o1))
}
func TestClusterObjectReference(t *testing.T) {
r := require.New(t)
o1 := ClusterObjectReference{
Cluster: "cluster",
ObjectReference: v1.ObjectReference{Kind: "kind"},
}
o2 := *o1.DeepCopy()
r.True(o1.Equal(o2))
o2.Cluster = "c"
r.False(o2.Equal(o1))
}

View File

@@ -407,6 +407,21 @@ func (in *KubeParameter) DeepCopy() *KubeParameter {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OAMObjectReference) DeepCopyInto(out *OAMObjectReference) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAMObjectReference.
func (in *OAMObjectReference) DeepCopy() *OAMObjectReference {
if in == nil {
return nil
}
out := new(OAMObjectReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyStatus) DeepCopyInto(out *PolicyStatus) {
*out = *in

View File

@@ -0,0 +1,27 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
const (
// ApplyOncePolicyType refers to the type of configuration drift policy
ApplyOncePolicyType = "apply-once"
)
// ApplyOncePolicySpec defines the spec of preventing configuration drift
type ApplyOncePolicySpec struct {
Enable bool `json:"enable"`
}

View File

@@ -25,9 +25,6 @@ import (
const (
// EnvBindingPolicyType refers to the type of EnvBinding
EnvBindingPolicyType = "env-binding"
// GarbageCollectPolicyType refers to the type of garbage-collect
GarbageCollectPolicyType = "garbage-collect"
)
// EnvTraitPatch is the patch to trait

View File

@@ -0,0 +1,81 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/oam-dev/kubevela/pkg/oam"
)
const (
// GarbageCollectPolicyType refers to the type of garbage-collect
GarbageCollectPolicyType = "garbage-collect"
)
// GarbageCollectPolicySpec defines the spec of configuration drift
type GarbageCollectPolicySpec struct {
// KeepLegacyResource if is set, outdated versioned resourcetracker will not be recycled automatically
// outdated resources will be kept until resourcetracker be deleted manually
KeepLegacyResource bool `json:"keepLegacyResource,omitempty"`
// Rules defines list of rules to control gc strategy at resource level
// if one resource is controlled by multiple rules, first rule will be used
Rules []GarbageCollectPolicyRule `json:"rules,omitempty"`
}
// GarbageCollectPolicyRule defines a single garbage-collect policy rule
type GarbageCollectPolicyRule struct {
Selector GarbageCollectPolicyRuleSelector `json:"selector"`
Strategy GarbageCollectStrategy `json:"strategy"`
}
// GarbageCollectPolicyRuleSelector select the targets of the rule
type GarbageCollectPolicyRuleSelector struct {
TraitTypes []string `json:"traitTypes"`
}
// GarbageCollectStrategy the strategy for target resource to recycle
type GarbageCollectStrategy string
const (
// GarbageCollectStrategyNever do not recycle target resource, leave it
GarbageCollectStrategyNever GarbageCollectStrategy = "never"
// GarbageCollectStrategyOnAppDelete do not recycle target resource until application is deleted
// this means the resource will be kept even it is not used in the latest version
GarbageCollectStrategyOnAppDelete GarbageCollectStrategy = "onAppDelete"
// GarbageCollectStrategyOnAppUpdate recycle target resource when it is not inUse
GarbageCollectStrategyOnAppUpdate GarbageCollectStrategy = "onAppUpdate"
)
// FindStrategy find gc strategy for target resource
func (in GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstructured) *GarbageCollectStrategy {
for _, rule := range in.Rules {
var traitType string
if manifest.GetLabels() != nil {
traitType = manifest.GetLabels()[oam.TraitTypeLabel]
}
if traitType != "" {
for _, _traitType := range rule.Selector.TraitTypes {
if _traitType == traitType {
return &rule.Strategy
}
}
}
}
return nil
}

View File

@@ -0,0 +1,83 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"testing"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/oam-dev/kubevela/pkg/oam"
)
func TestGarbageCollectPolicySpec_FindStrategy(t *testing.T) {
testCases := map[string]struct {
rules []GarbageCollectPolicyRule
input *unstructured.Unstructured
notFound bool
expectStrategy GarbageCollectStrategy
}{
"trait rule match": {
rules: []GarbageCollectPolicyRule{{
Selector: GarbageCollectPolicyRuleSelector{TraitTypes: []string{"a"}},
Strategy: GarbageCollectStrategyNever,
}},
input: &unstructured.Unstructured{Object: map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{oam.TraitTypeLabel: "a"},
},
}},
expectStrategy: GarbageCollectStrategyNever,
},
"trait rule mismatch": {
rules: []GarbageCollectPolicyRule{{
Selector: GarbageCollectPolicyRuleSelector{TraitTypes: []string{"a"}},
Strategy: GarbageCollectStrategyNever,
}},
input: &unstructured.Unstructured{Object: map[string]interface{}{}},
notFound: true,
},
"trait rule multiple match": {
rules: []GarbageCollectPolicyRule{{
Selector: GarbageCollectPolicyRuleSelector{TraitTypes: []string{"a"}},
Strategy: GarbageCollectStrategyOnAppDelete,
}, {
Selector: GarbageCollectPolicyRuleSelector{TraitTypes: []string{"a"}},
Strategy: GarbageCollectStrategyNever,
}},
input: &unstructured.Unstructured{Object: map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{oam.TraitTypeLabel: "a"},
},
}},
expectStrategy: GarbageCollectStrategyOnAppDelete,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
r := require.New(t)
spec := GarbageCollectPolicySpec{Rules: tc.rules}
strategy := spec.FindStrategy(tc.input)
if tc.notFound {
r.Nil(strategy)
} else {
r.Equal(tc.expectStrategy, *strategy)
}
})
}
}

View File

@@ -26,6 +26,21 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ApplyOncePolicySpec) DeepCopyInto(out *ApplyOncePolicySpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplyOncePolicySpec.
func (in *ApplyOncePolicySpec) DeepCopy() *ApplyOncePolicySpec {
if in == nil {
return nil
}
out := new(ApplyOncePolicySpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterConnection) DeepCopyInto(out *ClusterConnection) {
*out = *in
@@ -246,6 +261,64 @@ func (in *EnvTraitPatch) DeepCopy() *EnvTraitPatch {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GarbageCollectPolicyRule) DeepCopyInto(out *GarbageCollectPolicyRule) {
*out = *in
in.Selector.DeepCopyInto(&out.Selector)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GarbageCollectPolicyRule.
func (in *GarbageCollectPolicyRule) DeepCopy() *GarbageCollectPolicyRule {
if in == nil {
return nil
}
out := new(GarbageCollectPolicyRule)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GarbageCollectPolicyRuleSelector) DeepCopyInto(out *GarbageCollectPolicyRuleSelector) {
*out = *in
if in.TraitTypes != nil {
in, out := &in.TraitTypes, &out.TraitTypes
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GarbageCollectPolicyRuleSelector.
func (in *GarbageCollectPolicyRuleSelector) DeepCopy() *GarbageCollectPolicyRuleSelector {
if in == nil {
return nil
}
out := new(GarbageCollectPolicyRuleSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GarbageCollectPolicySpec) DeepCopyInto(out *GarbageCollectPolicySpec) {
*out = *in
if in.Rules != nil {
in, out := &in.Rules, &out.Rules
*out = make([]GarbageCollectPolicyRule, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GarbageCollectPolicySpec.
func (in *GarbageCollectPolicySpec) DeepCopy() *GarbageCollectPolicySpec {
if in == nil {
return nil
}
out := new(GarbageCollectPolicySpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NamespaceSelector) DeepCopyInto(out *NamespaceSelector) {
*out = *in

View File

@@ -1,146 +0,0 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/interfaces"
"github.com/oam-dev/kubevela/pkg/oam"
)
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// An ResourceTracker represents a tracker for track cross namespace resources
// +kubebuilder:resource:scope=Cluster,categories={oam},shortName=tracker
type ResourceTracker struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Status ResourceTrackerStatus `json:"status,omitempty"`
}
// ResourceTrackerStatus define the status of resourceTracker
type ResourceTrackerStatus struct {
TrackedResources []common.ClusterObjectReference `json:"trackedResources,omitempty"`
}
// +kubebuilder:object:root=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ResourceTrackerList contains a list of ResourceTracker
type ResourceTrackerList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ResourceTracker `json:"items"`
}
// ToOwnerReference convert ResourceTracker into owner reference for other resource to refer
func (in *ResourceTracker) ToOwnerReference() *metav1.OwnerReference {
return &metav1.OwnerReference{
APIVersion: SchemeGroupVersion.String(),
Kind: ResourceTrackerKind,
Name: in.Name,
UID: in.UID,
Controller: pointer.BoolPtr(true),
BlockOwnerDeletion: pointer.BoolPtr(true),
}
}
// AddOwnerReferenceToTrackerResource add resourcetracker as owner reference to target object, return true if already exists (outdated)
func (in *ResourceTracker) AddOwnerReferenceToTrackerResource(rsc interfaces.ObjectOwner) bool {
ownerRefs := []metav1.OwnerReference{*in.ToOwnerReference()}
exists := false
for _, owner := range rsc.GetOwnerReferences() {
// delete the old resourceTracker owner
if owner.Kind == ResourceTrackerKind && owner.APIVersion == SchemeGroupVersion.String() {
exists = true
continue
}
if owner.Controller != nil && *owner.Controller && owner.UID != in.UID {
owner.Controller = pointer.BoolPtr(false)
}
ownerRefs = append(ownerRefs, owner)
}
rsc.SetOwnerReferences(ownerRefs)
return exists
}
func (in *ResourceTracker) addClusterObjectReference(ref common.ClusterObjectReference) bool {
for _, _rsc := range in.Status.TrackedResources {
if _rsc.Equal(ref) {
return true
}
}
in.Status.TrackedResources = append(in.Status.TrackedResources, ref)
return false
}
// AddTrackedResource add new object reference into tracked resources, return if already exists
func (in *ResourceTracker) AddTrackedResource(rsc interfaces.TrackableResource) bool {
return in.addClusterObjectReference(common.ClusterObjectReference{
ObjectReference: v1.ObjectReference{
APIVersion: rsc.GetAPIVersion(),
Kind: rsc.GetKind(),
Name: rsc.GetName(),
Namespace: rsc.GetNamespace(),
UID: rsc.GetUID(),
},
})
}
// AddTrackedCluster add resourcetracker in remote cluster into tracked resources, return if already exists
func (in *ResourceTracker) AddTrackedCluster(clusterName string) bool {
if clusterName == "" {
return true
}
return in.addClusterObjectReference(common.ClusterObjectReference{
Cluster: clusterName,
ObjectReference: v1.ObjectReference{
APIVersion: SchemeGroupVersion.String(),
Kind: ResourceTrackerKind,
Name: in.GetName(),
},
})
}
// GetTrackedClusters return remote clusters recorded in the resource tracker
func (in *ResourceTracker) GetTrackedClusters() (clusters []string) {
for _, ref := range in.Status.TrackedResources {
if ref.APIVersion == SchemeGroupVersion.String() && ref.Kind == ResourceTrackerKind && ref.Name == in.Name && ref.Cluster != "" {
clusters = append(clusters, ref.Cluster)
}
}
return
}
// IsLifeLong check if resourcetracker shares the same whole life with the entire application
func (in *ResourceTracker) IsLifeLong() bool {
_, ok := in.GetAnnotations()[oam.AnnotationResourceTrackerLifeLong]
return ok
}
// SetLifeLong set life long to resource tracker
func (in *ResourceTracker) SetLifeLong() {
in.SetAnnotations(map[string]string{oam.AnnotationResourceTrackerLifeLong: "true"})
}

View File

@@ -0,0 +1,270 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
"encoding/json"
"reflect"
"strings"
errors2 "github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/interfaces"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/utils/errors"
)
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// An ResourceTracker represents a tracker for track cross namespace resources
// +kubebuilder:printcolumn:name="TYPE",type=string,JSONPath=`.spec.type`
// +kubebuilder:printcolumn:name="APP",type=string,JSONPath=`.metadata.labels['app\.oam\.dev\/name']`
// +kubebuilder:printcolumn:name="APP-NS",type=string,JSONPath=`.metadata.labels['app\.oam\.dev\/namespace']`
// +kubebuilder:printcolumn:name="APP-GEN",type=number,JSONPath=`.spec.applicationGeneration`
// +kubebuilder:resource:scope=Cluster,categories={oam},shortName=rt
type ResourceTracker struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ResourceTrackerSpec `json:"spec,omitempty"`
Status ResourceTrackerStatus `json:"status,omitempty"`
}
// ResourceTrackerType defines the type of resourceTracker
type ResourceTrackerType string
const (
// ResourceTrackerTypeRoot means resources in this resourceTracker will only be recycled when application is deleted
ResourceTrackerTypeRoot = ResourceTrackerType("root")
// ResourceTrackerTypeVersioned means resources in this resourceTracker will be recycled when this version is unused and this resource is not managed by latest RT
ResourceTrackerTypeVersioned = ResourceTrackerType("versioned")
// ResourceTrackerTypeComponentRevision stores all component revisions used
ResourceTrackerTypeComponentRevision = ResourceTrackerType("component-revision")
)
// ResourceTrackerSpec define the spec of resourceTracker
type ResourceTrackerSpec struct {
Type ResourceTrackerType `json:"type,omitempty"`
ApplicationGeneration int64 `json:"applicationGeneration"`
ManagedResources []ManagedResource `json:"managedResources,omitempty"`
}
// ManagedResource define the resource to be managed by ResourceTracker
type ManagedResource struct {
common.ClusterObjectReference `json:",inline"`
common.OAMObjectReference `json:",inline"`
// +kubebuilder:pruning:PreserveUnknownFields
Data *runtime.RawExtension `json:"raw,omitempty"`
// Deleted marks the resource to be deleted
Deleted bool `json:"deleted,omitempty"`
}
// Equal check if two managed resource equals
func (in ManagedResource) Equal(r ManagedResource) bool {
if !in.ClusterObjectReference.Equal(r.ClusterObjectReference) {
return false
}
if !in.OAMObjectReference.Equal(r.OAMObjectReference) {
return false
}
return reflect.DeepEqual(in.Data, r.Data)
}
// DisplayName readable name for locating resource
func (in ManagedResource) DisplayName() string {
s := in.Kind + " " + in.Name
if in.Namespace != "" || in.Cluster != "" {
s += " ("
if in.Cluster != "" {
s += "Cluster: " + in.Cluster
if in.Namespace != "" {
s += ", "
}
}
if in.Namespace != "" {
s += "Namespace: " + in.Namespace
}
s += ")"
}
return s
}
// NamespacedName namespacedName
func (in ManagedResource) NamespacedName() types.NamespacedName {
return types.NamespacedName{Namespace: in.Namespace, Name: in.Name}
}
// ResourceKey computes the key for managed resource, resources with the same key points to the same resource
func (in ManagedResource) ResourceKey() string {
gv, kind := in.GroupVersionKind().ToAPIVersionAndKind()
return strings.Join([]string{gv, kind, in.Cluster, in.Namespace, in.Name}, "/")
}
// ComponentKey computes the key for the component which managed resource belongs to
func (in ManagedResource) ComponentKey() string {
return strings.Join([]string{in.Env, in.Component}, "/")
}
// UnmarshalTo unmarshal ManagedResource into target object
func (in ManagedResource) UnmarshalTo(obj interface{}) error {
if in.Data == nil || in.Data.Raw == nil {
return errors.ManagedResourceHasNoDataError{}
}
return json.Unmarshal(in.Data.Raw, obj)
}
// ToUnstructured converts managed resource into unstructured
func (in ManagedResource) ToUnstructured() *unstructured.Unstructured {
obj := &unstructured.Unstructured{}
obj.SetGroupVersionKind(in.GroupVersionKind())
obj.SetName(in.Name)
if in.Namespace != "" {
obj.SetNamespace(in.Namespace)
}
oam.SetCluster(obj, in.Cluster)
return obj
}
// ToUnstructuredWithData converts managed resource into unstructured and unmarshal data
func (in ManagedResource) ToUnstructuredWithData() (*unstructured.Unstructured, error) {
obj := in.ToUnstructured()
if err := in.UnmarshalTo(obj); err != nil {
if errors2.Is(err, errors.ManagedResourceHasNoDataError{}) {
return nil, err
}
}
return obj, nil
}
// ResourceTrackerStatus define the status of resourceTracker
// For backward-compatibility
type ResourceTrackerStatus struct {
// Deprecated
TrackedResources []common.ClusterObjectReference `json:"trackedResources,omitempty"`
}
// +kubebuilder:object:root=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ResourceTrackerList contains a list of ResourceTracker
type ResourceTrackerList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ResourceTracker `json:"items"`
}
func (in *ResourceTracker) findMangedResourceIndex(mr ManagedResource) int {
for i, _mr := range in.Spec.ManagedResources {
if mr.ClusterObjectReference.Equal(_mr.ClusterObjectReference) {
return i
}
}
return -1
}
// AddManagedResource add object to managed resources, if exists, update
func (in *ResourceTracker) AddManagedResource(rsc client.Object, metaOnly bool) {
gvk := rsc.GetObjectKind().GroupVersionKind()
mr := ManagedResource{
ClusterObjectReference: common.ClusterObjectReference{
ObjectReference: v1.ObjectReference{
APIVersion: gvk.GroupVersion().String(),
Kind: gvk.Kind,
Name: rsc.GetName(),
Namespace: rsc.GetNamespace(),
},
Cluster: oam.GetCluster(rsc),
},
OAMObjectReference: common.NewOAMObjectReferenceFromObject(rsc),
Deleted: false,
}
if !metaOnly {
mr.Data = &runtime.RawExtension{Object: rsc}
}
if idx := in.findMangedResourceIndex(mr); idx >= 0 {
in.Spec.ManagedResources[idx] = mr
} else {
in.Spec.ManagedResources = append(in.Spec.ManagedResources, mr)
}
}
// DeleteManagedResource if remove flag is on, it will remove the object from recorded resources.
// otherwise, it will mark the object as deleted instead of removing it
// workflow stage: resources are marked as deleted (and execute the deletion action)
// state-keep stage: resources marked as deleted and successfully deleted will be removed from resourcetracker
func (in *ResourceTracker) DeleteManagedResource(rsc client.Object, remove bool) {
gvk := rsc.GetObjectKind().GroupVersionKind()
mr := ManagedResource{
ClusterObjectReference: common.ClusterObjectReference{
ObjectReference: v1.ObjectReference{
APIVersion: gvk.GroupVersion().String(),
Kind: gvk.Kind,
Name: rsc.GetName(),
Namespace: rsc.GetNamespace(),
},
Cluster: oam.GetCluster(rsc),
},
Deleted: true,
}
if idx := in.findMangedResourceIndex(mr); idx >= 0 {
if remove {
in.Spec.ManagedResources = append(in.Spec.ManagedResources[:idx], in.Spec.ManagedResources[idx+1:]...)
} else {
in.Spec.ManagedResources[idx] = mr
}
} else {
if !remove {
in.Spec.ManagedResources = append(in.Spec.ManagedResources, mr)
}
}
}
// addClusterObjectReference
// Deprecated
func (in *ResourceTracker) addClusterObjectReference(ref common.ClusterObjectReference) bool {
for _, _rsc := range in.Status.TrackedResources {
if _rsc.Equal(ref) {
return true
}
}
in.Status.TrackedResources = append(in.Status.TrackedResources, ref)
return false
}
// AddTrackedResource add new object reference into tracked resources, return if already exists
// Deprecated
func (in *ResourceTracker) AddTrackedResource(rsc interfaces.TrackableResource) bool {
return in.addClusterObjectReference(common.ClusterObjectReference{
ObjectReference: v1.ObjectReference{
APIVersion: rsc.GetAPIVersion(),
Kind: rsc.GetKind(),
Name: rsc.GetName(),
Namespace: rsc.GetNamespace(),
UID: rsc.GetUID(),
},
})
}

View File

@@ -0,0 +1,184 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
v12 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
v13 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/utils/errors"
)
func TestManagedResource_DeepCopyEqual(t *testing.T) {
r := require.New(t)
mr := ManagedResource{
ClusterObjectReference: common.ClusterObjectReference{Cluster: "cluster"},
OAMObjectReference: common.OAMObjectReference{Component: "component"},
Data: &runtime.RawExtension{Raw: []byte("data")},
}
r.True(mr.Equal(*mr.DeepCopy()))
}
func TestManagedResource_Equal(t *testing.T) {
testCases := map[string]struct {
input1 ManagedResource
input2 ManagedResource
equal bool
}{
"equal": {
input1: ManagedResource{
ClusterObjectReference: common.ClusterObjectReference{Cluster: "cluster"},
OAMObjectReference: common.OAMObjectReference{Component: "component"},
Data: &runtime.RawExtension{Raw: []byte("data")},
},
input2: ManagedResource{
ClusterObjectReference: common.ClusterObjectReference{Cluster: "cluster"},
OAMObjectReference: common.OAMObjectReference{Component: "component"},
Data: &runtime.RawExtension{Raw: []byte("data")},
},
equal: true,
},
"ClusterObjectReference not equal": {
input1: ManagedResource{
ClusterObjectReference: common.ClusterObjectReference{Cluster: "cluster"},
},
input2: ManagedResource{
ClusterObjectReference: common.ClusterObjectReference{Cluster: "c"},
},
equal: false,
},
"OAMObjectReference not equal": {
input1: ManagedResource{
OAMObjectReference: common.OAMObjectReference{Component: "component"},
},
input2: ManagedResource{
OAMObjectReference: common.OAMObjectReference{Component: "c"},
},
equal: false,
},
"Data content not equal": {
input1: ManagedResource{
Data: &runtime.RawExtension{Raw: []byte("data")},
},
input2: ManagedResource{
Data: &runtime.RawExtension{Raw: []byte("d")},
},
equal: false,
},
"one data empty, one data not empty": {
input1: ManagedResource{Data: nil},
input2: ManagedResource{
Data: &runtime.RawExtension{Raw: []byte("d")},
},
equal: false,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
r := require.New(t)
r.Equal(tc.equal, tc.input1.Equal(tc.input2))
r.Equal(tc.equal, tc.input2.Equal(tc.input1))
})
}
}
func TestManagedResourceKeys(t *testing.T) {
r := require.New(t)
input := ManagedResource{
ClusterObjectReference: common.ClusterObjectReference{
Cluster: "cluster",
ObjectReference: v1.ObjectReference{
Namespace: "namespace",
Name: "name",
APIVersion: v12.SchemeGroupVersion.String(),
Kind: "Deployment",
},
},
OAMObjectReference: common.OAMObjectReference{
Env: "env",
Component: "component",
Trait: "trait",
},
}
r.Equal("namespace/name", input.NamespacedName().String())
r.Equal("apps/v1/Deployment/cluster/namespace/name", input.ResourceKey())
r.Equal("env/component", input.ComponentKey())
r.Equal("Deployment name (Cluster: cluster, Namespace: namespace)", input.DisplayName())
var deploy1, deploy2 v12.Deployment
deploy1.Spec.Replicas = pointer.Int32(5)
bs, err := json.Marshal(deploy1)
r.NoError(err)
r.ErrorIs(input.UnmarshalTo(&deploy2), errors.ManagedResourceHasNoDataError{})
_, err = input.ToUnstructuredWithData()
r.ErrorIs(err, errors.ManagedResourceHasNoDataError{})
input.Data = &runtime.RawExtension{Raw: bs}
r.NoError(input.UnmarshalTo(&deploy2))
r.Equal(deploy1, deploy2)
obj := input.ToUnstructured()
r.Equal("Deployment", obj.GetKind())
r.Equal("apps/v1", obj.GetAPIVersion())
r.Equal("name", obj.GetName())
r.Equal("namespace", obj.GetNamespace())
r.Equal("cluster", oam.GetCluster(obj))
obj, err = input.ToUnstructuredWithData()
r.NoError(err)
val, correct, err := unstructured.NestedInt64(obj.Object, "spec", "replicas")
r.NoError(err)
r.True(correct)
r.Equal(int64(5), val)
}
func TestResourceTracker_ManagedResource(t *testing.T) {
r := require.New(t)
input := &ResourceTracker{}
deploy1 := v12.Deployment{ObjectMeta: v13.ObjectMeta{Name: "deploy1"}}
input.AddManagedResource(&deploy1, true)
r.Equal(1, len(input.Spec.ManagedResources))
cm2 := v1.ConfigMap{ObjectMeta: v13.ObjectMeta{Name: "cm2"}}
input.AddManagedResource(&cm2, false)
r.Equal(2, len(input.Spec.ManagedResources))
pod3 := v1.Pod{ObjectMeta: v13.ObjectMeta{Name: "pod3"}}
input.AddManagedResource(&pod3, false)
r.Equal(3, len(input.Spec.ManagedResources))
deploy1.Spec.Replicas = pointer.Int32(5)
input.AddManagedResource(&deploy1, false)
r.Equal(3, len(input.Spec.ManagedResources))
input.DeleteManagedResource(&cm2, false)
r.Equal(3, len(input.Spec.ManagedResources))
r.True(input.Spec.ManagedResources[1].Deleted)
input.DeleteManagedResource(&cm2, true)
r.Equal(2, len(input.Spec.ManagedResources))
input.DeleteManagedResource(&deploy1, true)
r.Equal(1, len(input.Spec.ManagedResources))
input.DeleteManagedResource(&pod3, true)
r.Equal(0, len(input.Spec.ManagedResources))
secret4 := v1.Secret{ObjectMeta: v13.ObjectMeta{Name: "secret4"}}
input.DeleteManagedResource(&secret4, true)
r.Equal(0, len(input.Spec.ManagedResources))
input.DeleteManagedResource(&secret4, false)
r.Equal(1, len(input.Spec.ManagedResources))
}

View File

@@ -855,6 +855,28 @@ func (in *LocalSecretReference) DeepCopy() *LocalSecretReference {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ManagedResource) DeepCopyInto(out *ManagedResource) {
*out = *in
out.ClusterObjectReference = in.ClusterObjectReference
out.OAMObjectReference = in.OAMObjectReference
if in.Data != nil {
in, out := &in.Data, &out.Data
*out = new(runtime.RawExtension)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedResource.
func (in *ManagedResource) DeepCopy() *ManagedResource {
if in == nil {
return nil
}
out := new(ManagedResource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PlacementStatus) DeepCopyInto(out *PlacementStatus) {
*out = *in
@@ -981,6 +1003,7 @@ func (in *ResourceTracker) DeepCopyInto(out *ResourceTracker) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
@@ -1034,6 +1057,28 @@ func (in *ResourceTrackerList) DeepCopyObject() runtime.Object {
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceTrackerSpec) DeepCopyInto(out *ResourceTrackerSpec) {
*out = *in
if in.ManagedResources != nil {
in, out := &in.ManagedResources, &out.ManagedResources
*out = make([]ManagedResource, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceTrackerSpec.
func (in *ResourceTrackerSpec) DeepCopy() *ResourceTrackerSpec {
if in == nil {
return nil
}
out := new(ResourceTrackerSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceTrackerStatus) DeepCopyInto(out *ResourceTrackerStatus) {
*out = *in

View File

@@ -20,13 +20,10 @@ import (
"encoding/json"
"cuelang.org/go/cue"
"github.com/getkin/kin-openapi/openapi3"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/runtime"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils"
)
// Source record the source of Capability
@@ -187,51 +184,3 @@ type Capability struct {
KubeTemplate runtime.RawExtension `json:"kubetemplate,omitempty"`
KubeParameter []common.KubeParameter `json:"kubeparameter,omitempty"`
}
// Addon contains all information represent an addon
type Addon struct {
AddonMeta
APISchema *openapi3.Schema `json:"schema"`
UISchema []*utils.UIParameter `json:"uiSchema"`
// More details about the addon, e.g. README
Detail string `json:"detail,omitempty"`
Definitions []AddonElementFile `json:"definitions"`
Parameters string `json:"parameters"`
CUETemplates []AddonElementFile `json:"cue_templates"`
YAMLTemplates []AddonElementFile `json:"yaml_templates,omitempty"`
DefSchemas []AddonElementFile `json:"def_schemas,omitempty"`
AppTemplate *v1beta1.Application `json:"app_template"`
}
// AddonMeta defines the format for a single addon
type AddonMeta struct {
Name string `json:"name" validate:"required"`
Version string `json:"version"`
Description string `json:"description"`
Icon string `json:"icon"`
URL string `json:"url,omitempty"`
Tags []string `json:"tags,omitempty"`
DeployTo *AddonDeployTo `json:"deployTo,omitempty"`
Dependencies []*AddonDependency `json:"dependencies,omitempty"`
NeedNamespace []string `json:"needNamespace,omitempty"`
Invisible bool `json:"invisible"`
}
// AddonDeployTo defines where the addon to deploy to
type AddonDeployTo struct {
ControlPlane bool `json:"control_plane"`
RuntimeCluster bool `json:"runtime_cluster"`
}
// AddonDependency defines the other addons it depends on
type AddonDependency struct {
Name string `json:"name,omitempty"`
}
// AddonElementFile can be addon's definition or addon's component
type AddonElementFile struct {
Data string
Name string
}

View File

@@ -18,13 +18,14 @@ package types
// reason for Application
const (
ReasonParsed = "Parsed"
ReasonRendered = "Rendered"
ReasonRevisoned = "Revisioned"
ReasonApplied = "Applied"
ReasonHealthCheck = "HealthChecked"
ReasonDeployed = "Deployed"
ReasonRollout = "Rollout"
ReasonParsed = "Parsed"
ReasonRendered = "Rendered"
ReasonPolicyGenerated = "PolicyGenerated"
ReasonRevisoned = "Revisioned"
ReasonApplied = "Applied"
ReasonHealthCheck = "HealthChecked"
ReasonDeployed = "Deployed"
ReasonRollout = "Rollout"
ReasonFailedParse = "FailedParse"
ReasonFailedRender = "FailedRender"
@@ -32,6 +33,7 @@ const (
ReasonFailedWorkflow = "FailedWorkflow"
ReasonFailedApply = "FailedApply"
ReasonFailedHealthCheck = "FailedHealthCheck"
ReasonFailedStateKeep = "FailedStateKeep"
ReasonFailedGC = "FailedGC"
ReasonFailedRollout = "FailedRollout"
)
@@ -40,6 +42,7 @@ const (
const (
MessageParsed = "Parsed successfully"
MessageRendered = "Rendered successfully"
MessagePolicyGenerated = "Policy generated successfully"
MessageRevisioned = "Revisioned successfully"
MessageApplied = "Applied successfully"
MessageWorkflowFinished = "Workflow finished"

View File

@@ -640,7 +640,8 @@ spec:
type: object
type: array
resourceTracker:
description: ResourceTracker record the status of the ResourceTracker
description: Deprecated ResourceTracker record the status
of the ResourceTracker
properties:
apiVersion:
description: API version of the referent.
@@ -985,6 +986,8 @@ spec:
type: object
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
@@ -2897,7 +2900,8 @@ spec:
type: object
type: array
resourceTracker:
description: ResourceTracker record the status of the ResourceTracker
description: Deprecated ResourceTracker record the status
of the ResourceTracker
properties:
apiVersion:
description: API version of the referent.
@@ -3242,6 +3246,8 @@ spec:
type: object
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string

View File

@@ -461,7 +461,7 @@ spec:
type: object
type: array
resourceTracker:
description: ResourceTracker record the status of the ResourceTracker
description: Deprecated ResourceTracker record the status of the ResourceTracker
properties:
apiVersion:
description: API version of the referent.
@@ -667,6 +667,8 @@ spec:
type: object
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
@@ -1285,7 +1287,7 @@ spec:
type: object
type: array
resourceTracker:
description: ResourceTracker record the status of the ResourceTracker
description: Deprecated ResourceTracker record the status of the ResourceTracker
properties:
apiVersion:
description: API version of the referent.
@@ -1491,6 +1493,8 @@ spec:
type: object
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string

View File

@@ -15,11 +15,24 @@ spec:
listKind: ResourceTrackerList
plural: resourcetrackers
shortNames:
- tracker
- rt
singular: resourcetracker
scope: Cluster
versions:
- name: v1beta1
- additionalPrinterColumns:
- jsonPath: .spec.type
name: TYPE
type: string
- jsonPath: .metadata.labels['app\.oam\.dev\/name']
name: APP
type: string
- jsonPath: .metadata.labels['app\.oam\.dev\/namespace']
name: APP-NS
type: string
- jsonPath: .spec.applicationGeneration
name: APP-GEN
type: number
name: v1beta1
schema:
openAPIV3Schema:
description: An ResourceTracker represents a tracker for track cross namespace
@@ -37,10 +50,80 @@ spec:
type: string
metadata:
type: object
spec:
description: ResourceTrackerSpec define the spec of resourceTracker
properties:
applicationGeneration:
format: int64
type: integer
managedResources:
items:
description: ManagedResource define the resource to be managed by
ResourceTracker
properties:
apiVersion:
description: API version of the referent.
type: string
cluster:
type: string
component:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
deleted:
description: Deleted marks the resource to be deleted
type: boolean
env:
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
an entire object, this string should contain a valid JSON/Go
field access statement, such as desiredState.manifest.containers[2].
For example, if the object reference is to a container within
a pod, this would take on a value like: "spec.containers{name}"
(where "name" refers to the name of the container that triggered
the event) or if no container name is specified "spec.containers[2]"
(container with index 2 in this pod). This syntax is chosen
only to have some well-defined way of referencing a part of
an object. TODO: this design is not final and this field is
subject to change in the future.'
type: string
kind:
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
namespace:
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
type: string
raw:
type: object
x-kubernetes-preserve-unknown-fields: true
resourceVersion:
description: 'Specific resourceVersion to which this reference
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
type: string
trait:
type: string
uid:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
type: array
type:
description: ResourceTrackerType defines the type of resourceTracker
type: string
required:
- applicationGeneration
type: object
status:
description: ResourceTrackerStatus define the status of resourceTracker
For backward-compatibility
properties:
trackedResources:
description: Deprecated
items:
description: ClusterObjectReference defines the object reference
with cluster.

View File

@@ -9,7 +9,8 @@ data:
"name": "KubeVela",
"oss": {
"end_point": "https://addons.kubevela.net",
"bucket": ""
"bucket": "",
"path": ""
}
}
}'

File diff suppressed because it is too large Load Diff

View File

@@ -1,261 +0,0 @@
apiVersion: v1
data:
application: |
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
annotations:
addons.oam.dev/description: istio Controller is a Kubernetes Controller for manage
traffic.
name: istio
namespace: vela-system
spec:
components:
- name: ns-istio-system
properties:
apiVersion: v1
kind: Namespace
metadata:
name: istio-system
type: raw
- name: istio
properties:
chart: istio
repoType: helm
url: https://charts.kubevela.net/addons
version: 1.11.1
type: helm
- name: canary-rollout
properties:
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
name: canary-rollout
namespace: vela-system
spec:
schematic:
cue:
template: |-
import ("vela/op")
parameter: {
batchPartition: int
traffic: weightedTargets: [...{
revision: string
weight: int
}]
}
comps__: op.#Load
compNames__: [ for name, c in comps__.value {name}]
comp__: compNames__[0]
apply: op.#ApplyComponent & {
value: comps__.value[comp__]
patch: {
traits: "rollout": {
spec: rolloutPlan: batchPartition: parameter.batchPartition
}
traits: "virtualService": {
spec:
// +patchStrategy=retainKeys
http: [
{
route: [
for i, t in parameter.traffic.weightedTargets {
destination: {
host: comp__
subset: t.revision
}
weight: t.weight
}]
},
]
}
traits: "destinationRule": {
// +patchStrategy=retainKeys
spec: {
host: comp__
subsets: [
for i, t in parameter.traffic.weightedTargets {
name: t.revision
labels: {"app.oam.dev/revision": t.revision}
},
]}
}
}
}
applyRemaining: op.#ApplyRemaining & {
exceptions: [comp__]
}
type: raw
- name: istio-gateway
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: use istio to manage in-cluster traffic
name: istio-gateway
namespace: vela-system
spec:
appliesToWorkloads:
- deployments.apps
podDisruptive: true
schematic:
cue:
template: "\noutputs: gateway: {\n apiVersion: \"networking.istio.io/v1alpha3\"\n
\ kind: \"Gateway\"\n metadata: {\n name: context.name\n
\ namespace: context.namespace\n }\n spec: {\n selector:
{\n istio: parameter.gateway\n }\n servers: [{\n hosts:
parameter.hosts\n port: {\n name: \"http\"\n number:
80\n protocol: \"HTTP\"\n }\n }]\n }\n}\n\noutputs:
virtualService: {\n apiVersion: \"networking.istio.io/v1alpha3\"\n
\ kind: \"VirtualService\"\n metadata: {\n name: context.name\n
\ namespace: context.namespace\n }\n spec: {\n gateways:
[context.name]\n hosts: parameter.hosts\n http:[{\n match:
[ for i, u in parameter.match { uri: u} ]\n route: [{destination:
{\n host: context.name\n port: number: parameter.port\n
\ }}]\n }]\n }\n}\n\nparameter: {\n hosts: [string]\n
\ gateway: *\"ingressgateway\"|string\n match: [...#uri]\n port:
int\n}\n\n#uri: {\n exact?: string\n prefix?: string\n} \n"
type: raw
- name: canary-rollback
properties:
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
name: canary-rollback
namespace: vela-system
spec:
schematic:
cue:
template: |-
import ("vela/op")
parameter: {...}
comps: op.#Load
compNames: [ for name, c in comps.value {name}]
firstcomp: compNames[0]
rolloutObj: op.#Read & {
value: {
apiVersion: "standard.oam.dev/v1alpha1"
kind: "Rollout"
metadata: {
name: firstcomp
namespace: context.namespace
}
}
}
_sourceRevision: rolloutObj.value.status.LastSourceRevision
apply: op.#ApplyComponent & {
value: comps.value[firstcomp]
patch: {
traits: "rollout": {
spec: {
targetRevisionName: _sourceRevision
}
}
traits: "virtualService": {
spec:
// +patchStrategy=retainKeys
http: [
{
route: [{
destination: {
host: firstcomp
subset: _sourceRevision
}
weight: 100
}]
},
]
}
traits: "destinationRule": {
// +patchStrategy=retainKeys
spec: {
host: firstcomp
subsets: [
{
name: _sourceRevision
labels: {"app.oam.dev/revision": _sourceRevision}
},
]
}
}
}
}
applyRemaining: op.#ApplyRemaining & {
exceptions: [firstcomp]
}
type: raw
- name: canary-traffic
properties:
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: use istio to manage traffic
name: canary-traffic
namespace: vela-system
spec:
appliesToWorkloads:
- deployments.apps
podDisruptive: true
schematic:
cue:
template: "outputs: service: {\n\t\tapiVersion: \"v1\"\n\t\tkind: \"Service\"\n\t\tmetadata:
name: context.name\n\t\tspec: {\n\t\t\tselector: \"app.oam.dev/component\":
context.name\n\t\t\tports: [\n\t\t\t\tfor p in parameter.port {\n\t\t\t\t\tport:
\ p\n\t\t\t\t\ttargetPort: p\n\t\t\t\t},\n\t\t\t]\n\t\t\ttype:
\"ClusterIP\"\n\t\t}\n}\n\noutputs: virtualService: {\n apiVersion:
\"networking.istio.io/v1alpha3\"\n kind: \"VirtualService\"\n metadata:
{\n name: context.name\n namespace: context.namespace\n
\ }\n spec: {\n hosts: [context.name]\n http: [{route:
[\n {destination: {\n host: context.name\n port:
{number: parameter.port[0]}\n }}]}]\n }\n}\n\noutputs: destinationRule:
{\n apiVersion: \"networking.istio.io/v1alpha3\"\n kind:
\"DestinationRule\"\n metadata: {\n name: context.name\n
\ namespace: context.namespace\n }\n spec: {\n
\ host: context.name\n subsets: [{\n name:
context.revision\n labels: {\"app.oam.dev/revision\": context.revision}\n
\ }]\n }\n}\n\nparameter: {\n port: [int]\n} \n"
type: raw
workflow:
steps:
- name: checking-depends-on
properties:
name: fluxcd
namespace: vela-system
type: depends-on-app
- name: apply-ns
properties:
component: ns-istio-system
type: apply-component
- name: apply-resources
type: apply-remaining
status: {}
detail: |-
# istio
This addon provides istio support for vela rollout.
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: istio Controller is a Kubernetes Controller for manage
traffic.
addons.oam.dev/name: istio
labels:
addons.oam.dev/type: istio
name: istio
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -1,186 +0,0 @@
apiVersion: v1
data:
application: |
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
annotations:
addons.oam.dev/description: Kruise is a Kubernetes extended suite for application
automations
name: kruise
namespace: vela-system
spec:
components:
- name: kruise
properties:
chart: ./charts/kruise/v0.9.0
git:
branch: master
repoType: git
url: https://github.com/openkruise/kruise
values:
featureGates: PreDownloadImageForInPlaceUpdate=true
type: helm
- name: cloneset
properties:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Describes long-running, scalable, containerized
services that have a stable network endpoint to receive external network
traffic from customers. If workload type is skipped for any service defined
in Appfile, it will be defaulted to `webservice` type.
name: cloneset
namespace: vela-system
spec:
schematic:
cue:
template: "output: {\n\tapiVersion: \"apps.kruise.io/v1alpha1\"\n\tkind:
\ \"CloneSet\"\n\tmetadata: labels: {\n\t\t\"app.oam.dev/component\":
context.name\n\t}\n\tspec: {\n\t\tselector: matchLabels: {\n\t\t\t\"app.oam.dev/component\":
context.name\n\t\t}\n\n\t\ttemplate: {\n\t\t\tmetadata: labels: {\n\t\t\t\t\"app.oam.dev/component\":
context.name\n\t\t\t}\n\n\t\t\tspec: {\n\t\t\t\tcontainers: [{\n\t\t\t\t\tname:
\ context.name\n\t\t\t\t\timage: parameter.image\n\n\t\t\t\t\tif parameter.cmd
!= _|_ {\n\t\t\t\t\t\tcommand: parameter.cmd\n\t\t\t\t\t}\n\t\t\t\t\tif
parameter.args != _|_ {\n\t\t\t\t\t\targs: parameter.args\n\t\t\t\t\t}\n\t\t\t\t\tif
parameter.env != _|_ {\n\t\t\t\t\t\tenv: parameter.env\n\t\t\t\t\t}\n\n\t\t\t\t\tif
context.config != _|_ {\n\t\t\t\t\t\tenv: context.config\n\t\t\t\t\t}\n\n\t\t\t\t\tif
parameter[\"imagePullPolicy\"] != _|_ {\n\t\t\t\t\t\timagePullPolicy:
parameter.imagePullPolicy\n\t\t\t\t\t}\n\n\t\t\t\t\tports: [{\n\t\t\t\t\t\tcontainerPort:
parameter.port\n\t\t\t\t\t}]\n\n\t\t\t\t\tif parameter[\"cpu\"] != _|_
{\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits: cpu: parameter.cpu\n\t\t\t\t\t\t\trequests:
cpu: parameter.cpu\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif parameter[\"memory\"]
!= _|_ {\n\t\t\t\t\t\tresources: {\n\t\t\t\t\t\t\tlimits: memory: parameter.memory\n\t\t\t\t\t\t\trequests:
memory: parameter.memory\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif
parameter[\"livenessProbe\"] != _|_ {\n\t\t\t\t\t\tlivenessProbe: parameter.livenessProbe\n\t\t\t\t\t}\n\n\t\t\t\t\tif
parameter[\"readinessProbe\"] != _|_ {\n\t\t\t\t\t\treadinessProbe:
parameter.readinessProbe\n\t\t\t\t\t}\n\n\t\t\t\t\tlifecycle: {\n\t\t\t\t\t\tif
parameter.postStart != _|_ {\n\t\t\t\t\t\t\tpostStart: exec: command:
parameter.postStart\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif parameter.preStop
!= _|_ {\n\t\t\t\t\t\t\tpreStop: exec: command: parameter.preStop\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}]\n\t\t\t\tif
parameter.hostAliases != _|_ {\n\t\t\t\t\thostAliases: parameter.hostAliases\n\t\t\t\t}\n\t\t\t\tif
parameter[\"imagePullSecrets\"] != _|_ {\n\t\t\t\t\timagePullSecrets:
[ for v in parameter.imagePullSecrets {name: v}]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif
parameter.updateStrategyType != _|_ {\n\t\t\tupdateStrategy: {\n\t\t\t\ttype:
parameter.updateStrategyType\n\t\t\t}\n\t\t}\n\t}\n}\nparameter: {\n\t//
+usage=Which image would you like to use for your service\n\t// +short=i\n\timage:
string\n\n\t// +usage=Specify image pull policy for your service\n\timagePullPolicy?:
string\n\n\t// +usage=Specify image pull secrets for your service\n\timagePullSecrets?:
[...string]\n\n\t// +usage=Number of CPU units for the service, like
`0.5` (0.5 CPU core), `1` (1 CPU core)\n\tcpu?: string\n\n\t// +usage=Specify
the amount of memory to limit\n\tmemory?: *\"2048Mi\" | =~\"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$\"\n\n\t//
+usage=Commands to run in the container\n\tcmd?: [...string]\n\n\t//
+usage=Arguments to the command.\n\targs?: [...string]\n\n\t// +usage=postStart
commands will be called immediately after a container is created.\n\tpostStart?:
[...string]\n\n\t// +usage=PreStop is called immediately before a container
is terminated due to an API request or management event such as liveness/startup
probe failure, preemption, resource contention, etc. The handler is
not called if the container crashes or exits. The reason for termination
is passed to the handler. The Pod's termination grace period countdown
begins before the PreStop hooked is executed. Regardless of the outcome
of the handler, the container will eventually terminate within the Pod's
termination grace period. Other management of the container blocks until
the hook completes or until the termination grace period is reached.
More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n\tpreStop?:
[...string]\n\n\t// +usage=Which port do you want customer traffic sent
to\n\t// +short=p\n\tport: *80 | int\n\n\t// +usage=Define arguments
by using environment variables\n\tenv?: [...#ENV]\n\n\t// +usage=Cloneset
updateStrategy, candidates are `ReCreate`/`InPlaceIfPossible`/`InPlaceOnly`\n\tupdateStrategyType?:
string\n\n\t// +usage=HostAliases is a list of hosts and IPs that will
be write into the pod's hosts file\n\thostAliases?: [...{\n\t\thostnames:
[...string]\n\t\tip: string\n\t}]\n\n\t// +usage=Instructions for assessing
whether the container is alive.\n\tlivenessProbe?: #HealthProbe\n\n\t//
+usage=Instructions for assessing whether the container is in a suitable
state to serve traffic.\n\treadinessProbe?: #HealthProbe\n}\n\n#ENV:
{\n\t// +usage=Environment variable name\n\tname: string\n\t// +usage=The
value of the environment variable\n\tvalue?: string\n\t// +usage=Specifies
a source the value of this var should come from\n\tvalueFrom?: {\n\t\t//
+usage=Selects a key of a secret in the pod's namespace\n\t\tsecretKeyRef:
{\n\t\t\t// +usage=The name of the secret in the pod's namespace to
select from\n\t\t\tname: string\n\t\t\t// +usage=The key of the secret
to select from. Must be a valid secret key\n\t\t\tkey: string\n\t\t}\n\t}\n}\n\n#HealthProbe:
{\n\n\t// +usage=Instructions for assessing container health by executing
a command. Either this attribute or the httpGet attribute or the tcpSocket
attribute MUST be specified. This attribute is mutually exclusive with
both the httpGet attribute and the tcpSocket attribute.\n\texec?: {\n\t\t//
+usage=A command to be executed inside the container to assess its health.
Each space delimited token of the command is a separate array element.
Commands exiting 0 are considered to be successful probes, whilst all
other exit codes are considered failures.\n\t\tcommand: [...string]\n\t}\n\n\t//
+usage=Instructions for assessing container health by executing an HTTP
GET request. Either this attribute or the exec attribute or the tcpSocket
attribute MUST be specified. This attribute is mutually exclusive with
both the exec attribute and the tcpSocket attribute.\n\thttpGet?: {\n\t\t//
+usage=The endpoint, relative to the port, to which the HTTP GET request
should be directed.\n\t\tpath: string\n\t\t// +usage=The TCP socket
within the container to which the HTTP GET request should be directed.\n\t\tport:
int\n\t\thttpHeaders?: [...{\n\t\t\tname: string\n\t\t\tvalue: string\n\t\t}]\n\t}\n\n\t//
+usage=Instructions for assessing container health by probing a TCP
socket. Either this attribute or the exec attribute or the httpGet attribute
MUST be specified. This attribute is mutually exclusive with both the
exec attribute and the httpGet attribute.\n\ttcpSocket?: {\n\t\t// +usage=The
TCP socket within the container that should be probed to assess container
health.\n\t\tport: int\n\t}\n\n\t// +usage=Number of seconds after the
container is started before the first probe is initiated.\n\tinitialDelaySeconds:
*0 | int\n\n\t// +usage=How often, in seconds, to execute the probe.\n\tperiodSeconds:
*10 | int\n\n\t// +usage=Number of seconds after which the probe times
out.\n\ttimeoutSeconds: *1 | int\n\n\t// +usage=Minimum consecutive
successes for the probe to be considered successful after having failed.\n\tsuccessThreshold:
*1 | int\n\n\t// +usage=Number of consecutive failures required to determine
the container is not alive (liveness probe) or not ready (readiness
probe).\n\tfailureThreshold: *3 | int\n} \n"
workload:
definition:
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
type: raw
- name: predownloadimage
properties:
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
name: predownloadimage
spec:
schematic:
cue:
template: "import (\"vela/op\")\nparameter: {\n image: string\n parallel:
int\n kvs: [string]: string\n type: *\"Always\" | string\n activeDeadlineSeconds:
*1200 | int\n ttlSecondsAfterFinished: *300 | int\n backoffLimit?:
int\n timeoutSeconds?: int\n arr: [...string]\n}\n\npullImageJob:
op.#Apply & {\n value:{\n apiVersion: \"apps.kruise.io/v1alpha1\"\n
\ kind: \"ImagePullJob\"\n metadata: {\n name: \"pull-image-job\"\n
\ }\n spec: {\n image: parameter.image\n parallelism:
parameter.parallel\n selector: matchLabels: parameter.kvs\n completionPolicy:
{\n type: parameter.type\n activeDeadlineSeconds: parameter.activeDeadlineSeconds\n
\ ttlSecondsAfterFinished: parameter.ttlSecondsAfterFinished\n
\ }\n pullPolicy: {\n if parameter.backoffLimit != _|_
{\n backoffLimit: parameter.backoffLimit\n }\n if
parameter.timeoutSeconds != _|_ {\n timeoutSeconds: parameter.timeoutSeconds\n
\ }\n }\n pullSecrets: parameter.arr\n } \n
\ } \n} \n"
type: raw
workflow:
steps:
- name: checking-depends-on
properties:
name: fluxcd
namespace: vela-system
type: depends-on-app
- name: apply-resources
type: apply-application
status: {}
detail: |-
# kruise
This addon provides [open-kruise](https://github.com/openkruise/kruise) workload.
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: Kruise is a Kubernetes extended suite for application
automations
addons.oam.dev/name: kruise
labels:
addons.oam.dev/type: kruise
name: kruise
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -1,137 +0,0 @@
apiVersion: v1
data:
application: |
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
annotations:
addons.oam.dev/description: An out of the box solution for KubeVela observability
name: observability
namespace: vela-system
spec:
components:
- name: grafana-registration
properties:
chart: ./chart
git:
branch: master
repoType: git
targetNamespace: vela-system
url: https://github.com/oam-dev/grafana-registration
values:
replicaCount: 1
type: helm
- name: grafana
properties:
chart: grafana
releaseName: grafana
repoType: helm
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
version: 6.14.1
traits:
- properties:
domain: '[[ index .Args "grafana-domain" ]]'
http:
/: 80
type: pure-ingress
- properties:
credentialSecret: grafana
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: vela-system
urls:
- https://charts.kubevela.net/addons/dashboards/kubevela_core_logging.json
- https://charts.kubevela.net/addons/dashboards/kubevela_core_monitoring.json
- https://charts.kubevela.net/addons/dashboards/kubevela_application_logging.json
- https://charts.kubevela.net/addons/dashboards/flux2/cluster.json
type: import-grafana-dashboard
type: helm
- name: loki
properties:
chart: loki-stack
releaseName: loki
repoType: helm
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
version: 2.4.1
traits:
- properties:
access: proxy
credentialSecret: grafana
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: vela-system
name: loki
namespace: vela-system
service: loki
type: loki
type: register-grafana-datasource
type: helm
- name: prometheus-server
properties:
chart: prometheus
releaseName: prometheus
repoType: helm
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
values:
alertmanager:
persistentVolume:
enabled: '[[ index .Args "alertmanager-pvc-enabled" | default "true" ]]'
size: '[[ index .Args "alertmanager-pvc-size" | default "20Gi" ]]'
storageClass: '[[ index .Args "alertmanager-pvc-class" ]]'
server:
persistentVolume:
enabled: '[[ index .Args "server-pvc-enabled" | default "true" ]]'
size: '[[ index .Args "server-pvc-size" | default "20Gi" ]]'
storageClass: '[[ index .Args "server-pvc-class" ]]'
version: 14.4.1
traits:
- properties:
access: proxy
credentialSecret: grafana
credentialSecretNamespace: vela-system
grafanaServiceName: grafana
grafanaServiceNamespace: vela-system
name: prometheus
namespace: vela-system
service: prometheus-server
type: prometheus
type: register-grafana-datasource
type: helm
- name: kube-state-metrics
properties:
chart: kube-state-metrics
repoType: helm
targetNamespace: vela-system
url: https://charts.kubevela.net/addons
values:
image:
repository: oamdev/kube-state-metrics
tag: v2.1.0
version: 3.4.1
type: helm
workflow:
steps:
- name: checking-depends-on
properties:
name: fluxcd
namespace: vela-system
type: depends-on-app
- name: apply-resources
type: apply-remaining
status: {}
detail: |-
# observability
This addon expose system and application level metrics for KubeVela.
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: An out of the box solution for KubeVela observability
addons.oam.dev/name: observability
labels:
addons.oam.dev/type: observability
name: observability
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -1,519 +0,0 @@
apiVersion: v1
data:
application: |
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
annotations:
addons.oam.dev/description: ocm-cluster-manager can deploy an OCM hub cluster
environment.
name: ocm-cluster-manager
namespace: vela-system
spec:
components:
- name: ns-open-cluster-management
properties:
apiVersion: v1
kind: Namespace
metadata:
name: open-cluster-management
type: raw
- name: cluster-manager-role-binding
properties:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-manager-role-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-manager-cluster-role
subjects:
- kind: ServiceAccount
name: cluster-manager-service-account
namespace: open-cluster-management
type: raw
- name: cluster-manager-cluster-role
properties:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-manager-cluster-role
rules:
- apiGroups:
- ""
resources:
- configmaps
- namespaces
- serviceaccounts
- services
- secrets
verbs:
- create
- get
- list
- update
- watch
- patch
- delete
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- ""
- events.k8s.io
resources:
- events
verbs:
- create
- patch
- update
- apiGroups:
- apps
resources:
- deployments
verbs:
- create
- get
- list
- update
- watch
- patch
- delete
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterrolebindings
- rolebindings
verbs:
- create
- get
- list
- update
- watch
- patch
- delete
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterroles
- roles
verbs:
- create
- get
- list
- update
- watch
- patch
- delete
- escalate
- bind
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- create
- get
- list
- update
- watch
- patch
- delete
- apiGroups:
- apiregistration.k8s.io
resources:
- apiservices
verbs:
- create
- get
- list
- update
- watch
- patch
- delete
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
- mutatingwebhookconfigurations
verbs:
- create
- get
- list
- update
- watch
- patch
- delete
- apiGroups:
- operator.open-cluster-management.io
resources:
- clustermanagers
verbs:
- get
- list
- watch
- update
- delete
- apiGroups:
- operator.open-cluster-management.io
resources:
- clustermanagers/status
verbs:
- update
- patch
type: raw
- name: cluster-manager-service-account
properties:
apiVersion: v1
kind: ServiceAccount
metadata:
name: cluster-manager-service-account
namespace: open-cluster-management
type: raw
- name: clustermanagers.operator.open-cluster-management.io
properties:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: clustermanagers.operator.open-cluster-management.io
spec:
group: operator.open-cluster-management.io
names:
kind: ClusterManager
listKind: ClusterManagerList
plural: clustermanagers
singular: clustermanager
preserveUnknownFields: false
scope: Cluster
versions:
- name: v1
schema:
openAPIV3Schema:
description: ClusterManager configures the controllers on the hub that
govern registration and work distribution for attached Klusterlets.
ClusterManager will only be deployed in open-cluster-management-hub
namespace.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the
latest internal value, and may reject unrecognized values. More
info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource
this object represents. Servers may infer this from the endpoint
the client submits requests to. Cannot be updated. In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: Spec represents a desired deployment configuration
of controllers that govern registration and work distribution
for attached Klusterlets.
properties:
placementImagePullSpec:
default: quay.io/open-cluster-management/placement
description: PlacementImagePullSpec represents the desired image
configuration of placement controller/webhook installed on
hub.
type: string
registrationImagePullSpec:
default: quay.io/open-cluster-management/registration
description: RegistrationImagePullSpec represents the desired
image of registration controller/webhook installed on hub.
type: string
workImagePullSpec:
default: quay.io/open-cluster-management/work
description: WorkImagePullSpec represents the desired image
configuration of work controller/webhook installed on hub.
type: string
type: object
status:
description: Status represents the current status of controllers
that govern the lifecycle of managed clusters.
properties:
conditions:
description: 'Conditions contain the different condition statuses
for this ClusterManager. Valid condition types are: Applied:
Components in hub are applied. Available: Components in hub
are available and ready to serve. Progressing: Components
in hub are in a transitioning state. Degraded: Components
in hub do not match the desired configuration and only provide
degraded service.'
items:
description: "Condition contains details for one aspect of
the current state of this API Resource. --- This struct
is intended for direct use as an array at the field path
.status.conditions. For example, type FooStatus struct{
\ // Represents the observations of a foo's current state.
\ // Known .status.conditions.type are: \"Available\",
\"Progressing\", and \"Degraded\" // +patchMergeKey=type
\ // +patchStrategy=merge // +listType=map //
+listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\"
patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
\n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition
transitioned from one status to another. This should
be when the underlying condition changed. If that is
not known, then using the time when the API field changed
is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating
details about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation
that the condition was set based upon. For instance,
if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration
is 9, the condition is out of date with respect to the
current state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier
indicating the reason for the condition's last transition.
Producers of specific condition types may define expected
values and meanings for this field, and whether the
values are considered a guaranteed API. The value should
be a CamelCase string. This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False,
Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase.
--- Many .condition.type values are consistent across
resources like Available, but because arbitrary conditions
can be useful (see .node.status.conditions), the ability
to deconflict is important. The regex it matches is
(dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
type: array
generations:
description: Generations are used to determine when an item
needs to be reconciled or has changed in a way that needs
a reaction.
items:
description: GenerationStatus keeps track of the generation
for a given resource so that decisions about forced updates
can be made. The definition matches the GenerationStatus
defined in github.com/openshift/api/v1
properties:
group:
description: group is the group of the resource that you're
tracking
type: string
lastGeneration:
description: lastGeneration is the last generation of
the resource that controller applies
format: int64
type: integer
name:
description: name is the name of the resource that you're
tracking
type: string
namespace:
description: namespace is where the resource that you're
tracking is
type: string
resource:
description: resource is the resource type of the resource
that you're tracking
type: string
version:
description: version is the version of the resource that
you're tracking
type: string
type: object
type: array
observedGeneration:
description: ObservedGeneration is the last generation change
you've dealt with
format: int64
type: integer
relatedResources:
description: RelatedResources are used to track the resources
that are related to this ClusterManager.
items:
description: RelatedResourceMeta represents the resource that
is managed by an operator
properties:
group:
description: group is the group of the resource that you're
tracking
type: string
name:
description: name is the name of the resource that you're
tracking
type: string
namespace:
description: namespace is where the thing you're tracking
is
type: string
resource:
description: resource is the resource type of the resource
that you're tracking
type: string
version:
description: version is the version of the thing you're
tracking
type: string
type: object
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
type: raw
- name: cluster-manager-hub
properties:
apiVersion: operator.open-cluster-management.io/v1
kind: ClusterManager
metadata:
name: cluster-manager-hub
spec:
placementImagePullSpec: quay.io/open-cluster-management/placement
registrationImagePullSpec: quay.io/open-cluster-management/registration
workImagePullSpec: quay.io/open-cluster-management/work
type: raw
- name: cluster-manager-controller
properties:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: cluster-manager
name: cluster-manager-controller
namespace: open-cluster-management
spec:
replicas: 1
selector:
matchLabels:
app: cluster-manager
template:
metadata:
labels:
app: cluster-manager
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cluster-manager
topologyKey: failure-domain.beta.kubernetes.io/zone
weight: 70
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cluster-manager
topologyKey: kubernetes.io/hostname
weight: 30
containers:
- args:
- /registration-operator
- hub
image: quay.io/open-cluster-management/registration-operator:latest
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
path: /healthz
port: 8443
scheme: HTTPS
initialDelaySeconds: 2
periodSeconds: 10
name: registration-operator
readinessProbe:
httpGet:
path: /healthz
port: 8443
scheme: HTTPS
initialDelaySeconds: 2
resources:
requests:
cpu: 10m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
runAsNonRoot: true
serviceAccountName: cluster-manager-service-account
type: raw
workflow:
steps:
- name: apply-ns
properties:
component: ns-open-cluster-management
type: apply-component
- name: apply-resources
type: apply-remaining
status: {}
detail: |-
# ocm-cluster-manager
This addon aims to support multi-cluster application deployment.
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: ocm-cluster-manager can deploy an OCM hub cluster
environment.
addons.oam.dev/name: ocm-cluster-manager
labels:
addons.oam.dev/type: ocm-cluster-manager
name: ocm-cluster-manager
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -1,67 +0,0 @@
apiVersion: v1
data:
application: |
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
annotations:
addons.oam.dev/description: Kubernetes Terraform Controller for Alibaba Cloud
addons.oam.dev/name: terraform-alibaba
name: terraform-alibaba
namespace: vela-system
spec:
components:
- name: alibaba-account-creds-[[ index .Args "providerName" ]]
properties:
apiVersion: v1
kind: Secret
metadata:
name: alibaba-account-creds-[[ index .Args "providerName" ]]
namespace: vela-system
stringData:
credentials: |
accessKeyID: [[ index .Args "ALICLOUD_ACCESS_KEY" ]]
accessKeySecret: [[ index .Args "ALICLOUD_SECRET_KEY" ]]
securityToken: [[ index .Args "ALICLOUD_SECURITY_TOKEN" ]]
type: Opaque
type: raw
- name: alibaba-[[ index .Args "providerName" ]]
properties:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Provider
metadata:
name: '[[ index .Args "providerName" ]]'
namespace: default
spec:
credentials:
secretRef:
key: credentials
name: alibaba-account-creds-[[ index .Args "providerName" ]]
namespace: vela-system
source: Secret
provider: alibaba
region: '[[ index .Args "ALICLOUD_REGION" ]]'
type: raw
workflow:
steps:
- name: ""
properties:
name: terraform
namespace: vela-system
type: depends-on-app
- name: ""
type: apply-application
status: {}
detail: |
# terraform-alibaba
This addon contains terraform provider for Alibaba Cloud.
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: Kubernetes Terraform Controller for Alibaba Cloud
addons.oam.dev/name: terraform-alibaba
labels:
addons.oam.dev/type: terraform-alibaba
name: terraform-alibaba
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -1,67 +0,0 @@
apiVersion: v1
data:
application: |
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
annotations:
addons.oam.dev/description: Kubernetes Terraform Controller for AWS
addons.oam.dev/name: terraform-aws
name: terraform-aws
namespace: vela-system
spec:
components:
- name: aws-account-creds
properties:
apiVersion: v1
kind: Secret
metadata:
name: aws-account-creds
namespace: vela-system
stringData:
credentials: |
awsAccessKeyID: [[ index .Args "AWS_ACCESS_KEY_ID" ]]
awsSecretAccessKey: [[ index .Args "AWS_SECRET_ACCESS_KEY" ]]
awsSessionToken: [[ index .Args "AWS_SESSION_TOKEN" ]]
type: Opaque
type: raw
- name: aws
properties:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Provider
metadata:
name: aws
namespace: default
spec:
credentials:
secretRef:
key: credentials
name: aws-account-creds
namespace: vela-system
source: Secret
provider: aws
region: '[[ index .Args "AWS_DEFAULT_REGION" ]]'
type: raw
workflow:
steps:
- name: ""
properties:
name: terraform
namespace: vela-system
type: depends-on-app
- name: ""
type: apply-application
status: {}
detail: |
# terraform-aws
This addon contains terraform provider for AWS.
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: Kubernetes Terraform Controller for AWS
addons.oam.dev/name: terraform-aws
labels:
addons.oam.dev/type: terraform-aws
name: terraform-aws
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -1,67 +0,0 @@
apiVersion: v1
data:
application: |
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
annotations:
addons.oam.dev/description: Kubernetes Terraform Controller for Azure
addons.oam.dev/name: terraform-azure
name: terraform-azure
namespace: vela-system
spec:
components:
- name: azure-account-creds
properties:
apiVersion: v1
kind: Secret
metadata:
name: azure-account-creds
namespace: vela-system
stringData:
credentials: |
armClientID: [[ index .Args "ARM_CLIENT_ID" ]]
armClientSecret: [[ index .Args "ARM_CLIENT_SECRET" ]]
armSubscriptionID: [[ index .Args "ARM_SUBSCRIPTION_ID" ]]
armTenantID: [[ index .Args "ARM_TENANT_ID" ]]
type: Opaque
type: raw
- name: azure
properties:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Provider
metadata:
name: azure
namespace: default
spec:
credentials:
secretRef:
key: credentials
name: azure-account-creds
namespace: vela-system
source: Secret
provider: azure
type: raw
workflow:
steps:
- name: ""
properties:
name: terraform
namespace: vela-system
type: depends-on-app
- name: ""
type: apply-application
status: {}
detail: |
# terraform-azure
This addon contains terraform provider for Azure.
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: Kubernetes Terraform Controller for Azure
addons.oam.dev/name: terraform-azure
labels:
addons.oam.dev/type: terraform-azure
name: terraform-azure
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -1,595 +0,0 @@
apiVersion: v1
data:
application: |
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
annotations:
addons.oam.dev/description: Terraform Controller is a Kubernetes Controller for
Terraform.
name: terraform
namespace: vela-system
spec:
components:
- name: terraform-controller
properties:
chart: terraform-controller
repoType: helm
url: https://charts.kubevela.net/addons
version: 0.2.10
type: helm
- name: alibaba-ack
properties:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
ACK cluster
labels:
type: terraform
name: alibaba-ack
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/kubevela-contrib/terraform-modules.git
path: alibaba/cs/dedicated-kubernetes
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-ask
properties:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
Serverless Kubernetes (ASK)
labels:
type: terraform
name: alibaba-ask
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/kubevela-contrib/terraform-modules.git
path: alibaba/cs/serverless-kubernetes
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-eip
properties:
apiVersion: core.oam.dev/v1alpha2
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
Elastic IP
labels:
type: terraform
name: alibaba-eip
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/oam-dev/terraform-alibaba-eip.git
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-oss
properties:
apiVersion: core.oam.dev/v1alpha2
kind: ComponentDefinition
metadata:
annotations:
cloud-resource/console-url: https://oss.console.aliyun.com/bucket/oss-{ALICLOUD_REGION}/{BUCKET_NAME}/overview
cloud-resource/identifier: BUCKET_NAME
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
OSS object
labels:
type: terraform
name: alibaba-oss
namespace: vela-system
spec:
schematic:
terraform:
configuration: "resource \"alicloud_oss_bucket\" \"bucket-acl\" {\n bucket
= var.bucket\n acl = var.acl\n}\noutput \"BUCKET_NAME\" {\n value
= \"${alicloud_oss_bucket.bucket-acl.bucket}.${alicloud_oss_bucket.bucket-acl.extranet_endpoint}\"\n}\nvariable
\"bucket\" {\n description = \"OSS bucket name\"\n default = \"vela-website\"\n
\ type = string\n}\nvariable \"acl\" {\n description = \"OSS bucket
ACL, supported 'private', 'public-read', 'public-read-write'\"\n default
= \"private\"\n type = string\n} \n"
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-rds
properties:
apiVersion: core.oam.dev/v1alpha2
kind: ComponentDefinition
metadata:
annotations:
cloud-resource/console-url: https://rdsnext.console.aliyun.com/detail/{DB_ID}/basicInfo?&region={ALICLOUD_REGION}
cloud-resource/identifier: DB_ID
cloud-resource/sensitive-outputs: DB_PASSWORD
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
RDS object
labels:
type: terraform
name: alibaba-rds
namespace: vela-system
spec:
schematic:
terraform:
configuration: |
module "rds" {
source = "github.com/kubevela-contrib/terraform-alicloud-rds"
engine = "MySQL"
engine_version = "8.0"
instance_type = "rds.mysql.c1.large"
instance_storage = "20"
instance_name = var.instance_name
account_name = var.account_name
password = var.password
allocate_public_connection = var.allocate_public_connection
security_ips = ["0.0.0.0/0",]
}
output "DB_ID" {
value = module.rds.db_instance_id
}
output "DB_NAME" {
value = module.rds.this_db_instance_name
}
output "DB_USER" {
value = module.rds.this_db_database_account
}
output "DB_PORT" {
value = module.rds.this_db_instance_port
}
output "DB_HOST" {
value = module.rds.this_db_instance_connection_string
}
output "DB_PASSWORD" {
value = var.password
}
output "DB_PUBLIC_HOST" {
value = module.rds.db_public_connection_string
}
variable "instance_name" {
description = "RDS instance name"
type = string
default = "poc"
}
variable "account_name" {
description = "RDS instance user account name"
type = string
default = "oam"
}
variable "password" {
description = "RDS instance account password"
type = string
default = "Xyfff83jfewGGfaked"
}
variable "allocate_public_connection" {
description = "Whether to allocate public connection for a RDS instance."
type = bool
default = true
}
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-redis
properties:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
Redis
labels:
type: terraform
name: alibaba-redis
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/kubevela-contrib/terraform-modules/alibaba/redis
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-sls-project
properties:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
SLS Project
labels:
type: terraform
name: alibaba-sls-project
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/kubevela-contrib/terraform-modules.git
path: alibaba/sls/project
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-sls-store
properties:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
SLS Store
labels:
type: terraform
name: alibaba-sls-store
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/kubevela-contrib/terraform-modules.git
path: alibaba/sls/store
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-vpc
properties:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
VPC
labels:
type: terraform
name: alibaba-vpc
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/kubevela-contrib/terraform-modules.git
path: alibaba/vpc
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: alibaba-vswitch
properties:
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Alibaba Cloud
VSwitch
labels:
type: terraform
name: alibaba-vswitch
namespace: vela-system
spec:
schematic:
terraform:
configuration: https://github.com/kubevela-contrib/terraform-modules.git
path: alibaba/vswitch
type: remote
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: aws-s3
properties:
apiVersion: core.oam.dev/v1alpha2
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for AWS S3
labels:
type: terraform
name: aws-s3
namespace: vela-system
spec:
schematic:
terraform:
configuration: |
resource "aws_s3_bucket" "bucket-acl" {
bucket = var.bucket
acl = var.acl
}
output "BUCKET_NAME" {
value = aws_s3_bucket.bucket-acl.bucket_domain_name
}
variable "bucket" {
description = "S3 bucket name"
default = "vela-website"
type = string
}
variable "acl" {
description = "S3 bucket ACL"
default = "private"
type = string
}
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: azure-database-mariadb
properties:
apiVersion: core.oam.dev/v1alpha2
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Azure Database
Mariadb
provider: azure
labels:
type: terraform
name: azure-database-mariadb
namespace: vela-system
spec:
schematic:
terraform:
configuration: |
# Configure the Microsoft Azure Provider
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "example" {
name = var.resource_group
location = var.location
}
resource "azurerm_mariadb_server" "example" {
name = var.server_name
location = var.location
resource_group_name = azurerm_resource_group.example.name
sku_name = "B_Gen5_2"
storage_mb = 51200
backup_retention_days = 7
geo_redundant_backup_enabled = false
administrator_login = var.username
administrator_login_password = var.password
version = "10.2"
ssl_enforcement_enabled = true
}
resource "azurerm_mariadb_database" "example" {
name = var.db_name
resource_group_name = azurerm_resource_group.example.name
server_name = azurerm_mariadb_server.example.name
charset = "utf8"
collation = "utf8_general_ci"
}
variable "server_name" {
type = string
description = "mariadb server name"
default = "mariadb-svr-sample"
}
variable "db_name" {
default = "backend"
type = string
description = "Database instance name"
}
variable "username" {
default = "acctestun"
type = string
description = "Database instance username"
}
variable "password" {
default = "H@Sh1CoR3!faked"
type = string
description = "Database instance password"
}
variable "location" {
description = "Azure location"
type = string
default = "West Europe"
}
variable "resource_group" {
description = "Resource group"
type = string
default = "kubevela-group"
}
output "SERVER_NAME" {
value = var.server_name
}
output "DB_NAME" {
value = var.db_name
}
output "DB_USER" {
value = var.username
}
output "DB_PASSWORD" {
sensitive = true
value = var.password
}
output "DB_PORT" {
value = "3306"
}
output "DB_HOST" {
value = azurerm_mariadb_server.example.fqdn
}
providerRef:
name: azure
namespace: default
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
- name: azure-storage-account
properties:
apiVersion: core.oam.dev/v1alpha2
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: Terraform configuration for Azure Blob Storage
Account
provider: azure
labels:
type: terraform
name: azure-storage-account
namespace: vela-system
spec:
schematic:
terraform:
configuration: |
# Configure the Microsoft Azure Provider
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "rsg" {
count = var.create_rsg ? 1 : 0
name = var.resource_group_name
location = var.location
}
resource "azurerm_storage_account" "sa" {
name = var.name
resource_group_name = var.create_rsg ? azurerm_resource_group.rsg[0].name : var.resource_group_name
location = var.location
account_tier = "Standard"
account_replication_type = "GRS"
enable_https_traffic_only = true
dynamic "static_website" {
for_each = var.static_website
content {
index_document = static_website.value["index_document"]
error_404_document = static_website.value["error_404_document"]
}
}
tags = var.tags
}
variable "create_rsg" {
description = "Conditional if resource group should be created. Defaults to 'true'."
type = bool
default = true
}
variable "resource_group_name" {
description = "Name of resource group. Defaults to 'rsg'."
type = string
default = "rsg"
}
variable "name" {
description = "Name of storage account. Defaults to 'storageaccount'."
type = string
default = "storageaccount"
}
variable "location" {
description = "Location of storage account. Defaults to 'West Europe'."
type = string
default = "West Europe"
}
variable "tags" {
description = "Tags for storage account. Defaults to '{}'."
type = map(string)
default = {}
}
variable "static_website" {
description = "Static website configuration. Defaults to disabled."
type = list(map(string))
default = [{
index_document = null
error_404_document = null
}]
}
output "BLOB_CONNECTION_STRING" {
description = "Blob storage connection string"
sensitive = true
value = azurerm_storage_account.sa.primary_connection_string
}
output "BLOB_WEB_ENDPOINT" {
description = "Blob storage static web endpoint"
value = azurerm_storage_account.sa.primary_web_endpoint
}
providerRef:
name: azure
namespace: default
workload:
definition:
apiVersion: terraform.core.oam.dev/v1beta1
kind: Configuration
type: raw
workflow:
steps:
- name: ""
properties:
name: fluxcd
namespace: vela-system
type: depends-on-app
- name: ""
type: apply-application
status: {}
detail: ""
kind: ConfigMap
metadata:
annotations:
addons.oam.dev/description: Terraform Controller is a Kubernetes Controller for
Terraform.
addons.oam.dev/name: terraform
labels:
addons.oam.dev/type: terraform
name: terraform
namespace: {{.Values.systemDefinitionNamespace}}

View File

@@ -1,4 +1,5 @@
{{ if .Values.multicluster.enabled }}
{{ if not (lookup "apps/v1" "Deployment" .Release.Namespace (printf "%s-cluster-gateway" .Release.Name)) }}
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -66,6 +67,12 @@ spec:
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
{{ end }}
{{ end }}
---
{{ if .Values.multicluster.enabled }}
@@ -84,6 +91,7 @@ spec:
{{ end }}
---
{{ if .Values.multicluster.enabled }}
{{ if not (lookup "apiregistration.k8s.io/v1" "APIService" "" "v1alpha1.cluster.core.oam.dev") }}
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
@@ -105,6 +113,7 @@ spec:
caBundle: Cg==
{{ end }}
{{ end }}
{{ end }}
---
{{ if and .Values.multicluster.enabled .Values.multicluster.clusterGateway.secureTLS.enabled }}
apiVersion: rbac.authorization.k8s.io/v1

View File

@@ -0,0 +1,21 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/apply-application-in-parallel.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Apply components of an application in parallel for your workflow steps
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: apply-application-in-parallel
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
output: op.#ApplyApplicationInParallel & {}

View File

@@ -16,9 +16,10 @@ spec:
)
app: op.#ApplyEnvBindApp & {
env: parameter.env
policy: parameter.policy
app: context.name
env: parameter.env
policy: parameter.policy
parallel: parameter.parallel
app: context.name
// context.namespace indicates the namespace of the app
namespace: context.namespace
}
@@ -27,5 +28,7 @@ spec:
policy: *"" | string
// +usage=Declare the name of the env in policy
env: string
// +usage=components are applied in parallel
parallel: *false | bool
}

View File

@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Deploy application to runtime clusters
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: deploy2runtime
namespace: {{.Values.systemDefinitionNamespace}}
spec:

View File

@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Export data to config map for your workflow steps
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: export2config
namespace: {{.Values.systemDefinitionNamespace}}
spec:
@@ -30,6 +32,7 @@ spec:
}
data: parameter.data
}
cluster: parameter.cluster
}
parameter: {
// +usage=Specify the name of the config map
@@ -38,5 +41,7 @@ spec:
namespace?: string
// +usage=Specify the data of config map
data: {}
// +usage=Specify the cluster of the config map
cluster: *"" | string
}

View File

@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Export data to secret for your workflow steps
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: export2secret
namespace: {{.Values.systemDefinitionNamespace}}
spec:
@@ -33,6 +35,7 @@ spec:
}
stringData: parameter.data
}
cluster: parameter.cluster
}
parameter: {
// +usage=Specify the name of the secret
@@ -43,5 +46,7 @@ spec:
type?: string
// +usage=Specify the data of secret
data: {}
// +usage=Specify the cluster of the config map
cluster: *"" | string
}

View File

@@ -18,13 +18,15 @@ spec:
parameter: {
dingding?: {
// +usage=Specify the the dingding url, you can either sepcify it in value or use secretRef
url: value | secretRef
// +useage=Specify the message that you want to sent
message: {
text?: *null | {
content: string
}
// +usage=msgType can be text, link, mardown, actionCard, feedCard
msgtype: string
msgtype: *"text" | "link" | "markdown" | "actionCard" | "feedCard"
link?: *null | {
text?: string
title?: string
@@ -63,7 +65,9 @@ spec:
}
slack?: {
// +usage=Specify the the slack url, you can either sepcify it in value or use secretRef
url: value | secretRef
// +useage=Specify the message that you want to sent
message: {
text: string
blocks?: *null | [...block]
@@ -77,17 +81,27 @@ spec:
}
email?: {
// +usage=Specify the email info that you want to send from
from: {
address: string
alias?: string
// +usage=Specify the email address that you want to send from
address: string
// +usage=The alias is the email alias to show after sending the email
alias?: string
// +usage=Specify the password of the email, you can either sepcify it in value or use secretRef
password: value | secretRef
host: string
port: *587 | int
// +usage=Specify the host of your email
host: string
// +usage=Specify the port of the email host, default to 587
port: *587 | int
}
// +usage=Specify the email address that you want to send to
to: [...string]
// +usage=Specify the content of the email
content: {
// +usage=Specify the subject of the email
subject: string
body: string
// +usage=Specify the context body of the email
body: string
}
}
}
@@ -137,8 +151,10 @@ spec:
url?: string
}
secretRef: {
// +usage=name is the name of the secret
name: string
key: string
// +usage=key is the key in the secret
key: string
}
value: string
// send webhook notification

View File

@@ -43,4 +43,7 @@ spec:
batchPartition?: int
}
rolloutBatch: replicas: int
status:
customStatus: 'message: context.outputs.rollout.status.rollingState'
healthPolicy: 'isHealth: context.outputs.rollout.status.batchRollingState == "batchReady"'

View File

@@ -5,8 +5,6 @@ kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Sync secrets created by terraform component to runtime clusters so that runtime clusters can share the created cloud resource.
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: share-cloud-resource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
@@ -27,7 +25,6 @@ spec:
name: context.name
}
parameter: {
env: string
// +usage=Declare the location to bind
placements: [...{
namespace?: string

View File

@@ -1,106 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: component-pod-view
namespace: {{.Values.systemDefinitionNamespace}}
data:
template: |
import (
"vela/ql"
"vela/op"
"strings"
)
parameter: {
appName: string
appNs: string
name?: string
cluster?: string
clusterNs?: string
}
annotationDeployVersion: "app.oam.dev/deployVersion"
annotationPublishVersion: "app.oam.dev/publishVersion"
resources: ql.#ListResourcesInApp & {
app: {
name: parameter.appName
namespace: parameter.appNs
filter: {
if parameter.cluster != _|_ {
cluster: parameter.cluster
}
if parameter.clusterNs != _|_ {
clusterNamespace: parameter.clusterNs
}
if parameter.name != _|_ {
components: [parameter.name]
}
}
}
}
if resources.err == _|_ {
collectedPods: op.#Steps & {
for i, resource in resources.list {
"\(i)": ql.#CollectPods & {
value: resource.object
cluster: resource.cluster
}
}
}
podsWithCluster: [ for pods in collectedPods if pods.list != _|_ for podObj in pods.list {
cluster: pods.cluster
obj: podObj
workload: {
apiVersion: pods.value.apiVersion
kind: pods.value.kind
}
if pods.value.metadata.annotations[annotationPublishVersion] != _|_ {
publishVersion: pods.value.metadata.annotations[annotationPublishVersion]
}
if pods.value.metadata.annotations[annotationDeployVersion] != _|_ {
deployVersion: pods.value.metadata.annotations[annotationDeployVersion]
}
}]
podsError: [ for pods in collectedPods if pods.err != _|_ {pods.err}]
status: {
if len(podsError) == 0 {
podList: [ for pod in podsWithCluster {
cluster: pod.cluster
workload: pod.workload
metadata: {
name: pod.obj.metadata.name
namespace: pod.obj.metadata.namespace
creationTime: pod.obj.metadata.creationTimestamp
version: {
if pod.publishVersion != _|_ {
publishVersion: pod.publishVersion
}
if pod.deployVersion != _|_ {
deployVersion: pod.deployVersion
}
}
}
status: {
phase: pod.obj.status.phase
// refer to https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
if phase != "Pending" && phase != "Unknown" {
podIP: pod.obj.status.podIP
hostIP: pod.obj.status.hostIP
nodeName: pod.obj.spec.nodeName
}
}
}]
}
if len(podsError) != 0 {
error: strings.Join(podsError, ",")
}
}
}
if resources.err != _|_ {
status: {
error: resources.err
}
}

View File

@@ -1,84 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: pod-view
namespace: {{.Values.systemDefinitionNamespace}}
data:
template: |
import (
"vela/ql"
)
parameter: {
name: string
namespace: string
cluster: *"" | string
}
pod: ql.#Read & {
value: {
apiVersion: "v1"
kind: "Pod"
metadata: {
name: parameter.name
namespace: parameter.namespace
}
}
cluster: parameter.cluster
}
eventList: ql.#SearchEvents & {
value: {
apiVersion: "v1"
kind: "Pod"
metadata: pod.value.metadata
}
cluster: parameter.cluster
}
podMetrics: ql.#Read & {
cluster: parameter.cluster
value: {
apiVersion: "metrics.k8s.io/v1beta1"
kind: "PodMetrics"
metadata: {
name: parameter.name
namespace: parameter.namespace
}
}
}
status: {
if pod.err == _|_ {
containers: [ for container in pod.value.spec.containers {
name: container.name
image: container.image
resources: {
if container.resources.limits != _|_ {
limits: container.resources.limits
}
if container.resources.requests != _|_ {
requests: container.resources.requests
}
if podMetrics.err == _|_ {
usage: {for containerUsage in podMetrics.value.containers {
if containerUsage.name == container.name {
cpu: containerUsage.usage.cpu
memory: containerUsage.usage.memory
}
}}
}
}
status: {for containerStatus in pod.value.status.containerStatuses if containerStatus.name == container.name {
state: containerStatus.state
restartCount: containerStatus.restartCount
}}
}]
if eventList.err == _|_ {
events: eventList.list
}
}
if pod.err != _|_ {
error: pod.err
}
}

View File

@@ -1,62 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: resource-view
namespace: {{.Values.systemDefinitionNamespace}}
data:
template: |
import (
"vela/ql"
)
parameter: {
type: string
namespace: *"" | string
cluster: *"" | string
}
schema: {
"secret": {
apiVersion: "v1"
kind: "Secret"
}
"configMap": {
apiVersion: "v1"
kind: "ConfigMap"
}
"pvc": {
apiVersion: "v1"
kind: "PersistentVolumeClaim"
}
"storageClass": {
apiVersion: "storage.k8s.io/v1"
kind: "StorageClass"
}
"ns": {
apiVersion: "v1"
kind: "Namespace"
}
}
List: ql.#List & {
resource: schema[parameter.type]
filter: {
namespace: parameter.namespace
}
cluster: parameter.cluster
}
status: {
if List.err == _|_ {
if len(List.list.items) == 0 {
error: "failed to list \(parameter.type) in namespace \(parameter.namespace)"
}
if len(List.list.items) != 0 {
list: List.list.items
}
}
if List.err != _|_ {
error: List.err
}
}

View File

@@ -107,13 +107,13 @@ dependCheckWait: 30s
OAMSpecVer: "v0.3"
multicluster:
enabled: false
enabled: true
clusterGateway:
replicaCount: 1
port: 9443
image:
repository: oamdev/cluster-gateway
tag: v1.1.6
tag: v1.1.7
pullPolicy: Always
resources:
limits:

View File

@@ -640,7 +640,8 @@ spec:
type: object
type: array
resourceTracker:
description: ResourceTracker record the status of the ResourceTracker
description: Deprecated ResourceTracker record the status
of the ResourceTracker
properties:
apiVersion:
description: API version of the referent.
@@ -985,6 +986,8 @@ spec:
type: object
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
@@ -2897,7 +2900,8 @@ spec:
type: object
type: array
resourceTracker:
description: ResourceTracker record the status of the ResourceTracker
description: Deprecated ResourceTracker record the status
of the ResourceTracker
properties:
apiVersion:
description: API version of the referent.
@@ -3242,6 +3246,8 @@ spec:
type: object
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string

View File

@@ -461,7 +461,7 @@ spec:
type: object
type: array
resourceTracker:
description: ResourceTracker record the status of the ResourceTracker
description: Deprecated ResourceTracker record the status of the ResourceTracker
properties:
apiVersion:
description: API version of the referent.
@@ -667,6 +667,8 @@ spec:
type: object
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
@@ -1285,7 +1287,7 @@ spec:
type: object
type: array
resourceTracker:
description: ResourceTracker record the status of the ResourceTracker
description: Deprecated ResourceTracker record the status of the ResourceTracker
properties:
apiVersion:
description: API version of the referent.
@@ -1491,6 +1493,8 @@ spec:
type: object
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string

View File

@@ -15,11 +15,24 @@ spec:
listKind: ResourceTrackerList
plural: resourcetrackers
shortNames:
- tracker
- rt
singular: resourcetracker
scope: Cluster
versions:
- name: v1beta1
- additionalPrinterColumns:
- jsonPath: .spec.type
name: TYPE
type: string
- jsonPath: .metadata.labels['app\.oam\.dev\/name']
name: APP
type: string
- jsonPath: .metadata.labels['app\.oam\.dev\/namespace']
name: APP-NS
type: string
- jsonPath: .spec.applicationGeneration
name: APP-GEN
type: number
name: v1beta1
schema:
openAPIV3Schema:
description: An ResourceTracker represents a tracker for track cross namespace
@@ -37,10 +50,80 @@ spec:
type: string
metadata:
type: object
spec:
description: ResourceTrackerSpec define the spec of resourceTracker
properties:
applicationGeneration:
format: int64
type: integer
managedResources:
items:
description: ManagedResource define the resource to be managed by
ResourceTracker
properties:
apiVersion:
description: API version of the referent.
type: string
cluster:
type: string
component:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
deleted:
description: Deleted marks the resource to be deleted
type: boolean
env:
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
an entire object, this string should contain a valid JSON/Go
field access statement, such as desiredState.manifest.containers[2].
For example, if the object reference is to a container within
a pod, this would take on a value like: "spec.containers{name}"
(where "name" refers to the name of the container that triggered
the event) or if no container name is specified "spec.containers[2]"
(container with index 2 in this pod). This syntax is chosen
only to have some well-defined way of referencing a part of
an object. TODO: this design is not final and this field is
subject to change in the future.'
type: string
kind:
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
namespace:
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
type: string
raw:
type: object
x-kubernetes-preserve-unknown-fields: true
resourceVersion:
description: 'Specific resourceVersion to which this reference
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
type: string
trait:
type: string
uid:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
type: array
type:
description: ResourceTrackerType defines the type of resourceTracker
type: string
required:
- applicationGeneration
type: object
status:
description: ResourceTrackerStatus define the status of resourceTracker
For backward-compatibility
properties:
trackedResources:
description: Deprecated
items:
description: ClusterObjectReference defines the object reference
with cluster.

View File

@@ -0,0 +1,21 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/apply-application-in-parallel.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Apply components of an application in parallel for your workflow steps
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: apply-application-in-parallel
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: |
import (
"vela/op"
)
output: op.#ApplyApplicationInParallel & {}

View File

@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Deploy application to runtime clusters
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: deploy2runtime
namespace: {{.Values.systemDefinitionNamespace}}
spec:

View File

@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Export data to config map for your workflow steps
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: export2config
namespace: {{.Values.systemDefinitionNamespace}}
spec:
@@ -30,6 +32,7 @@ spec:
}
data: parameter.data
}
cluster: parameter.cluster
}
parameter: {
// +usage=Specify the name of the config map
@@ -38,5 +41,7 @@ spec:
namespace?: string
// +usage=Specify the data of config map
data: {}
// +usage=Specify the cluster of the config map
cluster: *"" | string
}

View File

@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Export data to secret for your workflow steps
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: export2secret
namespace: {{.Values.systemDefinitionNamespace}}
spec:
@@ -33,6 +35,7 @@ spec:
}
stringData: parameter.data
}
cluster: parameter.cluster
}
parameter: {
// +usage=Specify the name of the secret
@@ -43,5 +46,7 @@ spec:
type?: string
// +usage=Specify the data of secret
data: {}
// +usage=Specify the cluster of the config map
cluster: *"" | string
}

View File

@@ -18,13 +18,15 @@ spec:
parameter: {
dingding?: {
// +usage=Specify the the dingding url, you can either sepcify it in value or use secretRef
url: value | secretRef
// +useage=Specify the message that you want to sent
message: {
text?: *null | {
content: string
}
// +usage=msgType can be text, link, mardown, actionCard, feedCard
msgtype: string
msgtype: *"text" | "link" | "markdown" | "actionCard" | "feedCard"
link?: *null | {
text?: string
title?: string
@@ -63,7 +65,9 @@ spec:
}
slack?: {
// +usage=Specify the the slack url, you can either sepcify it in value or use secretRef
url: value | secretRef
// +useage=Specify the message that you want to sent
message: {
text: string
blocks?: *null | [...block]
@@ -77,17 +81,27 @@ spec:
}
email?: {
// +usage=Specify the email info that you want to send from
from: {
address: string
alias?: string
// +usage=Specify the email address that you want to send from
address: string
// +usage=The alias is the email alias to show after sending the email
alias?: string
// +usage=Specify the password of the email, you can either sepcify it in value or use secretRef
password: value | secretRef
host: string
port: *587 | int
// +usage=Specify the host of your email
host: string
// +usage=Specify the port of the email host, default to 587
port: *587 | int
}
// +usage=Specify the email address that you want to send to
to: [...string]
// +usage=Specify the content of the email
content: {
// +usage=Specify the subject of the email
subject: string
body: string
// +usage=Specify the context body of the email
body: string
}
}
}
@@ -137,8 +151,10 @@ spec:
url?: string
}
secretRef: {
// +usage=name is the name of the secret
name: string
key: string
// +usage=key is the key in the secret
key: string
}
value: string
// send webhook notification

View File

@@ -43,4 +43,7 @@ spec:
batchPartition?: int
}
rolloutBatch: replicas: int
status:
customStatus: 'message: context.outputs.rollout.status.rollingState'
healthPolicy: 'isHealth: context.outputs.rollout.status.batchRollingState == "batchReady"'

View File

@@ -5,8 +5,6 @@ kind: WorkflowStepDefinition
metadata:
annotations:
definition.oam.dev/description: Sync secrets created by terraform component to runtime clusters so that runtime clusters can share the created cloud resource.
labels:
custom.definition.oam.dev/ui-hidden: "true"
name: share-cloud-resource
namespace: {{.Values.systemDefinitionNamespace}}
spec:
@@ -27,7 +25,6 @@ spec:
name: context.name
}
parameter: {
env: string
// +usage=Declare the location to bind
placements: [...{
namespace?: string

View File

@@ -112,7 +112,7 @@ multicluster:
port: 9443
image:
repository: oamdev/cluster-gateway
tag: v1.1.3
tag: v1.1.7
pullPolicy: Always
resources:
limits:

View File

@@ -45,6 +45,7 @@ func main() {
flag.StringVar(&s.restCfg.LeaderConfig.ID, "id", uuid.New().String(), "the holder identity name")
flag.StringVar(&s.restCfg.LeaderConfig.LockName, "lock-name", "apiserver-lock", "the lease lock resource name")
flag.DurationVar(&s.restCfg.LeaderConfig.Duration, "duration", time.Second*5, "the lease lock resource name")
flag.DurationVar(&s.restCfg.AddonCacheTime, "addon-cache-duration", time.Minute*10, "how long between two addon cache operation")
flag.Parse()
if len(os.Args) > 2 && os.Args[1] == "build-swagger" {

View File

@@ -37,7 +37,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
standardcontroller "github.com/oam-dev/kubevela/pkg/controller"
commonconfig "github.com/oam-dev/kubevela/pkg/controller/common"
oamcontroller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
@@ -211,7 +210,7 @@ func main() {
LeaseDuration: &leaseDuration,
RenewDeadline: &renewDeadline,
RetryPeriod: &retryPeriod,
ClientDisableCacheFor: []client.Object{&v1beta1.ResourceTracker{}, &appsv1.ControllerRevision{}},
ClientDisableCacheFor: []client.Object{&appsv1.ControllerRevision{}},
})
if err != nil {
klog.ErrorS(err, "Unable to create a controller manager")

View File

@@ -22,6 +22,10 @@
- Command-line flags should use dashes, not underscores
- API
- According to RFC3986, URLs are "case sensitive". KubeVela uses snake_case for API URLs.
- e.g.: `POST /v1/cloud_clusters`
- Naming
- Please consider package name when selecting an interface name, and avoid
redundancy.

View File

@@ -0,0 +1,56 @@
# ResourceTracker: Managing Resources behind Application
- Owner: Da Yin (@somefive)
- Reviewer: Jian Li (@leejanee), Jianbo Sun (@wonderflow)
- Date: 12/10/2021
- Status: Implemented
## Intro
As the release of Workflow in KubeVela v1.1, resources dispatched by application can be extremely dynamic.
Instead of simply declaring in Application Component, users can have advanced control for applied resources by leveraging WorkflowSteps such as `ApplyObject` or operators such as `op.Delete`.
Meanwhile, with EnvBinding Policy also released in KubeVela 1.1, users can have multiple same components but deployed in different clusters.
These techniques raise new challenges for tracking and maintaining of resources.
## Goal
To tackle these challenges, a new architecture of ResourceTracker is proposed and implemented.
Generally, there are several major technical changes compared to the previous version:
1. Resources do not use OwnerReference to track their ResourceTracker anymore. In other word, the previous bi-directional binding is simplified into uni-directional, which allows us to have more flexible resource management strategies (such as releasing the control of resources).
2. Resources rendered manifests are recorded in ResourceTracker optionally. Based on that, we can prevent configuration drift by leveraging the reconciling mechanism of the Kubernetes operator pattern.
3. ResourceTracker deletion now use finalizer and leverage ApplicationController to reconcile. This ensures the deletion of Application truly removes all managed resources. Also, it allows users to manage versioned resource manually.
4. ResourceTracker in the HubCluster can track resources in ManagedClusters, so that no ResourceTracker is needed anymore in ManagedCluster. Now we can use caches for ResourceTracker again. Additionally, we do not individual multicluster garbage-collect logic anymore.
From the perspective of users, the direct new-incoming capabilities include:
1. Users can prevent configuration drift by default, which is a common usage of the classical Application model. Alternatively, they can only dispatch resources by leveraging [ApplyOnce](../../docs/examples/app-with-policy/apply-once-policy) Policy, which is the mode of Application-as-Workflow.
2. Users can have customized life-cycle control for application resources by leveraging [GarbageCollect](../../docs/examples/app-with-policy/gc-policy) Policy. For example, users might want to keep resources after version updates or application removal.
## Implementations
### ResourceTracker Types
There are several *ResourceTrackers* maintained for one Application.
- **Versioned ResourceTracker**: Each ResourceTracker keeps the record for the resources of one Application generation. Most resources are kept here. When application spec is updated, new versioned ResourceTracker will be created and used.
- **Root ResourceTracker**: This ResourceTracker keeps the record of the resources that shares the life-cycle with the Application instead of a single version. Resources recorded here will not be recycled until Application is deleted.
- **ControllerRevision ResourceTracker**: This ResourceTracker tracks all the dispatched component revisions. When some components are not in use in new versions, this ResourceTracker can elegantly recycle the revisions for those components.
### ResourceKeeper
The main implementation of the resource management logic locates at [pkg/resourcekeeper](../../pkg/resourcekeeper).
The **ResourceKeeper** takes charge of the dispatching, tracking, and recycling of all resources.
- **Dispatch**: First record resources in **ResourceTracker**, then apply resources. Depending on the life-cycle of resources, either **Versioned ResourceTracker** or **Root ResourceTracker** will be used.
- **Delete**: First mark resources as deleted in **ResourceTracker**, then delete resources.
- **StateKeep**: Ranging over all managed resources in the latest **Versioned ResourceTracker** and **Root ResourceTracker**, re-apply those resources.
- **GarbageCollect**: Mark outdated or unused ResourceTrackers as deleted and garbage-collect their managed resources. Details will be delivered below.
### Garbage Collection Details
The **GarbageCollect** process includes several steps.
0. **Init**: Scanning over all managed resources in all **Versioned ResourceTrackers** and **Root ResourceTracker** (do not retrieve content from APIServer), aggregating the trackers of each resource and calculate which one RT is responsible for garbage collecting it.
1. **Mark Stage**: Ranging over all ResourceTrackers. If `KeepLegacyResources` is not enabled, outdated ResourceTrackers will be marked as deleted. If enabled, inactive ResourceTrackers, that have all managed resources removed or managed by newer ResourceTrackers, will be marked as deleted.
2. **Sweep Stage**: For all ResourceTrackers marked as deleted, check if all inactive managed resources (managed by newer RT or deleted) are removed (do not exist). If true, remove the finalizer of the ResourceTracker (truly remove it).
3. **Finalize Stage**: For all ResourceTrackers marked as deleted, deleting all inactive managed resources.
4. **GarbageCollectComponentRevisionResourceTracker**: Ranging over all resources in active ResourceTrackers and calculate the component usage. For ComponentRevisions whose component is not in-use anymore, remove them.
The **Mark Stage** and **GarbageCollectComponentRevisionResourceTracker** will only run when application workflow succeeded, which means when application is still running workflow or new release is not successful, outdated ResourceTrackers will not be marked and resources will not be recycled.

View File

@@ -52,10 +52,6 @@ spec:
# - should mark "finish" phase in status.conditions.
workflow:
# suspend can manually stop the workflow and resume. it will also allow suspend policy for workflow.
suspend:
manual: true
steps:
# blue-green rollout
@@ -64,6 +60,9 @@ spec:
properties:
partition: "50%"
# suspend can manually stop the workflow and resume. it will also allow suspend policy for workflow.
- type: suspend
# traffic shift
- type: traffic-shift
properties:
@@ -131,6 +130,46 @@ spec:
}
```
### Stability mechanism
#### Backoff Time
Sometimes a workflow step can take a long time, so we need a backoff time for workflow reconciliation.
If the status of workflow step is `waiting` or `failed`, the workflow will be reconciled after a backoff time like below:
```
int(0.05 * 2^(n-1))
```
Based on the above formula, we will take `1s` and `600s` as our min and max time.
For example, if the workflow is `waiting`, the first ten reconciliation will be like:
| Times | 2^(n-1) | 0.05*2^(n-1) | Requeue After(s) |
| ------ | ------ | ------ | ------ |
| 1 | 1 | 0.05 | 1 |
| 2 | 2 | 0.1 | 1 |
| 3 | 4 | 0.2 | 1 |
| 4 | 8 | 0.4 | 1 |
| 5 | 16 | 0.8 | 1 |
| 6 | 32 | 1.6 | 1 |
| 7 | 64 | 3.2 | 3 |
| 8 | 128 | 6.4 | 6 |
| 9 | 256 | 12.8 | 12 |
| 10 | 512 | 25.6 | 25 |
| ... | ... | ... | ... |
#### Failed Workflow Steps
If the workflow step is `failed`, it means that there may be some error in the workflow step, like some cue errors.
> Note that if the workflow step is unhealthy, the workflow step will be marked as `wait` but not `failed` and it will wait for healthy.
For this case, we will retry the workflow step 10 times, and if the workflow step is still `failed`, we will suspend this workflow, and it's message will be `The workflow suspends automatically because the failed times of steps have reached the limit(10 times)`.
After the workflow is suspended, we can change the workflow step to make it work, and then use `vela workflow resume <workflow-name>` to resume it.
## Implementation
In this section we will discuss the implementation details for supporting policies and workflow tasks.
@@ -235,6 +274,7 @@ Here are the steps in Task Manager:
- continue: continue to run the next action.
- wait: makes the workflow manager to retry later.
- break: makes the workflow manager to stop the entire workflow.
- failedAfterRetries: if there are no other running steps, makes the workflow manager to suspend the workflow.
- Task Manager will change status as needed based on the returned TaskStatus, e.g. change to wait.
@@ -417,11 +457,13 @@ Each workflow task has similar interactions with Task Manager as follows:
- The Task Manager will apply the workflow object with annotation `app.oam.dev/workflow-context`. This annotation will pass in the context marshalled in json defined as the following:
```go
type WorkflowContext struct {
AppName string
AppRevisionName string
StepIndex int
}
type WorkflowContext struct {
cli client.Client
store *corev1.ConfigMap
components map[string]*ComponentManifest
vars *value.Value
modified bool
}
```
- The workflow object's status condition should turn to be `True` status and `Succeeded` reason, and `observedGeneration` to match the resource's generation per se.

View File

@@ -70,7 +70,7 @@
"responses": {
"200": {
"schema": {
"$ref": "#/definitions/v1.AddonRegistryMeta"
"$ref": "#/definitions/v1.AddonRegistry"
}
},
"400": {
@@ -116,7 +116,7 @@
"responses": {
"200": {
"schema": {
"$ref": "#/definitions/v1.AddonRegistryMeta"
"$ref": "#/definitions/v1.AddonRegistry"
}
},
"400": {
@@ -152,7 +152,7 @@
"responses": {
"200": {
"schema": {
"$ref": "#/definitions/v1.AddonRegistryMeta"
"$ref": "#/definitions/v1.AddonRegistry"
}
},
"400": {
@@ -2278,7 +2278,7 @@
}
}
},
"/api/v1/clusters/cloud-clusters/{provider}": {
"/api/v1/clusters/cloud_clusters/{provider}": {
"post": {
"consumes": [
"application/xml",
@@ -2338,7 +2338,7 @@
}
}
},
"/api/v1/clusters/cloud-clusters/{provider}/connect": {
"/api/v1/clusters/cloud_clusters/{provider}/connect": {
"post": {
"consumes": [
"application/xml",
@@ -2384,7 +2384,7 @@
}
}
},
"/api/v1/clusters/cloud-clusters/{provider}/create": {
"/api/v1/clusters/cloud_clusters/{provider}/create": {
"post": {
"consumes": [
"application/xml",
@@ -2430,7 +2430,7 @@
}
}
},
"/api/v1/clusters/cloud-clusters/{provider}/creation": {
"/api/v1/clusters/cloud_clusters/{provider}/creation": {
"get": {
"consumes": [
"application/xml",
@@ -2468,7 +2468,7 @@
}
}
},
"/api/v1/clusters/cloud-clusters/{provider}/creation/{cloudClusterName}": {
"/api/v1/clusters/cloud_clusters/{provider}/creation/{cloudClusterName}": {
"get": {
"consumes": [
"application/xml",
@@ -2860,7 +2860,7 @@
}
}
},
"/api/v1/policydefinitions": {
"/api/v1/policy_definitions": {
"get": {
"consumes": [
"application/xml",
@@ -3193,7 +3193,7 @@
"application/xml"
],
"tags": [
"oam-application"
"oam_application"
],
"summary": "get the specified oam application in the specified namespace",
"operationId": "getApplication",
@@ -3231,7 +3231,7 @@
"application/xml"
],
"tags": [
"oam-application"
"oam_application"
],
"summary": "create or update oam application in the specified namespace",
"operationId": "createOrUpdateApplication",
@@ -3275,7 +3275,7 @@
"application/xml"
],
"tags": [
"oam-application"
"oam_application"
],
"summary": "create or update oam application in the specified namespace",
"operationId": "deleteApplication",
@@ -3304,6 +3304,31 @@
}
},
"definitions": {
"addon.Dependency": {
"properties": {
"name": {
"type": "string"
}
}
},
"addon.DeployTo": {
"required": [
"runtime_cluster",
"disableControlPlane",
"runtimeCluster"
],
"properties": {
"disableControlPlane": {
"type": "boolean"
},
"runtimeCluster": {
"type": "boolean"
},
"runtime_cluster": {
"type": "boolean"
}
}
},
"addon.GitAddonSource": {
"properties": {
"path": {
@@ -3317,10 +3342,61 @@
}
}
},
"addon.Meta": {
"required": [
"name",
"version",
"description",
"icon",
"invisible"
],
"properties": {
"dependencies": {
"type": "array",
"items": {
"$ref": "#/definitions/addon.Dependency"
}
},
"deployTo": {
"$ref": "#/definitions/addon.DeployTo"
},
"description": {
"type": "string"
},
"icon": {
"type": "string"
},
"invisible": {
"type": "boolean"
},
"name": {
"type": "string"
},
"needNamespace": {
"type": "array",
"items": {
"type": "string"
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"url": {
"type": "string"
},
"version": {
"type": "string"
}
}
},
"addon.OSSAddonSource": {
"required": [
"end_point",
"bucket"
"bucket",
"path"
],
"properties": {
"bucket": {
@@ -3328,6 +3404,9 @@
},
"end_point": {
"type": "string"
},
"path": {
"type": "string"
}
}
},
@@ -3405,11 +3484,11 @@
},
"common.AppRolloutStatus": {
"required": [
"upgradedReplicas",
"batchRollingState",
"upgradedReadyReplicas",
"rollingState",
"currentBatch",
"upgradedReadyReplicas",
"batchRollingState",
"upgradedReplicas",
"lastTargetAppRevision"
],
"properties": {
@@ -3735,6 +3814,9 @@
"finished": {
"type": "boolean"
},
"message": {
"type": "string"
},
"mode": {
"type": "string"
},
@@ -4224,77 +4306,6 @@
}
}
},
"types.AddonDependency": {
"properties": {
"name": {
"type": "string"
}
}
},
"types.AddonDeployTo": {
"required": [
"control_plane",
"runtime_cluster"
],
"properties": {
"control_plane": {
"type": "boolean"
},
"runtime_cluster": {
"type": "boolean"
}
}
},
"types.AddonMeta": {
"required": [
"name",
"version",
"description",
"icon",
"invisible"
],
"properties": {
"dependencies": {
"type": "array",
"items": {
"$ref": "#/definitions/types.AddonDependency"
}
},
"deployTo": {
"$ref": "#/definitions/types.AddonDeployTo"
},
"description": {
"type": "string"
},
"icon": {
"type": "string"
},
"invisible": {
"type": "boolean"
},
"name": {
"type": "string"
},
"needNamespace": {
"type": "array",
"items": {
"type": "string"
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"url": {
"type": "string"
},
"version": {
"type": "string"
}
}
},
"types.Parameter": {
"required": [
"name"
@@ -4477,7 +4488,7 @@
}
}
},
"v1.AddonRegistryMeta": {
"v1.AddonRegistry": {
"required": [
"name"
],
@@ -4500,6 +4511,9 @@
"args"
],
"properties": {
"appStatus": {
"$ref": "#/definitions/common.AppStatus"
},
"args": {
"type": "object",
"additionalProperties": {
@@ -4583,14 +4597,14 @@
},
"v1.ApplicationDeployResponse": {
"required": [
"status",
"reason",
"deployUser",
"note",
"envName",
"triggerType",
"createTime",
"version"
"version",
"status"
],
"properties": {
"createTime": {
@@ -5424,6 +5438,9 @@
},
"name": {
"type": "string"
},
"namespace": {
"type": "string"
}
}
},
@@ -5496,6 +5513,9 @@
"cluster": {
"$ref": "#/definitions/v1.ClusterTarget"
},
"clusterAlias": {
"type": "string"
},
"createTime": {
"type": "string",
"format": "date-time"
@@ -5520,11 +5540,11 @@
},
"v1.DetailAddonResponse": {
"required": [
"name",
"invisible",
"version",
"description",
"icon",
"name",
"version",
"schema",
"uiSchema",
"definitions"
@@ -5539,11 +5559,11 @@
"dependencies": {
"type": "array",
"items": {
"$ref": "#/definitions/types.AddonDependency"
"$ref": "#/definitions/addon.Dependency"
}
},
"deployTo": {
"$ref": "#/definitions/types.AddonDeployTo"
"$ref": "#/definitions/addon.DeployTo"
},
"description": {
"type": "string"
@@ -5591,13 +5611,13 @@
},
"v1.DetailApplicationResponse": {
"required": [
"description",
"createTime",
"updateTime",
"icon",
"name",
"alias",
"project",
"description",
"createTime",
"policies",
"envBindings",
"status",
@@ -5659,19 +5679,19 @@
},
"v1.DetailClusterResponse": {
"required": [
"alias",
"description",
"icon",
"labels",
"status",
"apiServerURL",
"dashboardURL",
"kubeConfigSecret",
"model",
"name",
"description",
"reason",
"provider",
"dashboardURL",
"kubeConfig",
"model",
"alias",
"status",
"reason",
"apiServerURL",
"kubeConfigSecret",
"name",
"resourceInfo"
],
"properties": {
@@ -5724,13 +5744,13 @@
},
"v1.DetailComponentResponse": {
"required": [
"appPrimaryKey",
"creator",
"alias",
"type",
"createTime",
"updateTime",
"name"
"type",
"creator",
"name",
"alias",
"appPrimaryKey"
],
"properties": {
"alias": {
@@ -5825,10 +5845,10 @@
},
"v1.DetailDeliveryTargetResponse": {
"required": [
"createTime",
"updateTime",
"name",
"project"
"project",
"createTime",
"updateTime"
],
"properties": {
"alias": {
@@ -5841,6 +5861,9 @@
"cluster": {
"$ref": "#/definitions/v1.ClusterTarget"
},
"clusterAlias": {
"type": "string"
},
"createTime": {
"type": "string",
"format": "date-time"
@@ -5901,17 +5924,17 @@
},
"v1.DetailRevisionResponse": {
"required": [
"reason",
"updateTime",
"version",
"deployUser",
"note",
"workflowName",
"createTime",
"appPrimaryKey",
"version",
"status",
"reason",
"note",
"triggerType",
"envName",
"updateTime"
"envName"
],
"properties": {
"appPrimaryKey": {
@@ -5959,12 +5982,12 @@
},
"v1.DetailWorkflowRecordResponse": {
"required": [
"status",
"name",
"namespace",
"workflowName",
"workflowAlias",
"applicationRevision",
"status",
"deployTime",
"deployUser",
"note",
@@ -6016,13 +6039,13 @@
},
"v1.DetailWorkflowResponse": {
"required": [
"default",
"createTime",
"name",
"alias",
"description",
"enable",
"default",
"envName",
"createTime",
"enable",
"updateTime"
],
"properties": {
@@ -6135,7 +6158,7 @@
"deliveryTargets": {
"type": "array",
"items": {
"$ref": "#/definitions/v1.NameAlias"
"$ref": "#/definitions/v1.EnvBindingTarget"
}
},
"description": {
@@ -6156,15 +6179,32 @@
}
}
},
"v1.ListAddonRegistryResponse": {
"v1.EnvBindingTarget": {
"required": [
"registrys"
"name",
"alias"
],
"properties": {
"registrys": {
"alias": {
"type": "string"
},
"cluster": {
"$ref": "#/definitions/v1.ClusterTarget"
},
"name": {
"type": "string"
}
}
},
"v1.ListAddonRegistryResponse": {
"required": [
"registries"
],
"properties": {
"registries": {
"type": "array",
"items": {
"$ref": "#/definitions/v1.AddonRegistryMeta"
"$ref": "#/definitions/v1.AddonRegistry"
}
}
}
@@ -6177,8 +6217,11 @@
"addons": {
"type": "array",
"items": {
"$ref": "#/definitions/types.AddonMeta"
"$ref": "#/definitions/addon.Meta"
}
},
"message": {
"type": "string"
}
}
},

View File

@@ -0,0 +1,31 @@
# How to use ApplyOnce policy
By default, the KubeVela operator will prevent configuration drift for applied resources by reconciling them routinely. This is useful if you want to keep your application always have the desired configuration in avoid of some unintentional changes by external modifiers.
However, sometimes, you might want to use KubeVela Application to do the dispatch job and recycle job but want to leave resources mutable after workflow is finished. In this case, you can use the following ApplyOnce policy.
```shell
$ cat <<EOF | kubectl apply -f -
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: apply-once-app
spec:
components:
- name: hello-world
type: webservice
properties:
image: crccheck/hello-world
traits:
- type: scaler
properties:
replicas: 1
policies:
- name: apply-once
type: apply-once
properties:
enable: true
EOF
```
In this case, if you change the replicas of the `hello-world` deployment after Application enters `running` state, it would be brought back. On the contrary, if you set the `apply-once` policy to be disabled (by default), any changes to the replicas of `hello-world` application will be brought back in the next reconcile loop.

View File

@@ -1,4 +1,4 @@
## How to use garbage-collect policy
## How to keep legacy resources
Suppose you want to keep the resources created by the old version of the app. You only need to specify garbage-collect in the policy field of the app and enable the option `keepLegacyResource`.

View File

@@ -0,0 +1,79 @@
# How to persist resources
By leveraging the garbage-collect policy, users can persist some resources, which skip the normal garbage-collect process when application is updated.
Take the following app as an example, in the garbage-collect policy, a rule is added which marks all the resources created by the `expose` trait to use the `onAppDelete` strategy. This will keep those services until application is deleted.
```shell
$ cat <<EOF | kubectl apply -f -
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: garbage-collect-app
spec:
components:
- name: hello-world
type: webservice
properties:
image: crccheck/hello-world
traits:
- type: expose
properties:
port: [8000]
policies:
- name: garbage-collect
type: garbage-collect
properties:
rules:
- selector:
traitTypes:
- expose
strategy: onAppDelete
EOF
```
You can find deployment and service are created.
```shell
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
hello-world 1/1 1 1 74s
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world ClusterIP 10.96.160.208 <none> 8000/TCP 78s
```
If you upgrade the application and use a different component, you will find the old versioned deployment is deleted by the service is kept.
```shell
$ cat <<EOF | kubectl apply -f -
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: garbage-collect-app
spec:
components:
- name: hello-world-new
type: webservice
properties:
image: crccheck/hello-world
traits:
- type: expose
properties:
port: [8000]
policies:
- name: garbage-collect
type: garbage-collect
properties:
rules:
- selector:
traitTypes:
- expose
strategy: onAppDelete
EOF
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
hello-world-new 1/1 1 1 10s
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world ClusterIP 10.96.160.208 <none> 8000/TCP 5m56s
hello-world-new ClusterIP 10.96.20.4 <none> 8000/TCP 13s
```

View File

@@ -18,4 +18,4 @@ spec:
chart: "podinfo"
version: "5.1.4"
repository:
url: "http://oam.dev/catalog/"
url: "https://charts.kubevela.net/example/"

View File

@@ -20,7 +20,7 @@ spec:
properties:
component: express-server
- name: export-config
type: export-config
type: export2config
inputs:
- from: status
parameterKey: data.serverstatus

View File

@@ -20,7 +20,7 @@ spec:
properties:
component: express-server
- name: export-secret
type: export-secret
type: export2secret
inputs:
- from: status
parameterKey: data.serverstatus

View File

@@ -0,0 +1,52 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: init-secret-with-http
namespace: default
spec:
components:
- name: my-server
type: webservice
properties:
image: crccheck/hello-world
port: 8000
traits:
- type: service-binding
properties:
envMappings:
MY_ENV:
secret: secret1
MY_ENV2:
secret: secret2
key: test
workflow:
steps:
- name: webhook
type: webhook
outputs:
- name: mysecret
valueFrom: webhook.http.response.body
properties:
url:
value: <url>
data:
value: "test"
- name: export2secret
type: export2secret
inputs:
- from: mysecret
parameterKey: data.secret1
properties:
secretName: secret1
- name: export2secret2
type: export2secret
inputs:
- from: mysecret
parameterKey: data.test
properties:
secretName: secret2
- name: apply-component
type: apply-component
properties:
component: my-server

View File

@@ -19,7 +19,7 @@ spec:
workflow:
steps:
- name: notification
type: webhook-notification
type: notification
properties:
dingding:
# directly specify the webhook url

View File

@@ -18,64 +18,24 @@ package e2e
import (
"context"
"encoding/xml"
"net/http"
"os"
"path"
"regexp"
"fmt"
"strings"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/ghttp"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/e2e"
"github.com/oam-dev/kubevela/pkg/utils/common"
)
var _ = Describe("Addon Test", func() {
args := common.Args{}
args := common.Args{Schema: common.Scheme}
k8sClient, err := args.GetClient()
Expect(err).Should(BeNil())
ctx := context.Background()
originCm := v1.ConfigMap{}
cm := v1.ConfigMap{}
BeforeEach(func() {
server := ghttp.NewServer()
pathExp, err := regexp.Compile(".+")
Expect(err).Should(BeNil())
server.RouteToHandler("GET", pathExp, ossHandler)
registryCmStr := strings.ReplaceAll(velaRegistry, "REGISTRY_ADDR", server.Addr())
Expect(yaml.Unmarshal([]byte(registryCmStr), &cm))
err = k8sClient.Get(ctx, types.NamespacedName{Name: cm.Name, Namespace: cm.Namespace}, &originCm)
if err != nil {
if apierrors.IsNotFound(err) {
Expect(k8sClient.Create(ctx, &cm)).Should(BeNil())
} else {
Expect(err).Should(BeNil())
}
} else {
cm.ResourceVersion = originCm.ResourceVersion
Expect(k8sClient.Update(ctx, &cm)).Should(BeNil())
}
})
AfterEach(func() {
// after test we should write configmap back
latestCm := v1.ConfigMap{}
Expect(k8sClient.Get(ctx, types.NamespacedName{Name: cm.Name, Namespace: cm.Namespace}, &latestCm))
originCm.ResourceVersion = latestCm.ResourceVersion
Expect(k8sClient.Update(ctx, &originCm)).Should(BeNil())
})
Context("List addons", func() {
It("List all addon", func() {
@@ -94,6 +54,9 @@ var _ = Describe("Addon Test", func() {
output, err := e2e.LongTimeExec("vela addon disable test-addon", 600*time.Second)
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("Successfully disable addon"))
Eventually(func(g Gomega) {
g.Expect(apierrors.IsNotFound(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-test-addon", Namespace: "vela-system"}, &v1beta1.Application{}))).Should(BeTrue())
}, 60*time.Second).Should(Succeed())
})
It("Enable addon with input", func() {
@@ -106,73 +69,45 @@ var _ = Describe("Addon Test", func() {
output, err := e2e.LongTimeExec("vela addon disable test-addon", 600*time.Second)
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("Successfully disable addon"))
Eventually(func(g Gomega) {
g.Expect(apierrors.IsNotFound(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-test-addon", Namespace: "vela-system"}, &v1beta1.Application{}))).Should(BeTrue())
}, 60*time.Second).Should(Succeed())
})
})
})
var velaRegistry = `
apiVersion: v1
data:
registries: '{ "KubeVela":{ "name": "KubeVela", "oss": { "end_point": "http://REGISTRY_ADDR",
"bucket": "" } } }'
kind: ConfigMap
metadata:
name: vela-addon-registry
namespace: vela-system
`
Context("Addon registry test", func() {
It("List all addon registry", func() {
output, err := e2e.Exec("vela addon registry list")
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("KubeVela"))
})
// ListBucketResult describe a file list from OSS
type ListBucketResult struct {
Files []File `xml:"Contents"`
Count int `xml:"KeyCount"`
}
It("Get addon registry", func() {
output, err := e2e.Exec("vela addon registry get KubeVela")
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("KubeVela"))
})
// File is for oss xml parse
type File struct {
Name string `xml:"Key"`
Size int `xml:"Size"`
}
It("Add test addon registry", func() {
output, err := e2e.LongTimeExec("vela addon registry add my-repo --type=git --gitUrl=https://github.com/oam-dev/catalog --path=/experimental/addons", 600*time.Second)
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("Successfully add an addon registry my-repo"))
var ossHandler http.HandlerFunc = func(rw http.ResponseWriter, req *http.Request) {
queryPath := strings.TrimPrefix(req.URL.Path, "/")
if strings.Contains(req.URL.RawQuery, "prefix") {
prefix := req.URL.Query().Get("prefix")
res := ListBucketResult{
Files: []File{},
Count: 0,
}
for _, p := range paths {
if strings.HasPrefix(p, prefix) {
res.Files = append(res.Files, File{Name: p, Size: 100})
res.Count += 1
}
}
data, err := xml.Marshal(res)
if err != nil {
rw.Write([]byte(err.Error()))
}
rw.Write(data)
} else {
found := false
for _, p := range paths {
if queryPath == p {
file, err := os.ReadFile(path.Join("testdata", queryPath))
Eventually(func() error {
output, err := e2e.LongTimeExec("vela addon registry update my-repo --type=git --gitUrl=https://github.com/oam-dev/catalog --path=/addons", 300*time.Second)
if err != nil {
rw.Write([]byte(err.Error()))
return err
}
found = true
rw.Write(file)
break
}
}
if !found {
rw.Write([]byte("not found"))
}
}
}
if !strings.Contains(output, "Successfully update an addon registry my-repo") {
return fmt.Errorf("cannot update addon registry")
}
return nil
}, 30*time.Second, 300*time.Millisecond).Should(BeNil())
var paths = []string{
"test-addon/metadata.yaml",
"test-addon/template.yaml",
}
output, err = e2e.LongTimeExec("vela addon registry delete my-repo", 600*time.Second)
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("Successfully delete an addon registry my-repo"))
})
})
})

View File

@@ -0,0 +1,112 @@
/*
Copyright 2021 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"embed"
"encoding/xml"
"fmt"
"io/fs"
"log"
"net/http"
"path"
"strings"
"github.com/oam-dev/kubevela/e2e/addon/mock/utils"
"github.com/oam-dev/kubevela/pkg/addon"
)
var (
//go:embed testdata
testData embed.FS
paths []struct {
path string
length int64
}
)
func main() {
err := utils.ApplyMockServerConfig()
if err != nil {
log.Fatal("Apply mock server config to ConfigMap fail")
}
http.HandleFunc("/", ossHandler)
err = http.ListenAndServe(fmt.Sprintf(":%d", utils.Port), nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
var ossHandler http.HandlerFunc = func(rw http.ResponseWriter, req *http.Request) {
queryPath := strings.TrimPrefix(req.URL.Path, "/")
if strings.Contains(req.URL.RawQuery, "prefix") {
prefix := req.URL.Query().Get("prefix")
res := addon.ListBucketResult{
Files: []addon.File{},
Count: 0,
}
for _, p := range paths {
if strings.HasPrefix(p.path, prefix) {
res.Files = append(res.Files, addon.File{Name: p.path, Size: int(p.length)})
res.Count++
}
}
data, err := xml.Marshal(res)
if err != nil {
_, _ = rw.Write([]byte(err.Error()))
}
_, _ = rw.Write(data)
} else {
found := false
for _, p := range paths {
if queryPath == p.path {
file, err := testData.ReadFile(path.Join("testdata", queryPath))
if err != nil {
_, _ = rw.Write([]byte(err.Error()))
}
found = true
_, _ = rw.Write(file)
break
}
}
if !found {
_, _ = rw.Write([]byte("not found"))
}
}
}
func init() {
_ = fs.WalkDir(testData, "testdata", func(path string, d fs.DirEntry, err error) error {
path = strings.TrimPrefix(path, "testdata/")
path = strings.TrimPrefix(path, "testdata")
info, _ := d.Info()
size := info.Size()
if path == "" {
return nil
}
if size == 0 {
path += "/"
}
paths = append(paths, struct {
path string
length int64
}{path: path, length: size})
return nil
})
}

View File

@@ -0,0 +1,62 @@
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: helm release is a group of K8s resources
from either git repository or helm repo
name: helm-example
namespace: vela-system
spec:
schematic:
cue:
template: "output: {\n\tapiVersion: \"source.toolkit.fluxcd.io/v1beta1\"\n\tmetadata:
{\n\t\tname: context.name\n\t}\n\tif parameter.repoType == \"git\" {\n\t\tkind:
\"GitRepository\"\n\t\tspec: {\n\t\t\turl: parameter.url\n\t\t\tif parameter.git.branch
!= _|_ {\n\t\t\t\tref: branch: parameter.git.branch\n\t\t\t}\n\t\t\t_secret\n\t\t\t_sourceCommonArgs\n\t\t}\n\t}\n\tif
parameter.repoType == \"oss\" {\n\t\tkind: \"Bucket\"\n\t\tspec: {\n\t\t\tendpoint:
\ parameter.url\n\t\t\tbucketName: parameter.oss.bucketName\n\t\t\tprovider:
\ parameter.oss.provider\n\t\t\tif parameter.oss.region != _|_ {\n\t\t\t\tregion:
parameter.oss.region\n\t\t\t}\n\t\t\t_secret\n\t\t\t_sourceCommonArgs\n\t\t}\n\t}\n\tif
parameter.repoType == \"helm\" {\n\t\tkind: \"HelmRepository\"\n\t\tspec:
{\n\t\t\turl: parameter.url\n\t\t\t_secret\n\t\t\t_sourceCommonArgs\n\t\t}\n\t}\n}\n\noutputs:
release: {\n\tapiVersion: \"helm.toolkit.fluxcd.io/v2beta1\"\n\tkind:
\ \"HelmRelease\"\n\tmetadata: {\n\t\tname: context.name\n\t}\n\tspec:
{\n\t\tinterval: parameter.pullInterval\n\t\tchart: {\n\t\t\tspec: {\n\t\t\t\tchart:
\ parameter.chart\n\t\t\t\tversion: parameter.version\n\t\t\t\tsourceRef:
{\n\t\t\t\t\tif parameter.repoType == \"git\" {\n\t\t\t\t\t\tkind: \"GitRepository\"\n\t\t\t\t\t}\n\t\t\t\t\tif
parameter.repoType == \"helm\" {\n\t\t\t\t\t\tkind: \"HelmRepository\"\n\t\t\t\t\t}\n\t\t\t\t\tif
parameter.repoType == \"oss\" {\n\t\t\t\t\t\tkind: \"Bucket\"\n\t\t\t\t\t}\n\t\t\t\t\tname:
\ context.name\n\t\t\t\t\tnamespace: context.namespace\n\t\t\t\t}\n\t\t\t\tinterval:
parameter.pullInterval\n\t\t\t}\n\t\t}\n\t\tif parameter.targetNamespace
!= _|_ {\n\t\t\ttargetNamespace: parameter.targetNamespace\n\t\t}\n\t\tif
parameter.releaseName != _|_ {\n\t\t\treleaseName: parameter.releaseName\n\t\t}\n\t\tif
parameter.values != _|_ {\n\t\t\tvalues: parameter.values\n\t\t}\n\t}\n}\n\n_secret:
{\n\tif parameter.secretRef != _|_ {\n\t\tsecretRef: {\n\t\t\tname:
parameter.secretRef\n\t\t}\n\t}\n}\n\n_sourceCommonArgs: {\n\tinterval:
parameter.pullInterval\n\tif parameter.timeout != _|_ {\n\t\ttimeout:
parameter.timeout\n\t}\n}\n\nparameter: {\n\trepoType: *\"helm\" | \"git\"
| \"oss\"\n\t// +usage=The interval at which to check for repository/bucket
and relese updates, default to 5m\n\tpullInterval: *\"5m\" | string\n\t//
+usage=The Git or Helm repository URL, OSS endpoint, accept HTTP/S or
SSH address as git url,\n\turl: string\n\t// +usage=The name of the
secret containing authentication credentials\n\tsecretRef?: string\n\t//
+usage=The timeout for operations like download index/clone repository,
optional\n\ttimeout?: string\n\n\tgit?: {\n\t\t// +usage=The Git reference
to checkout and monitor for changes, defaults to master branch\n\t\tbranch:
string\n\t}\n\toss?: {\n\t\t// +usage=The bucket's name, required if
repoType is oss\n\t\tbucketName: string\n\t\t// +usage=\"generic\" for
Minio, Amazon S3, Google Cloud Storage, Alibaba Cloud OSS, \"aws\" for
retrieve credentials from the EC2 service when credentials not specified,
default \"generic\"\n\t\tprovider: *\"generic\" | \"aws\"\n\t\t// +usage=The
bucket region, optional\n\t\tregion?: string\n\t}\n\n\t// +usage=1.The
relative path to helm chart for git/oss source. 2. chart name for helm
resource 3. relative path for chart package(e.g. ./charts/podinfo-1.2.3.tgz)\n\tchart:
string\n\t// +usage=Chart version\n\tversion: *\"*\" | string\n\t//
+usage=The namespace for helm chart, optional\n\ttargetNamespace?: string\n\t//
+usage=The release name\n\treleaseName?: string\n\t// +usage=Chart values\n\tvalues?:
#nestedmap\n}\n\n#nestedmap: {\n\t...\n}\n"
status:
healthPolicy: 'isHealth: len(context.outputs.release.status.conditions)
!= 0 && context.outputs.release.status.conditions[0]["status"]=="True"'
workload:
type: autodetects.core.oam.dev

View File

@@ -0,0 +1,23 @@
name: example
version: 1.0.0
description: Extended workload to do continuous and progressive delivery
icon: https://raw.githubusercontent.com/fluxcd/flux/master/docs/_files/weave-flux.png
url: https://fluxcd.io
tags:
- extended_workload
- gitops
- only_example
deployTo:
control_plane: true
runtime_cluster: false
dependencies: []
#- name: addon_name
# set invisible means this won't be list and will be enabled when depended on
# for example, terraform-alibaba depends on terraform which is invisible,
# when terraform-alibaba is enabled, terraform will be enabled automatically
# default: false
invisible: false

View File

@@ -0,0 +1,12 @@
output: {
type: "raw"
properties: {
apiVersion: "v1"
kind: "ConfigMap"
metadata: {
name: "exampleinput"
namespace: "default"
}
data: input: parameter.example
}
}

View File

@@ -0,0 +1,3 @@
parameter: {
example: string
}

View File

@@ -4,8 +4,8 @@ metadata:
labels:
app.kubernetes.io/instance: flux-system
control-plane: controller
name: notification-controller
namespace: flux-system
name: source-controller
namespace: example-system
spec:
ports:
- name: http
@@ -13,5 +13,5 @@ spec:
protocol: TCP
targetPort: http
selector:
app: notification-controller
type: ClusterIP
app: source-controller
type: ClusterIP

View File

@@ -0,0 +1,22 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example
namespace: vela-system
spec:
workflow:
steps:
- name: apply-ns
type: apply-component
properties:
component: ns-example-system
- name: apply-resources
type: apply-remaining
components:
- name: ns-example-system
type: raw
properties:
apiVersion: v1
kind: Namespace
metadata:
name: example-system

View File

@@ -57,6 +57,7 @@ spec:
name: context.name
}
spec: {
timeout: parameter.installTimeout
interval: parameter.pullInterval
chart: {
spec: {
@@ -115,6 +116,8 @@ spec:
secretRef?: string
// +usage=The timeout for operations like download index/clone repository, optional
timeout?: string
// +usage=The timeout for operation `helm install`, optional
installTimeout: *"10m" | string
git?: {
// +usage=The Git reference to checkout and monitor for changes, defaults to master branch

View File

@@ -4,6 +4,7 @@ metadata:
annotations:
definition.oam.dev/description: "A list of JSON6902 patch to selected target"
name: kustomize-json-patch
namespace: vela-system
spec:
schematic:
cue:

View File

@@ -4,6 +4,7 @@ metadata:
annotations:
definition.oam.dev/description: "A list of StrategicMerge or JSON6902 patch to selected target"
name: kustomize-patch
namespace: vela-system
spec:
schematic:
cue:

View File

@@ -4,6 +4,7 @@ metadata:
annotations:
definition.oam.dev/description: "A list of strategic merge to kustomize config"
name: kustomize-strategy-merge
namespace: vela-system
spec:
schematic:
cue:

View File

@@ -0,0 +1,18 @@
name: fluxcd
version: 1.0.0
description: Extended workload to do continuous and progressive delivery
icon: https://raw.githubusercontent.com/fluxcd/flux/master/docs/_files/weave-flux.png
url: https://fluxcd.io
tags:
- extended_workload
- gitops
deployTo:
control_plane: true
runtime_cluster: true
needNamespace:
- flux-system
invisible: false

View File

@@ -20,10 +20,4 @@ subjects:
namespace: flux-system
- kind: ServiceAccount
name: sa-notification-controller
namespace: flux-system
- kind: ServiceAccount
name: sa-image-reflector-controller
namespace: flux-system
- kind: ServiceAccount
name: sa-image-automation-controller
namespace: flux-system

View File

@@ -23,12 +23,6 @@ rules:
- '*'
verbs:
- '*'
- apiGroups:
- notification.toolkit.fluxcd.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- image.toolkit.fluxcd.io
resources:

View File

@@ -0,0 +1,6 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: fluxcd
namespace: vela-system
spec:

Some files were not shown because too many files have changed in this diff Show More