diff --git a/.github/workflows/e2e-advanced-deployment-1.19.yaml b/.github/workflows/e2e-advanced-deployment-1.19.yaml index 1b04da6e..dc623af5 100644 --- a/.github/workflows/e2e-advanced-deployment-1.19.yaml +++ b/.github/workflows/e2e-advanced-deployment-1.19.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-advanced-deployment-1.23.yaml b/.github/workflows/e2e-advanced-deployment-1.23.yaml index 10edb25e..41a5c6ea 100644 --- a/.github/workflows/e2e-advanced-deployment-1.23.yaml +++ b/.github/workflows/e2e-advanced-deployment-1.23.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-cloneset-1.19.yaml b/.github/workflows/e2e-cloneset-1.19.yaml index 04e0a8eb..a32e9ceb 100644 --- a/.github/workflows/e2e-cloneset-1.19.yaml +++ b/.github/workflows/e2e-cloneset-1.19.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-cloneset-1.23.yaml b/.github/workflows/e2e-cloneset-1.23.yaml index 2bc0b0c2..712ed6ed 100644 --- a/.github/workflows/e2e-cloneset-1.23.yaml +++ b/.github/workflows/e2e-cloneset-1.23.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-daemonset-1.19.yaml b/.github/workflows/e2e-daemonset-1.19.yaml index 15c868d3..573b0335 100644 --- a/.github/workflows/e2e-daemonset-1.19.yaml +++ b/.github/workflows/e2e-daemonset-1.19.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-daemonset-1.23.yaml b/.github/workflows/e2e-daemonset-1.23.yaml index 75ee88f2..fdddac80 100644 --- a/.github/workflows/e2e-daemonset-1.23.yaml +++ b/.github/workflows/e2e-daemonset-1.23.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-deployment-1.19.yaml b/.github/workflows/e2e-deployment-1.19.yaml index c67f45bd..1ae0f6d8 100644 --- a/.github/workflows/e2e-deployment-1.19.yaml +++ b/.github/workflows/e2e-deployment-1.19.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-deployment-1.23.yaml b/.github/workflows/e2e-deployment-1.23.yaml index 59ffe444..f929ca6d 100644 --- a/.github/workflows/e2e-deployment-1.23.yaml +++ b/.github/workflows/e2e-deployment-1.23.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-others-1.19.yaml b/.github/workflows/e2e-others-1.19.yaml index 8caa8c9f..c4b221d8 100644 --- a/.github/workflows/e2e-others-1.19.yaml +++ b/.github/workflows/e2e-others-1.19.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-others-1.23.yaml b/.github/workflows/e2e-others-1.23.yaml index 6fbfdab5..8757ffc8 100644 --- a/.github/workflows/e2e-others-1.23.yaml +++ b/.github/workflows/e2e-others-1.23.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-statefulset-1.19.yaml b/.github/workflows/e2e-statefulset-1.19.yaml index 571c82e0..8f6865e7 100644 --- a/.github/workflows/e2e-statefulset-1.19.yaml +++ b/.github/workflows/e2e-statefulset-1.19.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-statefulset-1.23.yaml b/.github/workflows/e2e-statefulset-1.23.yaml index 7045b962..401f073b 100644 --- a/.github/workflows/e2e-statefulset-1.23.yaml +++ b/.github/workflows/e2e-statefulset-1.23.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-v1beta1-bluegreen-1.19.yaml b/.github/workflows/e2e-v1beta1-bluegreen-1.19.yaml index 36e7e5fd..e38bb7d8 100644 --- a/.github/workflows/e2e-v1beta1-bluegreen-1.19.yaml +++ b/.github/workflows/e2e-v1beta1-bluegreen-1.19.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-v1beta1-bluegreen-1.23.yaml b/.github/workflows/e2e-v1beta1-bluegreen-1.23.yaml index 07035edb..4aa68abc 100644 --- a/.github/workflows/e2e-v1beta1-bluegreen-1.23.yaml +++ b/.github/workflows/e2e-v1beta1-bluegreen-1.23.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-v1beta1-jump-1.19.yaml b/.github/workflows/e2e-v1beta1-jump-1.19.yaml index 9b0d9c7e..b7afc005 100644 --- a/.github/workflows/e2e-v1beta1-jump-1.19.yaml +++ b/.github/workflows/e2e-v1beta1-jump-1.19.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/.github/workflows/e2e-v1beta1-jump-1.23.yaml b/.github/workflows/e2e-v1beta1-jump-1.23.yaml index fd56bf70..c553d2a7 100644 --- a/.github/workflows/e2e-v1beta1-jump-1.23.yaml +++ b/.github/workflows/e2e-v1beta1-jump-1.23.yaml @@ -44,7 +44,7 @@ jobs: make helm helm repo add openkruise https://openkruise.github.io/charts/ helm repo update - helm install kruise openkruise/kruise + helm install kruise openkruise/kruise --version 1.7.0 for ((i=1;i<10;i++)); do set +e diff --git a/api/v1alpha1/conversion.go b/api/v1alpha1/conversion.go index 442218ff..e37da38f 100644 --- a/api/v1alpha1/conversion.go +++ b/api/v1alpha1/conversion.go @@ -154,7 +154,7 @@ func ConversionToV1beta1TrafficRoutingRef(src TrafficRoutingRef) (dst v1beta1.Tr func ConversionToV1beta1TrafficRoutingStrategy(src TrafficRoutingStrategy) (dst v1beta1.TrafficRoutingStrategy) { if src.Weight != nil { - dst.Traffic = utilpointer.StringPtr(fmt.Sprintf("%d", *src.Weight) + "%") + dst.Traffic = utilpointer.String(fmt.Sprintf("%d", *src.Weight) + "%") } dst.RequestHeaderModifier = src.RequestHeaderModifier for _, match := range src.Matches { diff --git a/api/v1beta1/rollout_types.go b/api/v1beta1/rollout_types.go index 47051987..8c69b425 100644 --- a/api/v1beta1/rollout_types.go +++ b/api/v1beta1/rollout_types.go @@ -462,9 +462,9 @@ func (r *RolloutStatus) GetSubStatus() *CommonStatus { return nil } if r.CanaryStatus != nil { - return &(r.CanaryStatus.CommonStatus) + return &r.CanaryStatus.CommonStatus } - return &(r.BlueGreenStatus.CommonStatus) + return &r.BlueGreenStatus.CommonStatus } func (r *RolloutStatus) IsSubStatusEmpty() bool { diff --git a/pkg/controller/batchrelease/batchrelease_controller_test.go b/pkg/controller/batchrelease/batchrelease_controller_test.go index 8f79493e..20fda127 100644 --- a/pkg/controller/batchrelease/batchrelease_controller_test.go +++ b/pkg/controller/batchrelease/batchrelease_controller_test.go @@ -100,7 +100,7 @@ var ( }, }, Spec: apps.DeploymentSpec{ - Replicas: pointer.Int32Ptr(100), + Replicas: pointer.Int32(100), Strategy: apps.DeploymentStrategy{ Type: apps.RollingUpdateDeploymentStrategyType, RollingUpdate: &apps.RollingUpdateDeployment{ @@ -146,7 +146,7 @@ var ( Name: "sample", }, ReleasePlan: v1beta1.ReleasePlan{ - BatchPartition: pointer.Int32Ptr(0), + BatchPartition: pointer.Int32(0), RollingStyle: v1beta1.PartitionRollingStyle, Batches: []v1beta1.ReleaseBatch{ { @@ -178,7 +178,7 @@ var ( }, }, Spec: kruiseappsv1alpha1.CloneSetSpec{ - Replicas: pointer.Int32Ptr(100), + Replicas: pointer.Int32(100), UpdateStrategy: kruiseappsv1alpha1.CloneSetUpdateStrategy{ Partition: &intstr.IntOrString{Type: intstr.Int, IntVal: int32(1)}, MaxSurge: &intstr.IntOrString{Type: intstr.Int, IntVal: int32(2)}, @@ -394,7 +394,7 @@ func TestReconcile_CloneSet(t *testing.T) { }, GetCloneSet: func() []client.Object { stable := getStableWithReady(stableClone, "v2").(*kruiseappsv1alpha1.CloneSet) - stable.Spec.Replicas = pointer.Int32Ptr(200) + stable.Spec.Replicas = pointer.Int32(200) canary := getCanaryWithStage(stable, "v2", 0, true) return []client.Object{ canary, @@ -475,7 +475,7 @@ func TestReconcile_CloneSet(t *testing.T) { release.Status.UpdateRevision = util.ComputeHash(canaryTemplate, nil) release.Status.CanaryStatus.UpdatedReplicas = 10 release.Status.CanaryStatus.UpdatedReadyReplicas = 10 - release.Spec.ReleasePlan.BatchPartition = pointer.Int32Ptr(1) + release.Spec.ReleasePlan.BatchPartition = pointer.Int32(1) release.Status.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan) return release }, @@ -651,7 +651,7 @@ func TestReconcile_Deployment(t *testing.T) { release := releaseDeploy.DeepCopy() release.Status.CanaryStatus.UpdatedReplicas = 10 release.Status.CanaryStatus.UpdatedReadyReplicas = 10 - release.Spec.ReleasePlan.BatchPartition = pointer.Int32Ptr(1) + release.Spec.ReleasePlan.BatchPartition = pointer.Int32(1) return setState(release, v1beta1.ReadyBatchState) }, GetDeployments: func() []client.Object { @@ -694,7 +694,7 @@ func TestReconcile_Deployment(t *testing.T) { }, GetDeployments: func() []client.Object { stable := getStableWithReady(stableDeploy, "v2").(*apps.Deployment) - stable.Spec.Replicas = pointer.Int32Ptr(200) + stable.Spec.Replicas = pointer.Int32(200) canary := getCanaryWithStage(stable, "v2", 0, true) return []client.Object{ stable, canary, @@ -891,7 +891,7 @@ func getCanaryWithStage(workload client.Object, version string, stage int, ready d.ResourceVersion = strconv.Itoa(rand.Intn(100000000000)) d.Labels[util.CanaryDeploymentLabel] = "87076677" d.Finalizers = []string{util.CanaryDeploymentFinalizer} - d.Spec.Replicas = pointer.Int32Ptr(int32(stageReplicas)) + d.Spec.Replicas = pointer.Int32(int32(stageReplicas)) d.Spec.Template.Spec.Containers = containers(version) d.Status.Replicas = int32(stageReplicas) d.Status.ReadyReplicas = int32(stageReplicas) diff --git a/pkg/controller/batchrelease/batchrelease_event_handler_test.go b/pkg/controller/batchrelease/batchrelease_event_handler_test.go index 886ce7db..8357d065 100644 --- a/pkg/controller/batchrelease/batchrelease_event_handler_test.go +++ b/pkg/controller/batchrelease/batchrelease_event_handler_test.go @@ -91,14 +91,14 @@ func TestWorkloadEventHandler_Update(t *testing.T) { oldObject := getStableWithReady(stableDeploy, "v2").(*apps.Deployment) oldObject.SetGeneration(2) oldObject.Status.ObservedGeneration = 2 - oldObject.Spec.Replicas = pointer.Int32Ptr(1000) + oldObject.Spec.Replicas = pointer.Int32(1000) return oldObject }, GetNewWorkload: func() client.Object { newObject := getStableWithReady(stableDeploy, "v2").(*apps.Deployment) newObject.SetGeneration(2) newObject.Status.ObservedGeneration = 2 - newObject.Spec.Replicas = pointer.Int32Ptr(1000) + newObject.Spec.Replicas = pointer.Int32(1000) newObject.Status.Replicas = 1000 return newObject }, diff --git a/pkg/controller/batchrelease/context/context.go b/pkg/controller/batchrelease/context/context.go index 6ad325b0..e7772201 100644 --- a/pkg/controller/batchrelease/context/context.go +++ b/pkg/controller/batchrelease/context/context.go @@ -64,6 +64,8 @@ type BatchContext struct { // the next two fields are only used for bluegreen style CurrentSurge intstr.IntOrString `json:"currentSurge,omitempty"` DesiredSurge intstr.IntOrString `json:"desiredSurge,omitempty"` + // batches field is added to support complicated scenes such as batch-id label + Batches []v1beta1.ReleaseBatch } type FilterFuncType func(pods []*corev1.Pod, ctx *BatchContext) []*corev1.Pod diff --git a/pkg/controller/batchrelease/control/bluegreenstyle/cloneset/control.go b/pkg/controller/batchrelease/control/bluegreenstyle/cloneset/control.go index 1dadad0a..961fde31 100644 --- a/pkg/controller/batchrelease/control/bluegreenstyle/cloneset/control.go +++ b/pkg/controller/batchrelease/control/bluegreenstyle/cloneset/control.go @@ -217,6 +217,7 @@ func (rc *realController) CalculateBatchContext(release *v1beta1.BatchRelease) ( UpdatedReadyReplicas: rc.Status.UpdatedReadyReplicas, DesiredUpdatedReplicas: int32(desired), PlannedUpdatedReplicas: int32(desired), + Batches: release.Spec.ReleasePlan.Batches, //shallow copy } // the number of no need update pods that marked before rollout // if noNeedUpdate := release.Status.CanaryStatus.NoNeedUpdateReplicas; noNeedUpdate != nil { diff --git a/pkg/controller/batchrelease/control/bluegreenstyle/cloneset/control_test.go b/pkg/controller/batchrelease/control/bluegreenstyle/cloneset/control_test.go index 06a77197..c01be06a 100644 --- a/pkg/controller/batchrelease/control/bluegreenstyle/cloneset/control_test.go +++ b/pkg/controller/batchrelease/control/bluegreenstyle/cloneset/control_test.go @@ -305,7 +305,7 @@ func TestCalculateBatchContext(t *testing.T) { workload: func() *kruiseappsv1alpha1.CloneSet { return &kruiseappsv1alpha1.CloneSet{ Spec: kruiseappsv1alpha1.CloneSetSpec{ - Replicas: pointer.Int32Ptr(10), + Replicas: pointer.Int32(10), UpdateStrategy: kruiseappsv1alpha1.CloneSetUpdateStrategy{ MaxSurge: func() *intstr.IntOrString { p := intstr.FromInt(1); return &p }(), }, @@ -348,6 +348,11 @@ func TestCalculateBatchContext(t *testing.T) { UpdateRevision: "update-version", PlannedUpdatedReplicas: 5, DesiredUpdatedReplicas: 5, + Batches: []v1beta1.ReleaseBatch{ + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "50%"}}, + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "100%"}}, + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "100%"}}, + }, }, }, @@ -398,13 +403,18 @@ func TestCalculateBatchContext(t *testing.T) { UpdateRevision: "update-version", PlannedUpdatedReplicas: 10, DesiredUpdatedReplicas: 10, + Batches: []v1beta1.ReleaseBatch{ + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "50%"}}, + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "100%"}}, + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "100%"}}, + }, }, }, "normal case batch2": { workload: func() *kruiseappsv1alpha1.CloneSet { return &kruiseappsv1alpha1.CloneSet{ Spec: kruiseappsv1alpha1.CloneSetSpec{ - Replicas: pointer.Int32Ptr(10), + Replicas: pointer.Int32(10), UpdateStrategy: kruiseappsv1alpha1.CloneSetUpdateStrategy{ MaxSurge: func() *intstr.IntOrString { p := intstr.FromString("100%"); return &p }(), }, @@ -448,6 +458,11 @@ func TestCalculateBatchContext(t *testing.T) { UpdatedReadyReplicas: 10, PlannedUpdatedReplicas: 10, DesiredUpdatedReplicas: 10, + Batches: []v1beta1.ReleaseBatch{ + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "50%"}}, + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "100%"}}, + {CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "100%"}}, + }, }, }, } diff --git a/pkg/controller/batchrelease/control/bluegreenstyle/deployment/control.go b/pkg/controller/batchrelease/control/bluegreenstyle/deployment/control.go index 9e073b3b..bae158ec 100644 --- a/pkg/controller/batchrelease/control/bluegreenstyle/deployment/control.go +++ b/pkg/controller/batchrelease/control/bluegreenstyle/deployment/control.go @@ -220,6 +220,7 @@ func (rc *realController) CalculateBatchContext(release *v1beta1.BatchRelease) ( UpdatedReadyReplicas: rc.Status.UpdatedReadyReplicas, PlannedUpdatedReplicas: PlannedUpdatedReplicas, DesiredUpdatedReplicas: PlannedUpdatedReplicas, + Batches: release.Spec.ReleasePlan.Batches, //shallow copy }, nil } diff --git a/pkg/controller/batchrelease/control/bluegreenstyle/deployment/control_test.go b/pkg/controller/batchrelease/control/bluegreenstyle/deployment/control_test.go index f6fc934f..ef754d95 100644 --- a/pkg/controller/batchrelease/control/bluegreenstyle/deployment/control_test.go +++ b/pkg/controller/batchrelease/control/bluegreenstyle/deployment/control_test.go @@ -428,6 +428,14 @@ func TestCalculateBatchContext(t *testing.T) { UpdatedReadyReplicas: 2, PlannedUpdatedReplicas: 10, DesiredUpdatedReplicas: 10, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "50%"}, + }, + { + CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "100%"}, + }, + }, }, }, "maxSurge=99%, replicas=5": { @@ -439,7 +447,7 @@ func TestCalculateBatchContext(t *testing.T) { AvailableReplicas: 9, ReadyReplicas: 9, } - deployment.Spec.Replicas = pointer.Int32Ptr(5) + deployment.Spec.Replicas = pointer.Int32(5) // current partition, ie. maxSurge deployment.Spec.Strategy.RollingUpdate.MaxSurge = &intstr.IntOrString{Type: intstr.String, StrVal: "90%"} newRss := makeCanaryReplicaSets(deployment).(*apps.ReplicaSet) @@ -480,6 +488,14 @@ func TestCalculateBatchContext(t *testing.T) { UpdatedReadyReplicas: 4, PlannedUpdatedReplicas: 4, DesiredUpdatedReplicas: 4, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "90%"}, + }, + { + CanaryReplicas: intstr.IntOrString{Type: intstr.String, StrVal: "99%"}, + }, + }, }, }, diff --git a/pkg/controller/batchrelease/control/canarystyle/deployment/canary.go b/pkg/controller/batchrelease/control/canarystyle/deployment/canary.go index e8afc70c..88987af2 100644 --- a/pkg/controller/batchrelease/control/canarystyle/deployment/canary.go +++ b/pkg/controller/batchrelease/control/canarystyle/deployment/canary.go @@ -145,7 +145,7 @@ func (r *realCanaryController) create(release *v1beta1.BatchRelease, template *a canary.Spec.Template.Annotations[k] = v } } - canary.Spec.Replicas = pointer.Int32Ptr(0) + canary.Spec.Replicas = pointer.Int32(0) canary.Spec.Paused = false if err := r.canaryClient.Create(context.TODO(), canary); err != nil { diff --git a/pkg/controller/batchrelease/control/canarystyle/deployment/control.go b/pkg/controller/batchrelease/control/canarystyle/deployment/control.go index c0f61670..08d190e7 100644 --- a/pkg/controller/batchrelease/control/canarystyle/deployment/control.go +++ b/pkg/controller/batchrelease/control/canarystyle/deployment/control.go @@ -94,6 +94,7 @@ func (rc *realController) CalculateBatchContext(release *v1beta1.BatchRelease) * FailureThreshold: release.Spec.ReleasePlan.FailureThreshold, UpdatedReplicas: rc.canaryObject.Status.Replicas, UpdatedReadyReplicas: rc.canaryObject.Status.AvailableReplicas, + Batches: release.Spec.ReleasePlan.Batches, //shallow copy } } diff --git a/pkg/controller/batchrelease/control/canarystyle/deployment/control_test.go b/pkg/controller/batchrelease/control/canarystyle/deployment/control_test.go index fec464eb..af5531ad 100644 --- a/pkg/controller/batchrelease/control/canarystyle/deployment/control_test.go +++ b/pkg/controller/batchrelease/control/canarystyle/deployment/control_test.go @@ -101,7 +101,7 @@ var ( UpdatedReplicas: 10, ReadyReplicas: 10, AvailableReplicas: 10, - CollisionCount: pointer.Int32Ptr(1), + CollisionCount: pointer.Int32(1), ObservedGeneration: 1, }, } @@ -163,7 +163,7 @@ func TestCalculateBatchContext(t *testing.T) { workload: func() (*apps.Deployment, *apps.Deployment) { stable := &apps.Deployment{ Spec: apps.DeploymentSpec{ - Replicas: pointer.Int32Ptr(10), + Replicas: pointer.Int32(10), }, Status: apps.DeploymentStatus{ Replicas: 10, @@ -173,7 +173,7 @@ func TestCalculateBatchContext(t *testing.T) { } canary := &apps.Deployment{ Spec: apps.DeploymentSpec{ - Replicas: pointer.Int32Ptr(5), + Replicas: pointer.Int32(5), }, Status: apps.DeploymentStatus{ Replicas: 5, @@ -211,6 +211,11 @@ func TestCalculateBatchContext(t *testing.T) { UpdatedReplicas: 5, UpdatedReadyReplicas: 5, DesiredUpdatedReplicas: 2, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: percent, + }, + }, }, }, } diff --git a/pkg/controller/batchrelease/control/partitionstyle/cloneset/control.go b/pkg/controller/batchrelease/control/partitionstyle/cloneset/control.go index b136b104..2d728be1 100644 --- a/pkg/controller/batchrelease/control/partitionstyle/cloneset/control.go +++ b/pkg/controller/batchrelease/control/partitionstyle/cloneset/control.go @@ -182,6 +182,7 @@ func (rc *realController) CalculateBatchContext(release *v1beta1.BatchRelease) ( NoNeedUpdatedReplicas: noNeedUpdate, PlannedUpdatedReplicas: plannedUpdate, DesiredUpdatedReplicas: desiredUpdate, + Batches: release.Spec.ReleasePlan.Batches, //shallow copy } if noNeedUpdate != nil { diff --git a/pkg/controller/batchrelease/control/partitionstyle/cloneset/control_test.go b/pkg/controller/batchrelease/control/partitionstyle/cloneset/control_test.go index 2ad0b70c..92f13312 100644 --- a/pkg/controller/batchrelease/control/partitionstyle/cloneset/control_test.go +++ b/pkg/controller/batchrelease/control/partitionstyle/cloneset/control_test.go @@ -101,7 +101,7 @@ var ( UpdateRevision: "version-2", CurrentRevision: "version-1", ObservedGeneration: 1, - CollisionCount: pointer.Int32Ptr(1), + CollisionCount: pointer.Int32(1), }, } @@ -162,7 +162,7 @@ func TestCalculateBatchContext(t *testing.T) { workload: func() *kruiseappsv1alpha1.CloneSet { return &kruiseappsv1alpha1.CloneSet{ Spec: kruiseappsv1alpha1.CloneSetSpec{ - Replicas: pointer.Int32Ptr(10), + Replicas: pointer.Int32(10), UpdateStrategy: kruiseappsv1alpha1.CloneSetUpdateStrategy{ Partition: func() *intstr.IntOrString { p := intstr.FromString("100%"); return &p }(), }, @@ -205,13 +205,14 @@ func TestCalculateBatchContext(t *testing.T) { DesiredUpdatedReplicas: 2, CurrentPartition: intstr.FromString("100%"), DesiredPartition: intstr.FromString("80%"), + Batches: []v1beta1.ReleaseBatch{{CanaryReplicas: percent}}, }, }, "with NoNeedUpdate": { workload: func() *kruiseappsv1alpha1.CloneSet { return &kruiseappsv1alpha1.CloneSet{ Spec: kruiseappsv1alpha1.CloneSetSpec{ - Replicas: pointer.Int32Ptr(20), + Replicas: pointer.Int32(20), UpdateStrategy: kruiseappsv1alpha1.CloneSetUpdateStrategy{ Partition: func() *intstr.IntOrString { p := intstr.FromString("100%"); return &p }(), }, @@ -253,13 +254,14 @@ func TestCalculateBatchContext(t *testing.T) { Replicas: 20, UpdatedReplicas: 10, UpdatedReadyReplicas: 10, - NoNeedUpdatedReplicas: pointer.Int32Ptr(10), + NoNeedUpdatedReplicas: pointer.Int32(10), PlannedUpdatedReplicas: 4, DesiredUpdatedReplicas: 12, CurrentPartition: intstr.FromString("100%"), DesiredPartition: intstr.FromString("40%"), FailureThreshold: &percent, FilterFunc: labelpatch.FilterPodsForUnorderedUpdate, + Batches: []v1beta1.ReleaseBatch{{CanaryReplicas: percent}}, }, }, } diff --git a/pkg/controller/batchrelease/control/partitionstyle/daemonset/control.go b/pkg/controller/batchrelease/control/partitionstyle/daemonset/control.go index d1f03885..17719daa 100644 --- a/pkg/controller/batchrelease/control/partitionstyle/daemonset/control.go +++ b/pkg/controller/batchrelease/control/partitionstyle/daemonset/control.go @@ -189,6 +189,7 @@ func (rc *realController) CalculateBatchContext(release *v1beta1.BatchRelease) ( NoNeedUpdatedReplicas: noNeedUpdate, PlannedUpdatedReplicas: plannedUpdate, DesiredUpdatedReplicas: desiredUpdate, + Batches: release.Spec.ReleasePlan.Batches, //shallow copy } if noNeedUpdate != nil { diff --git a/pkg/controller/batchrelease/control/partitionstyle/daemonset/control_test.go b/pkg/controller/batchrelease/control/partitionstyle/daemonset/control_test.go index 2cd34dab..6b678a08 100644 --- a/pkg/controller/batchrelease/control/partitionstyle/daemonset/control_test.go +++ b/pkg/controller/batchrelease/control/partitionstyle/daemonset/control_test.go @@ -160,7 +160,7 @@ func TestCalculateBatchContext(t *testing.T) { Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}, UpdateStrategy: kruiseappsv1alpha1.DaemonSetUpdateStrategy{ RollingUpdate: &kruiseappsv1alpha1.RollingUpdateDaemonSet{ - Partition: pointer.Int32Ptr(10), + Partition: pointer.Int32(10), }, }, }, @@ -219,6 +219,11 @@ func TestCalculateBatchContext(t *testing.T) { CurrentPartition: intstr.FromInt(10), DesiredPartition: intstr.FromInt(8), Pods: generatePods(10, "", ""), + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: percent, + }, + }, }, }, "with NoNeedUpdate": { @@ -233,7 +238,7 @@ func TestCalculateBatchContext(t *testing.T) { Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}, UpdateStrategy: kruiseappsv1alpha1.DaemonSetUpdateStrategy{ RollingUpdate: &kruiseappsv1alpha1.RollingUpdateDaemonSet{ - Partition: pointer.Int32Ptr(10), + Partition: pointer.Int32(10), }, }, }, @@ -288,7 +293,7 @@ func TestCalculateBatchContext(t *testing.T) { Replicas: 10, UpdatedReplicas: 5, UpdatedReadyReplicas: 5, - NoNeedUpdatedReplicas: pointer.Int32Ptr(5), + NoNeedUpdatedReplicas: pointer.Int32(5), PlannedUpdatedReplicas: 2, DesiredUpdatedReplicas: 6, CurrentPartition: intstr.FromInt(10), @@ -296,6 +301,11 @@ func TestCalculateBatchContext(t *testing.T) { FailureThreshold: &percent, FilterFunc: labelpatch.FilterPodsForUnorderedUpdate, Pods: generatePods(10, "", ""), + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: percent, + }, + }, }, }, } diff --git a/pkg/controller/batchrelease/control/partitionstyle/deployment/control.go b/pkg/controller/batchrelease/control/partitionstyle/deployment/control.go index 94e8542d..e124ec89 100644 --- a/pkg/controller/batchrelease/control/partitionstyle/deployment/control.go +++ b/pkg/controller/batchrelease/control/partitionstyle/deployment/control.go @@ -183,6 +183,7 @@ func (rc *realController) CalculateBatchContext(release *v1beta1.BatchRelease) ( UpdatedReadyReplicas: rc.Status.UpdatedReadyReplicas, PlannedUpdatedReplicas: PlannedUpdatedReplicas, DesiredUpdatedReplicas: PlannedUpdatedReplicas, + Batches: release.Spec.ReleasePlan.Batches, //shallow copy }, nil } diff --git a/pkg/controller/batchrelease/control/partitionstyle/deployment/control_test.go b/pkg/controller/batchrelease/control/partitionstyle/deployment/control_test.go index f15b066c..1de63357 100644 --- a/pkg/controller/batchrelease/control/partitionstyle/deployment/control_test.go +++ b/pkg/controller/batchrelease/control/partitionstyle/deployment/control_test.go @@ -101,7 +101,7 @@ var ( UpdatedReplicas: 10, ReadyReplicas: 10, AvailableReplicas: 10, - CollisionCount: pointer.Int32Ptr(1), + CollisionCount: pointer.Int32(1), ObservedGeneration: 1, }, } @@ -178,7 +178,7 @@ func TestCalculateBatchContext(t *testing.T) { }, }, Spec: apps.DeploymentSpec{ - Replicas: pointer.Int32Ptr(10), + Replicas: pointer.Int32(10), }, Status: apps.DeploymentStatus{ Replicas: 10, @@ -222,6 +222,11 @@ func TestCalculateBatchContext(t *testing.T) { UpdatedReadyReplicas: 1, PlannedUpdatedReplicas: 2, DesiredUpdatedReplicas: 2, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: percent, + }, + }, }, }, "partition=90%, replicas=5": { @@ -242,7 +247,7 @@ func TestCalculateBatchContext(t *testing.T) { }, }, Spec: apps.DeploymentSpec{ - Replicas: pointer.Int32Ptr(5), + Replicas: pointer.Int32(5), }, Status: apps.DeploymentStatus{ Replicas: 5, @@ -286,6 +291,11 @@ func TestCalculateBatchContext(t *testing.T) { UpdatedReadyReplicas: 4, PlannedUpdatedReplicas: 4, DesiredUpdatedReplicas: 4, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.FromString("90%"), + }, + }, }, }, } diff --git a/pkg/controller/batchrelease/control/partitionstyle/statefulset/control.go b/pkg/controller/batchrelease/control/partitionstyle/statefulset/control.go index 8d83a559..88955c89 100644 --- a/pkg/controller/batchrelease/control/partitionstyle/statefulset/control.go +++ b/pkg/controller/batchrelease/control/partitionstyle/statefulset/control.go @@ -196,6 +196,7 @@ func (rc *realController) CalculateBatchContext(release *v1beta1.BatchRelease) ( NoNeedUpdatedReplicas: noNeedUpdate, PlannedUpdatedReplicas: plannedUpdate, DesiredUpdatedReplicas: desiredUpdate, + Batches: release.Spec.ReleasePlan.Batches, //shallow copy } if noNeedUpdate != nil { diff --git a/pkg/controller/batchrelease/control/partitionstyle/statefulset/control_test.go b/pkg/controller/batchrelease/control/partitionstyle/statefulset/control_test.go index 391bad73..aaa53318 100644 --- a/pkg/controller/batchrelease/control/partitionstyle/statefulset/control_test.go +++ b/pkg/controller/batchrelease/control/partitionstyle/statefulset/control_test.go @@ -108,7 +108,7 @@ var ( CurrentRevision: "version-1", ObservedGeneration: 1, UpdatedReadyReplicas: 0, - CollisionCount: pointer.Int32Ptr(1), + CollisionCount: pointer.Int32(1), }, } @@ -183,11 +183,11 @@ func TestCalculateBatchContextForNativeStatefulSet(t *testing.T) { }, Spec: apps.StatefulSetSpec{ Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}, - Replicas: pointer.Int32Ptr(10), + Replicas: pointer.Int32(10), UpdateStrategy: apps.StatefulSetUpdateStrategy{ Type: apps.RollingUpdateStatefulSetStrategyType, RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ - Partition: pointer.Int32Ptr(100), + Partition: pointer.Int32(100), }, }, }, @@ -242,6 +242,7 @@ func TestCalculateBatchContextForNativeStatefulSet(t *testing.T) { CurrentPartition: intstr.FromInt(100), DesiredPartition: intstr.FromInt(8), Pods: generatePods(10, "", ""), + Batches: []v1beta1.ReleaseBatch{{CanaryReplicas: percent}}, }, }, "with NoNeedUpdate": { @@ -258,11 +259,11 @@ func TestCalculateBatchContextForNativeStatefulSet(t *testing.T) { }, Spec: apps.StatefulSetSpec{ Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}, - Replicas: pointer.Int32Ptr(20), + Replicas: pointer.Int32(20), UpdateStrategy: apps.StatefulSetUpdateStrategy{ Type: apps.RollingUpdateStatefulSetStrategyType, RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ - Partition: pointer.Int32Ptr(100), + Partition: pointer.Int32(100), }, }, }, @@ -312,7 +313,7 @@ func TestCalculateBatchContextForNativeStatefulSet(t *testing.T) { Replicas: 20, UpdatedReplicas: 10, UpdatedReadyReplicas: 10, - NoNeedUpdatedReplicas: pointer.Int32Ptr(10), + NoNeedUpdatedReplicas: pointer.Int32(10), PlannedUpdatedReplicas: 4, DesiredUpdatedReplicas: 12, CurrentPartition: intstr.FromInt(100), @@ -320,6 +321,7 @@ func TestCalculateBatchContextForNativeStatefulSet(t *testing.T) { FailureThreshold: &percent, FilterFunc: labelpatch.FilterPodsForUnorderedUpdate, Pods: generatePods(20, "", ""), + Batches: []v1beta1.ReleaseBatch{{CanaryReplicas: percent}}, }, }, } @@ -377,11 +379,11 @@ func TestCalculateBatchContextForAdvancedStatefulSet(t *testing.T) { }, Spec: kruiseappsv1beta1.StatefulSetSpec{ Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}, - Replicas: pointer.Int32Ptr(10), + Replicas: pointer.Int32(10), UpdateStrategy: kruiseappsv1beta1.StatefulSetUpdateStrategy{ Type: apps.RollingUpdateStatefulSetStrategyType, RollingUpdate: &kruiseappsv1beta1.RollingUpdateStatefulSetStrategy{ - Partition: pointer.Int32Ptr(100), + Partition: pointer.Int32(100), UnorderedUpdate: &kruiseappsv1beta1.UnorderedUpdateStrategy{ PriorityStrategy: &appsv1pub.UpdatePriorityStrategy{ OrderPriority: []appsv1pub.UpdatePriorityOrderTerm{ @@ -445,6 +447,7 @@ func TestCalculateBatchContextForAdvancedStatefulSet(t *testing.T) { CurrentPartition: intstr.FromInt(100), DesiredPartition: intstr.FromInt(8), Pods: generatePods(10, "", ""), + Batches: []v1beta1.ReleaseBatch{{CanaryReplicas: percent}}, }, }, "with NoNeedUpdate": { @@ -461,11 +464,11 @@ func TestCalculateBatchContextForAdvancedStatefulSet(t *testing.T) { }, Spec: kruiseappsv1beta1.StatefulSetSpec{ Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}, - Replicas: pointer.Int32Ptr(20), + Replicas: pointer.Int32(20), UpdateStrategy: kruiseappsv1beta1.StatefulSetUpdateStrategy{ Type: apps.RollingUpdateStatefulSetStrategyType, RollingUpdate: &kruiseappsv1beta1.RollingUpdateStatefulSetStrategy{ - Partition: pointer.Int32Ptr(100), + Partition: pointer.Int32(100), UnorderedUpdate: &kruiseappsv1beta1.UnorderedUpdateStrategy{ PriorityStrategy: &appsv1pub.UpdatePriorityStrategy{ OrderPriority: []appsv1pub.UpdatePriorityOrderTerm{ @@ -524,7 +527,7 @@ func TestCalculateBatchContextForAdvancedStatefulSet(t *testing.T) { Replicas: 20, UpdatedReplicas: 10, UpdatedReadyReplicas: 10, - NoNeedUpdatedReplicas: pointer.Int32Ptr(10), + NoNeedUpdatedReplicas: pointer.Int32(10), PlannedUpdatedReplicas: 4, DesiredUpdatedReplicas: 12, CurrentPartition: intstr.FromInt(100), @@ -532,6 +535,7 @@ func TestCalculateBatchContextForAdvancedStatefulSet(t *testing.T) { FailureThreshold: &percent, FilterFunc: labelpatch.FilterPodsForUnorderedUpdate, Pods: generatePods(20, "", ""), + Batches: []v1beta1.ReleaseBatch{{CanaryReplicas: percent}}, }, }, } diff --git a/pkg/controller/batchrelease/labelpatch/filter.go b/pkg/controller/batchrelease/labelpatch/filter.go index 315109b1..8a33e978 100644 --- a/pkg/controller/batchrelease/labelpatch/filter.go +++ b/pkg/controller/batchrelease/labelpatch/filter.go @@ -39,8 +39,8 @@ import ( // the pods that are really need to be rolled back according to release plan, but patch batch label according // original release plan, and will patch the pods that are really rolled back in priority. // - in batch 0: really roll back (20 - 10) * 20% = 2 pods, but 20 * 20% = 4 pod will be patched batch label; -// - in batch 0: really roll back (20 - 10) * 50% = 5 pods, but 20 * 50% = 10 pod will be patched batch label; -// - in batch 0: really roll back (20 - 10) * 100% = 10 pods, but 20 * 100% = 20 pod will be patched batch label; +// - in batch 1: really roll back (20 - 10) * 50% = 5 pods, but 20 * 50% = 10 pod will be patched batch label; +// - in batch 2: really roll back (20 - 10) * 100% = 10 pods, but 20 * 100% = 20 pod will be patched batch label; // // Mainly for PaaS platform display pod list in conveniently. // @@ -92,8 +92,8 @@ func FilterPodsForUnorderedUpdate(pods []*corev1.Pod, ctx *batchcontext.BatchCon // the pods that are really need to be rolled back according to release plan, but patch batch label according // original release plan, and will patch the pods that are really rolled back in priority. // - in batch 0: really roll back (20 - 10) * 20% = 2 pods, but 20 * 20% = 4 pod will be patched batch label; -// - in batch 0: really roll back (20 - 10) * 50% = 5 pods, but 20 * 50% = 10 pod will be patched batch label; -// - in batch 0: really roll back (20 - 10) * 100% = 10 pods, but 20 * 100% = 20 pod will be patched batch label; +// - in batch 1: really roll back (20 - 10) * 50% = 5 pods, but 20 * 50% = 10 pod will be patched batch label; +// - in batch 2: really roll back (20 - 10) * 100% = 10 pods, but 20 * 100% = 20 pod will be patched batch label; // // Mainly for PaaS platform display pod list in conveniently. // diff --git a/pkg/controller/batchrelease/labelpatch/patcher.go b/pkg/controller/batchrelease/labelpatch/patcher.go index a0175b45..9bcf2c8b 100644 --- a/pkg/controller/batchrelease/labelpatch/patcher.go +++ b/pkg/controller/batchrelease/labelpatch/patcher.go @@ -19,12 +19,14 @@ package labelpatch import ( "context" "fmt" + "strconv" "github.com/openkruise/rollouts/api/v1beta1" batchcontext "github.com/openkruise/rollouts/pkg/controller/batchrelease/context" "github.com/openkruise/rollouts/pkg/util" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -55,59 +57,87 @@ func (r *realPatcher) PatchPodBatchLabel(ctx *batchcontext.BatchContext) error { // PatchPodBatchLabel will patch rollout-id && batch-id to pods func (r *realPatcher) patchPodBatchLabel(pods []*corev1.Pod, ctx *batchcontext.BatchContext) error { - // the number of active pods that has been patched successfully. - patchedUpdatedReplicas := int32(0) - // the number of target active pods that should be patched batch label. - plannedUpdatedReplicas := ctx.PlannedUpdatedReplicas + plannedUpdatedReplicasForBatches := CalculatePlannedStepIncrements(ctx.Batches, int(ctx.Replicas), int(ctx.CurrentBatch)) + klog.InfoS("CalculatePlannedStepIncrements", "plannedUpdatedReplicasForBatches", plannedUpdatedReplicasForBatches) + var updatedButUnpatchedPods []*corev1.Pod for _, pod := range pods { + if !pod.DeletionTimestamp.IsZero() { + klog.InfoS("Pod is being deleted, skip patching", "pod", klog.KObj(pod)) + continue + } + // we don't patch label for the active old revision pod if !util.IsConsistentWithRevision(pod, ctx.UpdateRevision) { + klog.InfoS("Pod is not consistent with revision, skip patching", "pod", klog.KObj(pod)) continue } - - podRolloutID := pod.Labels[v1beta1.RolloutIDLabel] - if pod.DeletionTimestamp.IsZero() && podRolloutID == ctx.RolloutID { - patchedUpdatedReplicas++ + // new/recreated pods should not be patched again + if pod.Labels[v1beta1.RolloutIDLabel] != ctx.RolloutID { + updatedButUnpatchedPods = append(updatedButUnpatchedPods, pod) + klog.InfoS("Find a pod to add updatedButUnpatchedPods", "pod", klog.KObj(pod)) + continue } - } - // all pods that should be patched have been patched - if patchedUpdatedReplicas >= plannedUpdatedReplicas { - return nil // return fast + podBatchID, err := strconv.Atoi(pod.Labels[v1beta1.RolloutBatchIDLabel]) + if err != nil { + return err + } + plannedUpdatedReplicasForBatches[podBatchID-1]-- } - - for _, pod := range pods { - if pod.DeletionTimestamp.IsZero() { - // we don't patch label for the active old revision pod - if !util.IsConsistentWithRevision(pod, ctx.UpdateRevision) { - continue + klog.Infof("updatedButUnpatchedPods amount is %d", len(updatedButUnpatchedPods)) + // patch the pods + for i := len(plannedUpdatedReplicasForBatches) - 1; i >= 0; i-- { + for ; plannedUpdatedReplicasForBatches[i] > 0; plannedUpdatedReplicasForBatches[i]-- { + if len(updatedButUnpatchedPods) == 0 { + return fmt.Errorf("no pods to patch for %v, batch %d", r.logKey, i+1) } - // we don't continue to patch if the goal is met - if patchedUpdatedReplicas >= ctx.PlannedUpdatedReplicas { - continue + // patch the updated but unpatced pod + pod := updatedButUnpatchedPods[len(updatedButUnpatchedPods)-1] + clone := util.GetEmptyObjectWithKey(pod) + by := fmt.Sprintf(`{"metadata":{"labels":{"%s":"%s","%s":"%d"}}}`, + v1beta1.RolloutIDLabel, ctx.RolloutID, v1beta1.RolloutBatchIDLabel, i+1) + if err := r.Patch(context.TODO(), clone, client.RawPatch(types.StrategicMergePatchType, []byte(by))); err != nil { + return err } + klog.InfoS("Successfully patch Pod batchID", "batchID", i+1, "rollout", r.logKey, "pod", klog.KObj(pod)) + // update the counter + updatedButUnpatchedPods = updatedButUnpatchedPods[:len(updatedButUnpatchedPods)-1] } + klog.InfoS("All pods has been patched batchID", "batchID", i+1, "rollout", r.logKey) + } - // if it has been patched, just ignore - if pod.Labels[v1beta1.RolloutIDLabel] == ctx.RolloutID { - continue - } - - clone := util.GetEmptyObjectWithKey(pod) - by := fmt.Sprintf(`{"metadata":{"labels":{"%s":"%s","%s":"%d"}}}`, - v1beta1.RolloutIDLabel, ctx.RolloutID, v1beta1.RolloutBatchIDLabel, ctx.CurrentBatch+1) - if err := r.Patch(context.TODO(), clone, client.RawPatch(types.StrategicMergePatchType, []byte(by))); err != nil { - return err - } + // for rollback in batch, it is possible that some updated pods are remained unpatched, we won't report error + if len(updatedButUnpatchedPods) != 0 { + klog.Warningf("still has %d pods to patch for %v", len(updatedButUnpatchedPods), r.logKey) + // return fmt.Errorf("still has %d pods to patch for %v", len(updatedButUnpatchedPods), r.logKey) + } + return nil +} - if pod.DeletionTimestamp.IsZero() { - patchedUpdatedReplicas++ +func CalculatePlannedStepIncrements(batches []v1beta1.ReleaseBatch, workloadReplicas, currentBatch int) (res []int) { + // batchIndex greater than currentBatch will be patched with zero + res = make([]int, len(batches)) + for i := 0; i <= currentBatch; i++ { + res[i] = CalculateBatchReplicas(batches, workloadReplicas, i) + } + for i := currentBatch; i > 0; i-- { + res[i] -= res[i-1] + // webhook can ensure the steps replicas is non-decreasing + if res[i] < 0 { + panic("batch replicas increment is less than 0") } - klog.Infof("Successfully patch Pod(%v) batchID %d label", klog.KObj(pod), ctx.CurrentBatch+1) } + return +} - if patchedUpdatedReplicas >= plannedUpdatedReplicas { - return nil +func CalculateBatchReplicas(batches []v1beta1.ReleaseBatch, workloadReplicas, currentBatch int) int { + batchSize, _ := intstr.GetScaledValueFromIntOrPercent(&batches[currentBatch].CanaryReplicas, workloadReplicas, true) + if batchSize > workloadReplicas { + klog.Warningf("releasePlan has wrong batch replicas, batches[%d].replicas %v is more than workload.replicas %v", currentBatch, batchSize, workloadReplicas) + batchSize = workloadReplicas + } else if batchSize < 0 { + klog.Warningf("releasePlan has wrong batch replicas, batches[%d].replicas %v is less than 0 %v", currentBatch, batchSize) + batchSize = 0 } - return fmt.Errorf("patched %v pods for %v, however the goal is %d", patchedUpdatedReplicas, r.logKey, plannedUpdatedReplicas) + return batchSize } diff --git a/pkg/controller/batchrelease/labelpatch/patcher_test.go b/pkg/controller/batchrelease/labelpatch/patcher_test.go index f8bcbf38..8e129260 100644 --- a/pkg/controller/batchrelease/labelpatch/patcher_test.go +++ b/pkg/controller/batchrelease/labelpatch/patcher_test.go @@ -28,6 +28,7 @@ import ( apps "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -54,8 +55,12 @@ func TestLabelPatcher(t *testing.T) { RolloutID: "rollout-1", UpdateRevision: "version-1", PlannedUpdatedReplicas: 5, - CurrentBatch: 0, Replicas: 10, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.FromInt(5), + }, + }, } pods := generatePods(1, ctx.Replicas, 0, "", "", ctx.UpdateRevision) ctx.Pods = pods @@ -70,9 +75,14 @@ func TestLabelPatcher(t *testing.T) { UpdateRevision: "version-1", PlannedUpdatedReplicas: 5, Replicas: 10, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.FromInt(5), + }, + }, } pods := generatePods(1, ctx.Replicas, 2, - ctx.RolloutID, strconv.Itoa(int(ctx.CurrentBatch)), ctx.UpdateRevision) + ctx.RolloutID, strconv.Itoa(int(ctx.CurrentBatch+1)), ctx.UpdateRevision) ctx.Pods = pods return ctx }, @@ -85,9 +95,14 @@ func TestLabelPatcher(t *testing.T) { UpdateRevision: "version-1", PlannedUpdatedReplicas: 5, Replicas: 10, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.FromInt(5), + }, + }, } pods := generatePods(1, ctx.Replicas, 5, - ctx.RolloutID, strconv.Itoa(int(ctx.CurrentBatch)), ctx.UpdateRevision) + ctx.RolloutID, strconv.Itoa(int(ctx.CurrentBatch+1)), ctx.UpdateRevision) ctx.Pods = pods return ctx }, @@ -100,9 +115,14 @@ func TestLabelPatcher(t *testing.T) { UpdateRevision: "version-1", PlannedUpdatedReplicas: 5, Replicas: 10, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.FromInt(5), + }, + }, } pods := generatePods(1, ctx.Replicas, 7, - ctx.RolloutID, strconv.Itoa(int(ctx.CurrentBatch)), ctx.UpdateRevision) + ctx.RolloutID, strconv.Itoa(int(ctx.CurrentBatch+1)), ctx.UpdateRevision) ctx.Pods = pods return ctx }, @@ -115,9 +135,14 @@ func TestLabelPatcher(t *testing.T) { UpdateRevision: "version-1", PlannedUpdatedReplicas: 5, Replicas: 10, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.FromInt(5), + }, + }, } pods := generatePods(1, 2, 0, - ctx.RolloutID, strconv.Itoa(int(ctx.CurrentBatch)), ctx.UpdateRevision) + ctx.RolloutID, strconv.Itoa(int(ctx.CurrentBatch+1)), ctx.UpdateRevision) ctx.Pods = pods return ctx }, @@ -130,9 +155,14 @@ func TestLabelPatcher(t *testing.T) { UpdateRevision: "version-1", PlannedUpdatedReplicas: 5, Replicas: 10, + Batches: []v1beta1.ReleaseBatch{ + { + CanaryReplicas: intstr.FromInt(5), + }, + }, } pods := generatePods(1, ctx.Replicas, 3, - "previous-rollout-id", strconv.Itoa(int(ctx.CurrentBatch)), ctx.UpdateRevision) + "previous-rollout-id", strconv.Itoa(int(ctx.CurrentBatch+1)), ctx.UpdateRevision) ctx.Pods = pods return ctx }, diff --git a/pkg/controller/rollout/rollout_bluegreen.go b/pkg/controller/rollout/rollout_bluegreen.go index 7cfeaa82..b6d97ae2 100644 --- a/pkg/controller/rollout/rollout_bluegreen.go +++ b/pkg/controller/rollout/rollout_bluegreen.go @@ -366,7 +366,7 @@ func (m *blueGreenReleaseManager) createBatchRelease(rollout *v1beta1.Rollout, r ReleasePlan: v1beta1.ReleasePlan{ Batches: batches, RolloutID: rolloutID, - BatchPartition: utilpointer.Int32Ptr(batch), + BatchPartition: utilpointer.Int32(batch), FailureThreshold: rollout.Spec.Strategy.BlueGreen.FailureThreshold, RollingStyle: v1beta1.BlueGreenRollingStyle, }, diff --git a/pkg/controller/rollout/rollout_canary.go b/pkg/controller/rollout/rollout_canary.go index cc64c0ef..b5e47b09 100644 --- a/pkg/controller/rollout/rollout_canary.go +++ b/pkg/controller/rollout/rollout_canary.go @@ -429,7 +429,7 @@ func (m *canaryReleaseManager) createBatchRelease(rollout *v1beta1.Rollout, roll ReleasePlan: v1beta1.ReleasePlan{ Batches: batches, RolloutID: rolloutID, - BatchPartition: utilpointer.Int32Ptr(batch), + BatchPartition: utilpointer.Int32(batch), FailureThreshold: rollout.Spec.Strategy.Canary.FailureThreshold, PatchPodTemplateMetadata: rollout.Spec.Strategy.Canary.PatchPodTemplateMetadata, RollingStyle: rollout.Spec.Strategy.GetRollingStyle(), diff --git a/pkg/controller/rollout/rollout_canary_test.go b/pkg/controller/rollout/rollout_canary_test.go index cbefcdc1..69df96d0 100644 --- a/pkg/controller/rollout/rollout_canary_test.go +++ b/pkg/controller/rollout/rollout_canary_test.go @@ -123,7 +123,7 @@ func TestRunCanary(t *testing.T) { Kind: "Deployment", Name: dep2.Name, UID: "1ca4d850-9ec3-48bd-84cb-19f2e8cf4180", - Controller: utilpointer.BoolPtr(true), + Controller: utilpointer.Bool(true), }, } rs2.Labels["pod-template-hash"] = "pod-template-hash-v2" diff --git a/pkg/controller/rollout/rollout_controller_test.go b/pkg/controller/rollout/rollout_controller_test.go index 3d29d379..c11d75f0 100644 --- a/pkg/controller/rollout/rollout_controller_test.go +++ b/pkg/controller/rollout/rollout_controller_test.go @@ -238,7 +238,7 @@ var ( Kind: "Deployment", Name: "echoserver", UID: types.UID("606132e0-85ef-460a-8cf5-cd8f915a8cc3"), - Controller: utilpointer.BoolPtr(true), + Controller: utilpointer.Bool(true), }, }, }, diff --git a/pkg/trafficrouting/manager.go b/pkg/trafficrouting/manager.go index 86bc6e90..6af6eced 100644 --- a/pkg/trafficrouting/manager.go +++ b/pkg/trafficrouting/manager.go @@ -251,7 +251,7 @@ func (m *Manager) RouteAllTrafficToNewVersion(c *TrafficRoutingContext) (bool, e retry, remaining, err := grace.RunWithGraceSeconds(string(c.OwnerRef.UID), "updateRoute", graceSeconds, func() (bool, error) { // route all traffic to new version c.Strategy.Matches = nil - c.Strategy.Traffic = utilpointer.StringPtr("100%") + c.Strategy.Traffic = utilpointer.String("100%") //NOTE - This return value "verified" has the opposite semantics with "modified" verified, err := trController.EnsureRoutes(context.TODO(), &c.Strategy) if !verified { diff --git a/test/e2e/rollout_v1beta1_test.go b/test/e2e/rollout_v1beta1_test.go index 1ed52170..7035271f 100644 --- a/test/e2e/rollout_v1beta1_test.go +++ b/test/e2e/rollout_v1beta1_test.go @@ -5070,8 +5070,8 @@ var _ = SIGDescribe("Rollout v1beta1", func() { // check pod batch label after scale By("check pod batch label after scale") - CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1) - CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 3) + CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 2) + CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 2) // resume rollout canary By("check rollout canary status success, resume rollout, and wait rollout canary complete") @@ -5080,8 +5080,8 @@ var _ = SIGDescribe("Rollout v1beta1", func() { WaitCloneSetAllPodsReady(workload) By("rollout completed, and check pod batch label") - CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1) - CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 3) + CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 2) + CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 2) CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "3", 2) CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "4", 4) })