466 lines
21 KiB
Go
466 lines
21 KiB
Go
/*
|
|
Copyright 2022 The Kruise Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package rollout
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/openkruise/rollouts/api/v1alpha1"
|
|
"github.com/openkruise/rollouts/api/v1beta1"
|
|
"github.com/openkruise/rollouts/pkg/trafficrouting"
|
|
"github.com/openkruise/rollouts/pkg/util"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
|
"k8s.io/klog/v2"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
|
)
|
|
|
|
var defaultGracePeriodSeconds int32 = 3
|
|
|
|
type RolloutContext struct {
|
|
Rollout *v1beta1.Rollout
|
|
NewStatus *v1beta1.RolloutStatus
|
|
// related workload
|
|
Workload *util.Workload
|
|
// reconcile RequeueAfter recheckTime
|
|
RecheckTime *time.Time
|
|
// wait stable workload pods ready
|
|
WaitReady bool
|
|
}
|
|
|
|
// parameter1 retryReconcile, parameter2 error
|
|
func (r *RolloutReconciler) reconcileRolloutProgressing(rollout *v1beta1.Rollout, newStatus *v1beta1.RolloutStatus) (*time.Time, error) {
|
|
cond := util.GetRolloutCondition(rollout.Status, v1beta1.RolloutConditionProgressing)
|
|
klog.Infof("reconcile rollout(%s/%s) progressing action...", rollout.Namespace, rollout.Name)
|
|
workload, err := r.finder.GetWorkloadForRef(rollout)
|
|
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 is inconsistent, then wait a moment", rollout.Namespace, rollout.Name)
|
|
return nil, nil
|
|
}
|
|
rolloutContext := &RolloutContext{Rollout: rollout, NewStatus: newStatus, Workload: workload}
|
|
switch cond.Reason {
|
|
case v1alpha1.ProgressingReasonInitializing:
|
|
klog.Infof("rollout(%s/%s) is Progressing, and in reason(%s)", rollout.Namespace, rollout.Name, cond.Reason)
|
|
// new canaryStatus
|
|
newStatus.CanaryStatus = &v1beta1.CanaryStatus{
|
|
ObservedWorkloadGeneration: rolloutContext.Workload.Generation,
|
|
RolloutHash: rolloutContext.Rollout.Annotations[util.RolloutHashAnnotation],
|
|
ObservedRolloutID: getRolloutID(rolloutContext.Workload),
|
|
StableRevision: rolloutContext.Workload.StableRevision,
|
|
CanaryRevision: rolloutContext.Workload.CanaryRevision,
|
|
CurrentStepIndex: 1,
|
|
CurrentStepState: v1beta1.CanaryStepStateUpgrade,
|
|
LastUpdateTime: &metav1.Time{Time: time.Now()},
|
|
}
|
|
done, err := r.doProgressingInitializing(rolloutContext)
|
|
if err != nil {
|
|
klog.Errorf("rollout(%s/%s) doProgressingInitializing error(%s)", rollout.Namespace, rollout.Name, err.Error())
|
|
return nil, err
|
|
} else if done {
|
|
progressingStateTransition(newStatus, corev1.ConditionTrue, v1alpha1.ProgressingReasonInRolling, "Rollout is in Progressing")
|
|
} else {
|
|
// Incomplete, recheck
|
|
expectedTime := time.Now().Add(time.Duration(defaultGracePeriodSeconds) * time.Second)
|
|
rolloutContext.RecheckTime = &expectedTime
|
|
klog.Infof("rollout(%s/%s) doProgressingInitializing is incomplete, and recheck(%s)", rollout.Namespace, rollout.Name, expectedTime.String())
|
|
}
|
|
|
|
case v1alpha1.ProgressingReasonInRolling:
|
|
klog.Infof("rollout(%s/%s) is Progressing, and in reason(%s)", rollout.Namespace, rollout.Name, cond.Reason)
|
|
err = r.doProgressingInRolling(rolloutContext)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
case v1alpha1.ProgressingReasonFinalising:
|
|
klog.Infof("rollout(%s/%s) is Progressing, and in reason(%s)", rollout.Namespace, rollout.Name, cond.Reason)
|
|
var done bool
|
|
rolloutContext.WaitReady = true
|
|
done, err = r.doFinalising(rolloutContext)
|
|
if err != nil {
|
|
return nil, err
|
|
// finalizer is finished
|
|
} else if done {
|
|
progressingStateTransition(newStatus, corev1.ConditionFalse, v1alpha1.ProgressingReasonCompleted, "Rollout progressing has been completed")
|
|
setRolloutSucceededCondition(newStatus, corev1.ConditionTrue)
|
|
} else {
|
|
// Incomplete, recheck
|
|
expectedTime := time.Now().Add(time.Duration(defaultGracePeriodSeconds) * time.Second)
|
|
rolloutContext.RecheckTime = &expectedTime
|
|
klog.Infof("rollout(%s/%s) doProgressingFinalising is incomplete, and recheck(%s)", rollout.Namespace, rollout.Name, expectedTime.String())
|
|
}
|
|
|
|
case v1alpha1.ProgressingReasonPaused:
|
|
// from paused to rolling progressing
|
|
if !rollout.Spec.Strategy.Paused {
|
|
klog.Infof("rollout(%s/%s) is Progressing, from paused to rolling", rollout.Namespace, rollout.Name)
|
|
progressingStateTransition(newStatus, corev1.ConditionTrue, v1alpha1.ProgressingReasonInRolling, "")
|
|
}
|
|
|
|
case v1alpha1.ProgressingReasonCancelling:
|
|
klog.Infof("rollout(%s/%s) is Progressing, and in reason(%s)", rollout.Namespace, rollout.Name, cond.Reason)
|
|
var done bool
|
|
done, err = r.doFinalising(rolloutContext)
|
|
if err != nil {
|
|
return nil, err
|
|
// finalizer is finished
|
|
} else if done {
|
|
progressingStateTransition(newStatus, corev1.ConditionFalse, v1alpha1.ProgressingReasonCompleted, "Rollout progressing has been cancelled")
|
|
setRolloutSucceededCondition(newStatus, corev1.ConditionFalse)
|
|
} else {
|
|
// Incomplete, recheck
|
|
expectedTime := time.Now().Add(time.Duration(defaultGracePeriodSeconds) * time.Second)
|
|
rolloutContext.RecheckTime = &expectedTime
|
|
klog.Infof("rollout(%s/%s) doProgressingCancelling is incomplete, and recheck(%s)", rollout.Namespace, rollout.Name, expectedTime.String())
|
|
}
|
|
|
|
case v1alpha1.ProgressingReasonCompleted:
|
|
// rollout phase from progressing to healthy
|
|
klog.Infof("rollout(%s/%s) phase is from progressing to healthy", rollout.Namespace, rollout.Name)
|
|
newStatus.Phase = v1beta1.RolloutPhaseHealthy
|
|
}
|
|
|
|
return rolloutContext.RecheckTime, nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) doProgressingInitializing(c *RolloutContext) (bool, error) {
|
|
// Traffic routing
|
|
if len(c.Rollout.Spec.Strategy.Canary.TrafficRoutings) > 0 {
|
|
if err := r.trafficRoutingManager.InitializeTrafficRouting(newTrafficRoutingContext(c)); err != nil {
|
|
return false, err
|
|
}
|
|
}
|
|
|
|
// It is not allowed to modify the rollout.spec in progressing phase (validate webhook rollout),
|
|
// but in many scenarios the user may modify the workload and rollout spec at the same time,
|
|
// and there is a possibility that the workload is released first, and due to some network or other reasons the rollout spec is delayed by a few seconds,
|
|
// so this is mainly compatible with this scenario.
|
|
cond := util.GetRolloutCondition(*c.NewStatus, v1beta1.RolloutConditionProgressing)
|
|
if verifyTime := cond.LastUpdateTime.Add(time.Second * time.Duration(defaultGracePeriodSeconds)); verifyTime.After(time.Now()) {
|
|
klog.Infof("verify rollout(%s/%s) TrafficRouting, and wait a moment", c.Rollout.Namespace, c.Rollout.Name)
|
|
return false, nil
|
|
}
|
|
|
|
// TrafficRouting indicates the gateway traffic routing, and rollout release will trigger the trafficRouting
|
|
if c.Rollout.Annotations[v1alpha1.TrafficRoutingAnnotation] != "" {
|
|
return r.handleTrafficRouting(c.Rollout.Namespace, c.Rollout.Name, c.Rollout.Annotations[v1alpha1.TrafficRoutingAnnotation])
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) doProgressingInRolling(c *RolloutContext) error {
|
|
// Handle the 5 special cases firstly, and we had better keep the order of following cases:
|
|
|
|
switch {
|
|
// 1. In case of rollback in a quick way, un-paused and just use workload rolling strategy
|
|
case isRollingBackDirectly(c.Rollout, c.Workload):
|
|
return r.handleRollbackDirectly(c.Rollout, c.Workload, c.NewStatus)
|
|
|
|
// 2. In case of rollout paused, just stop reconcile
|
|
case isRolloutPaused(c.Rollout):
|
|
return r.handleRolloutPaused(c.Rollout, c.NewStatus)
|
|
|
|
// 3. In case of rollback in a batch way, use rollout step strategy
|
|
case isRollingBackInBatches(c.Rollout, c.Workload):
|
|
return r.handleRollbackInBatches(c.Rollout, c.Workload, c.NewStatus)
|
|
|
|
// 4. In case of continuous publishing(v1 -> v2 -> v3), restart publishing
|
|
case isContinuousRelease(c.Rollout, c.Workload):
|
|
return r.handleContinuousRelease(c)
|
|
|
|
// 5. In case of rollout plan changed, recalculate and publishing
|
|
case isRolloutPlanChanged(c.Rollout):
|
|
return r.handleRolloutPlanChanged(c)
|
|
}
|
|
return r.handleNormalRolling(c)
|
|
}
|
|
|
|
func (r *RolloutReconciler) handleRolloutPaused(rollout *v1beta1.Rollout, newStatus *v1beta1.RolloutStatus) error {
|
|
klog.Infof("rollout(%s/%s) is Progressing, but paused", rollout.Namespace, rollout.Name)
|
|
progressingStateTransition(newStatus, corev1.ConditionTrue, v1alpha1.ProgressingReasonPaused, "Rollout has been paused, you can resume it by kube-cli")
|
|
return nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) handleContinuousRelease(c *RolloutContext) error {
|
|
r.Recorder.Eventf(c.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",
|
|
c.Rollout.Namespace, c.Rollout.Name, c.NewStatus.CanaryStatus.CanaryRevision, c.Workload.CanaryRevision)
|
|
|
|
done, err := r.doProgressingReset(c)
|
|
if err != nil {
|
|
klog.Errorf("rollout(%s/%s) doProgressingReset failed: %s", c.Rollout.Namespace, c.Rollout.Name, err.Error())
|
|
return err
|
|
} else if done {
|
|
c.NewStatus.CanaryStatus = nil
|
|
progressingStateTransition(c.NewStatus, corev1.ConditionTrue, v1alpha1.ProgressingReasonInitializing, "Workload is continuous release")
|
|
klog.Infof("rollout(%s/%s) workload is continuous publishing, reset complete", c.Rollout.Namespace, c.Rollout.Name)
|
|
} else {
|
|
// Incomplete, recheck
|
|
expectedTime := time.Now().Add(time.Duration(defaultGracePeriodSeconds) * time.Second)
|
|
c.RecheckTime = &expectedTime
|
|
klog.Infof("rollout(%s/%s) workload is continuous publishing, reset incomplete, and recheck(%s)", c.Rollout.Namespace, c.Rollout.Name, expectedTime.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) handleRollbackDirectly(rollout *v1beta1.Rollout, workload *util.Workload, newStatus *v1beta1.RolloutStatus) error {
|
|
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 directly, then rollout canceled", rollout.Namespace, rollout.Name)
|
|
progressingStateTransition(newStatus, corev1.ConditionTrue, v1alpha1.ProgressingReasonCancelling, "The workload has been rolled back and the rollout process will be cancelled")
|
|
return nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) handleRollbackInBatches(rollout *v1beta1.Rollout, workload *util.Workload, newStatus *v1beta1.RolloutStatus) error {
|
|
// restart from the beginning
|
|
newStatus.CanaryStatus.CurrentStepIndex = 1
|
|
newStatus.CanaryStatus.CanaryRevision = workload.CanaryRevision
|
|
newStatus.CanaryStatus.CurrentStepState = v1beta1.CanaryStepStateUpgrade
|
|
newStatus.CanaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()}
|
|
newStatus.CanaryStatus.RolloutHash = rollout.Annotations[util.RolloutHashAnnotation]
|
|
klog.Infof("rollout(%s/%s) workload has been rollback in batches, then restart from beginning", rollout.Namespace, rollout.Name)
|
|
return nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) handleRolloutPlanChanged(c *RolloutContext) error {
|
|
newStepIndex, err := r.recalculateCanaryStep(c)
|
|
if err != nil {
|
|
klog.Errorf("rollout(%s/%s) reCalculate Canary StepIndex failed: %s", c.Rollout.Namespace, c.Rollout.Name, err.Error())
|
|
return err
|
|
}
|
|
// canary step configuration change causes current step index change
|
|
c.NewStatus.CanaryStatus.CurrentStepIndex = newStepIndex
|
|
c.NewStatus.CanaryStatus.CurrentStepState = v1beta1.CanaryStepStateUpgrade
|
|
c.NewStatus.CanaryStatus.LastUpdateTime = &metav1.Time{Time: time.Now()}
|
|
c.NewStatus.CanaryStatus.RolloutHash = c.Rollout.Annotations[util.RolloutHashAnnotation]
|
|
klog.Infof("rollout(%s/%s) canary step configuration change, and stepIndex(%d) state(%s)",
|
|
c.Rollout.Namespace, c.Rollout.Name, c.NewStatus.CanaryStatus.CurrentStepIndex, c.NewStatus.CanaryStatus.CurrentStepState)
|
|
return nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) handleNormalRolling(c *RolloutContext) error {
|
|
// check if canary is done
|
|
if c.NewStatus.CanaryStatus.CurrentStepState == v1beta1.CanaryStepStateCompleted {
|
|
klog.Infof("rollout(%s/%s) progressing rolling done", c.Rollout.Namespace, c.Rollout.Name)
|
|
progressingStateTransition(c.NewStatus, corev1.ConditionTrue, v1alpha1.ProgressingReasonFinalising, "Rollout has been completed and some closing work is being done")
|
|
return nil
|
|
}
|
|
return r.canaryManager.runCanary(c)
|
|
}
|
|
|
|
// name is rollout name, tr is trafficRouting name
|
|
func (r *RolloutReconciler) handleTrafficRouting(namespace, name, tr string) (bool, error) {
|
|
obj := &v1alpha1.TrafficRouting{}
|
|
err := r.Get(context.TODO(), client.ObjectKey{Namespace: namespace, Name: tr}, obj)
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
klog.Warningf("rollout(%s/%s) trafficRouting(%s) Not Found, and wait a moment", namespace, name, tr)
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|
|
if controllerutil.ContainsFinalizer(obj, util.ProgressingRolloutFinalizer(name)) {
|
|
return true, nil
|
|
}
|
|
if obj.Status.Phase == v1alpha1.TrafficRoutingPhaseFinalizing || obj.Status.Phase == v1alpha1.TrafficRoutingPhaseTerminating {
|
|
klog.Infof("rollout(%s/%s) trafficRouting(%s) phase(%s), and wait a moment", namespace, name, tr, obj.Status.Phase)
|
|
return false, nil
|
|
}
|
|
err = util.UpdateFinalizer(r.Client, obj, util.AddFinalizerOpType, util.ProgressingRolloutFinalizer(name))
|
|
if err != nil {
|
|
klog.Errorf("rollout(%s/%s) add trafficRouting(%s) finalizer failed: %s", namespace, name, tr, err.Error())
|
|
return false, err
|
|
}
|
|
klog.Infof("rollout(%s/%s) add trafficRouting(%s) finalizer(%s) success", namespace, name, tr, util.ProgressingRolloutFinalizer(name))
|
|
return false, nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) finalizeTrafficRouting(namespace, name, tr string) error {
|
|
obj := &v1alpha1.TrafficRouting{}
|
|
err := r.Get(context.TODO(), client.ObjectKey{Namespace: namespace, Name: tr}, obj)
|
|
if err != nil {
|
|
if errors.IsNotFound(err) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
// progressing.rollouts.kruise.io/rollout-b
|
|
finalizer := util.ProgressingRolloutFinalizer(name)
|
|
if controllerutil.ContainsFinalizer(obj, finalizer) {
|
|
err = util.UpdateFinalizer(r.Client, obj, util.RemoveFinalizerOpType, finalizer)
|
|
if err != nil {
|
|
klog.Errorf("rollout(%s/%s) remove trafficRouting(%s) finalizer failed: %s", namespace, name, tr, err.Error())
|
|
return err
|
|
}
|
|
klog.Infof("rollout(%s/%s) remove trafficRouting(%s) remove finalizer(%s) success", namespace, name, tr, finalizer)
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|
|
|
|
/*
|
|
**********************************************************************
|
|
|
|
help functions
|
|
|
|
***********************************************************************
|
|
*/
|
|
func isRolloutPaused(rollout *v1beta1.Rollout) bool {
|
|
return rollout.Spec.Strategy.Paused
|
|
}
|
|
|
|
func isRolloutPlanChanged(rollout *v1beta1.Rollout) bool {
|
|
status := &rollout.Status
|
|
return status.CanaryStatus.RolloutHash != "" && status.CanaryStatus.RolloutHash != rollout.Annotations[util.RolloutHashAnnotation]
|
|
}
|
|
|
|
func isContinuousRelease(rollout *v1beta1.Rollout, workload *util.Workload) bool {
|
|
status := &rollout.Status
|
|
return status.CanaryStatus.CanaryRevision != "" && workload.CanaryRevision != status.CanaryStatus.CanaryRevision && !workload.IsInRollback
|
|
}
|
|
|
|
func isRollingBackDirectly(rollout *v1beta1.Rollout, workload *util.Workload) bool {
|
|
status := &rollout.Status
|
|
inBatch := util.IsRollbackInBatchPolicy(rollout, workload.Labels)
|
|
return workload.IsInRollback && workload.CanaryRevision != status.CanaryStatus.CanaryRevision && !inBatch
|
|
}
|
|
|
|
func isRollingBackInBatches(rollout *v1beta1.Rollout, workload *util.Workload) bool {
|
|
status := &rollout.Status
|
|
inBatch := util.IsRollbackInBatchPolicy(rollout, workload.Labels)
|
|
return workload.IsInRollback && workload.CanaryRevision != status.CanaryStatus.CanaryRevision && inBatch
|
|
}
|
|
|
|
// 1. modify network api(ingress or gateway api) configuration, and route 100% traffic to stable pods
|
|
// 2. remove batchRelease CR.
|
|
func (r *RolloutReconciler) doProgressingReset(c *RolloutContext) (bool, error) {
|
|
if len(c.Rollout.Spec.Strategy.Canary.TrafficRoutings) > 0 {
|
|
// modify network api(ingress or gateway api) configuration, and route 100% traffic to stable pods
|
|
tr := newTrafficRoutingContext(c)
|
|
done, err := r.trafficRoutingManager.FinalisingTrafficRouting(tr, false)
|
|
c.NewStatus.CanaryStatus.LastUpdateTime = tr.LastUpdateTime
|
|
if err != nil || !done {
|
|
return done, err
|
|
}
|
|
}
|
|
done, err := r.canaryManager.removeBatchRelease(c)
|
|
if err != nil {
|
|
klog.Errorf("rollout(%s/%s) DoFinalising batchRelease failed: %s", c.Rollout.Namespace, c.Rollout.Name, err.Error())
|
|
return false, err
|
|
} else if !done {
|
|
return false, nil
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) recalculateCanaryStep(c *RolloutContext) (int32, error) {
|
|
batch, err := r.canaryManager.fetchBatchRelease(c.Rollout.Namespace, c.Rollout.Name)
|
|
if errors.IsNotFound(err) {
|
|
return 1, nil
|
|
} else if err != nil {
|
|
return 0, err
|
|
}
|
|
currentReplicas, _ := intstr.GetScaledValueFromIntOrPercent(&batch.Spec.ReleasePlan.Batches[*batch.Spec.ReleasePlan.BatchPartition].CanaryReplicas, int(c.Workload.Replicas), true)
|
|
var stepIndex int32
|
|
for i := range c.Rollout.Spec.Strategy.Canary.Steps {
|
|
step := c.Rollout.Spec.Strategy.Canary.Steps[i]
|
|
var desiredReplicas int
|
|
desiredReplicas, _ = intstr.GetScaledValueFromIntOrPercent(step.Replicas, int(c.Workload.Replicas), true)
|
|
stepIndex = int32(i + 1)
|
|
if currentReplicas <= desiredReplicas {
|
|
break
|
|
}
|
|
}
|
|
return stepIndex, nil
|
|
}
|
|
|
|
func (r *RolloutReconciler) doFinalising(c *RolloutContext) (bool, error) {
|
|
klog.Infof("reconcile rollout(%s/%s) doFinalising", c.Rollout.Namespace, c.Rollout.Name)
|
|
// TrafficRouting indicates the gateway traffic routing, and rollout finalizer will trigger the trafficRouting finalizer
|
|
if c.Rollout.Annotations[v1alpha1.TrafficRoutingAnnotation] != "" {
|
|
err := r.finalizeTrafficRouting(c.Rollout.Namespace, c.Rollout.Name, c.Rollout.Annotations[v1alpha1.TrafficRoutingAnnotation])
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
}
|
|
done, err := r.canaryManager.doCanaryFinalising(c)
|
|
if err != nil {
|
|
klog.Errorf("rollout(%s/%s) Progressing failed: %s", c.Rollout.Namespace, c.Rollout.Name, err.Error())
|
|
return false, err
|
|
} else if !done {
|
|
klog.Infof("rollout(%s/%s) finalizer is not finished, and retry reconcile", c.Rollout.Namespace, c.Rollout.Name)
|
|
return false, nil
|
|
}
|
|
klog.Infof("run rollout(%s/%s) Progressing Finalising done", c.Rollout.Namespace, c.Rollout.Name)
|
|
return true, nil
|
|
}
|
|
|
|
func progressingStateTransition(status *v1beta1.RolloutStatus, condStatus corev1.ConditionStatus, reason, message string) {
|
|
cond := util.GetRolloutCondition(*status, v1beta1.RolloutConditionProgressing)
|
|
if cond == nil {
|
|
cond = util.NewRolloutCondition(v1beta1.RolloutConditionProgressing, condStatus, reason, message)
|
|
} else {
|
|
cond.Status = condStatus
|
|
cond.Reason = reason
|
|
if message != "" {
|
|
cond.Message = message
|
|
}
|
|
}
|
|
util.SetRolloutCondition(status, *cond)
|
|
status.Message = cond.Message
|
|
}
|
|
|
|
func setRolloutSucceededCondition(status *v1beta1.RolloutStatus, condStatus corev1.ConditionStatus) {
|
|
cond := util.GetRolloutCondition(*status, v1beta1.RolloutConditionSucceeded)
|
|
if cond == nil {
|
|
cond = util.NewRolloutCondition(v1beta1.RolloutConditionSucceeded, condStatus, "", "")
|
|
} else {
|
|
cond.Status = condStatus
|
|
}
|
|
util.SetRolloutCondition(status, *cond)
|
|
}
|
|
|
|
func newTrafficRoutingContext(c *RolloutContext) *trafficrouting.TrafficRoutingContext {
|
|
currentStep := c.Rollout.Spec.Strategy.Canary.Steps[c.NewStatus.CanaryStatus.CurrentStepIndex-1]
|
|
var revisionLabelKey string
|
|
if c.Workload != nil {
|
|
revisionLabelKey = c.Workload.RevisionLabelKey
|
|
}
|
|
return &trafficrouting.TrafficRoutingContext{
|
|
Key: fmt.Sprintf("Rollout(%s/%s)", c.Rollout.Namespace, c.Rollout.Name),
|
|
Namespace: c.Rollout.Namespace,
|
|
ObjectRef: c.Rollout.Spec.Strategy.Canary.TrafficRoutings,
|
|
Strategy: currentStep.TrafficRoutingStrategy,
|
|
OwnerRef: *metav1.NewControllerRef(c.Rollout, rolloutControllerKind),
|
|
RevisionLabelKey: revisionLabelKey,
|
|
StableRevision: c.NewStatus.CanaryStatus.StableRevision,
|
|
CanaryRevision: c.NewStatus.CanaryStatus.PodTemplateHash,
|
|
LastUpdateTime: c.NewStatus.CanaryStatus.LastUpdateTime,
|
|
}
|
|
}
|