80 lines
2.4 KiB
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
|
|
}
|