kruise-tools/pkg/internal/polymorphichelpers/steps.go

80 lines
2.4 KiB
Go

package polymorphichelpers
import (
"fmt"
"github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/klog/v2"
"k8s.io/kubectl/pkg/scheme"
)
func defaultRolloutRollbackGetter(targetStep int32) func(runtime.Object) ([]byte, error) {
return func(obj runtime.Object) ([]byte, error) {
switch rollout := obj.(type) {
case *v1beta1.Rollout:
steps := rollout.Spec.Strategy.GetSteps()
curStep := rollout.Status.CurrentStepIndex
if len(steps) < int(curStep) {
return nil, fmt.Errorf("has %d steps, but current step is too large %d", len(steps), curStep)
}
if curStep <= 1 {
return nil, fmt.Errorf("already at the first step")
}
if targetStep == -1 {
s, err := findPreviousStepWithNoTrafficAndMostReplicas(steps, rollout.Status.CurrentStepIndex)
if err != nil {
return nil, err
}
targetStep = s
}
if targetStep >= rollout.Status.CurrentStepIndex {
return nil, fmt.Errorf("specified step %d is not a previous step (current step is %d)", targetStep, rollout.Status.CurrentStepIndex)
}
style := rollout.Spec.Strategy.GetRollingStyle()
switch style {
case v1beta1.BlueGreenRollingStyle:
rollout.Status.BlueGreenStatus.NextStepIndex = targetStep
default:
// canary and partition
rollout.Status.CanaryStatus.NextStepIndex = targetStep
}
return runtime.Encode(scheme.Codecs.LegacyCodec(v1beta1.GroupVersion), rollout)
default:
return nil, fmt.Errorf("rollback is not supported on given object")
}
}
}
func findPreviousStepWithNoTrafficAndMostReplicas(steps []v1beta1.CanaryStep, curStep int32) (int32, error) {
maxReplicas := 0
var targetStep int32 = -1
for i := curStep - 2; i >= 0; i-- {
step := steps[i]
if hasTraffic(step) {
klog.V(5).InfoS("has traffic", "step", i+1)
continue
}
replicas, _ := intstr.GetScaledValueFromIntOrPercent(step.Replicas, 100, true)
klog.V(5).InfoS("replicas percent", "percent", replicas, "step", i+1, "obj", step)
if replicas > maxReplicas {
maxReplicas = replicas
targetStep = i + 1
}
}
if targetStep == -1 {
return 0, fmt.Errorf("no previous step with no traffic found")
}
return targetStep, nil
}
func hasTraffic(step v1beta1.CanaryStep) bool {
if step.Traffic == nil {
return false
}
is := intstr.FromString(*step.Traffic)
trafficPercent, _ := intstr.GetScaledValueFromIntOrPercent(&is, 100, true)
return trafficPercent != 0
}