From 15d5a772606bd00e07e7ed8dcc0d2b0719a6fef0 Mon Sep 17 00:00:00 2001 From: berg Date: Wed, 20 Apr 2022 20:22:38 +0800 Subject: [PATCH] Code optimization (#25) * code optimization rollout Signed-off-by: liheng.zms * changelog 0.1.0 Signed-off-by: liheng.zms * github workflow e2e test Signed-off-by: liheng.zms * Optimize rollout state transition related code Signed-off-by: liheng.zms --- .github/workflows/e2e-1.19.yaml | 203 ++++++++ .github/workflows/e2e-1.23.yaml | 203 ++++++++ .golangci.yml | 4 - CHANGELOG.md | 10 + Makefile | 10 +- api/v1alpha1/batchrelease_plan_types.go | 2 +- api/v1alpha1/rollout_types.go | 21 +- api/v1alpha1/zz_generated.deepcopy.go | 9 +- .../rollouts.kruise.io_batchreleases.yaml | 17 +- .../bases/rollouts.kruise.io_rollouts.yaml | 33 +- docs/getting_started/installation.md | 2 +- docs/getting_started/introduction.md | 2 +- docs/images/rollout-arch.jpg | Bin 88314 -> 0 bytes docs/images/rollout-arch.png | Bin 0 -> 179280 bytes docs/tutorials/basic_usage.md | 2 +- .../batchrelease_controller_test.go | 38 +- .../batchrelease_plan_executor.go | 3 +- .../batchrelease_special_cases_handler.go | 10 +- .../batchrelease/batchrelease_util.go | 25 +- .../rollout/batchrelease/batchrelease.go | 5 +- .../batchrelease/inner_batchrelease.go | 25 +- pkg/controller/rollout/canary.go | 84 ++-- pkg/controller/rollout/context.go | 3 +- pkg/controller/rollout/progressing.go | 63 +-- pkg/controller/rollout/progressing_test.go | 66 ++- pkg/controller/rollout/rollout_controller.go | 4 +- .../rollout/rollout_controller_test.go | 39 +- pkg/controller/rollout/status.go | 74 +-- pkg/controller/rollout/trafficrouting.go | 48 +- pkg/util/controller_finder.go | 103 ++-- pkg/util/workloads_utils.go | 12 +- .../rollout_create_update_handler.go | 32 +- .../rollout_create_update_handler_test.go | 30 +- .../mutating/workload_update_handler.go | 8 +- .../mutating/workload_update_handler_test.go | 1 - scripts/deploy_kind.sh | 15 + temp | 0 test/e2e/batchrelease_test.go | 13 +- test/e2e/rollout_test.go | 470 +++++++++++++----- test/e2e/test_data/batchrelease/cloneset.yaml | 3 + .../test_data/batchrelease/deployment.yaml | 5 + test/e2e/test_data/rollout/cloneset.yaml | 4 +- test/e2e/test_data/rollout/deployment.yaml | 56 +-- .../rollout/rollout_canary_base.yaml | 2 +- test/kind-conf.yaml | 8 + 45 files changed, 1279 insertions(+), 488 deletions(-) create mode 100644 .github/workflows/e2e-1.19.yaml create mode 100644 .github/workflows/e2e-1.23.yaml create mode 100644 CHANGELOG.md delete mode 100644 docs/images/rollout-arch.jpg create mode 100644 docs/images/rollout-arch.png create mode 100755 scripts/deploy_kind.sh delete mode 100644 temp create mode 100644 test/kind-conf.yaml diff --git a/.github/workflows/e2e-1.19.yaml b/.github/workflows/e2e-1.19.yaml new file mode 100644 index 00000000..84a20729 --- /dev/null +++ b/.github/workflows/e2e-1.19.yaml @@ -0,0 +1,203 @@ +name: E2E-1.19 + +on: + push: + branches: + - master + - release-* + pull_request: {} + workflow_dispatch: {} + +env: + # Common versions + GO_VERSION: '1.17' + KIND_IMAGE: 'kindest/node:v1.19.16' + KIND_CLUSTER_NAME: 'ci-testing' + +jobs: + + rollout: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + - name: Setup Kind Cluster + uses: helm/kind-action@v1.2.0 + with: + node_image: ${{ env.KIND_IMAGE }} + cluster_name: ${{ env.KIND_CLUSTER_NAME }} + config: ./test/kind-conf.yaml + - name: Build image + run: | + export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}" + docker build --pull --no-cache . -t $IMAGE + kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; } + - name: Install Kruise + run: | + set -ex + kubectl cluster-info + make helm + helm repo add openkruise https://openkruise.github.io/charts/ + helm repo update + helm install kruise openkruise/kruise + for ((i=1;i<10;i++)); + do + set +e + PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l) + set -e + if [ "$PODS" -eq "2" ]; then + break + fi + sleep 3 + done + set +e + PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l) + set -e + if [ "$PODS" -eq "2" ]; then + echo "Wait for kruise-manager ready successfully" + else + echo "Timeout to wait for kruise-manager ready" + exit 1 + fi + - name: Install Kruise Rollout + run: | + set -ex + kubectl cluster-info + IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh + for ((i=1;i<10;i++)); + do + set +e + PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l) + set -e + if [ "$PODS" -eq "1" ]; then + break + fi + sleep 3 + done + set +e + PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l) + kubectl get node -o yaml + kubectl get all -n kruise-rollout -o yaml + set -e + if [ "$PODS" -eq "1" ]; then + echo "Wait for kruise-rollout ready successfully" + else + echo "Timeout to wait for kruise-rollout ready" + exit 1 + fi + - name: Run E2E Tests + run: | + export KUBECONFIG=/home/runner/.kube/config + make ginkgo + set +e + ./bin/ginkgo -timeout 60m -v --focus='\[rollouts\] (Rollout)' test/e2e + retVal=$? + # kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout + restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}') + if [ "${restartCount}" -eq "0" ];then + echo "Kruise-rollout has not restarted" + else + kubectl get pod -n kruise-rollout --no-headers + echo "Kruise-rollout has restarted, abort!!!" + kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout + exit 1 + fi + exit $retVal + + batchRelease: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + - name: Setup Kind Cluster + uses: helm/kind-action@v1.2.0 + with: + node_image: ${{ env.KIND_IMAGE }} + cluster_name: ${{ env.KIND_CLUSTER_NAME }} + config: ./test/kind-conf.yaml + - name: Build image + run: | + export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}" + docker build --pull --no-cache . -t $IMAGE + kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; } + - name: Install Kruise + run: | + set -ex + kubectl cluster-info + make helm + helm repo add openkruise https://openkruise.github.io/charts/ + helm repo update + helm install kruise openkruise/kruise + for ((i=1;i<10;i++)); + do + set +e + PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l) + set -e + if [ "$PODS" -eq "2" ]; then + break + fi + sleep 3 + done + set +e + PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l) + set -e + if [ "$PODS" -eq "2" ]; then + echo "Wait for kruise-manager ready successfully" + else + echo "Timeout to wait for kruise-manager ready" + exit 1 + fi + - name: Install Kruise Rollout + run: | + set -ex + kubectl cluster-info + IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh + for ((i=1;i<10;i++)); + do + set +e + PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l) + set -e + if [ "$PODS" -eq "1" ]; then + break + fi + sleep 3 + done + set +e + PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l) + kubectl get node -o yaml + kubectl get all -n kruise-rollout -o yaml + set -e + if [ "$PODS" -eq "1" ]; then + echo "Wait for kruise-rollout ready successfully" + else + echo "Timeout to wait for kruise-rollout ready" + exit 1 + fi + - name: Run E2E Tests + run: | + export KUBECONFIG=/home/runner/.kube/config + make ginkgo + set +e + ./bin/ginkgo -timeout 60m -v --focus='\[rollouts\] (BatchRelease)' test/e2e + retVal=$? + # kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout + restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}') + if [ "${restartCount}" -eq "0" ];then + echo "Kruise-rollout has not restarted" + else + kubectl get pod -n kruise-rollout --no-headers + echo "Kruise-rollout has restarted, abort!!!" + kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout + exit 1 + fi + exit $retVal diff --git a/.github/workflows/e2e-1.23.yaml b/.github/workflows/e2e-1.23.yaml new file mode 100644 index 00000000..ab70915d --- /dev/null +++ b/.github/workflows/e2e-1.23.yaml @@ -0,0 +1,203 @@ +name: E2E-1.23 + +on: + push: + branches: + - master + - release-* + pull_request: {} + workflow_dispatch: {} + +env: + # Common versions + GO_VERSION: '1.17' + KIND_IMAGE: 'kindest/node:v1.23.3' + KIND_CLUSTER_NAME: 'ci-testing' + +jobs: + + rollout: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + - name: Setup Kind Cluster + uses: helm/kind-action@v1.2.0 + with: + node_image: ${{ env.KIND_IMAGE }} + cluster_name: ${{ env.KIND_CLUSTER_NAME }} + config: ./test/kind-conf.yaml + - name: Build image + run: | + export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}" + docker build --pull --no-cache . -t $IMAGE + kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; } + - name: Install Kruise + run: | + set -ex + kubectl cluster-info + make helm + helm repo add openkruise https://openkruise.github.io/charts/ + helm repo update + helm install kruise openkruise/kruise + for ((i=1;i<10;i++)); + do + set +e + PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l) + set -e + if [ "$PODS" -eq "2" ]; then + break + fi + sleep 3 + done + set +e + PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l) + set -e + if [ "$PODS" -eq "2" ]; then + echo "Wait for kruise-manager ready successfully" + else + echo "Timeout to wait for kruise-manager ready" + exit 1 + fi + - name: Install Kruise Rollout + run: | + set -ex + kubectl cluster-info + IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh + for ((i=1;i<10;i++)); + do + set +e + PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l) + set -e + if [ "$PODS" -eq "1" ]; then + break + fi + sleep 3 + done + set +e + PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l) + kubectl get node -o yaml + kubectl get all -n kruise-rollout -o yaml + set -e + if [ "$PODS" -eq "1" ]; then + echo "Wait for kruise-rollout ready successfully" + else + echo "Timeout to wait for kruise-rollout ready" + exit 1 + fi + - name: Run E2E Tests + run: | + export KUBECONFIG=/home/runner/.kube/config + make ginkgo + set +e + ./bin/ginkgo -timeout 60m -v --focus='\[rollouts\] (Rollout)' test/e2e + retVal=$? + # kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout + restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}') + if [ "${restartCount}" -eq "0" ];then + echo "Kruise-rollout has not restarted" + else + kubectl get pod -n kruise-rollout --no-headers + echo "Kruise-rollout has restarted, abort!!!" + kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout + exit 1 + fi + exit $retVal + + batchRelease: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + - name: Setup Kind Cluster + uses: helm/kind-action@v1.2.0 + with: + node_image: ${{ env.KIND_IMAGE }} + cluster_name: ${{ env.KIND_CLUSTER_NAME }} + config: ./test/kind-conf.yaml + - name: Build image + run: | + export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}" + docker build --pull --no-cache . -t $IMAGE + kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; } + - name: Install Kruise + run: | + set -ex + kubectl cluster-info + make helm + helm repo add openkruise https://openkruise.github.io/charts/ + helm repo update + helm install kruise openkruise/kruise + for ((i=1;i<10;i++)); + do + set +e + PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l) + set -e + if [ "$PODS" -eq "2" ]; then + break + fi + sleep 3 + done + set +e + PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l) + set -e + if [ "$PODS" -eq "2" ]; then + echo "Wait for kruise-manager ready successfully" + else + echo "Timeout to wait for kruise-manager ready" + exit 1 + fi + - name: Install Kruise Rollout + run: | + set -ex + kubectl cluster-info + IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh + for ((i=1;i<10;i++)); + do + set +e + PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l) + set -e + if [ "$PODS" -eq "1" ]; then + break + fi + sleep 3 + done + set +e + PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l) + kubectl get node -o yaml + kubectl get all -n kruise-rollout -o yaml + set -e + if [ "$PODS" -eq "1" ]; then + echo "Wait for kruise-rollout ready successfully" + else + echo "Timeout to wait for kruise-rollout ready" + exit 1 + fi + - name: Run E2E Tests + run: | + export KUBECONFIG=/home/runner/.kube/config + make ginkgo + set +e + ./bin/ginkgo -timeout 60m -v --focus='\[rollouts\] (BatchRelease)' test/e2e + retVal=$? + # kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout + restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}') + if [ "${restartCount}" -eq "0" ];then + echo "Kruise-rollout has not restarted" + else + kubectl get pod -n kruise-rollout --no-headers + echo "Kruise-rollout has restarted, abort!!!" + kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout + exit 1 + fi + exit $retVal diff --git a/.golangci.yml b/.golangci.yml index d7bdb8d5..a4eac5e0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -69,14 +69,10 @@ linters: disable-all: true enable: # TODO Enforce the below linters later - - deadcode - gofmt - - govet - goimports - ineffassign - misspell - - vet - - unconvert issues: exclude: # staticcheck diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..17ab16aa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Change Log + +## v0.1.0 + +### Kruise-Rollout-Controller +- Support Canary Publishing + Nginx Ingress + Workload(CloneSet, Deployment) +- Support for Batch Release(e.g. 20%, 40%, 60%, 80, 100%) for workload(CloneSet) + +### Documents +- Introduction, Installation, Basic Usage diff --git a/Makefile b/Makefile index 9c84adb6..38999fd3 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,14 @@ KUSTOMIZE = $(shell pwd)/bin/kustomize kustomize: ## Download kustomize locally if necessary. $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v3@v3.8.7) +GINKGO = $(shell pwd)/bin/ginkgo +ginkgo: ## Download ginkgo locally if necessary. + $(call go-get-tool,$(GINKGO),github.com/onsi/ginkgo/ginkgo@v1.16.4) + +HELM = $(shell pwd)/bin/helm +helm: ## Download helm locally if necessary. + $(call go-get-tool,$(HELM),helm.sh/helm/v3@v3.8.1) + # go-get-tool will 'go get' any package $2 and install it to $1. PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) define go-get-tool @@ -106,7 +114,7 @@ TMP_DIR=$$(mktemp -d) ;\ cd $$TMP_DIR ;\ go mod init tmp ;\ echo "Downloading $(2)" ;\ -GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\ +GOBIN=$(PROJECT_DIR)/bin go get $(2) ;\ rm -rf $$TMP_DIR ;\ } endef diff --git a/api/v1alpha1/batchrelease_plan_types.go b/api/v1alpha1/batchrelease_plan_types.go index 64e20b45..fe820d16 100644 --- a/api/v1alpha1/batchrelease_plan_types.go +++ b/api/v1alpha1/batchrelease_plan_types.go @@ -97,7 +97,7 @@ type BatchReleaseCanaryStatus struct { // BatchReadyTime is the ready timestamp of the current batch or the last batch. // This field is updated once a batch ready, and the batches[x].pausedSeconds // relies on this field to calculate the real-time duration. - BatchReadyTime metav1.Time `json:"lastBatchReadyTime,omitempty"` + BatchReadyTime *metav1.Time `json:"batchReadyTime,omitempty"` // UpdatedReplicas is the number of upgraded Pods. UpdatedReplicas int32 `json:"updatedReplicas,omitempty"` // UpdatedReadyReplicas is the number upgraded Pods that have a Ready Condition. diff --git a/api/v1alpha1/rollout_types.go b/api/v1alpha1/rollout_types.go index a382b901..6a5edfad 100644 --- a/api/v1alpha1/rollout_types.go +++ b/api/v1alpha1/rollout_types.go @@ -36,9 +36,6 @@ type RolloutSpec struct { } type ObjectRef struct { - // workloadRef, revisionRef - // default is workloadRef - Type ObjectRefType `json:"type,omitempty"` // WorkloadRef contains enough information to let you identify a workload for Rollout // Batch release of the bypass WorkloadRef *WorkloadRef `json:"workloadRef,omitempty"` @@ -75,9 +72,6 @@ type RolloutStrategy struct { // Paused indicates that the Rollout is paused. // Default value is false Paused bool `json:"paused,omitempty"` - // canary, BlueGreenPlan - // Default value is canary - Type RolloutStrategyType `json:"type,omitempty"` // +optional Canary *CanaryStrategy `json:"canary,omitempty"` // +optional @@ -96,9 +90,9 @@ type CanaryStrategy struct { // Steps define the order of phases to execute release in batches(20%, 40%, 60%, 80%, 100%) // +optional Steps []CanaryStep `json:"steps,omitempty"` - // TrafficRouting hosts all the supported service meshes supported to enable more fine-grained traffic routing + // TrafficRoutings hosts all the supported service meshes supported to enable more fine-grained traffic routing // todo current only support one - TrafficRouting []*TrafficRouting `json:"trafficRouting,omitempty"` + TrafficRoutings []*TrafficRouting `json:"trafficRoutings,omitempty"` // MetricsAnalysis *MetricsAnalysisBackground `json:"metricsAnalysis,omitempty"` } @@ -125,11 +119,10 @@ type RolloutPause struct { // TrafficRouting hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing type TrafficRouting struct { // Service holds the name of a service which selects pods with stable version and don't select any pods with canary version. - // +optional Service string `json:"service"` // Optional duration in seconds the traffic provider(e.g. nginx ingress controller) consumes the service, ingress configuration changes gracefully. GracePeriodSeconds int32 `json:"gracePeriodSeconds,omitempty"` - // nginx, alb etc. + // nginx, alb, istio etc. Type string `json:"type"` // Ingress holds Ingress specific configuration to route traffic, e.g. Nginx, Alb. Ingress *IngressTrafficRouting `json:"ingress,omitempty"` @@ -150,7 +143,7 @@ type RolloutStatus struct { ObservedGeneration int64 `json:"observedGeneration,omitempty"` // CanaryRevision the hash of the canary pod template // +optional - CanaryRevision string `json:"canaryRevision,omitempty"` + //CanaryRevision string `json:"canaryRevision,omitempty"` // StableRevision indicates the revision pods that has successfully rolled out StableRevision string `json:"stableRevision,omitempty"` // Conditions a list of conditions a rollout can have. @@ -217,9 +210,12 @@ type CanaryStatus struct { RolloutHash string `json:"rolloutHash,omitempty"` // CanaryService holds the name of a service which selects pods with canary version and don't select any pods with stable version. CanaryService string `json:"canaryService"` - // CanaryRevision the hash of the current pod template + // CanaryRevision is calculated by rollout based on podTemplateHash, and the internal logic flow uses + // It may be different from rs podTemplateHash in different k8s versions, so it cannot be used as service selector label // +optional CanaryRevision string `json:"canaryRevision"` + // pod template hash is used as service selector label + PodTemplateHash string `json:"podTemplateHash"` // CanaryReplicas the numbers of canary revision pods CanaryReplicas int32 `json:"canaryReplicas"` // CanaryReadyReplicas the numbers of ready canary revision pods @@ -274,6 +270,7 @@ const ( // +kubebuilder:printcolumn:name="CANARY_STEP",type="integer",JSONPath=".status.canaryStatus.currentStepIndex",description="The rollout canary status step" // +kubebuilder:printcolumn:name="CANARY_STATE",type="string",JSONPath=".status.canaryStatus.currentStepState",description="The rollout canary status step state" // +kubebuilder:printcolumn:name="MESSAGE",type="string",JSONPath=".status.message",description="The rollout canary status message" +// +kubebuilder:printcolumn:name="AGE",type=date,JSONPath=".metadata.creationTimestamp" // Rollout is the Schema for the rollouts API type Rollout struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 5fa24359..a227eeff 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -56,7 +56,10 @@ func (in *BatchRelease) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BatchReleaseCanaryStatus) DeepCopyInto(out *BatchReleaseCanaryStatus) { *out = *in - in.BatchReadyTime.DeepCopyInto(&out.BatchReadyTime) + if in.BatchReadyTime != nil { + in, out := &in.BatchReadyTime, &out.BatchReadyTime + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BatchReleaseCanaryStatus. @@ -196,8 +199,8 @@ func (in *CanaryStrategy) DeepCopyInto(out *CanaryStrategy) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.TrafficRouting != nil { - in, out := &in.TrafficRouting, &out.TrafficRouting + if in.TrafficRoutings != nil { + in, out := &in.TrafficRoutings, &out.TrafficRoutings *out = make([]*TrafficRouting, len(*in)) for i := range *in { if (*in)[i] != nil { diff --git a/config/crd/bases/rollouts.kruise.io_batchreleases.yaml b/config/crd/bases/rollouts.kruise.io_batchreleases.yaml index 74dd6472..86e19774 100644 --- a/config/crd/bases/rollouts.kruise.io_batchreleases.yaml +++ b/config/crd/bases/rollouts.kruise.io_batchreleases.yaml @@ -102,9 +102,6 @@ spec: description: TargetRef contains the GVK and name of the workload that we need to upgrade to. properties: - type: - description: workloadRef, revisionRef default is workloadRef - type: string workloadRef: description: WorkloadRef contains enough information to let you identify a workload for Rollout Batch release of the bypass @@ -135,6 +132,13 @@ spec: canaryStatus: description: CanaryStatus describes the state of the canary rollout. properties: + batchReadyTime: + description: BatchReadyTime is the ready timestamp of the current + batch or the last batch. This field is updated once a batch + ready, and the batches[x].pausedSeconds relies on this field + to calculate the real-time duration. + format: date-time + type: string batchState: description: CurrentBatchState indicates the release state of the current batch. @@ -144,13 +148,6 @@ spec: it starts from 0 format: int32 type: integer - lastBatchReadyTime: - description: BatchReadyTime is the ready timestamp of the current - batch or the last batch. This field is updated once a batch - ready, and the batches[x].pausedSeconds relies on this field - to calculate the real-time duration. - format: date-time - type: string updatedReadyReplicas: description: UpdatedReadyReplicas is the number upgraded Pods that have a Ready Condition. diff --git a/config/crd/bases/rollouts.kruise.io_rollouts.yaml b/config/crd/bases/rollouts.kruise.io_rollouts.yaml index 56c05e9b..9819a100 100644 --- a/config/crd/bases/rollouts.kruise.io_rollouts.yaml +++ b/config/crd/bases/rollouts.kruise.io_rollouts.yaml @@ -33,6 +33,9 @@ spec: jsonPath: .status.message name: MESSAGE type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date name: v1alpha1 schema: openAPIV3Schema: @@ -58,9 +61,6 @@ spec: Important: Run "make" to regenerate code after modifying this file ObjectRef indicates workload' properties: - type: - description: workloadRef, revisionRef default is workloadRef - type: string workloadRef: description: WorkloadRef contains enough information to let you identify a workload for Rollout Batch release of the bypass @@ -118,8 +118,8 @@ spec: type: integer type: object type: array - trafficRouting: - description: TrafficRouting hosts all the supported service + trafficRoutings: + description: TrafficRoutings hosts all the supported service meshes supported to enable more fine-grained traffic routing todo current only support one items: @@ -150,9 +150,10 @@ spec: any pods with canary version. type: string type: - description: nginx, alb etc. + description: nginx, alb, istio etc. type: string required: + - service - type type: object type: array @@ -161,9 +162,6 @@ spec: description: Paused indicates that the Rollout is paused. Default value is false type: boolean - type: - description: canary, BlueGreenPlan Default value is canary - type: string type: object required: - objectRef @@ -172,9 +170,6 @@ spec: status: description: RolloutStatus defines the observed state of Rollout properties: - canaryRevision: - description: CanaryRevision the hash of the canary pod template - type: string canaryStatus: description: Canary describes the state of the canary rollout properties: @@ -188,7 +183,10 @@ spec: format: int32 type: integer canaryRevision: - description: CanaryRevision the hash of the current pod template + description: CanaryRevision is calculated by rollout based on + podTemplateHash, and the internal logic flow uses It may be + different from rs podTemplateHash in different k8s versions, + so it cannot be used as service selector label type: string canaryService: description: CanaryService holds the name of a service which selects @@ -214,6 +212,9 @@ spec: observed for this Rollout ref workload generation. format: int64 type: integer + podTemplateHash: + description: pod template hash is used as service selector label + type: string rolloutHash: description: RolloutHash from rollout.spec object type: string @@ -222,6 +223,7 @@ spec: - canaryReplicas - canaryService - currentStepState + - podTemplateHash type: object conditions: description: Conditions a list of conditions a rollout can have. @@ -272,8 +274,9 @@ spec: Phase is the rollout phase. type: string stableRevision: - description: StableRevision indicates the revision pods that has successfully - rolled out + description: CanaryRevision the hash of the canary pod template CanaryRevision + string `json:"canaryRevision,omitempty"` StableRevision indicates + the revision pods that has successfully rolled out type: string type: object type: object diff --git a/docs/getting_started/installation.md b/docs/getting_started/installation.md index 32938bd2..0587ec03 100644 --- a/docs/getting_started/installation.md +++ b/docs/getting_started/installation.md @@ -1,7 +1,7 @@ # Installation ## Requirements -- Install Kubernetes Cluster, requires **Kubernetes version >= 1.16**. +- Install Kubernetes Cluster, requires **Kubernetes version >= 1.19**. - (Optional, If Use CloneSet) Helm installation of OpenKruise, **Since v1.1.0**, Reference [Install OpenKruise](https://openkruise.io/docs/installation). ## Install with helm diff --git a/docs/getting_started/introduction.md b/docs/getting_started/introduction.md index 2c07ad74..2a9713c2 100644 --- a/docs/getting_started/introduction.md +++ b/docs/getting_started/introduction.md @@ -5,7 +5,7 @@ Kruise Rollouts is **a Bypass component which provides advanced deployment capab Kruise Rollout integrates with ingress controllers and service meshes, leveraging their traffic shaping abilities to gradually shift traffic to the new version during an update. In addition, the business Pods metrics analysis can be used during rollout to determine whether the release will continue or be suspended. -![arch](../images/rollout-arch.jpg) +![arch](../images/rollout-arch.png) ## Why is Kruise Rollout? The native Kubernetes Deployment Object supports the **RollingUpdate** strategy which provides a basic set of safety guarantees(maxUnavailable, maxSurge) during an update. However the rolling update strategy faces many limitations: diff --git a/docs/images/rollout-arch.jpg b/docs/images/rollout-arch.jpg deleted file mode 100644 index 1b246f14c581c80b904579018c4891fbcd916b0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88314 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

`W&jiI`s17xVSExr#`sU{xod$N!S021whI3 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 z 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 UBlBzRYz83kboFyt=akR{06O5guK)l5 literal 0 HcmV?d00001 diff --git a/docs/tutorials/basic_usage.md b/docs/tutorials/basic_usage.md index c6d989bc..c6a75bb8 100644 --- a/docs/tutorials/basic_usage.md +++ b/docs/tutorials/basic_usage.md @@ -105,7 +105,7 @@ spec: pause: {} # optional, The first step of released replicas. If not set, the default is to use 'weight', as shown above is 5%. replicas: 20% - trafficRouting: + trafficRoutings: # echoserver service name - service: echoserver # nginx ingress diff --git a/pkg/controller/batchrelease/batchrelease_controller_test.go b/pkg/controller/batchrelease/batchrelease_controller_test.go index 3e90d6d1..3e752a45 100644 --- a/pkg/controller/batchrelease/batchrelease_controller_test.go +++ b/pkg/controller/batchrelease/batchrelease_controller_test.go @@ -371,7 +371,7 @@ func TestReconcile_CloneSet(t *testing.T) { Name: "Progressing, stage=0->1, Input-State=BatchReady, Output-State=Upgrade", GetRelease: func() client.Object { release := setState(releaseClone, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = *getOldTime() + release.Status.CanaryStatus.BatchReadyTime = getOldTime() stableTemplate := stableClone.Spec.Template.DeepCopy() canaryTemplate := stableClone.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -395,7 +395,8 @@ func TestReconcile_CloneSet(t *testing.T) { Name: "Progressing, stage=0->1, Input-State=BatchReady, Output-State=BatchReady", GetRelease: func() client.Object { release := setState(releaseClone, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now stableTemplate := stableClone.Spec.Template.DeepCopy() canaryTemplate := stableClone.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -418,7 +419,8 @@ func TestReconcile_CloneSet(t *testing.T) { Name: "Special Case: Scaling, Input-State=BatchReady, Output-State=Upgrade", GetRelease: func() client.Object { release := setState(releaseClone, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now stableTemplate := stableClone.Spec.Template.DeepCopy() canaryTemplate := stableClone.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -442,7 +444,8 @@ func TestReconcile_CloneSet(t *testing.T) { Name: `Special Case: RollBack, Input-Phase=Progressing, Output-Phase=Abort`, GetRelease: func() client.Object { release := setState(releaseClone, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now stableTemplate := stableClone.Spec.Template.DeepCopy() canaryTemplate := stableClone.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -469,7 +472,8 @@ func TestReconcile_CloneSet(t *testing.T) { Name: `Special Case: Deletion, Input-Phase=Progressing, Output-Phase=Terminating`, GetRelease: func() client.Object { release := setState(releaseClone, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now stableTemplate := stableClone.Spec.Template.DeepCopy() canaryTemplate := stableClone.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -494,7 +498,8 @@ func TestReconcile_CloneSet(t *testing.T) { Name: `Special Case: Continuous Release, Input-Phase=Progressing, Output-Phase=Initial`, GetRelease: func() client.Object { release := setState(releaseClone, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now stableTemplate := stableClone.Spec.Template.DeepCopy() canaryTemplate := stableClone.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -663,7 +668,7 @@ func TestReconcile_Deployment(t *testing.T) { Name: "Progressing, stage=0->1, Input-State=BatchReady, Output-State=Upgrade", GetRelease: func() client.Object { release := setState(releaseDeploy, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = *getOldTime() + release.Status.CanaryStatus.BatchReadyTime = getOldTime() return release }, GetDeployments: func() []client.Object { @@ -681,7 +686,8 @@ func TestReconcile_Deployment(t *testing.T) { Name: "Progressing, stage=0->1, Input-State=BatchReady, Output-State=BatchReady", GetRelease: func() client.Object { release := setState(releaseDeploy, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now return release }, GetDeployments: func() []client.Object { @@ -698,7 +704,8 @@ func TestReconcile_Deployment(t *testing.T) { Name: "Special Case: Scaling, Input-State=BatchReady, Output-State=Upgrade", GetRelease: func() client.Object { release := setState(releaseDeploy, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now return release }, GetDeployments: func() []client.Object { @@ -716,7 +723,8 @@ func TestReconcile_Deployment(t *testing.T) { Name: `Special Case: RollBack, Input-Phase=Progressing, Output-Phase=Abort`, GetRelease: func() client.Object { release := setState(releaseDeploy, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now stableTemplate := stableDeploy.Spec.Template.DeepCopy() canaryTemplate := stableDeploy.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -739,7 +747,8 @@ func TestReconcile_Deployment(t *testing.T) { Name: `Special Case: Deletion, Input-Phase=Progressing, Output-Phase=Terminating`, GetRelease: func() client.Object { release := setState(releaseDeploy, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now stableTemplate := stableDeploy.Spec.Template.DeepCopy() canaryTemplate := stableDeploy.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -764,7 +773,8 @@ func TestReconcile_Deployment(t *testing.T) { Name: `Special Case: Continuous Release, Input-Phase=Progressing, Output-Phase=Initial`, GetRelease: func() client.Object { release := setState(releaseDeploy, v1alpha1.ReadyBatchState) - release.Status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + release.Status.CanaryStatus.BatchReadyTime = &now stableTemplate := stableDeploy.Spec.Template.DeepCopy() canaryTemplate := stableDeploy.Spec.Template.DeepCopy() stableTemplate.Spec.Containers = containers("v1") @@ -840,7 +850,7 @@ func setPhase(release *v1alpha1.BatchRelease, phase v1alpha1.RolloutPhase) *v1al case v1alpha1.RolloutPhaseInitial, v1alpha1.RolloutPhaseHealthy: default: r.Status.ObservedWorkloadReplicas = 100 - r.Status.ObservedReleasePlanHash = hashReleasePlanBatches(&release.Spec.ReleasePlan) + r.Status.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan) } return r } @@ -850,7 +860,7 @@ func setState(release *v1alpha1.BatchRelease, state v1alpha1.BatchReleaseBatchSt r.Status.Phase = v1alpha1.RolloutPhaseProgressing r.Status.CanaryStatus.CurrentBatchState = state r.Status.ObservedWorkloadReplicas = 100 - r.Status.ObservedReleasePlanHash = hashReleasePlanBatches(&release.Spec.ReleasePlan) + r.Status.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan) return r } diff --git a/pkg/controller/batchrelease/batchrelease_plan_executor.go b/pkg/controller/batchrelease/batchrelease_plan_executor.go index 864532f0..d3582b62 100644 --- a/pkg/controller/batchrelease/batchrelease_plan_executor.go +++ b/pkg/controller/batchrelease/batchrelease_plan_executor.go @@ -205,7 +205,8 @@ func (r *Executor) progressBatches(workloadController workloads.WorkloadControll setCondition(status, "Progressing", v1.ConditionFalse, "VerifyBatchFailed", err.Error()) case verified: result = reconcile.Result{RequeueAfter: DefaultDuration} - status.CanaryStatus.BatchReadyTime = metav1.Now() + now := metav1.Now() + status.CanaryStatus.BatchReadyTime = &now status.CanaryStatus.CurrentBatchState = v1alpha1.ReadyBatchState default: status.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState diff --git a/pkg/controller/batchrelease/batchrelease_special_cases_handler.go b/pkg/controller/batchrelease/batchrelease_special_cases_handler.go index ca198336..bd950232 100644 --- a/pkg/controller/batchrelease/batchrelease_special_cases_handler.go +++ b/pkg/controller/batchrelease/batchrelease_special_cases_handler.go @@ -21,6 +21,7 @@ import ( "github.com/openkruise/rollouts/api/v1alpha1" "github.com/openkruise/rollouts/pkg/controller/batchrelease/workloads" + "github.com/openkruise/rollouts/pkg/util" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/klog/v2" @@ -170,10 +171,9 @@ func refreshStatus(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchRele newStatus.CanaryStatus.UpdatedReplicas = workloadInfo.Status.UpdatedReplicas newStatus.CanaryStatus.UpdatedReadyReplicas = workloadInfo.Status.UpdatedReadyReplicas } - planHash := hashReleasePlanBatches(&release.Spec.ReleasePlan) - if newStatus.ObservedReleasePlanHash != planHash { - newStatus.ObservedReleasePlanHash = planHash - } + } + if len(newStatus.ObservedReleasePlanHash) == 0 { + newStatus.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan) } } @@ -182,7 +182,7 @@ func isPlanTerminating(release *v1alpha1.BatchRelease, status *v1alpha1.BatchRel } func isPlanChanged(plan *v1alpha1.ReleasePlan, status *v1alpha1.BatchReleaseStatus) bool { - return status.ObservedReleasePlanHash != hashReleasePlanBatches(plan) && status.Phase == v1alpha1.RolloutPhaseProgressing + return status.ObservedReleasePlanHash != util.HashReleasePlanBatches(plan) && status.Phase == v1alpha1.RolloutPhaseProgressing } func isPlanUnhealthy(plan *v1alpha1.ReleasePlan, status *v1alpha1.BatchReleaseStatus) bool { diff --git a/pkg/controller/batchrelease/batchrelease_util.go b/pkg/controller/batchrelease/batchrelease_util.go index 4c818d1e..467fa883 100644 --- a/pkg/controller/batchrelease/batchrelease_util.go +++ b/pkg/controller/batchrelease/batchrelease_util.go @@ -17,11 +17,8 @@ limitations under the License. package batchrelease import ( - "crypto/sha256" - "encoding/hex" - "encoding/json" - "github.com/openkruise/rollouts/api/v1alpha1" + "github.com/openkruise/rollouts/pkg/util" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog/v2" @@ -39,12 +36,6 @@ func HasTerminatingCondition(status v1alpha1.BatchReleaseStatus) bool { return false } -func hashReleasePlanBatches(releasePlan *v1alpha1.ReleasePlan) string { - by, _ := json.Marshal(releasePlan.Batches) - md5Hash := sha256.Sum256(by) - return hex.EncodeToString(md5Hash[:]) -} - func initializeStatusIfNeeds(status *v1alpha1.BatchReleaseStatus) { if len(status.Phase) == 0 { resetStatus(status) @@ -76,13 +67,14 @@ func signalRecalculate(release *v1alpha1.BatchRelease, newStatus *v1alpha1.Batch currentBatch := int32(0) if release.Spec.ReleasePlan.BatchPartition != nil { // ensure current batch upper bound - currentBatch = integer.Int32Min(*release.Spec.ReleasePlan.BatchPartition, currentBatch) + currentBatch = integer.Int32Min(*release.Spec.ReleasePlan.BatchPartition, int32(len(release.Spec.ReleasePlan.Batches)-1)) } klog.Infof("BatchRelease(%v) canary batch changed from %v to %v when the release plan changed", client.ObjectKeyFromObject(release), newStatus.CanaryStatus.CurrentBatch, currentBatch) newStatus.CanaryStatus.CurrentBatch = currentBatch newStatus.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState + newStatus.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan) } func resetStatus(status *v1alpha1.BatchReleaseStatus) { @@ -101,11 +93,12 @@ func setCondition(status *v1alpha1.BatchReleaseStatus, condType v1alpha1.Rollout if len(status.Conditions) == 0 { status.Conditions = append(status.Conditions, v1alpha1.RolloutCondition{ - Type: condType, - Status: condStatus, - Reason: reason, - Message: message, - LastUpdateTime: metav1.Now(), + Type: condType, + Status: condStatus, + Reason: reason, + Message: message, + LastUpdateTime: metav1.Now(), + LastTransitionTime: metav1.Now(), }) return } diff --git a/pkg/controller/rollout/batchrelease/batchrelease.go b/pkg/controller/rollout/batchrelease/batchrelease.go index dc0a6b2c..99de7446 100644 --- a/pkg/controller/rollout/batchrelease/batchrelease.go +++ b/pkg/controller/rollout/batchrelease/batchrelease.go @@ -21,8 +21,9 @@ import rolloutv1alpha1 "github.com/openkruise/rollouts/api/v1alpha1" // BatchRelease is not the actual controller of the BatchRelease controller, // but rather the ability to interact with the BatchRelease controller through the BatchRelease CRD to achieve a batch release type BatchRelease interface { - // Verify will create batchRelease or update batchRelease steps configuration - Verify(index int32) error + // Verify will create batchRelease or update batchRelease steps configuration and + // return whether the batchRelease configuration is consistent with the rollout step + Verify(index int32) (bool, error) // 1. Promote release workload in step(index), 1<=index<=len(step) // 2. Promote will resume stable workload if the last batch(index=-1) is finished diff --git a/pkg/controller/rollout/batchrelease/inner_batchrelease.go b/pkg/controller/rollout/batchrelease/inner_batchrelease.go index 98e39403..d81fa4e2 100644 --- a/pkg/controller/rollout/batchrelease/inner_batchrelease.go +++ b/pkg/controller/rollout/batchrelease/inner_batchrelease.go @@ -59,7 +59,7 @@ func NewInnerBatchController(c client.Client, rollout *rolloutv1alpha1.Rollout) return r } -func (r *innerBatchRelease) Verify(index int32) error { +func (r *innerBatchRelease) Verify(index int32) (bool, error) { index = index - 1 batch := &rolloutv1alpha1.BatchRelease{} err := r.Get(context.TODO(), client.ObjectKey{Namespace: r.rollout.Namespace, Name: r.batchName}, batch) @@ -68,42 +68,42 @@ func (r *innerBatchRelease) Verify(index int32) error { br := createBatchRelease(r.rollout, r.batchName) if err = r.Create(context.TODO(), br); err != nil && !errors.IsAlreadyExists(err) { klog.Errorf("rollout(%s/%s) create BatchRelease failed: %s", r.rollout.Namespace, r.rollout.Name, err.Error()) - return err + return false, err } data := util.DumpJSON(br) klog.Infof("rollout(%s/%s) create BatchRelease(%s) success", r.rollout.Namespace, r.rollout.Name, data) - return nil + return false, nil } else if err != nil { klog.Errorf("rollout(%s/%s) fetch BatchRelease failed: %s", r.rollout.Namespace, r.rollout.Name, err.Error()) - return err + return false, err } // check whether batchRelease configuration is the latest newBr := createBatchRelease(r.rollout, r.batchName) if reflect.DeepEqual(batch.Spec.ReleasePlan.Batches, newBr.Spec.ReleasePlan.Batches) { - klog.Infof("rollout(%s/%s) batchRelease is initialize done", r.rollout.Namespace, r.rollout.Name) - return nil + klog.Infof("rollout(%s/%s) batchRelease(generation:%d) configuration is the latest", r.rollout.Namespace, r.rollout.Name, batch.Generation) + return true, nil } // update batchRelease to the latest version - if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { - if err := r.Get(context.TODO(), client.ObjectKey{Namespace: r.rollout.Namespace, Name: r.batchName}, batch); err != nil { + if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + if err = r.Get(context.TODO(), client.ObjectKey{Namespace: r.rollout.Namespace, Name: r.batchName}, batch); err != nil { klog.Errorf("error getting updated BatchRelease(%s/%s) from client", batch.Namespace, batch.Name) return err } batch.Spec.ReleasePlan.Batches = newBr.Spec.ReleasePlan.Batches batch.Spec.ReleasePlan.BatchPartition = utilpointer.Int32Ptr(index) - if err := r.Client.Update(context.TODO(), batch); err != nil { + if err = r.Client.Update(context.TODO(), batch); err != nil { return err } return nil }); err != nil { klog.Errorf("rollout(%s/%s) update batchRelease configuration failed: %s", r.rollout.Namespace, r.rollout.Name, err.Error()) - return err + return false, err } data := util.DumpJSON(batch) klog.Infof("rollout(%s/%s) update batchRelease configuration(%s) to the latest", r.rollout.Namespace, r.rollout.Name, data) - return nil + return false, nil } func (r *innerBatchRelease) FetchBatchRelease() (*rolloutv1alpha1.BatchRelease, error) { @@ -161,7 +161,7 @@ func (r *innerBatchRelease) resumeStableWorkload(checkReady bool) (bool, error) return false, err } // default partition.IntVal=0 - if !obj.Spec.UpdateStrategy.Paused && obj.Spec.UpdateStrategy.Partition.IntVal == 0 { + if !obj.Spec.UpdateStrategy.Paused && obj.Spec.UpdateStrategy.Partition.IntVal == 0 && obj.Spec.UpdateStrategy.Partition.Type == intstr.Int { return true, nil } @@ -276,7 +276,6 @@ func createBatchRelease(rollout *rolloutv1alpha1.Rollout, batchName string) *rol }, Spec: rolloutv1alpha1.BatchReleaseSpec{ TargetRef: rolloutv1alpha1.ObjectRef{ - Type: rolloutv1alpha1.WorkloadRefType, WorkloadRef: &rolloutv1alpha1.WorkloadRef{ APIVersion: rollout.Spec.ObjectRef.WorkloadRef.APIVersion, Kind: rollout.Spec.ObjectRef.WorkloadRef.Kind, diff --git a/pkg/controller/rollout/canary.go b/pkg/controller/rollout/canary.go index 348eb14b..605fb7ba 100644 --- a/pkg/controller/rollout/canary.go +++ b/pkg/controller/rollout/canary.go @@ -26,7 +26,6 @@ import ( "github.com/openkruise/rollouts/pkg/util" apps "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" @@ -43,42 +42,41 @@ func (r *rolloutContext) runCanary() error { canaryStatus.CurrentStepIndex = 1 canaryStatus.RolloutHash = r.rollout.Annotations[util.RolloutHashAnnotation] } - if r.rollout.Spec.Strategy.Canary.TrafficRouting[0].GracePeriodSeconds <= 0 { - r.rollout.Spec.Strategy.Canary.TrafficRouting[0].GracePeriodSeconds = defaultGracePeriodSeconds - } + // update canary status canaryStatus.CanaryReplicas = r.workload.CanaryReplicas canaryStatus.CanaryReadyReplicas = r.workload.CanaryReadyReplicas switch canaryStatus.CurrentStepState { case rolloutv1alpha1.CanaryStepStateUpgrade: klog.Infof("rollout(%s/%s) run canary strategy, and state(%s)", r.rollout.Namespace, r.rollout.Name, rolloutv1alpha1.CanaryStepStateUpgrade) - done, err := r.doCanaryUpgrade() - if err != nil { - return err - } else if done { - canaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateTrafficRouting + // If the last step is 100%, there is no need to execute the canary process at this time + if r.rollout.Spec.Strategy.Canary.Steps[canaryStatus.CurrentStepIndex-1].Weight == 100 { + klog.Infof("rollout(%s/%s) last step is 100%, there is no need to execute the canary process at this time, and set state=%s", + r.rollout.Namespace, r.rollout.Name, canaryStatus.CurrentStepIndex-1, canaryStatus.CurrentStepIndex, rolloutv1alpha1.CanaryStepStateCompleted) canaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()} - klog.Infof("rollout(%s/%s) step(%d) state from(%s) -> to(%s)", r.rollout.Namespace, r.rollout.Name, - canaryStatus.CurrentStepIndex, rolloutv1alpha1.CanaryStepStateUpgrade, canaryStatus.CurrentStepState) + canaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateCompleted + } else { + done, err := r.doCanaryUpgrade() + if err != nil { + return err + } else if done { + canaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateTrafficRouting + canaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()} + klog.Infof("rollout(%s/%s) step(%d) state from(%s) -> to(%s)", r.rollout.Namespace, r.rollout.Name, + canaryStatus.CurrentStepIndex, rolloutv1alpha1.CanaryStepStateUpgrade, canaryStatus.CurrentStepState) + } } + case rolloutv1alpha1.CanaryStepStateTrafficRouting: klog.Infof("rollout(%s/%s) run canary strategy, and state(%s)", r.rollout.Namespace, r.rollout.Name, rolloutv1alpha1.CanaryStepStateTrafficRouting) done, err := r.doCanaryTrafficRouting() if err != nil { return err } else if done { - // if 100% completed - if len(r.rollout.Spec.Strategy.Canary.Steps) == int(canaryStatus.CurrentStepIndex) && - r.rollout.Spec.Strategy.Canary.Steps[canaryStatus.CurrentStepIndex-1].Weight == 100 { - klog.Infof("rollout(%s/%s) canary run all steps, and completed", r.rollout.Namespace, r.rollout.Name, canaryStatus.CurrentStepIndex-1, canaryStatus.CurrentStepIndex) - canaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()} - canaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateCompleted - } else { - canaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()} - canaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateMetricsAnalysis - klog.Infof("rollout(%s/%s) step(%d) state from(%s) -> to(%s)", r.rollout.Namespace, r.rollout.Name, - canaryStatus.CurrentStepIndex, rolloutv1alpha1.CanaryStepStateTrafficRouting, canaryStatus.CurrentStepState) - } + canaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()} + canaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateMetricsAnalysis + klog.Infof("rollout(%s/%s) step(%d) state from(%s) -> to(%s)", r.rollout.Namespace, r.rollout.Name, + canaryStatus.CurrentStepIndex, rolloutv1alpha1.CanaryStepStateTrafficRouting, canaryStatus.CurrentStepState) } expectedTime := time.Now().Add(time.Duration(defaultGracePeriodSeconds) * time.Second) r.recheckTime = &expectedTime @@ -115,7 +113,7 @@ func (r *rolloutContext) runCanary() error { canaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateUpgrade klog.Infof("rollout(%s/%s) canary step from(%d) -> to(%d)", r.rollout.Namespace, r.rollout.Name, canaryStatus.CurrentStepIndex-1, canaryStatus.CurrentStepIndex) } else { - klog.Infof("rollout(%s/%s) canary run all steps, and completed", r.rollout.Namespace, r.rollout.Name, canaryStatus.CurrentStepIndex-1, canaryStatus.CurrentStepIndex) + klog.Infof("rollout(%s/%s) canary run all steps, and completed", r.rollout.Namespace, r.rollout.Name) canaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()} canaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateCompleted } @@ -142,18 +140,26 @@ func (r *rolloutContext) doCanaryUpgrade() (bool, error) { return false, nil }*/ + // verify whether batchRelease configuration is the latest steps := len(r.rollout.Spec.Strategy.Canary.Steps) - // canary release + canaryStatus := r.newStatus.CanaryStatus + isLatest, err := r.batchControl.Verify(canaryStatus.CurrentStepIndex) + if err != nil { + return false, err + } else if !isLatest { + return false, nil + } + + // fetch batchRelease batch, err := r.batchControl.FetchBatchRelease() - if errors.IsNotFound(err) { - // the first step, and create batch release crd - return false, r.batchControl.Verify(r.newStatus.CanaryStatus.CurrentStepIndex) - } else if err != nil { + if err != nil { return false, err - } else if batch.Generation != batch.Status.ObservedGeneration { + } else if batch.Status.ObservedReleasePlanHash != util.HashReleasePlanBatches(&batch.Spec.ReleasePlan) || + batch.Generation != batch.Status.ObservedGeneration { + klog.Infof("rollout(%s/%s) batchReleasePlan is not consistent, and wait a moment", r.rollout.Namespace, r.rollout.Name) return false, nil } - canaryStatus := r.newStatus.CanaryStatus + batchData := util.DumpJSON(batch.Status) cond := util.GetRolloutCondition(*r.newStatus, rolloutv1alpha1.RolloutConditionProgressing) cond.Message = fmt.Sprintf("Rollout is in step(%d/%d), and upgrade workload new versions", canaryStatus.CurrentStepIndex, steps) r.newStatus.Message = cond.Message @@ -165,14 +171,15 @@ func (r *rolloutContext) doCanaryUpgrade() (bool, error) { } // check whether batchRelease is ready - if batch.Status.CanaryStatus.CurrentBatchState != rolloutv1alpha1.ReadyBatchState { - klog.Infof("rollout(%s/%s) workload(%s) batch(%d) ReadyReplicas(%d) state(%s), and wait a moment", - r.rollout.Namespace, r.rollout.Name, r.workload.Name, canaryStatus.CurrentStepIndex, batch.Status.CanaryStatus.UpdatedReadyReplicas, batch.Status.CanaryStatus.CurrentBatchState) + if batch.Status.CanaryStatus.CurrentBatchState != rolloutv1alpha1.ReadyBatchState || + batch.Status.CanaryStatus.CurrentBatch+1 != canaryStatus.CurrentStepIndex { + klog.Infof("rollout(%s/%s) batch(%s) state(%s), and wait a moment", + r.rollout.Namespace, r.rollout.Name, batchData, batch.Status.CanaryStatus.CurrentBatchState) return false, nil } r.recorder.Eventf(r.rollout, corev1.EventTypeNormal, "Progressing", fmt.Sprintf("upgrade step(%d) canary pods with new versions done", canaryStatus.CurrentStepIndex)) - klog.Infof("rollout(%s/%s) workload(%s) batch(%d) availableReplicas(%d) state(%s), and continue", - r.rollout.Namespace, r.rollout.Name, r.workload.Name, canaryStatus.CurrentStepIndex, batch.Status.CanaryStatus.UpdatedReadyReplicas, batch.Status.CanaryStatus.CurrentBatchState) + klog.Infof("rollout(%s/%s) batch(%s) state(%s), and success", + r.rollout.Namespace, r.rollout.Name, batchData, batch.Status.CanaryStatus.CurrentBatchState) return true, nil } @@ -194,7 +201,7 @@ func (r *rolloutContext) doCanaryPaused() (bool, error) { // need manual confirmation if currentStep.Pause.Duration == nil { klog.Infof("rollout(%s/%s) don't set pause duration, and need manual confirmation", r.rollout.Namespace, r.rollout.Name) - cond.Message = fmt.Sprintf("Rollout is in step(%d/%d), and you need manually confirm(kube-cli approve) to enter the next step", canaryStatus.CurrentStepIndex, steps) + cond.Message = fmt.Sprintf("Rollout is in step(%d/%d), and you need manually confirm to enter the next step", canaryStatus.CurrentStepIndex, steps) r.newStatus.Message = cond.Message return false, nil } @@ -218,9 +225,6 @@ func (r *rolloutContext) doCanaryFinalising() (bool, error) { if r.newStatus.CanaryStatus == nil { return true, nil } - if r.rollout.Spec.Strategy.Canary.TrafficRouting[0].GracePeriodSeconds <= 0 { - r.rollout.Spec.Strategy.Canary.TrafficRouting[0].GracePeriodSeconds = defaultGracePeriodSeconds - } // 1. rollout progressing complete, allow workload paused=false in webhook err := r.removeRolloutStateInWorkload() if err != nil { diff --git a/pkg/controller/rollout/context.go b/pkg/controller/rollout/context.go index a23af63a..9d2598dc 100644 --- a/pkg/controller/rollout/context.go +++ b/pkg/controller/rollout/context.go @@ -22,6 +22,7 @@ import ( rolloutv1alpha1 "github.com/openkruise/rollouts/api/v1alpha1" "github.com/openkruise/rollouts/pkg/controller/rollout/batchrelease" "github.com/openkruise/rollouts/pkg/util" + apps "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/record" "k8s.io/klog/v2" @@ -74,5 +75,5 @@ func (r *rolloutContext) finalising() (bool, error) { } func (r *rolloutContext) podRevisionLabelKey() string { - return util.RsPodRevisionLabelKey + return apps.DefaultDeploymentUniqueLabelKey } diff --git a/pkg/controller/rollout/progressing.go b/pkg/controller/rollout/progressing.go index 5c811786..066a1af8 100644 --- a/pkg/controller/rollout/progressing.go +++ b/pkg/controller/rollout/progressing.go @@ -40,8 +40,18 @@ var defaultGracePeriodSeconds int32 = 3 func (r *RolloutReconciler) reconcileRolloutProgressing(rollout *rolloutv1alpha1.Rollout) (*time.Time, error) { cond := util.GetRolloutCondition(rollout.Status, rolloutv1alpha1.RolloutConditionProgressing) klog.Infof("reconcile rollout(%s/%s) progressing action", rollout.Namespace, rollout.Name) + workload, err := r.Finder.GetWorkloadForRef(rollout.Namespace, rollout.Spec.ObjectRef.WorkloadRef) + if err != nil { + klog.Errorf("rollout(%s/%s) get workload failed: %s", rollout.Namespace, rollout.Name, err.Error()) + return nil, err + } else if workload == nil { + klog.Errorf("rollout(%s/%s) workload Not Found", rollout.Namespace, rollout.Name) + return nil, nil + } else if !workload.IsStatusConsistent { + klog.Infof("rollout(%s/%s) workload status isn't consistent, then wait a moment", rollout.Namespace, rollout.Name) + return nil, nil + } - var err error var recheckTime *time.Time newStatus := rollout.Status.DeepCopy() switch cond.Reason { @@ -63,25 +73,21 @@ func (r *RolloutReconciler) reconcileRolloutProgressing(rollout *rolloutv1alpha1 } case rolloutv1alpha1.ProgressingReasonInRolling: - // paused rollout progress - if rollout.Spec.Strategy.Paused { - klog.Infof("rollout(%s/%s) is Progressing, but paused", rollout.Namespace, rollout.Name) - progressingStateTransition(newStatus, corev1.ConditionFalse, rolloutv1alpha1.ProgressingReasonPaused, "Rollout has been paused, you can resume it by kube-cli") - // rollout canceled, indicates rollback(v1 -> v2 -> v1) - } else if newStatus.StableRevision == newStatus.CanaryRevision && newStatus.CanaryRevision != newStatus.CanaryStatus.CanaryRevision { - workload, _ := r.Finder.GetWorkloadForRef(rollout.Namespace, rollout.Spec.ObjectRef.WorkloadRef) - if workload != nil { - // rollback, mark stable revision - newStatus.CanaryStatus.CanaryRevision = workload.CurrentPodTemplateHash - } + // rollout canceled, indicates rollback(v1 -> v2 -> v1) + if workload.IsInRollback { + newStatus.CanaryStatus.CanaryRevision = workload.CanaryRevision r.Recorder.Eventf(rollout, corev1.EventTypeNormal, "Progressing", "workload has been rollback, then rollout is canceled") klog.Infof("rollout(%s/%s) workload has been rollback, then rollout canceled", rollout.Namespace, rollout.Name) - progressingStateTransition(newStatus, corev1.ConditionFalse, rolloutv1alpha1.ProgressingReasonCancelling, "The workload has been rolled back and the rollout process has been cancelled") + progressingStateTransition(newStatus, corev1.ConditionFalse, rolloutv1alpha1.ProgressingReasonCancelling, "The workload has been rolled back and the rollout process will be cancelled") + // paused rollout progress + } else if rollout.Spec.Strategy.Paused { + klog.Infof("rollout(%s/%s) is Progressing, but paused", rollout.Namespace, rollout.Name) + progressingStateTransition(newStatus, corev1.ConditionFalse, rolloutv1alpha1.ProgressingReasonPaused, "Rollout has been paused, you can resume it by kube-cli") // In case of continuous publishing(v1 -> v2 -> v3), then restart publishing - } else if newStatus.CanaryStatus.CanaryRevision != "" && newStatus.CanaryRevision != newStatus.CanaryStatus.CanaryRevision { + } else if newStatus.CanaryStatus.CanaryRevision != "" && workload.CanaryRevision != newStatus.CanaryStatus.CanaryRevision { r.Recorder.Eventf(rollout, corev1.EventTypeNormal, "Progressing", "workload continuous publishing canaryRevision, then restart publishing") klog.Infof("rollout(%s/%s) workload continuous publishing canaryRevision from(%s) -> to(%s), then restart publishing", - rollout.Namespace, rollout.Name, newStatus.CanaryStatus.CanaryRevision, newStatus.CanaryRevision) + rollout.Namespace, rollout.Name, newStatus.CanaryStatus.CanaryRevision, workload.CanaryRevision) done, err := r.doProgressingReset(rollout, newStatus) if err != nil { klog.Errorf("rollout(%s/%s) doProgressingReset failed: %s", rollout.Namespace, rollout.Name, err.Error()) @@ -103,12 +109,6 @@ func (r *RolloutReconciler) reconcileRolloutProgressing(rollout *rolloutv1alpha1 klog.Errorf("rollout(%s/%s) reCalculate Canary StepIndex failed: %s", rollout.Namespace, rollout.Name, err.Error()) return nil, err } - // update batchRelease to the latest version - err = batchControl.Verify(newStepIndex) - if err != nil { - klog.Errorf("rollout(%s/%s) canary step configuration change, but update batchRelease crd failed: %s", rollout.Namespace, rollout.Name, err.Error()) - return nil, err - } // canary step configuration change causes current step index change newStatus.CanaryStatus.CurrentStepIndex = newStepIndex newStatus.CanaryStatus.CurrentStepState = rolloutv1alpha1.CanaryStepStateUpgrade @@ -123,6 +123,7 @@ func (r *RolloutReconciler) reconcileRolloutProgressing(rollout *rolloutv1alpha1 klog.Infof("rollout(%s/%s) progressing rolling done", rollout.Namespace, rollout.Name) progressingStateTransition(newStatus, corev1.ConditionTrue, rolloutv1alpha1.ProgressingReasonFinalising, "Rollout has been completed and some closing work is being done") } else { // rollout is in rolling + newStatus.CanaryStatus.PodTemplateHash = workload.PodTemplateHash recheckTime, err = r.doProgressingInRolling(rollout, newStatus) if err != nil { return nil, err @@ -142,7 +143,14 @@ func (r *RolloutReconciler) reconcileRolloutProgressing(rollout *rolloutv1alpha1 } case rolloutv1alpha1.ProgressingReasonPaused: - if !rollout.Spec.Strategy.Paused { + // rollout canceled, indicates rollback(v1 -> v2 -> v1) + if workload.IsInRollback { + newStatus.CanaryStatus.CanaryRevision = workload.CanaryRevision + r.Recorder.Eventf(rollout, corev1.EventTypeNormal, "Progressing", "workload has been rollback, then rollout is canceled") + klog.Infof("rollout(%s/%s) workload has been rollback, then rollout canceled", rollout.Namespace, rollout.Name) + progressingStateTransition(newStatus, corev1.ConditionFalse, rolloutv1alpha1.ProgressingReasonCancelling, "The workload has been rolled back and the rollout process will be cancelled") + // from paused to inRolling + } else if !rollout.Spec.Strategy.Paused { klog.Infof("rollout(%s/%s) is Progressing, but paused", rollout.Namespace, rollout.Name) progressingStateTransition(newStatus, corev1.ConditionFalse, rolloutv1alpha1.ProgressingReasonInRolling, "") } @@ -187,10 +195,7 @@ func progressingStateTransition(status *rolloutv1alpha1.RolloutStatus, condStatu func (r *RolloutReconciler) doProgressingInitializing(rollout *rolloutv1alpha1.Rollout, newStatus *rolloutv1alpha1.RolloutStatus) (bool, string, error) { // canary release - if rollout.Spec.Strategy.Type == "" || rollout.Spec.Strategy.Type == rolloutv1alpha1.RolloutStrategyCanary { - return r.verifyCanaryStrategy(rollout, newStatus) - } - return true, "", nil + return r.verifyCanaryStrategy(rollout, newStatus) } func (r *RolloutReconciler) doProgressingInRolling(rollout *rolloutv1alpha1.Rollout, newStatus *rolloutv1alpha1.RolloutStatus) (*time.Time, error) { @@ -230,7 +235,7 @@ func (r *RolloutReconciler) doProgressingReset(rollout *rolloutv1alpha1.Rollout, recorder: r.Recorder, } - if rolloutCon.rollout.Spec.Strategy.Canary.TrafficRouting != nil { + if rolloutCon.rollout.Spec.Strategy.Canary.TrafficRoutings != nil { // 1. remove stable service podRevision selector done, err := rolloutCon.restoreStableService() if err != nil || !done { @@ -257,8 +262,8 @@ func (r *RolloutReconciler) doProgressingReset(rollout *rolloutv1alpha1.Rollout, func (r *RolloutReconciler) verifyCanaryStrategy(rollout *rolloutv1alpha1.Rollout, newStatus *rolloutv1alpha1.RolloutStatus) (bool, string, error) { canary := rollout.Spec.Strategy.Canary // Traffic routing - if canary.TrafficRouting != nil { - if ok, msg, err := r.verifyTrafficRouting(rollout.Namespace, canary.TrafficRouting[0]); !ok { + if canary.TrafficRoutings != nil { + if ok, msg, err := r.verifyTrafficRouting(rollout.Namespace, canary.TrafficRoutings[0]); !ok { return ok, msg, err } } diff --git a/pkg/controller/rollout/progressing_test.go b/pkg/controller/rollout/progressing_test.go index 64a029a9..623d6a7a 100644 --- a/pkg/controller/rollout/progressing_test.go +++ b/pkg/controller/rollout/progressing_test.go @@ -32,16 +32,16 @@ import ( func TestReCalculateCanaryStepIndex(t *testing.T) { cases := []struct { name string - getObj func() *apps.Deployment + getObj func() (*apps.Deployment, *apps.ReplicaSet) getRollout func() *rolloutv1alpha1.Rollout getBatchRelease func() *rolloutv1alpha1.BatchRelease expectStepIndex int32 }{ { name: "steps changed v1", - getObj: func() *apps.Deployment { + getObj: func() (*apps.Deployment, *apps.ReplicaSet) { obj := deploymentDemo.DeepCopy() - return obj + return obj, rsDemo.DeepCopy() }, getRollout: func() *rolloutv1alpha1.Rollout { obj := rolloutDemo.DeepCopy() @@ -78,9 +78,9 @@ func TestReCalculateCanaryStepIndex(t *testing.T) { }, { name: "steps changed v2", - getObj: func() *apps.Deployment { + getObj: func() (*apps.Deployment, *apps.ReplicaSet) { obj := deploymentDemo.DeepCopy() - return obj + return obj, rsDemo.DeepCopy() }, getRollout: func() *rolloutv1alpha1.Rollout { obj := rolloutDemo.DeepCopy() @@ -117,9 +117,9 @@ func TestReCalculateCanaryStepIndex(t *testing.T) { }, { name: "steps changed v3", - getObj: func() *apps.Deployment { + getObj: func() (*apps.Deployment, *apps.ReplicaSet) { obj := deploymentDemo.DeepCopy() - return obj + return obj, rsDemo.DeepCopy() }, getRollout: func() *rolloutv1alpha1.Rollout { obj := rolloutDemo.DeepCopy() @@ -156,9 +156,9 @@ func TestReCalculateCanaryStepIndex(t *testing.T) { }, { name: "steps changed v4", - getObj: func() *apps.Deployment { + getObj: func() (*apps.Deployment, *apps.ReplicaSet) { obj := deploymentDemo.DeepCopy() - return obj + return obj, rsDemo.DeepCopy() }, getRollout: func() *rolloutv1alpha1.Rollout { obj := rolloutDemo.DeepCopy() @@ -193,13 +193,59 @@ func TestReCalculateCanaryStepIndex(t *testing.T) { }, expectStepIndex: 2, }, + { + name: "steps changed v5", + getObj: func() (*apps.Deployment, *apps.ReplicaSet) { + obj := deploymentDemo.DeepCopy() + return obj, rsDemo.DeepCopy() + }, + getRollout: func() *rolloutv1alpha1.Rollout { + obj := rolloutDemo.DeepCopy() + obj.Spec.Strategy.Canary.Steps = []rolloutv1alpha1.CanaryStep{ + { + Weight: 2, + Replicas: &intstr.IntOrString{ + Type: intstr.String, + StrVal: "10%", + }, + }, + { + Weight: 3, + Replicas: &intstr.IntOrString{ + Type: intstr.String, + StrVal: "10%", + }, + }, + } + return obj + }, + getBatchRelease: func() *rolloutv1alpha1.BatchRelease { + obj := batchDemo.DeepCopy() + obj.Spec.ReleasePlan.Batches = []rolloutv1alpha1.ReleaseBatch{ + { + CanaryReplicas: intstr.FromString("10%"), + }, + { + CanaryReplicas: intstr.FromString("20%"), + }, + { + CanaryReplicas: intstr.FromString("30%"), + }, + } + obj.Spec.ReleasePlan.BatchPartition = utilpointer.Int32(0) + return obj + }, + expectStepIndex: 1, + }, } for _, cs := range cases { t.Run(cs.name, func(t *testing.T) { client := fake.NewClientBuilder().WithScheme(scheme).Build() client.Create(context.TODO(), cs.getBatchRelease()) - client.Create(context.TODO(), cs.getObj()) + dep, rs := cs.getObj() + client.Create(context.TODO(), dep) + client.Create(context.TODO(), rs) client.Create(context.TODO(), cs.getRollout()) reconciler := &RolloutReconciler{ diff --git a/pkg/controller/rollout/rollout_controller.go b/pkg/controller/rollout/rollout_controller.go index bcf11120..1fcc6854 100644 --- a/pkg/controller/rollout/rollout_controller.go +++ b/pkg/controller/rollout/rollout_controller.go @@ -87,9 +87,11 @@ func (r *RolloutReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct return ctrl.Result{}, err } // update rollout status - err = r.updateRolloutStatus(rollout) + done, err := r.updateRolloutStatus(rollout) if err != nil { return ctrl.Result{}, err + } else if !done { + return ctrl.Result{}, nil } var recheckTime *time.Time diff --git a/pkg/controller/rollout/rollout_controller_test.go b/pkg/controller/rollout/rollout_controller_test.go index 450ed0be..e0831946 100644 --- a/pkg/controller/rollout/rollout_controller_test.go +++ b/pkg/controller/rollout/rollout_controller_test.go @@ -22,6 +22,7 @@ import ( apps "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" clientgoscheme "k8s.io/client-go/kubernetes/scheme" utilpointer "k8s.io/utils/pointer" ) @@ -36,7 +37,6 @@ var ( }, Spec: rolloutv1alpha1.RolloutSpec{ ObjectRef: rolloutv1alpha1.ObjectRef{ - Type: rolloutv1alpha1.WorkloadRefType, WorkloadRef: &rolloutv1alpha1.WorkloadRef{ APIVersion: "apps/v1", Kind: "Deployment", @@ -55,11 +55,43 @@ var ( Kind: "Deployment", }, ObjectMeta: metav1.ObjectMeta{ - Name: "echoserver", - Labels: map[string]string{}, + Name: "echoserver", + Labels: map[string]string{}, + Generation: 1, + UID: types.UID("606132e0-85ef-460a-8cf5-cd8f915a8cc3"), }, Spec: apps.DeploymentSpec{ Replicas: utilpointer.Int32(100), + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "echoserver", + }, + }, + }, + Status: apps.DeploymentStatus{ + ObservedGeneration: 1, + }, + } + + rsDemo = &apps.ReplicaSet{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "ReplicaSet", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "echoserver-xxx", + Labels: map[string]string{ + "app": "echoserver", + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "apps/v1", + Kind: "Deployment", + Name: "echoserver", + UID: types.UID("606132e0-85ef-460a-8cf5-cd8f915a8cc3"), + Controller: utilpointer.BoolPtr(true), + }, + }, }, } @@ -70,7 +102,6 @@ var ( }, Spec: rolloutv1alpha1.BatchReleaseSpec{ TargetRef: rolloutv1alpha1.ObjectRef{ - Type: rolloutv1alpha1.WorkloadRefType, WorkloadRef: &rolloutv1alpha1.WorkloadRef{ APIVersion: "apps/v1", Kind: "Deployment", diff --git a/pkg/controller/rollout/status.go b/pkg/controller/rollout/status.go index 5d693bc4..6b83c10d 100644 --- a/pkg/controller/rollout/status.go +++ b/pkg/controller/rollout/status.go @@ -33,9 +33,22 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -func (r *RolloutReconciler) updateRolloutStatus(rollout *rolloutv1alpha1.Rollout) error { +func (r *RolloutReconciler) updateRolloutStatus(rollout *rolloutv1alpha1.Rollout) (done bool, err error) { newStatus := *rollout.Status.DeepCopy() newStatus.ObservedGeneration = rollout.GetGeneration() + defer func() { + err = r.updateRolloutStatusInternal(rollout, newStatus) + if err != nil { + klog.Errorf("update rollout(%s/%s) status failed: %s", rollout.Namespace, rollout.Name, err.Error()) + return + } + err = r.calculateRolloutHash(rollout) + if err != nil { + return + } + rollout.Status = newStatus + }() + // delete rollout CRD if !rollout.DeletionTimestamp.IsZero() && newStatus.Phase != rolloutv1alpha1.RolloutPhaseTerminating { newStatus.Phase = rolloutv1alpha1.RolloutPhaseTerminating @@ -48,29 +61,36 @@ func (r *RolloutReconciler) updateRolloutStatus(rollout *rolloutv1alpha1.Rollout workload, err := r.Finder.GetWorkloadForRef(rollout.Namespace, rollout.Spec.ObjectRef.WorkloadRef) if err != nil { klog.Errorf("rollout(%s/%s) get workload failed: %s", rollout.Namespace, rollout.Name, err.Error()) - return err - } else if workload == nil && rollout.DeletionTimestamp.IsZero() { - resetStatus(&newStatus) - klog.Infof("rollout(%s/%s) workload not found, and reset status be Initial", rollout.Namespace, rollout.Name) - } else if workload != nil { - newStatus.StableRevision = workload.StableRevision - newStatus.CanaryRevision = workload.CanaryRevision - // update workload generation to canaryStatus.ObservedWorkloadGeneration - // rollout is a target ref bypass, so there needs to be a field to identify the rollout execution process or results, - // which version of deployment is targeted, ObservedWorkloadGeneration that is to compare with the workload generation - if newStatus.CanaryStatus != nil && newStatus.CanaryStatus.CanaryRevision != "" && - newStatus.CanaryStatus.CanaryRevision == workload.CanaryRevision { - newStatus.CanaryStatus.ObservedWorkloadGeneration = workload.Generation + return + } else if workload == nil { + if rollout.DeletionTimestamp.IsZero() { + resetStatus(&newStatus) + klog.Infof("rollout(%s/%s) workload not found, and reset status be Initial", rollout.Namespace, rollout.Name) } + done = true + return + } + + // workload status is not consistent + if !workload.IsStatusConsistent { + klog.Infof("rollout(%s/%s) workload status isn't consistent, then wait a moment", rollout.Namespace, rollout.Name) + done = false + return + } + newStatus.StableRevision = workload.StableRevision + // update workload generation to canaryStatus.ObservedWorkloadGeneration + // rollout is a target ref bypass, so there needs to be a field to identify the rollout execution process or results, + // which version of deployment is targeted, ObservedWorkloadGeneration that is to compare with the workload generation + if newStatus.CanaryStatus != nil && newStatus.CanaryStatus.CanaryRevision != "" && + newStatus.CanaryStatus.CanaryRevision == workload.CanaryRevision { + newStatus.CanaryStatus.ObservedWorkloadGeneration = workload.Generation } switch newStatus.Phase { case rolloutv1alpha1.RolloutPhaseInitial: - if workload != nil { - klog.Infof("rollout(%s/%s) status phase from(%s) -> to(%s)", rollout.Namespace, rollout.Name, rolloutv1alpha1.RolloutPhaseInitial, rolloutv1alpha1.RolloutPhaseHealthy) - newStatus.Phase = rolloutv1alpha1.RolloutPhaseHealthy - newStatus.Message = "rollout is healthy" - } + klog.Infof("rollout(%s/%s) status phase from(%s) -> to(%s)", rollout.Namespace, rollout.Name, rolloutv1alpha1.RolloutPhaseInitial, rolloutv1alpha1.RolloutPhaseHealthy) + newStatus.Phase = rolloutv1alpha1.RolloutPhaseHealthy + newStatus.Message = "rollout is healthy" case rolloutv1alpha1.RolloutPhaseHealthy: // from healthy to progressing if workload.InRolloutProgressing { @@ -85,17 +105,8 @@ func (r *RolloutReconciler) updateRolloutStatus(rollout *rolloutv1alpha1.Rollout newStatus.Phase = rolloutv1alpha1.RolloutPhaseHealthy } } - err = r.updateRolloutStatusInternal(rollout, newStatus) - if err != nil { - klog.Errorf("update rollout(%s/%s) status failed: %s", rollout.Namespace, rollout.Name, err.Error()) - return err - } - err = r.calculateRolloutHash(rollout) - if err != nil { - return err - } - rollout.Status = newStatus - return nil + done = true + return } func (r *RolloutReconciler) updateRolloutStatusInternal(rollout *rolloutv1alpha1.Rollout, newStatus rolloutv1alpha1.RolloutStatus) error { @@ -124,9 +135,8 @@ func (r *RolloutReconciler) updateRolloutStatusInternal(rollout *rolloutv1alpha1 // ResetStatus resets the status of the rollout to start from beginning func resetStatus(status *rolloutv1alpha1.RolloutStatus) { - status.CanaryRevision = "" status.StableRevision = "" - util.RemoveRolloutCondition(status, rolloutv1alpha1.RolloutConditionProgressing) + //util.RemoveRolloutCondition(status, rolloutv1alpha1.RolloutConditionProgressing) status.Phase = rolloutv1alpha1.RolloutPhaseInitial status.Message = "workload not found" } diff --git a/pkg/controller/rollout/trafficrouting.go b/pkg/controller/rollout/trafficrouting.go index 809156e6..e2ceaa02 100644 --- a/pkg/controller/rollout/trafficrouting.go +++ b/pkg/controller/rollout/trafficrouting.go @@ -36,12 +36,20 @@ import ( ) func (r *rolloutContext) doCanaryTrafficRouting() (bool, error) { - if r.rollout.Spec.Strategy.Canary.TrafficRouting == nil { + if len(r.rollout.Spec.Strategy.Canary.TrafficRoutings) == 0 { return true, nil } + + if r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds <= 0 { + r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds = defaultGracePeriodSeconds + } canaryStatus := r.newStatus.CanaryStatus + if r.newStatus.StableRevision == "" || canaryStatus.PodTemplateHash == "" { + klog.Warningf("rollout(%s/%s) stableRevision or podTemplateHash can't be empty, and wait a moment", r.rollout.Namespace, r.rollout.Name) + return false, nil + } //fetch stable service - sName := r.rollout.Spec.Strategy.Canary.TrafficRouting[0].Service + sName := r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].Service r.stableService = &corev1.Service{} err := r.Get(context.TODO(), client.ObjectKey{Namespace: r.rollout.Namespace, Name: sName}, r.stableService) if err != nil { @@ -71,8 +79,8 @@ func (r *rolloutContext) doCanaryTrafficRouting() (bool, error) { // update service selector // update service selector specific revision pods - if r.canaryService.Spec.Selector[r.podRevisionLabelKey()] != canaryStatus.CanaryRevision { - body := fmt.Sprintf(`{"spec":{"selector":{"%s":"%s"}}}`, r.podRevisionLabelKey(), canaryStatus.CanaryRevision) + if r.canaryService.Spec.Selector[r.podRevisionLabelKey()] != canaryStatus.PodTemplateHash { + body := fmt.Sprintf(`{"spec":{"selector":{"%s":"%s"}}}`, r.podRevisionLabelKey(), canaryStatus.PodTemplateHash) if err = r.Patch(context.TODO(), r.canaryService, client.RawPatch(types.StrategicMergePatchType, []byte(body))); err != nil { klog.Errorf("rollout(%s/%s) patch canary service(%s) failed: %s", r.rollout.Namespace, r.rollout.Name, r.canaryService.Name, err.Error()) return false, err @@ -80,7 +88,7 @@ func (r *rolloutContext) doCanaryTrafficRouting() (bool, error) { // update canary service time, and wait 3 seconds, just to be safe canaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()} klog.Infof("add rollout(%s/%s) canary service(%s) selector(%s=%s) success", - r.rollout.Namespace, r.rollout.Name, r.canaryService.Name, r.podRevisionLabelKey(), canaryStatus.CanaryRevision) + r.rollout.Namespace, r.rollout.Name, r.canaryService.Name, r.podRevisionLabelKey(), canaryStatus.PodTemplateHash) } if r.stableService.Spec.Selector[r.podRevisionLabelKey()] != r.newStatus.StableRevision { body := fmt.Sprintf(`{"spec":{"selector":{"%s":"%s"}}}`, r.podRevisionLabelKey(), r.newStatus.StableRevision) @@ -96,7 +104,7 @@ func (r *rolloutContext) doCanaryTrafficRouting() (bool, error) { } // After restore stable service configuration, give the ingress provider 3 seconds to take effect - if verifyTime := canaryStatus.LastUpdateTime.Add(time.Second * time.Duration(r.rollout.Spec.Strategy.Canary.TrafficRouting[0].GracePeriodSeconds)); verifyTime.After(time.Now()) { + if verifyTime := canaryStatus.LastUpdateTime.Add(time.Second * time.Duration(r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds)); verifyTime.After(time.Now()) { klog.Infof("update rollout(%s/%s) stable service(%s) done, and wait 3 seconds", r.rollout.Namespace, r.rollout.Name, r.stableService.Name) return false, nil } @@ -121,16 +129,20 @@ func (r *rolloutContext) doCanaryTrafficRouting() (bool, error) { r.recorder.Eventf(r.rollout, corev1.EventTypeNormal, "Progressing", fmt.Sprintf("traffic route weight(%d) done", desiredWeight)) return false, trController.SetRoutes(desiredWeight) } - klog.Infof("rollout(%s/%s) do step(%d) trafficRouting(%d%) success", r.rollout.Namespace, r.rollout.Name, r.newStatus.CanaryStatus.CurrentStepIndex, desiredWeight) + klog.Infof("rollout(%s/%s) do step(%d) trafficRouting(%d) success", r.rollout.Namespace, r.rollout.Name, r.newStatus.CanaryStatus.CurrentStepIndex, desiredWeight) return true, nil } func (r *rolloutContext) restoreStableService() (bool, error) { - if r.rollout.Spec.Strategy.Canary.TrafficRouting == nil { + if len(r.rollout.Spec.Strategy.Canary.TrafficRoutings) == 0 { return true, nil } + + if r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds <= 0 { + r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds = defaultGracePeriodSeconds + } //fetch stable service - sName := r.rollout.Spec.Strategy.Canary.TrafficRouting[0].Service + sName := r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].Service r.stableService = &corev1.Service{} err := r.Get(context.TODO(), client.ObjectKey{Namespace: r.rollout.Namespace, Name: sName}, r.stableService) if err != nil { @@ -157,7 +169,7 @@ func (r *rolloutContext) restoreStableService() (bool, error) { } // After restore stable service configuration, give the ingress provider 3 seconds to take effect if r.newStatus.CanaryStatus.LastUpdateTime != nil { - if verifyTime := r.newStatus.CanaryStatus.LastUpdateTime.Add(time.Second * time.Duration(r.rollout.Spec.Strategy.Canary.TrafficRouting[0].GracePeriodSeconds)); verifyTime.After(time.Now()) { + if verifyTime := r.newStatus.CanaryStatus.LastUpdateTime.Add(time.Second * time.Duration(r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds)); verifyTime.After(time.Now()) { klog.Infof("restore rollout(%s/%s) stable service(%s) done, and wait a moment", r.rollout.Namespace, r.rollout.Name, r.stableService.Name) return false, nil } @@ -167,9 +179,13 @@ func (r *rolloutContext) restoreStableService() (bool, error) { } func (r *rolloutContext) doFinalisingTrafficRouting() (bool, error) { - if r.rollout.Spec.Strategy.Canary.TrafficRouting == nil { + if len(r.rollout.Spec.Strategy.Canary.TrafficRoutings) == 0 { return true, nil } + + if r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds <= 0 { + r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds = defaultGracePeriodSeconds + } if r.newStatus.CanaryStatus == nil { r.newStatus.CanaryStatus = &rolloutv1alpha1.CanaryStatus{} } @@ -194,7 +210,7 @@ func (r *rolloutContext) doFinalisingTrafficRouting() (bool, error) { // After do TrafficRouting configuration, give the ingress provider 3 seconds to take effect if r.newStatus.CanaryStatus.LastUpdateTime != nil { - if verifyTime := r.newStatus.CanaryStatus.LastUpdateTime.Add(time.Second * time.Duration(r.rollout.Spec.Strategy.Canary.TrafficRouting[0].GracePeriodSeconds)); verifyTime.After(time.Now()) { + if verifyTime := r.newStatus.CanaryStatus.LastUpdateTime.Add(time.Second * time.Duration(r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].GracePeriodSeconds)); verifyTime.After(time.Now()) { klog.Infof("rollout(%s/%s) doFinalisingTrafficRouting done, and wait a moment", r.rollout.Namespace, r.rollout.Name) return false, nil } @@ -225,7 +241,7 @@ func (r *rolloutContext) doFinalisingTrafficRouting() (bool, error) { func (r *rolloutContext) newTrafficRoutingController(roCtx *rolloutContext) (trafficrouting.Controller, error) { canary := roCtx.rollout.Spec.Strategy.Canary - switch canary.TrafficRouting[0].Type { + switch canary.TrafficRoutings[0].Type { case "nginx": gvk := schema.GroupVersionKind{Group: rolloutv1alpha1.GroupVersion.Group, Version: rolloutv1alpha1.GroupVersion.Version, Kind: "Rollout"} return nginx.NewNginxTrafficRouting(r.Client, r.newStatus, nginx.Config{ @@ -233,12 +249,12 @@ func (r *rolloutContext) newTrafficRoutingController(roCtx *rolloutContext) (tra RolloutNs: r.rollout.Namespace, CanaryService: r.canaryService, StableService: r.stableService, - TrafficConf: r.rollout.Spec.Strategy.Canary.TrafficRouting[0].Ingress, + TrafficConf: r.rollout.Spec.Strategy.Canary.TrafficRoutings[0].Ingress, OwnerRef: *metav1.NewControllerRef(r.rollout, gvk), }) } - return nil, fmt.Errorf("TrafficRouting(%s) not support", canary.TrafficRouting[0].Type) + return nil, fmt.Errorf("TrafficRouting(%s) not support", canary.TrafficRoutings[0].Type) } func (r *rolloutContext) createCanaryService() error { @@ -266,7 +282,7 @@ func (r *rolloutContext) createCanaryService() error { r.canaryService.Spec.IPFamilyPolicy = nil r.canaryService.Spec.IPFamilies = nil r.canaryService.Spec.LoadBalancerIP = "" - r.canaryService.Spec.Selector[r.podRevisionLabelKey()] = r.newStatus.CanaryStatus.CanaryRevision + r.canaryService.Spec.Selector[r.podRevisionLabelKey()] = r.newStatus.CanaryStatus.PodTemplateHash err := r.Create(context.TODO(), r.canaryService) if err != nil && !errors.IsAlreadyExists(err) { klog.Errorf("create rollout(%s/%s) canary service(%s) failed: %s", r.rollout.Namespace, r.rollout.Name, r.canaryService.Name, err.Error()) diff --git a/pkg/util/controller_finder.go b/pkg/util/controller_finder.go index e8117779..a95cec44 100644 --- a/pkg/util/controller_finder.go +++ b/pkg/util/controller_finder.go @@ -43,17 +43,23 @@ type Workload struct { StableRevision string // canary revision CanaryRevision string + // pod template hash is used as service selector hash + PodTemplateHash string // canary replicas CanaryReplicas int32 // canary ready replicas CanaryReadyReplicas int32 - // spec.pod.template hash - CurrentPodTemplateHash string + // Is it in rollback phase + IsInRollback bool // indicate whether the workload can enter the rollout process // 1. workload.Spec.Paused = true // 2. the Deployment is not in a stable version (only one version of RS) InRolloutProgressing bool + + // whether the status consistent with the spec + // workload.generation == status.observedGeneration + IsStatusConsistent bool } // ControllerFinderFunc is a function type that maps a pod to a list of @@ -112,15 +118,19 @@ func (r *ControllerFinder) getKruiseCloneSet(namespace string, ref *rolloutv1alp } return nil, err } + if cloneSet.Generation != cloneSet.Status.ObservedGeneration { + return &Workload{IsStatusConsistent: false}, nil + } workload := &Workload{ - StableRevision: cloneSet.Status.CurrentRevision[strings.LastIndex(cloneSet.Status.CurrentRevision, "-")+1:], - CanaryRevision: cloneSet.Status.UpdateRevision[strings.LastIndex(cloneSet.Status.UpdateRevision, "-")+1:], - CanaryReplicas: cloneSet.Status.UpdatedReplicas, - CanaryReadyReplicas: cloneSet.Status.UpdatedReadyReplicas, - ObjectMeta: cloneSet.ObjectMeta, - TypeMeta: cloneSet.TypeMeta, - Replicas: *cloneSet.Spec.Replicas, - CurrentPodTemplateHash: cloneSet.Status.UpdateRevision, + StableRevision: cloneSet.Status.CurrentRevision[strings.LastIndex(cloneSet.Status.CurrentRevision, "-")+1:], + CanaryRevision: cloneSet.Status.UpdateRevision[strings.LastIndex(cloneSet.Status.UpdateRevision, "-")+1:], + CanaryReplicas: cloneSet.Status.UpdatedReplicas, + CanaryReadyReplicas: cloneSet.Status.UpdatedReadyReplicas, + ObjectMeta: cloneSet.ObjectMeta, + TypeMeta: cloneSet.TypeMeta, + Replicas: *cloneSet.Spec.Replicas, + PodTemplateHash: cloneSet.Status.UpdateRevision[strings.LastIndex(cloneSet.Status.UpdateRevision, "-")+1:], + IsStatusConsistent: true, } // not in rollout progressing if _, ok = workload.Annotations[InRolloutProgressingAnnotation]; !ok { @@ -128,6 +138,10 @@ func (r *ControllerFinder) getKruiseCloneSet(namespace string, ref *rolloutv1alp } // in rollout progressing workload.InRolloutProgressing = true + // Is it in rollback phase + if cloneSet.Status.CurrentRevision == cloneSet.Status.UpdateRevision && cloneSet.Status.UpdatedReplicas != cloneSet.Status.Replicas { + workload.IsInRollback = true + } return workload, nil } @@ -147,21 +161,23 @@ func (r *ControllerFinder) getDeployment(namespace string, ref *rolloutv1alpha1. } return nil, err } - workload := &Workload{ - ObjectMeta: stable.ObjectMeta, - TypeMeta: stable.TypeMeta, - Replicas: *stable.Spec.Replicas, + if stable.Generation != stable.Status.ObservedGeneration { + return &Workload{IsStatusConsistent: false}, nil } // stable replicaSet - stableRs, err := r.GetDeploymentStableRs(stable) + stableRs, err := r.getDeploymentStableRs(stable) if err != nil || stableRs == nil { - return workload, err + return &Workload{IsStatusConsistent: false}, err + } + + workload := &Workload{ + ObjectMeta: stable.ObjectMeta, + TypeMeta: stable.TypeMeta, + Replicas: *stable.Spec.Replicas, + IsStatusConsistent: true, + StableRevision: stableRs.Labels[apps.DefaultDeploymentUniqueLabelKey], + CanaryRevision: ComputeHash(&stable.Spec.Template, nil), } - // stable revision - workload.StableRevision = stableRs.Labels[RsPodRevisionLabelKey] - // canary revision - workload.CanaryRevision = ComputeHash(&stable.Spec.Template, nil) - workload.CurrentPodTemplateHash = workload.CanaryRevision // not in rollout progressing if _, ok = workload.Annotations[InRolloutProgressingAnnotation]; !ok { return workload, nil @@ -171,24 +187,24 @@ func (r *ControllerFinder) getDeployment(namespace string, ref *rolloutv1alpha1. workload.InRolloutProgressing = true // workload is continuous release, indicates rollback(v1 -> v2 -> v1) // delete auto-generated labels - delete(stableRs.Spec.Template.Labels, RsPodRevisionLabelKey) + delete(stableRs.Spec.Template.Labels, apps.DefaultDeploymentUniqueLabelKey) if EqualIgnoreHash(&stableRs.Spec.Template, &stable.Spec.Template) { - workload.CanaryRevision = workload.StableRevision + workload.IsInRollback = true return workload, nil } - // canary workload status + // canary deployment canary, err := r.getLatestCanaryDeployment(stable) - if err != nil { - return nil, err - } else if canary != nil { - workload.CanaryReplicas = canary.Status.Replicas - workload.CanaryReadyReplicas = canary.Status.ReadyReplicas - canaryRs, err := r.GetDeploymentStableRs(canary) - if err != nil || canaryRs == nil { - return workload, err - } + if err != nil || canary == nil { + return workload, err + } + workload.CanaryReplicas = canary.Status.Replicas + workload.CanaryReadyReplicas = canary.Status.ReadyReplicas + canaryRs, err := r.getDeploymentStableRs(canary) + if err != nil || canaryRs == nil { + return workload, err } + workload.PodTemplateHash = canaryRs.Labels[apps.DefaultDeploymentUniqueLabelKey] return workload, err } @@ -204,10 +220,16 @@ func (r *ControllerFinder) getLatestCanaryDeployment(stable *apps.Deployment) (* sort.Slice(canaryList.Items, func(i, j int) bool { return canaryList.Items[j].CreationTimestamp.Before(&canaryList.Items[i].CreationTimestamp) }) - return &canaryList.Items[0], nil + for i := range canaryList.Items { + obj := &canaryList.Items[i] + if obj.DeletionTimestamp.IsZero() { + return obj, nil + } + } + return nil, nil } -func (r *ControllerFinder) getReplicaSetsForDeployment(obj *apps.Deployment) ([]apps.ReplicaSet, error) { +func (r *ControllerFinder) GetReplicaSetsForDeployment(obj *apps.Deployment) ([]apps.ReplicaSet, error) { // List ReplicaSets owned by this Deployment rsList := &apps.ReplicaSetList{} selector, err := metav1.LabelSelectorAsSelector(obj.Spec.Selector) @@ -219,6 +241,7 @@ func (r *ControllerFinder) getReplicaSetsForDeployment(obj *apps.Deployment) ([] if err != nil { return nil, err } + rss := make([]apps.ReplicaSet, 0) for i := range rsList.Items { rs := rsList.Items[i] @@ -234,14 +257,18 @@ func (r *ControllerFinder) getReplicaSetsForDeployment(obj *apps.Deployment) ([] return rss, nil } -func (r *ControllerFinder) GetDeploymentStableRs(obj *apps.Deployment) (*apps.ReplicaSet, error) { - rss, err := r.getReplicaSetsForDeployment(obj) +func (r *ControllerFinder) getDeploymentStableRs(obj *apps.Deployment) (*apps.ReplicaSet, error) { + rss, err := r.GetReplicaSetsForDeployment(obj) if err != nil { return nil, err } - if len(rss) != 1 { + if len(rss) == 0 { return nil, nil } + // get oldest rs + sort.Slice(rss, func(i, j int) bool { + return rss[i].CreationTimestamp.Before(&rss[j].CreationTimestamp) + }) return &rss[0], nil } diff --git a/pkg/util/workloads_utils.go b/pkg/util/workloads_utils.go index 9b15b4c4..3981b8dd 100644 --- a/pkg/util/workloads_utils.go +++ b/pkg/util/workloads_utils.go @@ -18,7 +18,9 @@ package util import ( "context" + "crypto/sha256" "encoding/binary" + "encoding/hex" "encoding/json" "fmt" "hash" @@ -41,8 +43,6 @@ import ( ) const ( - // workload pod revision label - RsPodRevisionLabelKey = "pod-template-hash" CanaryDeploymentLabel = "rollouts.kruise.io/canary-deployment" BatchReleaseControlAnnotation = "batchrelease.rollouts.kruise.io/control-info" StashCloneSetPartition = "batchrelease.rollouts.kruise.io/stash-partition" @@ -137,6 +137,12 @@ func EqualIgnoreHash(template1, template2 *v1.PodTemplateSpec) bool { return apiequality.Semantic.DeepEqual(t1Copy, t2Copy) } +func HashReleasePlanBatches(releasePlan *v1alpha1.ReleasePlan) string { + by, _ := json.Marshal(releasePlan.Batches) + md5Hash := sha256.Sum256(by) + return hex.EncodeToString(md5Hash[:]) +} + type FinalizerOpType string const ( @@ -148,7 +154,7 @@ func UpdateFinalizer(c client.Client, object client.Object, op FinalizerOpType, switch op { case AddFinalizerOpType, RemoveFinalizerOpType: default: - panic(fmt.Sprintf("UpdateFinalizer Func 'op' parameter must be 'Add' or 'Remove'")) + panic("UpdateFinalizer Func 'op' parameter must be 'Add' or 'Remove'") } key := client.ObjectKeyFromObject(object) diff --git a/pkg/webhook/rollout/validating/rollout_create_update_handler.go b/pkg/webhook/rollout/validating/rollout_create_update_handler.go index d4eab9e3..ebc57602 100644 --- a/pkg/webhook/rollout/validating/rollout_create_update_handler.go +++ b/pkg/webhook/rollout/validating/rollout_create_update_handler.go @@ -92,14 +92,9 @@ func (h *RolloutCreateUpdateHandler) validateRolloutUpdate(oldObj, newObj *appsv if !reflect.DeepEqual(oldObj.Spec.ObjectRef, newObj.Spec.ObjectRef) { return field.ErrorList{field.Forbidden(field.NewPath("Spec.ObjectRef"), "Rollout 'ObjectRef' field is immutable")} } - if oldObj.Spec.Strategy.Type != newObj.Spec.Strategy.Type { - return field.ErrorList{field.Forbidden(field.NewPath("Spec.Strategy"), "Rollout 'Strategy.type' field is immutable")} - } // canary strategy - if oldObj.Spec.Strategy.Type != appsv1alpha1.RolloutStrategyBlueGreen { - if !reflect.DeepEqual(oldObj.Spec.Strategy.Canary.TrafficRouting, newObj.Spec.Strategy.Canary.TrafficRouting) { - return field.ErrorList{field.Forbidden(field.NewPath("Spec.Strategy.Canary.TrafficRouting"), "Rollout 'Strategy.Canary.TrafficRouting' field is immutable")} - } + if !reflect.DeepEqual(oldObj.Spec.Strategy.Canary.TrafficRoutings, newObj.Spec.Strategy.Canary.TrafficRoutings) { + return field.ErrorList{field.Forbidden(field.NewPath("Spec.Strategy.Canary.TrafficRoutings"), "Rollout 'Strategy.Canary.TrafficRoutings' field is immutable")} } } @@ -147,24 +142,14 @@ func validateRolloutSpec(rollout *appsv1alpha1.Rollout, fldPath *field.Path) fie } func validateRolloutSpecObjectRef(objectRef *appsv1alpha1.ObjectRef, fldPath *field.Path) field.ErrorList { - switch objectRef.Type { - case "", appsv1alpha1.WorkloadRefType: - if objectRef.WorkloadRef == nil || (objectRef.WorkloadRef.Kind != "Deployment" && objectRef.WorkloadRef.Kind != "CloneSet") { - return field.ErrorList{field.Invalid(fldPath.Child("WorkloadRef"), objectRef.WorkloadRef, "WorkloadRef only support 'Deployments', 'CloneSet'")} - } - default: - return field.ErrorList{field.Invalid(fldPath.Child("Type"), objectRef.Type, "ObjectRef only support 'workloadRef' type")} + if objectRef.WorkloadRef == nil || (objectRef.WorkloadRef.Kind != "Deployment" && objectRef.WorkloadRef.Kind != "CloneSet") { + return field.ErrorList{field.Invalid(fldPath.Child("WorkloadRef"), objectRef.WorkloadRef, "WorkloadRef only support 'Deployments', 'CloneSet'")} } return nil } func validateRolloutSpecStrategy(strategy *appsv1alpha1.RolloutStrategy, fldPath *field.Path) field.ErrorList { - switch strategy.Type { - case "", appsv1alpha1.RolloutStrategyCanary: - return validateRolloutSpecCanaryStrategy(strategy.Canary, fldPath.Child("Canary")) - default: - return field.ErrorList{field.Invalid(fldPath.Child("Type"), strategy.Type, "Strategy type only support 'canary'")} - } + return validateRolloutSpecCanaryStrategy(strategy.Canary, fldPath.Child("Canary")) } func validateRolloutSpecCanaryStrategy(canary *appsv1alpha1.CanaryStrategy, fldPath *field.Path) field.ErrorList { @@ -173,7 +158,10 @@ func validateRolloutSpecCanaryStrategy(canary *appsv1alpha1.CanaryStrategy, fldP } errList := validateRolloutSpecCanarySteps(canary.Steps, fldPath.Child("Steps")) - for _, traffic := range canary.TrafficRouting { + if len(canary.TrafficRoutings) > 1 { + errList = append(errList, field.Invalid(fldPath, canary.TrafficRoutings, "Rollout currently only support single TrafficRouting.")) + } + for _, traffic := range canary.TrafficRoutings { errList = append(errList, validateRolloutSpecCanaryTraffic(traffic, fldPath.Child("TrafficRouting"))...) } return errList @@ -181,7 +169,7 @@ func validateRolloutSpecCanaryStrategy(canary *appsv1alpha1.CanaryStrategy, fldP func validateRolloutSpecCanaryTraffic(traffic *appsv1alpha1.TrafficRouting, fldPath *field.Path) field.ErrorList { if traffic == nil { - return field.ErrorList{field.Invalid(fldPath, nil, "Canary.TrafficRouting cannot be empty")} + return field.ErrorList{field.Invalid(fldPath, nil, "Canary.TrafficRoutings cannot be empty")} } errList := field.ErrorList{} diff --git a/pkg/webhook/rollout/validating/rollout_create_update_handler_test.go b/pkg/webhook/rollout/validating/rollout_create_update_handler_test.go index add5ff2e..0c8b97bc 100644 --- a/pkg/webhook/rollout/validating/rollout_create_update_handler_test.go +++ b/pkg/webhook/rollout/validating/rollout_create_update_handler_test.go @@ -29,7 +29,6 @@ var ( }, Spec: appsv1alpha1.RolloutSpec{ ObjectRef: appsv1alpha1.ObjectRef{ - Type: appsv1alpha1.WorkloadRefType, WorkloadRef: &appsv1alpha1.WorkloadRef{ APIVersion: apps.SchemeGroupVersion.String(), Kind: "Deployment", @@ -37,7 +36,6 @@ var ( }, }, Strategy: appsv1alpha1.RolloutStrategy{ - Type: appsv1alpha1.RolloutStrategyCanary, Canary: &appsv1alpha1.CanaryStrategy{ Steps: []appsv1alpha1.CanaryStep{ { @@ -58,7 +56,7 @@ var ( Weight: 100, }, }, - TrafficRouting: []*appsv1alpha1.TrafficRouting{ + TrafficRoutings: []*appsv1alpha1.TrafficRouting{ { Type: "nginx", Service: "service-demo", @@ -126,7 +124,7 @@ func TestRolloutValidateCreate(t *testing.T) { Succeed: false, GetObject: func() []client.Object { object := rollout.DeepCopy() - object.Spec.Strategy.Canary.TrafficRouting[0].Service = "" + object.Spec.Strategy.Canary.TrafficRoutings[0].Service = "" return []client.Object{object} }, }, @@ -135,7 +133,7 @@ func TestRolloutValidateCreate(t *testing.T) { Succeed: false, GetObject: func() []client.Object { object := rollout.DeepCopy() - object.Spec.Strategy.Canary.TrafficRouting[0].Ingress.Name = "" + object.Spec.Strategy.Canary.TrafficRoutings[0].Ingress.Name = "" return []client.Object{object} }, }, @@ -234,30 +232,12 @@ func TestRolloutValidateCreate(t *testing.T) { // return []client.Object{object} // }, //}, - { - Name: "Wrong objectRef type", - Succeed: false, - GetObject: func() []client.Object { - object := rollout.DeepCopy() - object.Spec.ObjectRef.Type = "Whatever" - return []client.Object{object} - }, - }, - { - Name: "Wrong strategy type", - Succeed: false, - GetObject: func() []client.Object { - object := rollout.DeepCopy() - object.Spec.Strategy.Type = "Whatever" - return []client.Object{object} - }, - }, { Name: "Wrong Traffic type", Succeed: false, GetObject: func() []client.Object { object := rollout.DeepCopy() - object.Spec.Strategy.Canary.TrafficRouting[0].Type = "Whatever" + object.Spec.Strategy.Canary.TrafficRoutings[0].Type = "Whatever" return []client.Object{object} }, }, @@ -390,7 +370,7 @@ func TestRolloutValidateUpdate(t *testing.T) { GetNewObject: func() client.Object { object := rollout.DeepCopy() object.Status.Phase = appsv1alpha1.RolloutPhaseTerminating - object.Spec.Strategy.Canary.TrafficRouting[0].Type = "alb" + object.Spec.Strategy.Canary.TrafficRoutings[0].Type = "alb" return object }, }, diff --git a/pkg/webhook/workload/mutating/workload_update_handler.go b/pkg/webhook/workload/mutating/workload_update_handler.go index fb289f9f..8b394ea5 100644 --- a/pkg/webhook/workload/mutating/workload_update_handler.go +++ b/pkg/webhook/workload/mutating/workload_update_handler.go @@ -148,10 +148,11 @@ func (h *WorkloadHandler) handlerDeployment(newObj, oldObj *apps.Deployment) (ch return } // 4. the deployment must be in a stable version (only one version of rs) - stableRs, err := h.Finder.GetDeploymentStableRs(newObj) + rss, err := h.Finder.GetReplicaSetsForDeployment(newObj) if err != nil { return - } else if stableRs == nil { + } else if len(rss) != 1 { + klog.Warningf("deployment(%s/%s) contains len(%d) replicaSet, can't in rollout progressing", newObj.Namespace, newObj.Name, len(rss)) return } // 5. have matched rollout crd @@ -184,8 +185,7 @@ func (h *WorkloadHandler) fetchMatchedRollout(obj client.Object) (*appsv1alpha1. } for i := range rolloutList.Items { rollout := &rolloutList.Items[i] - if !rollout.DeletionTimestamp.IsZero() || rollout.Spec.ObjectRef.Type == appsv1alpha1.RevisionRefType || - rollout.Spec.ObjectRef.WorkloadRef == nil { + if !rollout.DeletionTimestamp.IsZero() || rollout.Spec.ObjectRef.WorkloadRef == nil { continue } ref := rollout.Spec.ObjectRef.WorkloadRef diff --git a/pkg/webhook/workload/mutating/workload_update_handler_test.go b/pkg/webhook/workload/mutating/workload_update_handler_test.go index 885b3b3d..5d5f632b 100644 --- a/pkg/webhook/workload/mutating/workload_update_handler_test.go +++ b/pkg/webhook/workload/mutating/workload_update_handler_test.go @@ -159,7 +159,6 @@ var ( }, Spec: appsv1alpha1.RolloutSpec{ ObjectRef: appsv1alpha1.ObjectRef{ - Type: appsv1alpha1.WorkloadRefType, WorkloadRef: &appsv1alpha1.WorkloadRef{ APIVersion: "apps/v1", Kind: "Deployment", diff --git a/scripts/deploy_kind.sh b/scripts/deploy_kind.sh new file mode 100755 index 00000000..741bd623 --- /dev/null +++ b/scripts/deploy_kind.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +if [ -z "$IMG" ]; then + echo "no found IMG env" + exit 1 +fi + +set -e + +make kustomize +KUSTOMIZE=$(pwd)/bin/kustomize +(cd config/manager && "${KUSTOMIZE}" edit set image controller="${IMG}") +"${KUSTOMIZE}" build config/default | sed -e 's/imagePullPolicy: Always/imagePullPolicy: IfNotPresent/g' > /tmp/rollout-kustomization.yaml +echo -e "resources:\n- manager.yaml" > config/manager/kustomization.yaml +kubectl apply -f /tmp/rollout-kustomization.yaml diff --git a/temp b/temp deleted file mode 100644 index e69de29b..00000000 diff --git a/test/e2e/batchrelease_test.go b/test/e2e/batchrelease_test.go index a7e92595..712c0cf1 100644 --- a/test/e2e/batchrelease_test.go +++ b/test/e2e/batchrelease_test.go @@ -678,7 +678,7 @@ var _ = SIGDescribe("BatchRelease", func() { }, 15*time.Minute, 5*time.Second).Should(BeTrue()) }) - It("Rollback V1->V2->V1: Percentage, 100%, Succeeded", func() { + /*It("Rollback V1->V2->V1: Percentage, 100%, Succeeded", func() { release := &rolloutsv1alpha1.BatchRelease{} Expect(ReadYamlToObject("./test_data/batchrelease/cloneset_percentage_100.yaml", release)).ToNot(HaveOccurred()) CreateObject(release) @@ -695,7 +695,8 @@ var _ = SIGDescribe("BatchRelease", func() { stableRevision := GetUpdateRevision(cloneset) cloneset.Spec.UpdateStrategy.Paused = true - cloneset.Spec.Replicas = pointer.Int32Ptr(10) + // todo + //cloneset.Spec.Replicas = pointer.Int32Ptr(10) cloneset.Spec.Template.Spec.Containers[0].Image = images.GetE2EImage(images.FailedImage) UpdateCloneSet(cloneset) @@ -708,6 +709,8 @@ var _ = SIGDescribe("BatchRelease", func() { for i := 0; i < 30; i++ { fetchedRelease := &rolloutsv1alpha1.BatchRelease{} Expect(GetObject(release.Namespace, release.Name, fetchedRelease)).NotTo(HaveOccurred()) + Expect(fetchedRelease.Status.CanaryStatus.UpdatedReplicas).Should(Equal(int32(1))) + Expect(fetchedRelease.Status.CanaryStatus.UpdatedReadyReplicas).Should(Equal(int32(0))) Expect(fetchedRelease.Status.CanaryStatus.CurrentBatch).Should(Equal(int32(0))) time.Sleep(time.Second) } @@ -723,7 +726,7 @@ var _ = SIGDescribe("BatchRelease", func() { Expect(GetObject(release.Namespace, release.Name, clone)).NotTo(HaveOccurred()) return clone.Status.Phase }, 15*time.Minute, 5*time.Second).Should(Equal(rolloutsv1alpha1.RolloutPhaseCancelled)) - }) + })*/ }) KruiseDescribe("Deployment BatchRelease Checker", func() { @@ -1286,7 +1289,7 @@ var _ = SIGDescribe("BatchRelease", func() { stableRevisionV1 := workloads.ComputeHash(&deployment.Spec.Template, deployment.Status.CollisionCount) deployment.Spec.Paused = true - deployment.Spec.Replicas = pointer.Int32Ptr(10) + //deployment.Spec.Replicas = pointer.Int32Ptr(10) deployment.Spec.Template.Spec.Containers[0].Image = images.GetE2EImage(images.FailedImage) UpdateDeployment(deployment) @@ -1299,6 +1302,8 @@ var _ = SIGDescribe("BatchRelease", func() { for i := 0; i < 30; i++ { fetchedRelease := &rolloutsv1alpha1.BatchRelease{} Expect(GetObject(release.Namespace, release.Name, fetchedRelease)).NotTo(HaveOccurred()) + Expect(fetchedRelease.Status.CanaryStatus.UpdatedReplicas).Should(Equal(int32(1))) + Expect(fetchedRelease.Status.CanaryStatus.UpdatedReadyReplicas).Should(Equal(int32(0))) Expect(fetchedRelease.Status.CanaryStatus.CurrentBatch).Should(Equal(int32(0))) time.Sleep(time.Second) } diff --git a/test/e2e/rollout_test.go b/test/e2e/rollout_test.go index ef3904e1..1f778d91 100644 --- a/test/e2e/rollout_test.go +++ b/test/e2e/rollout_test.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "sort" + "strings" "time" . "github.com/onsi/ginkgo" @@ -47,6 +48,24 @@ const ( var _ = SIGDescribe("Rollout", func() { var namespace string + DumpAllResources := func() { + rollout := &rolloutsv1alpha1.RolloutList{} + k8sClient.List(context.TODO(), rollout, client.InNamespace(namespace)) + fmt.Println(util.DumpJSON(rollout)) + batch := &rolloutsv1alpha1.BatchReleaseList{} + k8sClient.List(context.TODO(), batch, client.InNamespace(namespace)) + fmt.Println(util.DumpJSON(batch)) + deploy := &apps.DeploymentList{} + k8sClient.List(context.TODO(), deploy, client.InNamespace(namespace)) + fmt.Println(util.DumpJSON(deploy)) + rs := &apps.ReplicaSetList{} + k8sClient.List(context.TODO(), rs, client.InNamespace(namespace)) + fmt.Println(util.DumpJSON(rs)) + cloneSet := &appsv1alpha1.CloneSetList{} + k8sClient.List(context.TODO(), cloneSet, client.InNamespace(namespace)) + fmt.Println(util.DumpJSON(cloneSet)) + } + CreateObject := func(object client.Object, options ...client.CreateOption) { object.SetNamespace(namespace) Expect(k8sClient.Create(context.TODO(), object)).NotTo(HaveOccurred()) @@ -103,15 +122,18 @@ var _ = SIGDescribe("Rollout", func() { } ResumeRolloutCanary := func(name string) { - Expect(retry.RetryOnConflict(retry.DefaultRetry, func() error { + Eventually(func() bool { clone := &rolloutsv1alpha1.Rollout{} - err := GetObject(name, clone) - if err != nil { - return err + Expect(GetObject(name, clone)).NotTo(HaveOccurred()) + if clone.Status.CanaryStatus.CurrentStepState != rolloutsv1alpha1.CanaryStepStatePaused { + fmt.Println("resume rollout success, and CurrentStepState", util.DumpJSON(clone.Status)) + return true } - clone.Status.CanaryStatus.CurrentStepState = rolloutsv1alpha1.CanaryStepStateReady - return k8sClient.Status().Update(context.TODO(), clone) - })).NotTo(HaveOccurred()) + + body := fmt.Sprintf(`{"status":{"canaryStatus":{"currentStepState":"%s"}}}`, rolloutsv1alpha1.CanaryStepStateReady) + Expect(k8sClient.Status().Patch(context.TODO(), clone, client.RawPatch(types.MergePatchType, []byte(body)))).NotTo(HaveOccurred()) + return false + }, 10*time.Second, time.Second).Should(BeTrue()) } WaitDeploymentAllPodsReady := func(deployment *apps.Deployment) { @@ -142,14 +164,19 @@ var _ = SIGDescribe("Rollout", func() { } WaitRolloutCanaryStepPaused := func(name string, stepIndex int32) { + start := time.Now() Eventually(func() bool { + if start.Add(time.Minute * 5).Before(time.Now()) { + DumpAllResources() + Expect(true).Should(BeFalse()) + } clone := &rolloutsv1alpha1.Rollout{} Expect(GetObject(name, clone)).NotTo(HaveOccurred()) if clone.Status.CanaryStatus == nil { return false } return clone.Status.CanaryStatus.CurrentStepIndex == stepIndex && clone.Status.CanaryStatus.CurrentStepState == rolloutsv1alpha1.CanaryStepStatePaused - }, 5*time.Minute, time.Second).Should(BeTrue()) + }, 10*time.Minute, time.Second).Should(BeTrue()) } WaitRolloutStatusPhase := func(name string, phase rolloutsv1alpha1.RolloutPhase) { @@ -157,7 +184,15 @@ var _ = SIGDescribe("Rollout", func() { clone := &rolloutsv1alpha1.Rollout{} Expect(GetObject(name, clone)).NotTo(HaveOccurred()) return clone.Status.Phase == phase - }, 5*time.Minute, time.Second).Should(BeTrue()) + }, 10*time.Minute, time.Second).Should(BeTrue()) + } + + WaitRolloutWorkloadGenration := func(name string, generation int64) { + Eventually(func() bool { + clone := &rolloutsv1alpha1.Rollout{} + Expect(GetObject(name, clone)).NotTo(HaveOccurred()) + return clone.Status.CanaryStatus.ObservedWorkloadGeneration == generation + }, time.Minute, time.Second).Should(BeTrue()) } WaitRolloutNotFound := func(name string) { @@ -296,6 +331,7 @@ var _ = SIGDescribe("Rollout", func() { // resume rollout canary ResumeRolloutCanary(rollout.Name) + By("resume rollout, and wait next step(2)") WaitRolloutCanaryStepPaused(rollout.Name, 2) // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) @@ -306,6 +342,7 @@ var _ = SIGDescribe("Rollout", func() { // resume rollout canary ResumeRolloutCanary(rollout.Name) + By("resume rollout, and wait next step(3)") WaitRolloutCanaryStepPaused(rollout.Name, 3) // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) @@ -316,6 +353,7 @@ var _ = SIGDescribe("Rollout", func() { // resume rollout canary ResumeRolloutCanary(rollout.Name) + By("resume rollout, and wait next step(4)") WaitRolloutCanaryStepPaused(rollout.Name, 4) // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) @@ -326,6 +364,7 @@ var _ = SIGDescribe("Rollout", func() { // resume rollout canary ResumeRolloutCanary(rollout.Name) + By("resume rollout, and wait next step(5)") WaitRolloutCanaryStepPaused(rollout.Name, 5) // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) @@ -345,7 +384,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService := &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -365,10 +404,11 @@ var _ = SIGDescribe("Rollout", func() { Expect(cond.Reason).Should(Equal(rolloutsv1alpha1.ProgressingReasonSucceeded)) Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage 20%,60% Succeeded", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -400,12 +440,16 @@ var _ = SIGDescribe("Rollout", func() { Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred()) CreateObject(workload) WaitDeploymentAllPodsReady(workload) + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) + rss, err := finder.GetReplicaSetsForDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(rss)).Should(BeNumerically("==", 1)) + stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).ShouldNot(Equal("")) - stableRevision := rollout.Status.StableRevision + Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) By("check rollout status & paused success") // v1 -> v2, start rollout action @@ -425,32 +469,15 @@ var _ = SIGDescribe("Rollout", func() { // wait step 1 complete WaitRolloutCanaryStepPaused(rollout.Name, 1) - // check rollout status - Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) - Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) - Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) - Expect(rollout.Status.CanaryRevision).ShouldNot(Equal("")) - canaryRevision := rollout.Status.CanaryRevision - Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) - Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2)) - Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2)) // check stable, canary service & ingress - // stable service - Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(stableRevision)) - //canary service - cService := &v1.Service{} - Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cService)).NotTo(HaveOccurred()) - Expect(cService.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(canaryRevision)) - // canary ingress - cIngress := &netv1.Ingress{} - Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cIngress)).NotTo(HaveOccurred()) - Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true")) - Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", rollout.Spec.Strategy.Canary.Steps[0].Weight))) // canary deployment cWorkload, err := GetCanaryDeployment(workload) Expect(err).NotTo(HaveOccurred()) + crss, err := finder.GetReplicaSetsForDeployment(cWorkload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(crss)).Should(BeNumerically("==", 1)) + canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 2)) Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 2)) for _, env := range cWorkload.Spec.Template.Spec.Containers[0].Env { @@ -458,10 +485,32 @@ var _ = SIGDescribe("Rollout", func() { Expect(env.Value).Should(Equal("version2")) } } + // stable service + Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) + Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision)) + //canary service + cService := &v1.Service{} + Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cService)).NotTo(HaveOccurred()) + Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision)) + // canary ingress + cIngress := &netv1.Ingress{} + Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cIngress)).NotTo(HaveOccurred()) + Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true")) + Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", rollout.Spec.Strategy.Canary.Steps[0].Weight))) + + // check rollout status + Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) + Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) + Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) + Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) + Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2)) + Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2)) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision)) // resume rollout canary ResumeRolloutCanary(rollout.Name) - By("check rollout canary status success, resume rollout, and wait rollout canary complete") + By("resume rollout, and wait next step(2)") WaitRolloutCanaryStepPaused(rollout.Name, 2) // check stable, canary service & ingress @@ -492,7 +541,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService = &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -506,6 +555,11 @@ var _ = SIGDescribe("Rollout", func() { Expect(env.Value).Should(Equal("version2")) } } + rss, err = finder.GetReplicaSetsForDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(rss)).Should(BeNumerically("==", 1)) + Expect(rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision)) + // check progressing succeed Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) cond := util.GetRolloutCondition(rollout.Status, rolloutsv1alpha1.RolloutConditionProgressing) @@ -513,7 +567,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(rollout.Status.StableRevision).Should(Equal(canaryRevision)) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) // scale up replicas 5 -> 6 workload.Spec.Replicas = utilpointer.Int32(6) @@ -523,10 +577,11 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage 20%, and rollback(v1)", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -546,18 +601,22 @@ var _ = SIGDescribe("Rollout", func() { Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred()) CreateObject(workload) WaitDeploymentAllPodsReady(workload) - apps, err := GetPodsOfDeployment(workload) + pods, err := GetPodsOfDeployment(workload) Expect(err).NotTo(HaveOccurred()) appNames := make(map[string]struct{}) - for _, app := range apps { + for _, app := range pods { appNames[app.Name] = struct{}{} } + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) + rss, err := finder.GetReplicaSetsForDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(rss)).Should(BeNumerically("==", 1)) + stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).ShouldNot(Equal("")) - stableRevision := rollout.Status.StableRevision + Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) By("check rollout status & paused success") // v1 -> v2, start rollout action @@ -582,10 +641,10 @@ var _ = SIGDescribe("Rollout", func() { workload.Spec.Template.Spec.Containers[0].Env = newEnvs UpdateDeployment(workload) By("Rollback deployment env NODE_NAME from(version2) -> to(version1)") - time.Sleep(time.Second * 2) WaitRolloutStatusPhase(rollout.Name, rolloutsv1alpha1.RolloutPhaseHealthy) klog.Infof("rollout(%s) completed, and check", namespace) + time.Sleep(time.Second * 10) // check service & ingress & deployment // ingress @@ -594,7 +653,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService := &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -609,23 +668,25 @@ var _ = SIGDescribe("Rollout", func() { } } // deployment pods not changed - capps, err := GetPodsOfDeployment(workload) + cpods, err := GetPodsOfDeployment(workload) Expect(err).NotTo(HaveOccurred()) cappNames := make(map[string]struct{}) - for _, app := range capps { - cappNames[app.Name] = struct{}{} + for _, pod := range cpods { + cappNames[pod.Name] = struct{}{} } Expect(cappNames).Should(Equal(appNames)) // check progressing canceled + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) cond := util.GetRolloutCondition(rollout.Status, rolloutsv1alpha1.RolloutConditionProgressing) Expect(cond.Reason).Should(Equal(rolloutsv1alpha1.ProgressingReasonCanceled)) Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) Expect(string(cond.Status)).Should(Equal("False")) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage 20%,40% and continuous release v3", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -645,12 +706,16 @@ var _ = SIGDescribe("Rollout", func() { Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred()) CreateObject(workload) WaitDeploymentAllPodsReady(workload) + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) + rss, err := finder.GetReplicaSetsForDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(rss)).Should(BeNumerically("==", 1)) + stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).ShouldNot(Equal("")) - stableRevision := rollout.Status.StableRevision + Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) By("check rollout status & paused success") // v1 -> v2, start rollout action @@ -669,12 +734,19 @@ var _ = SIGDescribe("Rollout", func() { By("check deployment status & paused success") // wait step 1 complete WaitRolloutCanaryStepPaused(rollout.Name, 1) + + // canary deployment + cWorkload, err := GetCanaryDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + crss, err := finder.GetReplicaSetsForDeployment(cWorkload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(crss)).Should(BeNumerically("==", 1)) + canaryRevisionV1 := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) - Expect(rollout.Status.CanaryRevision).ShouldNot(Equal("")) - canaryRevisionV1 := rollout.Status.CanaryRevision + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevisionV1)) Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) // resume rollout canary @@ -688,34 +760,38 @@ var _ = SIGDescribe("Rollout", func() { UpdateDeployment(workload) By("Update deployment env NODE_NAME from(version2) -> to(version3)") time.Sleep(time.Second * 2) - // wait step 0 complete WaitRolloutCanaryStepPaused(rollout.Name, 1) + + cWorkload, err = GetCanaryDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + crss, err = finder.GetReplicaSetsForDeployment(cWorkload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(crss)).Should(BeNumerically("==", 1)) + canaryRevisionV2 := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) - Expect(rollout.Status.CanaryRevision).ShouldNot(Equal("")) - Expect(rollout.Status.CanaryRevision).ShouldNot(Equal(canaryRevisionV1)) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevisionV2)) Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1)) Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 1)) - canaryRevisionV2 := rollout.Status.CanaryRevision Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) // check stable, canary service & ingress // stable service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(stableRevision)) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision)) //canary service cService := &v1.Service{} Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cService)).NotTo(HaveOccurred()) - Expect(cService.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(canaryRevisionV2)) + Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevisionV2)) // canary ingress cIngress := &netv1.Ingress{} Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cIngress)).NotTo(HaveOccurred()) Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true")) Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", rollout.Spec.Strategy.Canary.Steps[0].Weight))) // canary deployment - cWorkload, err := GetCanaryDeployment(workload) + cWorkload, err = GetCanaryDeployment(workload) Expect(err).NotTo(HaveOccurred()) Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 1)) Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 1)) @@ -738,7 +814,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService = &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -759,10 +835,11 @@ var _ = SIGDescribe("Rollout", func() { Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(rollout.Status.StableRevision).Should(Equal(canaryRevisionV2)) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage 20%,40% and scale up replicas from(5) -> to(10)", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -820,21 +897,29 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(workload.Spec.Paused).Should(BeTrue()) By("check deployment status & paused success") - // wait step 2 complete WaitRolloutCanaryStepPaused(rollout.Name, 2) + + // canary deployment + cWorkload, err := GetCanaryDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + crss, err := finder.GetReplicaSetsForDeployment(cWorkload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(crss)).Should(BeNumerically("==", 1)) + canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 2)) - canaryRevision := rollout.Status.CanaryStatus.CanaryRevision + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision)) // scale up replicas, 5 -> 10 workload.Spec.Replicas = utilpointer.Int32(10) UpdateDeployment(workload) time.Sleep(time.Second * 3) - cWorkload, _ := GetCanaryDeployment(workload) + cWorkload, _ = GetCanaryDeployment(workload) WaitDeploymentAllPodsReady(cWorkload) + time.Sleep(time.Second * 5) // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) @@ -843,7 +928,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 4)) Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 4)) Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(rolloutsv1alpha1.CanaryStepStatePaused)) - Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(canaryRevision)) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision)) // resume rollout canary ResumeRolloutCanary(rollout.Name) @@ -858,7 +943,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService := &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -879,10 +964,11 @@ var _ = SIGDescribe("Rollout", func() { Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(rollout.Status.StableRevision).Should(Equal(canaryRevision)) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage 20%,40%, and scale down replicas from(10) -> to(5)", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -939,14 +1025,20 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(workload.Spec.Paused).Should(BeTrue()) By("check deployment status & paused success") - // wait step 3 complete WaitRolloutCanaryStepPaused(rollout.Name, 3) + + // canary deployment + cWorkload, err := GetCanaryDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + crss, err := finder.GetReplicaSetsForDeployment(cWorkload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(crss)).Should(BeNumerically("==", 1)) + canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 3)) - canaryRevision := rollout.Status.CanaryStatus.CanaryRevision // scale up replicas, 10 -> 5 workload.Spec.Replicas = utilpointer.Int32(5) @@ -961,7 +1053,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 6)) Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 6)) Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(rolloutsv1alpha1.CanaryStepStatePaused)) - Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(canaryRevision)) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision)) // resume rollout canary ResumeRolloutCanary(rollout.Name) @@ -976,7 +1068,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService := &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -997,10 +1089,11 @@ var _ = SIGDescribe("Rollout", func() { Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(rollout.Status.StableRevision).Should(Equal(canaryRevision)) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage 20%,40%, paused and resume", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -1049,11 +1142,16 @@ var _ = SIGDescribe("Rollout", func() { Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred()) CreateObject(workload) WaitDeploymentAllPodsReady(workload) + // deployment + rss, err := finder.GetReplicaSetsForDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(rss)).Should(BeNumerically("==", 1)) + stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).ShouldNot(Equal("")) + Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) By("check rollout status & paused success") // v1 -> v2, start rollout action @@ -1098,7 +1196,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService := &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -1118,10 +1216,11 @@ var _ = SIGDescribe("Rollout", func() { Expect(cond.Reason).Should(Equal(rolloutsv1alpha1.ProgressingReasonSucceeded)) Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage 20%,40%, but delete rollout crd", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -1160,11 +1259,16 @@ var _ = SIGDescribe("Rollout", func() { Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred()) CreateObject(workload) WaitDeploymentAllPodsReady(workload) + // deployment + rss, err := finder.GetReplicaSetsForDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(rss)).Should(BeNumerically("==", 1)) + stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).ShouldNot(Equal("")) + Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) By("check rollout status & paused success") // v1 -> v2, start rollout action @@ -1190,7 +1294,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService := &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -1207,6 +1311,7 @@ var _ = SIGDescribe("Rollout", func() { }) It("V1->V2: Percentage 20% v2 failed image, and v3 succeed image", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -1245,11 +1350,16 @@ var _ = SIGDescribe("Rollout", func() { Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred()) CreateObject(workload) WaitDeploymentAllPodsReady(workload) + // deployment + rss, err := finder.GetReplicaSetsForDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(rss)).Should(BeNumerically("==", 1)) + stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).ShouldNot(Equal("")) + Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) By("check rollout status & paused success") // v1 -> v2, start rollout action @@ -1290,7 +1400,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService := &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -1310,10 +1420,11 @@ var _ = SIGDescribe("Rollout", func() { Expect(cond.Reason).Should(Equal(rolloutsv1alpha1.ProgressingReasonSucceeded)) Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage, 20%,40%,60%,80%,100%, steps changed v1", func() { + finder := util.NewControllerFinder(k8sClient) By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -1333,9 +1444,10 @@ var _ = SIGDescribe("Rollout", func() { workload.Spec.Replicas = utilpointer.Int32(10) CreateObject(workload) WaitDeploymentAllPodsReady(workload) - // check rollout status - Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) - stableRevision := rollout.Status.StableRevision + rss, err := finder.GetReplicaSetsForDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(rss)).Should(BeNumerically("==", 1)) + stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // v1 -> v2, start rollout action newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"}) @@ -1364,31 +1476,40 @@ var _ = SIGDescribe("Rollout", func() { }, } rollout = UpdateRollout(rollout) - time.Sleep(time.Second * 3) + By("update rollout configuration, and wait rollout next step(2)") // wait step 1 complete WaitRolloutCanaryStepPaused(rollout.Name, 2) + batch := &rolloutsv1alpha1.BatchRelease{} + Expect(GetObject(rollout.Name, batch)).NotTo(HaveOccurred()) + + // canary deployment + cWorkload, err := GetCanaryDeployment(workload) + Expect(err).NotTo(HaveOccurred()) + crss, err := finder.GetReplicaSetsForDeployment(cWorkload) + Expect(err).NotTo(HaveOccurred()) + Expect(len(crss)).Should(BeNumerically("==", 1)) + canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey] // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) - Expect(rollout.Status.CanaryRevision).ShouldNot(Equal("")) - canaryRevision := rollout.Status.CanaryRevision + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision)) Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 2)) // check stable, canary service & ingress // stable service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(stableRevision)) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision)) //canary service cService := &v1.Service{} Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cService)).NotTo(HaveOccurred()) - Expect(cService.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(canaryRevision)) + Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision)) // canary ingress cIngress := &netv1.Ingress{} Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cIngress)).NotTo(HaveOccurred()) Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true")) Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", rollout.Spec.Strategy.Canary.Steps[1].Weight))) // canary deployment - cWorkload, err := GetCanaryDeployment(workload) + cWorkload, err = GetCanaryDeployment(workload) Expect(err).NotTo(HaveOccurred()) Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 3)) Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 3)) @@ -1406,7 +1527,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService = &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // deployment @@ -1426,13 +1547,12 @@ var _ = SIGDescribe("Rollout", func() { Expect(cond.Reason).Should(Equal(rolloutsv1alpha1.ProgressingReasonSucceeded)) Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) }) KruiseDescribe("CloneSet rollout canary nginx", func() { - - It("V1->V2: Percentage, 20%,40%,60%,80%,100% Succeeded", func() { + It("V1->V2: Percentage, 20%,60% Succeeded", func() { By("Creating Rollout...") rollout := &rolloutsv1alpha1.Rollout{} Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) @@ -1472,7 +1592,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).Should(Equal(workload.Status.CurrentRevision)) + Expect(rollout.Status.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:])) stableRevision := rollout.Status.StableRevision By("check rollout status & paused success") @@ -1488,7 +1608,6 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1)) Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 1)) - Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 4)) Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse()) By("check cloneSet status & paused success") @@ -1496,18 +1615,19 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) - Expect(rollout.Status.CanaryRevision).Should(Equal(workload.Status.UpdateRevision)) - canaryRevision := rollout.Status.CanaryRevision + Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation])) // check stable, canary service & ingress // stable service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(stableRevision)) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision)) //canary service cService := &v1.Service{} Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cService)).NotTo(HaveOccurred()) - Expect(cService.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(canaryRevision)) + Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision)) // canary ingress cIngress := &netv1.Ingress{} Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cIngress)).NotTo(HaveOccurred()) @@ -1516,7 +1636,7 @@ var _ = SIGDescribe("Rollout", func() { // resume rollout canary ResumeRolloutCanary(rollout.Name) - By("check rollout canary status success, resume rollout, and wait rollout canary complete") + By("resume rollout, and wait next step(2)") WaitRolloutCanaryStepPaused(rollout.Name, 2) // check stable, canary service & ingress @@ -1528,7 +1648,6 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3)) Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 3)) - Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 2)) Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse()) // resume rollout @@ -1544,7 +1663,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService = &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // cloneset @@ -1568,7 +1687,7 @@ var _ = SIGDescribe("Rollout", func() { cond := util.GetRolloutCondition(rollout.Status, rolloutsv1alpha1.RolloutConditionProgressing) Expect(cond.Reason).Should(Equal(rolloutsv1alpha1.ProgressingReasonSucceeded)) Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) Expect(rollout.Status.StableRevision).Should(Equal(canaryRevision)) // scale up replicas 5 -> 6 @@ -1579,7 +1698,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) }) It("V1->V2: Percentage, 20%, and rollback(v1)", func() { @@ -1608,11 +1727,12 @@ var _ = SIGDescribe("Rollout", func() { CreateObject(workload) WaitCloneSetAllPodsReady(workload) + // check rollout status // check rollout status Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).Should(Equal(workload.Status.CurrentRevision)) + Expect(rollout.Status.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:])) stableRevision := rollout.Status.StableRevision By("check rollout status & paused success") @@ -1622,13 +1742,13 @@ var _ = SIGDescribe("Rollout", func() { workload.Spec.Template.Spec.Containers[0].Env = newEnvs UpdateCloneSet(workload) By("Update cloneSet env NODE_NAME from(version1) -> to(version2)") - time.Sleep(time.Second * 10) + // wait step 1 complete + time.Sleep(time.Second * 20) // check workload status & paused Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1)) Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 0)) - Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 4)) Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse()) By("check cloneSet status & paused success") @@ -1636,11 +1756,16 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) - Expect(rollout.Status.CanaryRevision).Should(Equal(workload.Status.UpdateRevision)) + Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(rolloutsv1alpha1.CanaryStepStateUpgrade)) Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation])) + // resume rollout canary + ResumeRolloutCanary(rollout.Name) + time.Sleep(time.Second * 15) + // rollback -> v1 newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version1"}) workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:latest" @@ -1666,7 +1791,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService := &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // cloneset @@ -1714,7 +1839,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) - Expect(rollout.Status.StableRevision).Should(Equal(workload.Status.CurrentRevision)) + Expect(rollout.Status.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:])) stableRevision := rollout.Status.StableRevision By("check rollout status & paused success") @@ -1730,7 +1855,6 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1)) Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 1)) - Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 4)) Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse()) By("check cloneSet status & paused success") @@ -1739,14 +1863,14 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) - Expect(rollout.Status.CanaryRevision).Should(Equal(workload.Status.UpdateRevision)) - canaryRevisionV1 := rollout.Status.CanaryRevision + Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + canaryRevisionV1 := rollout.Status.CanaryStatus.PodTemplateHash Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation])) // resume rollout canary ResumeRolloutCanary(rollout.Name) - By("check rollout canary status success, resume rollout, and wait rollout canary complete") time.Sleep(time.Second * 15) // v1 -> v2 -> v3, continuous release @@ -1765,18 +1889,19 @@ var _ = SIGDescribe("Rollout", func() { Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1)) Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 1)) Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) - Expect(rollout.Status.CanaryRevision).ShouldNot(Equal(canaryRevisionV1)) - Expect(rollout.Status.CanaryRevision).Should(Equal(workload.Status.UpdateRevision)) - canaryRevisionV2 := rollout.Status.CanaryRevision + Expect(rollout.Status.CanaryStatus.CanaryRevision).ShouldNot(Equal(canaryRevisionV1)) + Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + canaryRevisionV2 := rollout.Status.CanaryStatus.PodTemplateHash Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) // check stable, canary service & ingress // stable service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(stableRevision)) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision)) //canary service cService := &v1.Service{} Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cService)).NotTo(HaveOccurred()) - Expect(cService.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal(canaryRevisionV2)) + Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevisionV2)) // canary ingress cIngress := &netv1.Ingress{} Expect(GetObject(rollout.Status.CanaryStatus.CanaryService, cIngress)).NotTo(HaveOccurred()) @@ -1787,6 +1912,7 @@ var _ = SIGDescribe("Rollout", func() { ResumeRolloutCanary(rollout.Name) By("check rollout canary status success, resume rollout, and wait rollout canary complete") WaitRolloutStatusPhase(rollout.Name, rolloutsv1alpha1.RolloutPhaseHealthy) + WaitCloneSetAllPodsReady(workload) By("rollout completed, and check") // check service & ingress & deployment @@ -1796,7 +1922,7 @@ var _ = SIGDescribe("Rollout", func() { Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred()) // service Expect(GetObject(service.Name, service)).NotTo(HaveOccurred()) - Expect(service.Spec.Selector[util.RsPodRevisionLabelKey]).Should(Equal("")) + Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal("")) cService = &v1.Service{} Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred()) // cloneset @@ -1820,9 +1946,111 @@ var _ = SIGDescribe("Rollout", func() { cond := util.GetRolloutCondition(rollout.Status, rolloutsv1alpha1.RolloutConditionProgressing) Expect(cond.Reason).Should(Equal(rolloutsv1alpha1.ProgressingReasonSucceeded)) Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) - Expect(rollout.Status.CanaryStatus.ObservedWorkloadGeneration).Should(BeNumerically("==", workload.Generation)) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) Expect(rollout.Status.StableRevision).Should(Equal(canaryRevisionV2)) }) + + It("V1->V2: Percentage, 20%,40%,60%,80%,100%, no traffic, Succeeded", func() { + By("Creating Rollout...") + rollout := &rolloutsv1alpha1.Rollout{} + Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred()) + rollout.Spec.ObjectRef.WorkloadRef = &rolloutsv1alpha1.WorkloadRef{ + APIVersion: "apps.kruise.io/v1alpha1", + Kind: "CloneSet", + Name: "echoserver", + } + rollout.Spec.Strategy.Canary.TrafficRoutings = nil + CreateObject(rollout) + + By("Creating workload and waiting for all pods ready...") + // service + service := &v1.Service{} + Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred()) + CreateObject(service) + // ingress + ingress := &netv1.Ingress{} + Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred()) + CreateObject(ingress) + // workload + workload := &appsv1alpha1.CloneSet{} + Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred()) + workload.Spec.UpdateStrategy.Type = appsv1alpha1.InPlaceOnlyCloneSetUpdateStrategyType + workload.Spec.UpdateStrategy.MaxUnavailable = &intstr.IntOrString{ + Type: intstr.Int, + IntVal: 1, + } + workload.Spec.UpdateStrategy.MaxSurge = nil + CreateObject(workload) + WaitCloneSetAllPodsReady(workload) + + // check rollout status + Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) + Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseHealthy)) + Expect(rollout.Status.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:])) + stableRevision := rollout.Status.StableRevision + By("check rollout status & paused success") + + // v1 -> v2, start rollout action + //newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"}) + workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:1.10.2" + UpdateCloneSet(workload) + By("Update cloneSet env NODE_NAME from(version1) -> to(version2)") + // wait step 1 complete + WaitRolloutCanaryStepPaused(rollout.Name, 1) + + // check workload status & paused + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) + Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1)) + Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 1)) + Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse()) + By("check cloneSet status & paused success") + + // check rollout status + Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) + Expect(rollout.Status.Phase).Should(Equal(rolloutsv1alpha1.RolloutPhaseProgressing)) + Expect(rollout.Status.StableRevision).Should(Equal(stableRevision)) + Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:])) + canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash + Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1)) + Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation])) + + // resume rollout + ResumeRolloutCanary(rollout.Name) + WaitRolloutStatusPhase(rollout.Name, rolloutsv1alpha1.RolloutPhaseHealthy) + WaitCloneSetAllPodsReady(workload) + By("rollout completed, and check") + + // cloneset + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) + Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5)) + Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 5)) + Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 0)) + Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse()) + Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevision)) + Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevision)) + time.Sleep(time.Second * 3) + + // check progressing succeed + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) + Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) + cond := util.GetRolloutCondition(rollout.Status, rolloutsv1alpha1.RolloutConditionProgressing) + Expect(cond.Reason).Should(Equal(rolloutsv1alpha1.ProgressingReasonSucceeded)) + Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue))) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) + Expect(rollout.Status.StableRevision).Should(Equal(canaryRevision)) + + // scale up replicas 5 -> 6 + workload.Spec.Replicas = utilpointer.Int32(6) + UpdateCloneSet(workload) + By("Update cloneSet replicas from(5) -> to(6)") + time.Sleep(time.Second * 2) + + Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred()) + Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred()) + WaitRolloutWorkloadGenration(rollout.Name, workload.Generation) + }) }) }) diff --git a/test/e2e/test_data/batchrelease/cloneset.yaml b/test/e2e/test_data/batchrelease/cloneset.yaml index da657a2c..1d187df0 100644 --- a/test/e2e/test_data/batchrelease/cloneset.yaml +++ b/test/e2e/test_data/batchrelease/cloneset.yaml @@ -6,6 +6,9 @@ metadata: name: sample spec: replicas: 5 + updateStrategy: + maxUnavailable: 0 + maxSurge: 1 selector: matchLabels: app: busybox diff --git a/test/e2e/test_data/batchrelease/deployment.yaml b/test/e2e/test_data/batchrelease/deployment.yaml index edf9a8db..fbd137aa 100644 --- a/test/e2e/test_data/batchrelease/deployment.yaml +++ b/test/e2e/test_data/batchrelease/deployment.yaml @@ -6,6 +6,11 @@ metadata: app: busybox spec: replicas: 5 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 0 + maxSurge: 1 selector: matchLabels: app: busybox diff --git a/test/e2e/test_data/rollout/cloneset.yaml b/test/e2e/test_data/rollout/cloneset.yaml index 032d4e20..fa48094a 100644 --- a/test/e2e/test_data/rollout/cloneset.yaml +++ b/test/e2e/test_data/rollout/cloneset.yaml @@ -20,10 +20,12 @@ spec: containers: - name: echoserver image: cilium/echoserver:latest - imagePullPolicy: IfNotPresent + # imagePullPolicy: IfNotPresent ports: - containerPort: 8080 env: + - name: PORT + value: '8080' - name: POD_NAME valueFrom: fieldRef: diff --git a/test/e2e/test_data/rollout/deployment.yaml b/test/e2e/test_data/rollout/deployment.yaml index bfdc2396..68e1fea0 100644 --- a/test/e2e/test_data/rollout/deployment.yaml +++ b/test/e2e/test_data/rollout/deployment.yaml @@ -5,7 +5,12 @@ metadata: labels: app: echoserver spec: - replicas: 1 + replicas: 5 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 0 + maxSurge: 1 selector: matchLabels: app: echoserver @@ -17,43 +22,24 @@ spec: containers: - name: echoserver image: cilium/echoserver:latest + # imagePullPolicy: IfNotPresent ports: - containerPort: 8080 env: - name: PORT value: '8080' ---- -apiVersion: v1 -kind: Service -metadata: - name: echoserver - labels: - app: echoserver -spec: - ports: - - port: 80 - targetPort: 8080 - protocol: TCP - name: http - selector: - app: echoserver ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: echoserver - annotations: - kubernetes.io/ingress.class: nginx -spec: - rules: - - host: echoserver.example.com - http: - paths: - - backend: - service: - name: echoserver - port: - number: 80 - path: /apis/echo - pathType: Exact + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: NODE_NAME + value: version1 diff --git a/test/e2e/test_data/rollout/rollout_canary_base.yaml b/test/e2e/test_data/rollout/rollout_canary_base.yaml index dd46464d..f230dfeb 100644 --- a/test/e2e/test_data/rollout/rollout_canary_base.yaml +++ b/test/e2e/test_data/rollout/rollout_canary_base.yaml @@ -22,7 +22,7 @@ spec: - weight: 80 pause: {duration: 10} - weight: 100 - trafficRouting: + trafficRoutings: - service: echoserver type: nginx ingress: diff --git a/test/kind-conf.yaml b/test/kind-conf.yaml new file mode 100644 index 00000000..bb854bff --- /dev/null +++ b/test/kind-conf.yaml @@ -0,0 +1,8 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: + - role: control-plane + - role: worker + - role: worker +featureGates: + EphemeralContainers: true