Skip to content

Commit 89dc0a1

Browse files
committed
rewrite step jump logic
Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
1 parent 00aae12 commit 89dc0a1

File tree

7 files changed

+623
-56
lines changed

7 files changed

+623
-56
lines changed

api/v1beta1/rollout_types.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,24 @@ type BlueGreenStatus struct {
459459
UpdatedReadyReplicas int32 `json:"updatedReadyReplicas"`
460460
}
461461

462+
// UnifiedStatus is a data structure used to unify BlueGreenStatus and CanaryStatus, allowing the controller to operate
463+
// the current release status in a unified manner without considering the release form.
464+
type UnifiedStatus struct {
465+
*CommonStatus
466+
// UpdatedRevision is the pointer of BlueGreenStatus.UpdatedRevision or CanaryStatus.CanaryRevision
467+
UpdatedRevision *string `json:"updatedRevision"`
468+
// UpdatedReplicas is the pointer of BlueGreenStatus.UpdatedReplicas or CanaryStatus.CanaryReplicas
469+
UpdatedReplicas *int32 `json:"updatedReplicas"`
470+
// UpdatedReadyReplicas is the pointer of BlueGreenStatus.UpdatedReadyReplicas or CanaryStatus.CanaryReadyReplicas
471+
UpdatedReadyReplicas *int32 `json:"updatedReadyReplicas"`
472+
}
473+
474+
func (u UnifiedStatus) IsNil() bool {
475+
return u.CommonStatus == nil || u.UpdatedReplicas == nil || u.UpdatedReadyReplicas == nil || u.UpdatedRevision == nil
476+
}
477+
462478
// GetSubStatus returns the ethier canary or bluegreen status
479+
// Deprecated: use
463480
func (r *RolloutStatus) GetSubStatus() *CommonStatus {
464481
if r.CanaryStatus == nil && r.BlueGreenStatus == nil {
465482
return nil
@@ -470,6 +487,22 @@ func (r *RolloutStatus) GetSubStatus() *CommonStatus {
470487
return &r.BlueGreenStatus.CommonStatus
471488
}
472489

490+
func (r *RolloutStatus) GetUnifiedStatus() UnifiedStatus {
491+
status := UnifiedStatus{}
492+
if r.CanaryStatus != nil {
493+
status.CommonStatus = &r.CanaryStatus.CommonStatus
494+
status.UpdatedReadyReplicas = &r.CanaryStatus.CanaryReadyReplicas
495+
status.UpdatedReplicas = &r.CanaryStatus.CanaryReplicas
496+
status.UpdatedRevision = &r.CanaryStatus.CanaryRevision
497+
} else if r.BlueGreenStatus != nil {
498+
status.CommonStatus = &r.BlueGreenStatus.CommonStatus
499+
status.UpdatedReadyReplicas = &r.BlueGreenStatus.UpdatedReadyReplicas
500+
status.UpdatedReplicas = &r.BlueGreenStatus.UpdatedReplicas
501+
status.UpdatedRevision = &r.BlueGreenStatus.UpdatedRevision
502+
}
503+
return status
504+
}
505+
473506
func (r *RolloutStatus) IsSubStatusEmpty() bool {
474507
return r.CanaryStatus == nil && r.BlueGreenStatus == nil
475508
}

pkg/controller/batchrelease/labelpatch/patcher.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,9 @@ func (r *realPatcher) patchPodBatchLabel(pods []*corev1.Pod, ctx *batchcontext.B
124124
klog.InfoS("Pod batchID is not a number, skip patching", "pod", klog.KObj(pod), "rollout", r.logKey)
125125
continue
126126
}
127-
plannedUpdatedReplicasForBatches[podBatchID-1]--
127+
if podBatchID > 0 && podBatchID <= len(plannedUpdatedReplicasForBatches) {
128+
plannedUpdatedReplicasForBatches[podBatchID-1]--
129+
}
128130
}
129131
klog.InfoS("updatedButUnpatchedPods amount calculated", "amount", len(updatedButUnpatchedPods),
130132
"rollout", r.logKey, "plan", plannedUpdatedReplicasForBatches)

pkg/controller/rollout/rollout_bluegreen.go

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package rollout
1919
import (
2020
"context"
2121
"fmt"
22-
"reflect"
2322
"time"
2423

2524
corev1 "k8s.io/api/core/v1"
@@ -248,31 +247,10 @@ func (m *blueGreenReleaseManager) doCanaryPaused(c *RolloutContext) (bool, error
248247
}
249248

250249
func (m *blueGreenReleaseManager) doCanaryJump(c *RolloutContext) (jumped bool) {
251-
bluegreenStatus := c.NewStatus.BlueGreenStatus
252-
// since we forbid adding or removing steps, currentStepIndex should always be valid
253-
currentStep := c.Rollout.Spec.Strategy.BlueGreen.Steps[bluegreenStatus.CurrentStepIndex-1]
254-
// nextIndex=-1 means the release is done, nextIndex=0 is not used
255-
if nextIndex := bluegreenStatus.NextStepIndex; nextIndex != util.NextBatchIndex(c.Rollout, bluegreenStatus.CurrentStepIndex) && nextIndex > 0 {
256-
currentIndexBackup := bluegreenStatus.CurrentStepIndex
257-
currentStepStateBackup := bluegreenStatus.CurrentStepState
258-
// update the current and next stepIndex
259-
bluegreenStatus.CurrentStepIndex = nextIndex
260-
bluegreenStatus.NextStepIndex = util.NextBatchIndex(c.Rollout, nextIndex)
261-
nextStep := c.Rollout.Spec.Strategy.BlueGreen.Steps[nextIndex-1]
262-
// compare next step and current step to decide the state we should go
263-
if reflect.DeepEqual(nextStep.Replicas, currentStep.Replicas) {
264-
bluegreenStatus.CurrentStepState = v1beta1.CanaryStepStateTrafficRouting
265-
} else {
266-
bluegreenStatus.CurrentStepState = v1beta1.CanaryStepStateInit
267-
}
268-
bluegreenStatus.LastUpdateTime = &metav1.Time{Time: time.Now()}
269-
klog.Infof("rollout(%s/%s) step(%d->%d) state from(%s -> %s)",
270-
c.Rollout.Namespace, c.Rollout.Name,
271-
currentIndexBackup, bluegreenStatus.CurrentStepIndex,
272-
currentStepStateBackup, bluegreenStatus.CurrentStepState)
273-
return true
250+
if c.Workload == nil {
251+
return false
274252
}
275-
return false
253+
return doStepJump(c.Rollout, c.NewStatus, c.Rollout.Spec.Strategy.BlueGreen.Steps, int(c.Workload.Replicas))
276254
}
277255

278256
// cleanup after rollout is completed or finished

pkg/controller/rollout/rollout_canary.go

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package rollout
1919
import (
2020
"context"
2121
"fmt"
22-
"reflect"
2322
"time"
2423

2524
corev1 "k8s.io/api/core/v1"
@@ -313,34 +312,48 @@ func (m *canaryReleaseManager) doCanaryPaused(c *RolloutContext) (bool, error) {
313312
return false, nil
314313
}
315314

316-
func (m *canaryReleaseManager) doCanaryJump(c *RolloutContext) (jumped bool) {
317-
canaryStatus := c.NewStatus.CanaryStatus
318-
// since we forbid adding or removing steps, currentStepIndex should always be valid
319-
currentStep := c.Rollout.Spec.Strategy.Canary.Steps[canaryStatus.CurrentStepIndex-1]
320-
// nextIndex=-1 means the release is done, nextIndex=0 is not used
321-
if nextIndex := canaryStatus.NextStepIndex; nextIndex != util.NextBatchIndex(c.Rollout, canaryStatus.CurrentStepIndex) && nextIndex > 0 {
322-
currentIndexBackup := canaryStatus.CurrentStepIndex
323-
currentStepStateBackup := canaryStatus.CurrentStepState
315+
// doStepJump implements the common logic for both canary and bluegreen rollout strategies
316+
// to handle step jumping based on NextStepIndex.
317+
func doStepJump(rollout *v1beta1.Rollout, newStatus *v1beta1.RolloutStatus, steps []v1beta1.CanaryStep, workloadReplicas int) (jumped bool) {
318+
status := newStatus.GetUnifiedStatus()
319+
if status.IsNil() {
320+
klog.InfoS("doStepJump skipped: unified status is nil")
321+
return false
322+
}
323+
klog.InfoS("will do step jump", "steps", len(steps), "updatedReplicas", *status.UpdatedReplicas,
324+
"nextStepIndex", status.NextStepIndex, "rollout", klog.KObj(rollout))
325+
if nextIndex := status.NextStepIndex; nextIndex != util.NextBatchIndex(rollout, status.CurrentStepIndex) &&
326+
nextIndex > 0 && nextIndex <= int32(len(steps)) {
327+
currentIndexBackup := status.CurrentStepIndex
328+
currentStepStateBackup := status.CurrentStepState
324329
// update the current and next stepIndex
325-
canaryStatus.CurrentStepIndex = nextIndex
326-
canaryStatus.NextStepIndex = util.NextBatchIndex(c.Rollout, nextIndex)
327-
nextStep := c.Rollout.Spec.Strategy.Canary.Steps[nextIndex-1]
330+
status.CurrentStepIndex = nextIndex
331+
status.NextStepIndex = util.NextBatchIndex(rollout, nextIndex)
332+
nextStep := steps[nextIndex-1]
328333
// compare next step and current step to decide the state we should go
329-
if reflect.DeepEqual(nextStep.Replicas, currentStep.Replicas) {
330-
canaryStatus.CurrentStepState = v1beta1.CanaryStepStateTrafficRouting
334+
nextStepReplicas, _ := intstr.GetScaledValueFromIntOrPercent(nextStep.Replicas, workloadReplicas, true)
335+
if int32(nextStepReplicas) == *status.UpdatedReplicas {
336+
status.CurrentStepState = v1beta1.CanaryStepStateTrafficRouting
331337
} else {
332-
canaryStatus.CurrentStepState = v1beta1.CanaryStepStateInit
338+
status.CurrentStepState = v1beta1.CanaryStepStateInit
333339
}
334-
canaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()}
335-
klog.Infof("rollout(%s/%s) step(%d->%d) state from(%s -> %s)",
336-
c.Rollout.Namespace, c.Rollout.Name,
337-
currentIndexBackup, canaryStatus.CurrentStepIndex,
338-
currentStepStateBackup, canaryStatus.CurrentStepState)
340+
status.LastUpdateTime = &metav1.Time{Time: time.Now()}
341+
klog.InfoS("step jumped", "rollout", klog.KObj(rollout),
342+
"oldCurrentIndex", currentIndexBackup, "newCurrentIndex", status.CurrentStepIndex,
343+
"oldCurrentStepState", currentStepStateBackup, "newCurrentStepState", status.CurrentStepState)
339344
return true
340345
}
346+
klog.InfoS("step not jumped")
341347
return false
342348
}
343349

350+
func (m *canaryReleaseManager) doCanaryJump(c *RolloutContext) (jumped bool) {
351+
if c.Workload == nil {
352+
return false
353+
}
354+
return doStepJump(c.Rollout, c.NewStatus, c.Rollout.Spec.Strategy.Canary.Steps, int(c.Workload.Replicas))
355+
}
356+
344357
// cleanup after rollout is completed or finished
345358
func (m *canaryReleaseManager) doCanaryFinalising(c *RolloutContext) (bool, error) {
346359
canaryStatus := c.NewStatus.CanaryStatus

0 commit comments

Comments
 (0)