From 0c0b9d0774d4f8f0337522a1f4e395b3145bda6a Mon Sep 17 00:00:00 2001 From: wyike <77846369+wangyikewxgm@users.noreply.github.com> Date: Thu, 19 Aug 2021 15:33:40 +0800 Subject: [PATCH] rollout OCM demo and defer rollout pass owner to handleSucceed (#2121) * finish test fix demo finish test finish docs fix rollout template add more test add comment * impove test coverage and wrap error fix checkdiff add more time --- .../templates/defwithtemplate/rollout.yaml | 5 +- .../workflow-with-ocm/rollout/README.md | 119 ++++++++++++++++++ .../rollout/app-first-scale.yaml | 35 ++++++ .../workflow-with-ocm/rollout/app-revert.yaml | 41 ++++++ .../rollout/app-scale-down-v1.yaml | 41 ++++++ .../rollout/app-update-v2.yaml | 41 ++++++ .../rollout/app-v2-scale.yaml | 41 ++++++ .../rollout/dispatchRevDef.yaml | 60 +++++++++ .../rollout/dispatchTraits.yaml | 34 +++++ .../v1alpha1/rollout/handler.go | 30 +++-- .../v1alpha1/rollout/handler_suit_test.go | 69 ++++++++++ .../v1alpha1/rollout/handler_test.go | 78 +++++++++++- test/e2e-test/rollout_trait_test.go | 59 ++++++++- .../definitions/internal/rollout.cue | 7 +- 14 files changed, 638 insertions(+), 22 deletions(-) create mode 100644 docs/examples/workflow-with-ocm/rollout/README.md create mode 100644 docs/examples/workflow-with-ocm/rollout/app-first-scale.yaml create mode 100644 docs/examples/workflow-with-ocm/rollout/app-revert.yaml create mode 100644 docs/examples/workflow-with-ocm/rollout/app-scale-down-v1.yaml create mode 100644 docs/examples/workflow-with-ocm/rollout/app-update-v2.yaml create mode 100644 docs/examples/workflow-with-ocm/rollout/app-v2-scale.yaml create mode 100644 docs/examples/workflow-with-ocm/rollout/dispatchRevDef.yaml create mode 100644 docs/examples/workflow-with-ocm/rollout/dispatchTraits.yaml diff --git a/charts/vela-core/templates/defwithtemplate/rollout.yaml b/charts/vela-core/templates/defwithtemplate/rollout.yaml index 07ae4fca4..0c0c9ecca 100644 --- a/charts/vela-core/templates/defwithtemplate/rollout.yaml +++ b/charts/vela-core/templates/defwithtemplate/rollout.yaml @@ -26,7 +26,9 @@ spec: rolloutStrategy: "IncreaseFirst" rolloutBatches: parameter.rolloutBatches targetSize: parameter.targetSize - batchPartition: parameter.batchPartition + if parameter["batchPartition"] != _|_ { + batchPartition: parameter.batchPartition + } } } } @@ -37,5 +39,4 @@ spec: batchPartition?: int } rolloutBatch: replicas: int - skipRevisionAffect: true diff --git a/docs/examples/workflow-with-ocm/rollout/README.md b/docs/examples/workflow-with-ocm/rollout/README.md new file mode 100644 index 000000000..24c374dbb --- /dev/null +++ b/docs/examples/workflow-with-ocm/rollout/README.md @@ -0,0 +1,119 @@ +# Rollout with OCM + +In this tutorial, you will use rollout in runtime cluster with OCM. + +## Prerequisites + +- Have a multi-cluster environment witch have installed OCM by following this [guid](../README.md). The name of managed cluster generally is `poc-01`. + +- install vela-rollout chart in managed-cluster with Helm. +```shell +$ helm repo add kubevela https://charts.kubevela.net/core +``` +```shell +$ helm isntall vela-rollout --create-namespace -n vela-system kubevela/vela-rollout +``` + +## Install workflowStepDefinition + +Apply workflowStepDefinitions in control-plane cluster. + +```shell +$ kubectl apply -f dispatchRevDef.yaml +``` + +```shell +$ kubectl apply -f dispatchTraits.yaml +``` + +## Deploy and rollout + +1. Apply application in control-plane cluster. + +```shell +$ kubectl apply -f app-first-scale.yaml +``` + +Wait a few minute, check rollout and workload status in managed cluster. +```shell +$ kubectl get rollout +NAME TARGET UPGRADED READY BATCH-STATE ROLLING-STATE AGE +nginx-server 2 2 2 batchReady rolloutSucceed 25h +``` +```shell +$ kubectl get deploy +NAME READY UP-TO-DATE AVAILABLE AGE +nginx-server-v1 2/2 2 2 25h +``` + +2. Update application to v2. + +```shell +$ kubectl apply -f app-update-v2.yaml +``` + +check rollout and workload status. +```shell +$ kubectl get rollout +NAME TARGET UPGRADED READY BATCH-STATE ROLLING-STATE AGE +nginx-server 2 2 2 batchReady rolloutSucceed 25h +``` +```shell +$ kubectl get deploy +NAME READY UP-TO-DATE AVAILABLE AGE +nginx-server-v2 2/2 2 2 25h +``` + +3. Scale up. + +```shell +$ kubectl apply -f app-v2-scale.yaml +``` + +check the status of rollout and workload. +```shell +$ kubectl get rollout +NAME TARGET UPGRADED READY BATCH-STATE ROLLING-STATE AGE +nginx-server 4 4 4 batchReady rolloutSucceed 25h +``` +```shell +$ kubectl get deploy +NAME READY UP-TO-DATE AVAILABLE AGE +nginx-server-v2 4/4 4 4 25h +``` + +4. Roll back to v1. +```shell +$ kubectl apply -f app-revert.yaml +``` + +check rollout and workload status. +```shell +$ kubectl get rollout +NAME TARGET UPGRADED READY BATCH-STATE ROLLING-STATE AGE +nginx-server 4 4 4 batchReady rolloutSucceed 25h +``` + +```shell +$ kubectl get deploy +NAME READY UP-TO-DATE AVAILABLE AGE +nginx-server-v1 4/4 4 4 25h +``` + +5. Scale down. +```shell +$ kubectl apply -f app-scale-down-v1.yaml +``` + +check rollout and workload status. +```shell +$ kubectl get rollout +NAME TARGET UPGRADED READY BATCH-STATE ROLLING-STATE AGE +nginx-server 2 2 2 batchReady rolloutSucceed 25h +``` + +```shell +$ kubectl get deploy +NAME READY UP-TO-DATE AVAILABLE AGE +nginx-server-v1 2/2 2 2 25h +``` \ No newline at end of file diff --git a/docs/examples/workflow-with-ocm/rollout/app-first-scale.yaml b/docs/examples/workflow-with-ocm/rollout/app-first-scale.yaml new file mode 100644 index 000000000..cd18e4679 --- /dev/null +++ b/docs/examples/workflow-with-ocm/rollout/app-first-scale.yaml @@ -0,0 +1,35 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: workflow-rollout-demo + namespace: default +spec: + components: + - name: nginx-server + externalRevision: nginx-server-v1 + type: webservice + properties: + image: nginx:1.20.0 + port: 80 + traits: + - type: rollout + properties: + targetRevision: nginx-server-v1 + targetSize: 2 + rolloutBatches: + - replicas: 1 + - replicas: 1 + + workflow: + steps: + - name: dispatch-comp-rev-v1 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v1 + cluster: poc-01 + + - name: dispatchRollout + type: dispatch-traits + properties: + component: nginx-server + cluster: poc-01 \ No newline at end of file diff --git a/docs/examples/workflow-with-ocm/rollout/app-revert.yaml b/docs/examples/workflow-with-ocm/rollout/app-revert.yaml new file mode 100644 index 000000000..b2c45696c --- /dev/null +++ b/docs/examples/workflow-with-ocm/rollout/app-revert.yaml @@ -0,0 +1,41 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: workflow-rollout-demo + namespace: default +spec: + components: + - name: nginx-server + externalRevision: nginx-server-v2 + type: webservice + properties: + image: nginx:1.21 + port: 80 + traits: + - type: rollout + properties: + targetRevision: nginx-server-v1 + targetSize: 4 + rolloutBatches: + - replicas: 2 + - replicas: 2 + + workflow: + steps: + - name: dispatch-comp-rev-v1 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v1 + cluster: poc-01 + + - name: dispatch-comp-rev-v2 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v2 + cluster: poc-01 + + - name: dispatchRollout + type: dispatch-traits + properties: + component: nginx-server + cluster: poc-01 \ No newline at end of file diff --git a/docs/examples/workflow-with-ocm/rollout/app-scale-down-v1.yaml b/docs/examples/workflow-with-ocm/rollout/app-scale-down-v1.yaml new file mode 100644 index 000000000..668151c25 --- /dev/null +++ b/docs/examples/workflow-with-ocm/rollout/app-scale-down-v1.yaml @@ -0,0 +1,41 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: workflow-rollout-demo + namespace: default +spec: + components: + - name: nginx-server + externalRevision: nginx-server-v2 + type: webservice + properties: + image: nginx:1.21 + port: 80 + traits: + - type: rollout + properties: + targetRevision: nginx-server-v1 + targetSize: 2 + rolloutBatches: + - replicas: 1 + - replicas: 1 + + workflow: + steps: + - name: dispatch-comp-rev-v1 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v1 + cluster: cluster2 + + - name: dispatch-comp-rev-v2 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v2 + cluster: cluster2 + + - name: dispatchRollout + type: dispatch-traits + properties: + component: nginx-server + cluster: cluster2 \ No newline at end of file diff --git a/docs/examples/workflow-with-ocm/rollout/app-update-v2.yaml b/docs/examples/workflow-with-ocm/rollout/app-update-v2.yaml new file mode 100644 index 000000000..5d597b3fc --- /dev/null +++ b/docs/examples/workflow-with-ocm/rollout/app-update-v2.yaml @@ -0,0 +1,41 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: workflow-rollout-demo + namespace: default +spec: + components: + - name: nginx-server + externalRevision: nginx-server-v2 + type: webservice + properties: + image: nginx:1.21 + port: 80 + traits: + - type: rollout + properties: + targetRevision: nginx-server-v2 + targetSize: 2 + rolloutBatches: + - replicas: 1 + - replicas: 1 + + workflow: + steps: + - name: dispatch-comp-rev-v1 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v1 + cluster: poc-01 + + - name: dispatch-comp-rev-v2 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v2 + cluster: poc-01 + + - name: dispatchRollout + type: dispatch-traits + properties: + component: nginx-server + cluster: poc-01 \ No newline at end of file diff --git a/docs/examples/workflow-with-ocm/rollout/app-v2-scale.yaml b/docs/examples/workflow-with-ocm/rollout/app-v2-scale.yaml new file mode 100644 index 000000000..a31a60fe7 --- /dev/null +++ b/docs/examples/workflow-with-ocm/rollout/app-v2-scale.yaml @@ -0,0 +1,41 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: workflow-rollout-demo + namespace: default +spec: + components: + - name: nginx-server + externalRevision: nginx-server-v2 + type: webservice + properties: + image: nginx:1.21 + port: 80 + traits: + - type: rollout + properties: + targetRevision: nginx-server-v2 + targetSize: 4 + rolloutBatches: + - replicas: 1 + - replicas: 1 + + workflow: + steps: + - name: dispatch-comp-rev-v1 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v1 + cluster: poc-01 + + - name: dispatch-comp-rev-v2 + type: dispatch-comp-rev + properties: + compRev: nginx-server-v2 + cluster: poc-01 + + - name: dispatchRollout + type: dispatch-traits + properties: + component: nginx-server + cluster: poc-01 \ No newline at end of file diff --git a/docs/examples/workflow-with-ocm/rollout/dispatchRevDef.yaml b/docs/examples/workflow-with-ocm/rollout/dispatchRevDef.yaml new file mode 100644 index 000000000..8a8c410d7 --- /dev/null +++ b/docs/examples/workflow-with-ocm/rollout/dispatchRevDef.yaml @@ -0,0 +1,60 @@ +apiVersion: core.oam.dev/v1beta1 +kind: WorkflowStepDefinition +metadata: + name: dispatch-comp-rev + namespace: vela-system +spec: + schematic: + cue: + template: | + import ("vela/op") + + componentRev: op.#Read & { + value: { + kind: "ControllerRevision" + apiVersion: "apps/v1" + metadata: { + name: parameter.compRev + namespace: context.namespace + } + } + } + + apply: op.#Apply & { + value: { + apiVersion: "work.open-cluster-management.io/v1" + kind: "ManifestWork" + metadata: { + namespace: parameter.cluster + name: "comprevision-" + parameter.compRev + } + spec: { + workload: { + manifests: [{ + kind: "ControllerRevision" + apiVersion: "apps/v1" + metadata: { + name: parameter.compRev + namespace: context.namespace + } + data: { + apiVersion: "core.oam.dev/v1alpha2" + kind: "Component" + metadata: + name: context.name + namespace: context.namespace + spec: + workload: { + componentRev.value.data.spec.workload + } + } + }] + } + } + } + } + + parameter: { + compRev: string + cluster: string + } \ No newline at end of file diff --git a/docs/examples/workflow-with-ocm/rollout/dispatchTraits.yaml b/docs/examples/workflow-with-ocm/rollout/dispatchTraits.yaml new file mode 100644 index 000000000..93a84d699 --- /dev/null +++ b/docs/examples/workflow-with-ocm/rollout/dispatchTraits.yaml @@ -0,0 +1,34 @@ +apiVersion: core.oam.dev/v1beta1 +kind: WorkflowStepDefinition +metadata: + name: dispatch-traits + namespace: vela-system +spec: + schematic: + cue: + template: | + import ("vela/op") + + comp: op.#Load & { + component: parameter.component + } + + apply: op.#Apply & { + value: { + apiVersion: "work.open-cluster-management.io/v1" + kind: "ManifestWork" + metadata: { + namespace: parameter.cluster + name: parameter.component + "-traits" + } + spec: { + workload: manifests : comp.value.auxiliaries + } + } + } + + + parameter: { + component: string + cluster: string + } \ No newline at end of file diff --git a/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler.go b/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler.go index 46ec7cb07..601c20a9e 100644 --- a/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler.go +++ b/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler.go @@ -22,6 +22,8 @@ import ( "github.com/pkg/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -123,10 +125,6 @@ func (h *handler) applyTargetWorkload(ctx context.Context) error { return err } - if err := h.recordWorkloadInResourceTracker(ctx); err != nil { - return errors.Wrap(err, "fail to add resourceTracker as owner for workload") - } - klog.InfoS("template rollout target workload", "namespace", h.rollout.Namespace, "rollout", h.rollout.Name, "targetWorkload", h.targetWorkload.GetName()) return nil @@ -134,7 +132,22 @@ func (h *handler) applyTargetWorkload(ctx context.Context) error { // handleFinalizeSucceed gc source workload if target and source are not same one func (h *handler) handleFinalizeSucceed(ctx context.Context) error { - // this is a scale operation + // patch target workload to pass rollout owner to workload + targetWl := h.targetWorkload.DeepCopy() + if err := h.Get(ctx, types.NamespacedName{Namespace: targetWl.GetNamespace(), Name: targetWl.GetName()}, targetWl); err != nil { + return errors.Wrap(err, "fail to get targetWorkload") + } + wlPatch := client.MergeFrom(targetWl.DeepCopy()) + h.passOwnerToTargetWorkload(targetWl) + if err := h.Patch(ctx, targetWl, wlPatch); err != nil { + return errors.Wrap(err, "fail to patch workload to pass rollout owners to workload") + } + + // recode targetWorkload + if err := h.recordWorkloadInResourceTracker(ctx); err != nil { + return errors.Wrap(err, "fail to add resourceTracker as owner for workload") + } + if h.sourceWorkload != nil && (h.sourceWorkload.GetName() != h.targetWorkload.GetName()) { if err := h.Delete(ctx, h.sourceWorkload); err != nil { return err @@ -183,9 +196,6 @@ func (h *handler) setWorkloadBaseInfo() { util.AddLabels(h.targetWorkload, map[string]string{oam.LabelAppComponentRevision: h.targetRevName}) util.AddAnnotations(h.targetWorkload, map[string]string{oam.AnnotationSkipGC: "true"}) - // pass rollout's ownerReference to workload - h.passOwnerToTargetWorkload() - if h.sourceWorkload != nil { h.sourceWorkload.SetName(h.compName) util.AddLabels(h.sourceWorkload, map[string]string{oam.LabelAppComponentRevision: h.sourceRevName}) @@ -270,11 +280,11 @@ func (h *handler) recordWorkloadInResourceTracker(ctx context.Context) error { return nil } -func (h *handler) passOwnerToTargetWorkload() { +func (h *handler) passOwnerToTargetWorkload(wl *unstructured.Unstructured) { var owners []metav1.OwnerReference for _, reference := range h.rollout.OwnerReferences { reference.Controller = pointer.Bool(false) owners = append(owners, reference) } - h.targetWorkload.SetOwnerReferences(owners) + wl.SetOwnerReferences(owners) } diff --git a/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler_suit_test.go b/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler_suit_test.go index e807e3e40..e5514da98 100644 --- a/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler_suit_test.go +++ b/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler_suit_test.go @@ -292,6 +292,75 @@ var _ = Describe("Test rollout related handler func", func() { Expect(checkRt.Status.TrackedResources[0].Name).Should(BeEquivalentTo("test-workload")) Expect(checkRt.Status.TrackedResources[0].UID).Should(BeEquivalentTo("test-uid")) }) + + It("Test handle succeed func", func() { + ctx := context.Background() + namespaceName := "default" + rtName := "resourcetracker-v1-test-default" + rt := v1beta1.ResourceTracker{ + ObjectMeta: metav1.ObjectMeta{ + Name: rtName, + }, + } + Expect(k8sClient.Create(ctx, &rt)).Should(BeNil()) + rollout := v1alpha1.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(&rt, v1beta1.ResourceTrackerKindVersionKind), + }, + }, + } + deploy := &appsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + Kind: "Deployment", + APIVersion: "apps/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "workload.oam.dev/type": "worker", + }, + Name: "test-workload", + Namespace: namespaceName, + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{ + "workload.oam.dev/type": "worker", + }}, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{ + "workload.oam.dev/type": "worker", + }}, + Spec: v1.PodSpec{Containers: []v1.Container{{ + Image: "busybox", + Name: "comp-name", + Command: []string{"sleep", "1000"}, + }, + }}}, + }, + } + u, err := util.Object2Unstructured(deploy) + Expect(err).Should(BeNil()) + Expect(k8sClient.Create(ctx, u)).Should(BeNil()) + h := &handler{ + reconciler: &reconciler{ + Client: k8sClient, + record: event.NewNopRecorder(), + }, + rollout: &rollout, + targetWorkload: u, + } + Expect(h.handleFinalizeSucceed(ctx)).Should(BeNil()) + checkDeploy := new(appsv1.Deployment) + Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: u.GetNamespace(), Name: u.GetName()}, checkDeploy)).Should(BeNil()) + Expect(len(checkDeploy.OwnerReferences)).Should(BeEquivalentTo(1)) + Expect(checkDeploy.OwnerReferences[0].Kind).Should(BeEquivalentTo(v1beta1.ResourceTrackerKind)) + Expect(checkDeploy.OwnerReferences[0].Name).Should(BeEquivalentTo(rtName)) + checkRt := v1beta1.ResourceTracker{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: rtName}, &checkRt)).Should(BeNil()) + Expect(len(checkRt.Status.TrackedResources)).Should(BeEquivalentTo(1)) + Expect(checkRt.Status.TrackedResources[0].Name).Should(BeEquivalentTo("test-workload")) + Expect(checkRt.Status.TrackedResources[0].UID).Should(BeEquivalentTo(u.GetUID())) + }) }) }) diff --git a/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler_test.go b/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler_test.go index 131a957a6..a9a5b39ed 100644 --- a/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler_test.go +++ b/pkg/controller/standard.oam.dev/v1alpha1/rollout/handler_test.go @@ -17,8 +17,14 @@ limitations under the License. package rollout import ( + "context" + "fmt" + "strings" "testing" + "github.com/crossplane/crossplane-runtime/pkg/test" + "sigs.k8s.io/controller-runtime/pkg/client" + "gotest.tools/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -324,10 +330,72 @@ func TestPassOwnerReference(t *testing.T) { u := &unstructured.Unstructured{} u.SetName("test-workload") h := &handler{ - rollout: &rollout, - targetWorkload: u, + rollout: &rollout, + } + h.passOwnerToTargetWorkload(u) + assert.Assert(t, len(u.GetOwnerReferences()) == 1) + assert.Assert(t, *u.GetOwnerReferences()[0].Controller == false) +} + +func TestHandleSucceedError(t *testing.T) { + getErr := fmt.Errorf("got error") + patchErr := fmt.Errorf("patch error") + object := &unstructured.Unstructured{} + object.SetName("name") + object.SetNamespace("namespace") + getClient := test.NewMockGetFn(getErr) + rollout := oamstandard.Rollout{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{ + { + UID: "test-UID", + Kind: v1beta1.ResourceTrackerKind, + }, + }, + }} + ctx := context.Background() + patchClient := test.MockClient{ + MockGet: func(_ context.Context, _ client.ObjectKey, obj client.Object) error { + if obj != nil { + obj = object + } + return nil + }, + MockPatch: test.NewMockPatchFn(patchErr), + } + testCase := map[string]struct { + h handler + err error + }{ + "Test get error": { + h: handler{ + targetWorkload: object, + reconciler: &reconciler{ + Client: &test.MockClient{ + MockGet: getClient, + }, + }, + }, + err: getErr, + }, + "Test patch error": { + h: handler{ + targetWorkload: object, + reconciler: &reconciler{ + Client: &patchClient, + }, + rollout: &rollout, + }, + err: patchErr, + }, + } + + for testName, oneCase := range testCase { + t.Run(testName, func(t *testing.T) { + got := oneCase.h.handleFinalizeSucceed(ctx) + if got == nil || !strings.Contains(oneCase.err.Error(), oneCase.err.Error()) { + t.Errorf("handleSucceed () got %v, want %v", got, oneCase.err) + } + }) } - h.passOwnerToTargetWorkload() - assert.Assert(t, len(h.targetWorkload.GetOwnerReferences()) == 1) - assert.Assert(t, *h.targetWorkload.GetOwnerReferences()[0].Controller == false) } diff --git a/test/e2e-test/rollout_trait_test.go b/test/e2e-test/rollout_trait_test.go index 6463c5d1b..dfce9a1cb 100644 --- a/test/e2e-test/rollout_trait_test.go +++ b/test/e2e-test/rollout_trait_test.go @@ -126,6 +126,7 @@ var _ = Describe("rollout related e2e-test,rollout trait test", func() { if len(targerDeploy.OwnerReferences) != 1 { return fmt.Errorf("workload ownerReference missMatch") } + // guarantee rollout's owners and workload's owners are same if targerDeploy.OwnerReferences[0].Kind != rollout.OwnerReferences[0].Kind || targerDeploy.OwnerReferences[0].Name != rollout.OwnerReferences[0].Name { return fmt.Errorf("workload ownerReference missMatch") @@ -236,6 +237,57 @@ var _ = Describe("rollout related e2e-test,rollout trait test", func() { return nil }, 30*time.Second, 300*time.Millisecond).Should(BeNil()) verifySuccess("express-server-v4") + By("update application batch upgrade to v5") + Eventually(func() error { + if err = k8sClient.Get(ctx, appKey, checkApp); err != nil { + return err + } + checkApp.Spec.Components[0].Properties.Raw = []byte(`{"image":"stefanprodan/podinfo:4.0.3","cpu":"0.5"}`) + checkApp.Spec.Components[0].Traits[0].Properties.Raw = + []byte(`{"firstBatchReplicas":2,"secondBatchReplicas":2,"targetSize":4,"batchPartition":0}`) + if err = k8sClient.Update(ctx, checkApp); err != nil { + return err + } + return nil + }, 30*time.Second, 300*time.Millisecond).Should(BeNil()) + // check rollout paused in partition 0 + time.Sleep(5 * time.Second) + Eventually(func() error { + rolloutKey := types.NamespacedName{Namespace: namespaceName, Name: componentName} + if err := k8sClient.Get(ctx, rolloutKey, &rollout); err != nil { + return err + } + if rollout.Spec.TargetRevisionName != "express-server-v5" { + return fmt.Errorf("rollout have not point to right targetRevision") + } + if rollout.Status.RollingState != v1alpha1.RollingInBatchesState { + return fmt.Errorf("error rollout status state %s", rollout.Status.RollingState) + } + if rollout.Status.CurrentBatch != 0 { + return fmt.Errorf("current batchPartition missmatch accutally %d", rollout.Status.CurrentBatch) + } + deployKey := types.NamespacedName{Namespace: namespaceName, Name: compRevName} + if err := k8sClient.Get(ctx, deployKey, &targerDeploy); err != nil { + return err + } + if *targerDeploy.Spec.Replicas != 2 { + return fmt.Errorf("targetDeploy replicas missMatch %d", *targerDeploy.Spec.Replicas) + } + return nil + }, 60*time.Second, 300*time.Millisecond).Should(BeNil()) + By("continue rollout upgrade legacy batches") + Eventually(func() error { + if err = k8sClient.Get(ctx, appKey, checkApp); err != nil { + return err + } + checkApp.Spec.Components[0].Traits[0].Properties.Raw = + []byte(`{"firstBatchReplicas":2,"secondBatchReplicas":2,"targetSize":4,"batchPartition":1}`) + if err = k8sClient.Update(ctx, checkApp); err != nil { + return err + } + return nil + }, 30*time.Second, 300*time.Millisecond).Should(BeNil()) + verifySuccess("express-server-v5") By("delete the application, check workload have been removed") Expect(k8sClient.Delete(ctx, checkApp)).Should(BeNil()) listOptions := []client.ListOption{ @@ -312,7 +364,6 @@ metadata: name: rollout spec: manageWorkload: true - skipRevisionAffect: true schematic: cue: template: | @@ -332,7 +383,10 @@ spec: { replicas: parameter.firstBatchReplicas}, { replicas: parameter.secondBatchReplicas}] targetSize: parameter.targetSize - } + if parameter["batchPartition"] != _|_ { + batchPartition: parameter.batchPartition + } + } } } @@ -341,5 +395,6 @@ spec: targetSize: *2|int firstBatchReplicas: *1|int secondBatchReplicas: *1|int + batchPartition?: int }` ) diff --git a/vela-templates/definitions/internal/rollout.cue b/vela-templates/definitions/internal/rollout.cue index 521660987..826fdc097 100644 --- a/vela-templates/definitions/internal/rollout.cue +++ b/vela-templates/definitions/internal/rollout.cue @@ -4,8 +4,7 @@ rollout: { labels: {} description: "rollout the component" attributes: { - manageWorkload: true - skipRevisionAffect: true + manageWorkload: true } } template: { @@ -23,7 +22,9 @@ template: { rolloutStrategy: "IncreaseFirst" rolloutBatches: parameter.rolloutBatches targetSize: parameter.targetSize - batchPartition: parameter.batchPartition + if parameter["batchPartition"] != _|_ { + batchPartition: parameter.batchPartition + } } } }