rollouts/test/e2e/rollout_test.go

5989 lines
275 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 e2e
import (
"context"
"fmt"
"sort"
"strings"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
appsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
appsv1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/util"
apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
netv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/util/retry"
"k8s.io/klog/v2"
utilpointer "k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
)
const (
nginxIngressAnnotationDefaultPrefix = "nginx.ingress.kubernetes.io"
OriginalSpecAnnotation = "rollouts.kruise.io/original-spec-configuration"
)
var _ = SIGDescribe("Rollout", func() {
var namespace string
DumpAllResources := func() {
rollout := &v1alpha1.RolloutList{}
k8sClient.List(context.TODO(), rollout, client.InNamespace(namespace))
fmt.Println(util.DumpJSON(rollout))
batch := &v1alpha1.BatchReleaseList{}
k8sClient.List(context.TODO(), batch, client.InNamespace(namespace))
fmt.Println(util.DumpJSON(batch))
deploy := &apps.DeploymentList{}
k8sClient.List(context.TODO(), deploy, client.InNamespace(namespace))
fmt.Println(util.DumpJSON(deploy))
rs := &apps.ReplicaSetList{}
k8sClient.List(context.TODO(), rs, client.InNamespace(namespace))
fmt.Println(util.DumpJSON(rs))
cloneSet := &appsv1alpha1.CloneSetList{}
k8sClient.List(context.TODO(), cloneSet, client.InNamespace(namespace))
fmt.Println(util.DumpJSON(cloneSet))
sts := &apps.StatefulSetList{}
k8sClient.List(context.TODO(), sts, client.InNamespace(namespace))
fmt.Println(util.DumpJSON(sts))
asts := &appsv1beta1.StatefulSetList{}
k8sClient.List(context.TODO(), asts, client.InNamespace(namespace))
fmt.Println(util.DumpJSON(asts))
}
CreateObject := func(object client.Object, options ...client.CreateOption) {
object.SetNamespace(namespace)
Expect(k8sClient.Create(context.TODO(), object)).NotTo(HaveOccurred())
}
GetObject := func(name string, object client.Object) error {
key := types.NamespacedName{Namespace: namespace, Name: name}
return k8sClient.Get(context.TODO(), key, object)
}
UpdateDeployment := func(object *apps.Deployment) *apps.Deployment {
var clone *apps.Deployment
Expect(retry.RetryOnConflict(retry.DefaultRetry, func() error {
clone = &apps.Deployment{}
err := GetObject(object.Name, clone)
if err != nil {
return err
}
clone.Spec.Replicas = utilpointer.Int32(*object.Spec.Replicas)
clone.Spec.Template = *object.Spec.Template.DeepCopy()
clone.Labels = mergeMap(clone.Labels, object.Labels)
clone.Annotations = mergeMap(clone.Annotations, object.Annotations)
clone.Spec.Paused = object.Spec.Paused
return k8sClient.Update(context.TODO(), clone)
})).NotTo(HaveOccurred())
return clone
}
UpdateCloneSet := func(object *appsv1alpha1.CloneSet) *appsv1alpha1.CloneSet {
var clone *appsv1alpha1.CloneSet
Expect(retry.RetryOnConflict(retry.DefaultRetry, func() error {
clone = &appsv1alpha1.CloneSet{}
err := GetObject(object.Name, clone)
if err != nil {
return err
}
clone.Spec.Replicas = utilpointer.Int32(*object.Spec.Replicas)
clone.Spec.Template = *object.Spec.Template.DeepCopy()
clone.Labels = mergeMap(clone.Labels, object.Labels)
clone.Annotations = mergeMap(clone.Annotations, object.Annotations)
return k8sClient.Update(context.TODO(), clone)
})).NotTo(HaveOccurred())
return clone
}
UpdateDaemonSet := func(object *appsv1alpha1.DaemonSet) *appsv1alpha1.DaemonSet {
var daemon *appsv1alpha1.DaemonSet
Expect(retry.RetryOnConflict(retry.DefaultRetry, func() error {
daemon = &appsv1alpha1.DaemonSet{}
err := GetObject(object.Name, daemon)
if err != nil {
return err
}
// daemon.Spec.Replicas = utilpointer.Int32(*object.Spec.Replicas)
daemon.Spec.Template = *object.Spec.Template.DeepCopy()
daemon.Spec.UpdateStrategy = *object.Spec.UpdateStrategy.DeepCopy()
daemon.Labels = mergeMap(daemon.Labels, object.Labels)
daemon.Annotations = mergeMap(daemon.Annotations, object.Annotations)
return k8sClient.Update(context.TODO(), daemon)
})).NotTo(HaveOccurred())
return daemon
}
UpdateNativeStatefulSet := func(object *apps.StatefulSet) *apps.StatefulSet {
var clone *apps.StatefulSet
Expect(retry.RetryOnConflict(retry.DefaultRetry, func() error {
clone = &apps.StatefulSet{}
err := GetObject(object.Name, clone)
if err != nil {
return err
}
clone.Spec.Replicas = utilpointer.Int32(*object.Spec.Replicas)
clone.Spec.Template = *object.Spec.Template.DeepCopy()
clone.Labels = mergeMap(clone.Labels, object.Labels)
clone.Annotations = mergeMap(clone.Annotations, object.Annotations)
return k8sClient.Update(context.TODO(), clone)
})).NotTo(HaveOccurred())
return clone
}
UpdateAdvancedStatefulSet := func(object *appsv1beta1.StatefulSet) *appsv1beta1.StatefulSet {
var clone *appsv1beta1.StatefulSet
Expect(retry.RetryOnConflict(retry.DefaultRetry, func() error {
clone = &appsv1beta1.StatefulSet{}
err := GetObject(object.Name, clone)
if err != nil {
return err
}
clone.Spec.Replicas = utilpointer.Int32(*object.Spec.Replicas)
clone.Spec.Template = *object.Spec.Template.DeepCopy()
clone.Labels = mergeMap(clone.Labels, object.Labels)
clone.Annotations = mergeMap(clone.Annotations, object.Annotations)
return k8sClient.Update(context.TODO(), clone)
})).NotTo(HaveOccurred())
return clone
}
UpdateRollout := func(object *v1alpha1.Rollout) *v1alpha1.Rollout {
var clone *v1alpha1.Rollout
Expect(retry.RetryOnConflict(retry.DefaultRetry, func() error {
clone = &v1alpha1.Rollout{}
err := GetObject(object.Name, clone)
if err != nil {
return err
}
clone.Spec = *object.Spec.DeepCopy()
return k8sClient.Update(context.TODO(), clone)
})).NotTo(HaveOccurred())
return clone
}
ResumeRolloutCanary := func(name string) {
Eventually(func() bool {
clone := &v1alpha1.Rollout{}
Expect(GetObject(name, clone)).NotTo(HaveOccurred())
if clone.Status.CanaryStatus.CurrentStepState != v1alpha1.CanaryStepStatePaused {
fmt.Println("resume rollout success, and CurrentStepState", util.DumpJSON(clone.Status))
return true
}
body := fmt.Sprintf(`{"status":{"canaryStatus":{"currentStepState":"%s"}}}`, v1alpha1.CanaryStepStateReady)
Expect(k8sClient.Status().Patch(context.TODO(), clone, client.RawPatch(types.MergePatchType, []byte(body)))).NotTo(HaveOccurred())
return false
}, 10*time.Second, time.Second).Should(BeTrue())
}
WaitDeploymentAllPodsReady := func(deployment *apps.Deployment) {
Eventually(func() bool {
clone := &apps.Deployment{}
Expect(GetObject(deployment.Name, clone)).NotTo(HaveOccurred())
return clone.Status.ObservedGeneration == clone.Generation && *clone.Spec.Replicas == clone.Status.UpdatedReplicas &&
*clone.Spec.Replicas == clone.Status.ReadyReplicas && *clone.Spec.Replicas == clone.Status.Replicas
}, 5*time.Minute, time.Second).Should(BeTrue())
}
WaitCloneSetAllPodsReady := func(cloneset *appsv1alpha1.CloneSet) {
Eventually(func() bool {
clone := &appsv1alpha1.CloneSet{}
Expect(GetObject(cloneset.Name, clone)).NotTo(HaveOccurred())
return clone.Status.ObservedGeneration == clone.Generation && *clone.Spec.Replicas == clone.Status.UpdatedReplicas &&
*clone.Spec.Replicas == clone.Status.ReadyReplicas && *clone.Spec.Replicas == clone.Status.Replicas
}, 5*time.Minute, time.Second).Should(BeTrue())
}
WaitNativeStatefulSetPodsReady := func(statefulset *apps.StatefulSet) {
Eventually(func() bool {
set := &apps.StatefulSet{}
Expect(GetObject(statefulset.Name, set)).NotTo(HaveOccurred())
return set.Status.ObservedGeneration == set.Generation && *set.Spec.Replicas == set.Status.UpdatedReplicas &&
*set.Spec.Replicas == set.Status.ReadyReplicas && *set.Spec.Replicas == set.Status.Replicas
}, 20*time.Minute, 3*time.Second).Should(BeTrue())
}
WaitAdvancedStatefulSetPodsReady := func(statefulset *appsv1beta1.StatefulSet) {
Eventually(func() bool {
set := &appsv1beta1.StatefulSet{}
Expect(GetObject(statefulset.Name, set)).NotTo(HaveOccurred())
return set.Status.ObservedGeneration == set.Generation && *set.Spec.Replicas == set.Status.UpdatedReplicas &&
*set.Spec.Replicas == set.Status.ReadyReplicas && *set.Spec.Replicas == set.Status.Replicas
}, 20*time.Minute, 3*time.Second).Should(BeTrue())
}
WaitDaemonSetAllPodsReady := func(daemonset *appsv1alpha1.DaemonSet) {
Eventually(func() bool {
daemon := &appsv1alpha1.DaemonSet{}
Expect(GetObject(daemonset.Name, daemon)).NotTo(HaveOccurred())
klog.Infof("DaemonSet updateStrategy(%s) Generation(%d) ObservedGeneration(%d) DesiredNumberScheduled(%d) UpdatedNumberScheduled(%d) NumberReady(%d)",
util.DumpJSON(daemon.Spec.UpdateStrategy), daemon.Generation, daemon.Status.ObservedGeneration, daemon.Status.DesiredNumberScheduled, daemon.Status.UpdatedNumberScheduled, daemon.Status.NumberReady)
return daemon.Status.ObservedGeneration == daemon.Generation && daemon.Status.DesiredNumberScheduled == daemon.Status.UpdatedNumberScheduled && daemon.Status.DesiredNumberScheduled == daemon.Status.NumberReady
}, 5*time.Minute, time.Second).Should(BeTrue())
}
WaitDeploymentReplicas := func(deployment *apps.Deployment) {
Eventually(func() bool {
clone := &apps.Deployment{}
Expect(GetObject(deployment.Name, clone)).NotTo(HaveOccurred())
return clone.Status.ObservedGeneration == clone.Generation &&
*clone.Spec.Replicas == clone.Status.ReadyReplicas && *clone.Spec.Replicas == clone.Status.Replicas
}, 10*time.Minute, time.Second).Should(BeTrue())
}
WaitRolloutCanaryStepPaused := func(name string, stepIndex int32) {
start := time.Now()
Eventually(func() bool {
if start.Add(time.Minute * 5).Before(time.Now()) {
DumpAllResources()
Expect(true).Should(BeFalse())
}
clone := &v1alpha1.Rollout{}
Expect(GetObject(name, clone)).NotTo(HaveOccurred())
if clone.Status.CanaryStatus == nil {
return false
}
klog.Infof("current step:%v target step:%v current step state %v", clone.Status.CanaryStatus.CurrentStepIndex, stepIndex, clone.Status.CanaryStatus.CurrentStepState)
return clone.Status.CanaryStatus.CurrentStepIndex == stepIndex && clone.Status.CanaryStatus.CurrentStepState == v1alpha1.CanaryStepStatePaused
}, 20*time.Minute, time.Second).Should(BeTrue())
}
WaitRolloutStatusPhase := func(name string, phase v1alpha1.RolloutPhase) {
Eventually(func() bool {
clone := &v1alpha1.Rollout{}
Expect(GetObject(name, clone)).NotTo(HaveOccurred())
return clone.Status.Phase == phase
}, 20*time.Minute, time.Second).Should(BeTrue())
}
WaitRolloutWorkloadGeneration := func(name string, generation int64) {
Eventually(func() bool {
clone := &v1alpha1.Rollout{}
Expect(GetObject(name, clone)).NotTo(HaveOccurred())
return clone.Status.CanaryStatus.ObservedWorkloadGeneration == generation
}, time.Minute, time.Second).Should(BeTrue())
}
WaitRolloutNotFound := func(name string) {
Eventually(func() bool {
clone := &v1alpha1.Rollout{}
err := GetObject(name, clone)
if err == nil {
return false
} else if errors.IsNotFound(err) {
return true
} else {
Expect(err).NotTo(HaveOccurred())
return false
}
}, 5*time.Minute, time.Second).Should(BeTrue())
}
GetCanaryDeployment := func(stable *apps.Deployment) (*apps.Deployment, error) {
canaryList := &apps.DeploymentList{}
selector, _ := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{util.CanaryDeploymentLabel: stable.Name}})
err := k8sClient.List(context.TODO(), canaryList, &client.ListOptions{Namespace: stable.Namespace, LabelSelector: selector})
if err != nil {
return nil, err
} else if len(canaryList.Items) == 0 {
return nil, nil
}
sort.Slice(canaryList.Items, func(i, j int) bool {
return canaryList.Items[j].CreationTimestamp.Before(&canaryList.Items[i].CreationTimestamp)
})
return &canaryList.Items[0], nil
}
ListPods := func(namespace string, labelSelector *metav1.LabelSelector) ([]*v1.Pod, error) {
appList := &v1.PodList{}
selector, _ := metav1.LabelSelectorAsSelector(labelSelector)
err := k8sClient.List(context.TODO(), appList, &client.ListOptions{Namespace: namespace, LabelSelector: selector})
if err != nil {
return nil, err
}
apps := make([]*v1.Pod, 0)
for i := range appList.Items {
pod := &appList.Items[i]
if pod.DeletionTimestamp.IsZero() {
apps = append(apps, pod)
}
}
return apps, nil
}
CheckPodBatchLabel := func(namespace string, labelSelector *metav1.LabelSelector, rolloutID, batchID string, expected int) {
pods, err := ListPods(namespace, labelSelector)
Expect(err).NotTo(HaveOccurred())
count := 0
for _, pod := range pods {
if pod.Labels[v1alpha1.RolloutIDLabel] == rolloutID &&
pod.Labels[v1alpha1.RolloutBatchIDLabel] == batchID {
count++
}
}
Expect(count).Should(BeNumerically("==", expected))
}
ListReplicaSet := func(d *apps.Deployment) []*apps.ReplicaSet {
var rss []*apps.ReplicaSet
rsLister := &apps.ReplicaSetList{}
selectorOpt, _ := metav1.LabelSelectorAsSelector(d.Spec.Selector)
err := k8sClient.List(context.TODO(), rsLister, &client.ListOptions{LabelSelector: selectorOpt, Namespace: d.Namespace})
Expect(err).NotTo(HaveOccurred())
for i := range rsLister.Items {
rs := &rsLister.Items[i]
if !rs.DeletionTimestamp.IsZero() {
continue
}
rss = append(rss, rs)
}
return rss
}
GetStableRSRevision := func(d *apps.Deployment) string {
rss := ListReplicaSet(d)
_, stable := util.FindCanaryAndStableReplicaSet(rss, d)
if stable != nil {
return stable.Labels[apps.DefaultDeploymentUniqueLabelKey]
}
return ""
}
GetCanaryRSRevision := func(d *apps.Deployment) string {
rss := ListReplicaSet(d)
canary, _ := util.FindCanaryAndStableReplicaSet(rss, d)
if canary != nil {
return canary.Labels[apps.DefaultDeploymentUniqueLabelKey]
}
return ""
}
BeforeEach(func() {
namespace = randomNamespaceName("rollout")
ns := v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
Expect(k8sClient.Create(context.TODO(), &ns)).Should(SatisfyAny(BeNil()))
})
AfterEach(func() {
By("[TEST] Clean up resources after an integration test")
k8sClient.DeleteAllOf(context.TODO(), &apps.Deployment{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(context.TODO(), &appsv1alpha1.CloneSet{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(context.TODO(), &v1alpha1.BatchRelease{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(context.TODO(), &v1alpha1.Rollout{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(context.TODO(), &v1.Service{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(context.TODO(), &netv1.Ingress{}, client.InNamespace(namespace))
Expect(k8sClient.Delete(context.TODO(), &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}, client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
time.Sleep(time.Second * 3)
})
KruiseDescribe("Deployment canary rollout with Ingress", func() {
It("Deployment V1->V2: Percentage 20%,40%,60%,80%,90%, and replicas=3", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(80),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(90),
},
},
}
rollout.Spec.Strategy.Canary.PatchPodTemplateMetadata = &v1alpha1.PatchPodTemplateMetadata{
Labels: map[string]string{"pod": "canary"},
Annotations: map[string]string{"pod": "canary"},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(3)
workload.Spec.Template.Labels["pod"] = "stable"
workload.Spec.Template.Annotations = map[string]string{
"pod": "stable",
}
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 1))
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("20"))
canaryWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(canaryWorkload.Spec.Template.Annotations["pod"]).Should(Equal("canary"))
Expect(canaryWorkload.Spec.Template.Labels["pod"]).Should(Equal("canary"))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2))
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("40"))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(3)")
WaitRolloutCanaryStepPaused(rollout.Name, 3)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2))
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("60"))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(4)")
WaitRolloutCanaryStepPaused(rollout.Name, 4)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 3))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 3))
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("80"))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(5)")
WaitRolloutCanaryStepPaused(rollout.Name, 5)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 3))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 3))
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("90"))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage 20%,60% Succeeded", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
replicas := intstr.FromInt(2)
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Replicas: &replicas,
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 0))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
By("check deployment status & paused success")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check stable, canary service & ingress
// canary deployment
cWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err := finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 2))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 2))
for _, env := range cWorkload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// stable service
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check stable, canary service & ingress
// canary ingress
cIngress = &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[1].Weight)))
// canary deployment
cWorkload, err = GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 3))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 3))
// stable deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 0))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
rss, err = finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
Expect(rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
// scale up replicas 5 -> 6
workload.Spec.Replicas = utilpointer.Int32(6)
UpdateDeployment(workload)
By("Update deployment replicas from(5) -> to(6)")
time.Sleep(time.Second * 2)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage 20%, and rollback-v1", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
pods, err := ListPods(workload.Name, workload.Spec.Selector)
Expect(err).NotTo(HaveOccurred())
appNames := make(map[string]struct{})
for _, app := range pods {
appNames[app.Name] = struct{}{}
}
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 0))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
By("check deployment status & paused success")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// rollback -> v1
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version1"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Rollback deployment env NODE_NAME from(version2) -> to(version1)")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
klog.Infof("rollout(%s) completed, and check", namespace)
time.Sleep(time.Second * 10)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version1"))
}
}
// deployment pods not changed
cpods, err := ListPods(workload.Name, workload.Spec.Selector)
Expect(err).NotTo(HaveOccurred())
cappNames := make(map[string]struct{})
for _, pod := range cpods {
cappNames[pod.Name] = struct{}{}
}
Expect(cappNames).Should(Equal(appNames))
// check progressing canceled
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage 20%,40% and continuous release v3", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 0))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
By("check deployment status & paused success")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// canary deployment
cWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err := finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevisionV1 := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevisionV1))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
time.Sleep(time.Second * 15)
// v1 -> v2 -> v3, continuous release
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version3"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version2) -> to(version3)")
time.Sleep(time.Second * 2)
// wait step 0 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
cWorkload, err = GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err = finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevisionV2 := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevisionV2))
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevisionV2))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// canary deployment
cWorkload, err = GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 1))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 1))
for _, env := range cWorkload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version3"))
}
}
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
klog.Infof("rollout(%s) completed, and check", namespace)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version3"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage 20%,40% and scale up replicas from(5) -> to(10)", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(0),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
By("check deployment status & paused success")
// wait step 2 complete
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// canary deployment
cWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err := finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision))
// scale up replicas, 5 -> 10
workload.Spec.Replicas = utilpointer.Int32(10)
UpdateDeployment(workload)
time.Sleep(time.Second * 3)
cWorkload, _ = GetCanaryDeployment(workload)
WaitDeploymentAllPodsReady(cWorkload)
time.Sleep(time.Second * 5)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 4))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 4))
Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(v1alpha1.CanaryStepStatePaused))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
klog.Infof("rollout(%s) completed, and check", namespace)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage 20%,40%, and scale down replicas from(10) -> to(5)", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(0),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(10)
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
By("check deployment status & paused success")
// wait step 3 complete
WaitRolloutCanaryStepPaused(rollout.Name, 3)
// canary deployment
cWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err := finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 3))
// scale up replicas, 10 -> 5
workload.Spec.Replicas = utilpointer.Int32(5)
UpdateDeployment(workload)
time.Sleep(time.Second * 3)
WaitDeploymentReplicas(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 3))
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 6))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 6))
Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(v1alpha1.CanaryStepStatePaused))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage 20%,40%, paused and resume", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(5),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(5),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(5),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(80),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(5),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(0),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// deployment
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 3)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
By("check deployment status & paused success")
// paused rollout
time.Sleep(time.Second * 10)
rollout.Spec.Strategy.Paused = true
UpdateRollout(rollout)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
cIndex := rollout.Status.CanaryStatus.CurrentStepIndex
time.Sleep(time.Second * 15)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonPaused))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", cIndex))
// resume rollout
rollout.Spec.Strategy.Paused = false
UpdateRollout(rollout)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
klog.Infof("rollout(%s) completed, and check", namespace)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage 20%,40%, but delete rollout crd", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// deployment
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 3)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
By("check deployment status & paused success")
// delete rollout
Expect(k8sClient.DeleteAllOf(context.TODO(), &v1alpha1.Rollout{}, client.InNamespace(namespace), client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
WaitRolloutNotFound(rollout.Name)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
workload.Spec.Paused = false
UpdateDeployment(workload)
By("Update deployment paused=false")
WaitDeploymentAllPodsReady(workload)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
})
It("V1->V2: Percentage 20% v2 failed image, and v3 succeed image", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(5),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(5),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(5),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// deployment
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Image = "echoserver:failed"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment image from(v1.0.0) -> to(failed)")
time.Sleep(time.Second * 3)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
By("check deployment status & paused success")
time.Sleep(time.Second * 10)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 0))
Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(v1alpha1.CanaryStepStateUpgrade))
// update success image, v3
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version3"})
workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:latest"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment image from(v2) -> to(v3)")
// wait rollout complete
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
klog.Infof("rollout(%s) completed, and check", namespace)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version3"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage, 20%,40%,60%,80%,100%, steps changed v1", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(10)
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment image from(version1) -> to(version2)")
time.Sleep(time.Second * 3)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// update rollout step configuration
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(10),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(30),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(5),
},
},
}
rollout = UpdateRollout(rollout)
By("update rollout configuration, and wait rollout next step(2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 2)
batch := &v1alpha1.BatchRelease{}
Expect(GetObject(rollout.Name, batch)).NotTo(HaveOccurred())
// canary deployment
cWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err := finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 2))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[1].Weight)))
// canary deployment
cWorkload, err = GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 3))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 3))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
// wait rollout complete
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
klog.Infof("rollout(%s) completed, and check", namespace)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: A/B testing, header & cookies", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
headerType := gatewayv1alpha2.HeaderMatchRegularExpression
replica1 := intstr.FromInt(1)
replica2 := intstr.FromInt(2)
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Matches: []v1alpha1.HttpRouteMatch{
{
Headers: []gatewayv1alpha2.HTTPHeaderMatch{
{
Type: &headerType,
Name: "user_id",
Value: "123456",
},
},
},
{
Headers: []gatewayv1alpha2.HTTPHeaderMatch{
{
Name: "canary-by-cookie",
Value: "demo",
},
},
},
},
},
Pause: v1alpha1.RolloutPause{},
Replicas: &replica1,
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(30),
},
Replicas: &replica2,
Pause: v1alpha1.RolloutPause{},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(3)
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment image from(version1) -> to(version2)")
time.Sleep(time.Second * 3)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// canary deployment
cWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err := finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-by-header", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("user_id"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-by-header-pattern", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("123456"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-by-cookie", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("demo"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(""))
// canary deployment
cWorkload, err = GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 1))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 1))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
// wait step 2 complete
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// canary ingress
cIngress = &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-by-header", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(""))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-by-header-pattern", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(""))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-by-cookie", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(""))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("30"))
// canary deployment
cWorkload, err = GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 2))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 2))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
// wait rollout complete
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
klog.Infof("rollout(%s) completed, and check", namespace)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: A/B testing, aliyun-alb, header & cookies", func() {
finder := util.NewControllerFinder(k8sClient)
configmap := &v1.ConfigMap{}
Expect(ReadYamlToObject("./test_data/rollout/rollout-configuration.yaml", configmap)).ToNot(HaveOccurred())
Expect(k8sClient.Create(context.TODO(), configmap)).NotTo(HaveOccurred())
defer k8sClient.Delete(context.TODO(), configmap)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
replica1 := intstr.FromInt(1)
replica2 := intstr.FromInt(2)
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Matches: []v1alpha1.HttpRouteMatch{
{
Headers: []gatewayv1alpha2.HTTPHeaderMatch{
{
Name: "Cookie",
Value: "demo1=value1;demo2=value2",
},
{
Name: "SourceIp",
Value: "192.168.0.0/16;172.16.0.0/16",
},
{
Name: "headername",
Value: "headervalue1;headervalue2",
},
},
},
},
},
Pause: v1alpha1.RolloutPause{},
Replicas: &replica1,
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(30),
},
Replicas: &replica2,
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.Strategy.Canary.TrafficRoutings[0].Ingress.ClassType = "aliyun-alb"
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
ingress.Annotations = map[string]string{}
ingress.Spec.IngressClassName = utilpointer.String("alb")
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(3)
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment image from(version1) -> to(version2)")
time.Sleep(time.Second * 3)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// canary deployment
cWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err := finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
labIngressAnnotationDefaultPrefix := "alb.ingress.kubernetes.io"
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", labIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", labIngressAnnotationDefaultPrefix)]).Should(Equal(""))
Expect(cIngress.Annotations[fmt.Sprintf("%s/conditions.echoserver-canary", labIngressAnnotationDefaultPrefix)]).Should(Equal(`[{"cookieConfig":{"values":[{"key":"demo1","value":"value1"},{"key":"demo2","value":"value2"}]},"type":"Cookie"},{"sourceIpConfig":{"values":["192.168.0.0/16","172.16.0.0/16"]},"type":"SourceIp"},{"headerConfig":{"key":"headername","values":["headervalue1","headervalue2"]},"type":"Header"}]`))
// canary deployment
cWorkload, err = GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 1))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 1))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
// wait step 2 complete
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// canary ingress
cIngress = &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", labIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/conditions.echoserver-canary", labIngressAnnotationDefaultPrefix)]).Should(Equal(""))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", labIngressAnnotationDefaultPrefix)]).Should(Equal("30"))
// canary deployment
cWorkload, err = GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 2))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 2))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
// wait rollout complete
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
klog.Infof("rollout(%s) completed, and check", namespace)
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: A/B testing, aliyun-alb, header & cookies. cloneSet workload", func() {
configmap := &v1.ConfigMap{}
Expect(ReadYamlToObject("./test_data/rollout/rollout-configuration.yaml", configmap)).ToNot(HaveOccurred())
if err := k8sClient.Create(context.TODO(), configmap); err != nil {
if !errors.IsAlreadyExists(err) {
Expect(err).Should(BeNil())
}
}
defer k8sClient.Delete(context.TODO(), configmap)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
replica1 := intstr.FromInt(1)
replica2 := intstr.FromInt(3)
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Matches: []v1alpha1.HttpRouteMatch{
{
Headers: []gatewayv1alpha2.HTTPHeaderMatch{
{
Name: "Cookie",
Value: "demo1=value1;demo2=value2",
},
{
Name: "SourceIp",
Value: "192.168.0.0/16;172.16.0.0/16",
},
{
Name: "headername",
Value: "headervalue1;headervalue2",
},
},
},
},
},
Pause: v1alpha1.RolloutPause{},
Replicas: &replica1,
},
{
Replicas: &replica2,
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.Strategy.Canary.TrafficRoutings[0].Ingress.ClassType = "aliyun-alb"
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
ingress.Annotations = map[string]string{}
ingress.Spec.IngressClassName = utilpointer.String("alb")
CreateObject(ingress)
// workload
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:]))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("Update cloneset EnvVar: NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 3)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
labIngressAnnotationDefaultPrefix := "alb.ingress.kubernetes.io"
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/conditions.echoserver-canary", labIngressAnnotationDefaultPrefix)]).Should(Equal(`[{"cookieConfig":{"values":[{"key":"demo1","value":"value1"},{"key":"demo2","value":"value2"}]},"type":"Cookie"},{"sourceIpConfig":{"values":["192.168.0.0/16","172.16.0.0/16"]},"type":"SourceIp"},{"headerConfig":{"key":"headername","values":["headervalue1","headervalue2"]},"type":"Header"}]`))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
// wait step 2 complete
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// canary ingress and canary service should be deleted
cIngress = &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).To(HaveOccurred())
cService = &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).To(HaveOccurred())
// check service update
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
// check cloneSet
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 3))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
// resume rollout to complete
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitCloneSetAllPodsReady(workload)
By("rollout completed, and check")
// check service & ingress & cloneSet
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
// cloneSet
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 5))
Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 0))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevision))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage 20%, Succeeded with NodePort-type service", func() {
finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
replicas := intstr.FromInt(2)
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Replicas: &replicas,
Pause: v1alpha1.RolloutPause{},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
service.Spec.Type = "NodePort"
service.Spec.Ports[0].NodePort = 30000
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
rss, err := finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
stableRevision := rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 0))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
By("check deployment status & paused success")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check stable, canary service & ingress
// canary deployment
cWorkload, err := GetCanaryDeployment(workload)
Expect(err).NotTo(HaveOccurred())
crss, err := finder.GetReplicaSetsForDeployment(cWorkload)
Expect(err).NotTo(HaveOccurred())
Expect(len(crss)).Should(BeNumerically("==", 1))
canaryRevision := crss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]
Expect(*cWorkload.Spec.Replicas).Should(BeNumerically("==", 2))
Expect(cWorkload.Status.ReadyReplicas).Should(BeNumerically("==", 2))
for _, env := range cWorkload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// stable service
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(canaryRevision))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
rss, err = finder.GetReplicaSetsForDeployment(workload)
Expect(err).NotTo(HaveOccurred())
Expect(len(rss)).Should(BeNumerically("==", 1))
Expect(rss[0].Labels[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
})
KruiseDescribe("Canary rollout with Gateway API", func() {
It("V1->V2: Percentage 20%,40%,60%,80%,90%, and replicas=3", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/gateway/rollout-test.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(80),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(90),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// route
route := &gatewayv1alpha2.HTTPRoute{}
Expect(ReadYamlToObject("./test_data/gateway/httproute-test.yaml", route)).ToNot(HaveOccurred())
CreateObject(route)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(3)
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2)")
time.Sleep(time.Second * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 1))
routeGet := &gatewayv1alpha2.HTTPRoute{}
Expect(GetObject(route.Name, routeGet)).NotTo(HaveOccurred())
stable, canary := getHTTPRouteWeight(*routeGet)
Expect(stable).Should(Equal(int32(80)))
Expect(canary).Should(Equal(int32(20)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2))
Expect(GetObject(route.Name, routeGet)).NotTo(HaveOccurred())
stable, canary = getHTTPRouteWeight(*routeGet)
Expect(stable).Should(Equal(int32(60)))
Expect(canary).Should(Equal(int32(40)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(3)")
WaitRolloutCanaryStepPaused(rollout.Name, 3)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2))
Expect(GetObject(route.Name, routeGet)).NotTo(HaveOccurred())
stable, canary = getHTTPRouteWeight(*routeGet)
Expect(stable).Should(Equal(int32(40)))
Expect(canary).Should(Equal(int32(60)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(4)")
WaitRolloutCanaryStepPaused(rollout.Name, 4)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 3))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 3))
Expect(GetObject(route.Name, routeGet)).NotTo(HaveOccurred())
stable, canary = getHTTPRouteWeight(*routeGet)
Expect(stable).Should(Equal(int32(20)))
Expect(canary).Should(Equal(int32(80)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(5)")
WaitRolloutCanaryStepPaused(rollout.Name, 5)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 3))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 3))
Expect(GetObject(route.Name, routeGet)).NotTo(HaveOccurred())
stable, canary = getHTTPRouteWeight(*routeGet)
Expect(stable).Should(Equal(int32(10)))
Expect(canary).Should(Equal(int32(90)))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
By("rollout completed, and check")
// check service & httproute & deployment
// httproute
Expect(GetObject(routeGet.Name, routeGet)).NotTo(HaveOccurred())
stable, canary = getHTTPRouteWeight(*routeGet)
Expect(stable).Should(Equal(int32(1)))
Expect(canary).Should(Equal(int32(-1)))
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
})
KruiseDescribe("Canary rollout with custon network provider", func() {
It("V1->V2: Route traffic with header matches and weight using rollout for VirtualService", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/customNetworkProvider/rollout_with_trafficrouting.yaml", rollout)).ToNot(HaveOccurred())
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// istio api
vs := &unstructured.Unstructured{}
Expect(ReadYamlToObject("./test_data/customNetworkProvider/virtualservice_without_destinationrule.yaml", vs)).ToNot(HaveOccurred())
vs.SetAPIVersion("networking.istio.io/v1alpha3")
vs.SetKind("VirtualService")
CreateObject(vs)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(4)
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2), routing traffic with header agent:pc to new version pods")
time.Sleep(time.Second * 2)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 1))
// check virtualservice spec
Expect(GetObject(vs.GetName(), vs)).NotTo(HaveOccurred())
expectedSpec := `{"gateways":["nginx-gateway"],"hosts":["*"],"http":[{"match":[{"headers":{"user-agent":{"exact":"pc"}}}],"route":[{"destination":{"host":"echoserver-canary"}}]},{"route":[{"destination":{"host":"echoserver"}}]}]}`
Expect(util.DumpJSON(vs.Object["spec"])).Should(Equal(expectedSpec))
// check original spec annotation
expectedAnno := `{"spec":{"gateways":["nginx-gateway"],"hosts":["*"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]}}`
Expect(vs.GetAnnotations()[OriginalSpecAnnotation]).Should(Equal(expectedAnno))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("Resume rollout, and wait next step(2), routing 50% traffic to new version pods")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2))
// check virtualservice spec
Expect(GetObject(vs.GetName(), vs)).NotTo(HaveOccurred())
expectedSpec = `{"gateways":["nginx-gateway"],"hosts":["*"],"http":[{"route":[{"destination":{"host":"echoserver"},"weight":50},{"destination":{"host":"echoserver-canary"},"weight":50}]}]}`
Expect(util.DumpJSON(vs.Object["spec"])).Should(Equal(expectedSpec))
// check original spec annotation
Expect(vs.GetAnnotations()[OriginalSpecAnnotation]).Should(Equal(expectedAnno))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
By("rollout completed, and check")
// check service & virtualservice & deployment
// virtualservice
Expect(GetObject(vs.GetName(), vs)).NotTo(HaveOccurred())
expectedSpec = `{"gateways":["nginx-gateway"],"hosts":["*"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]}`
Expect(util.DumpJSON(vs.Object["spec"])).Should(Equal(expectedSpec))
Expect(vs.GetAnnotations()[OriginalSpecAnnotation]).Should(Equal(""))
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Route traffic with header matches and weight for VirtualService and DestinationRule", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/customNetworkProvider/rollout_without_trafficrouting.yaml", rollout)).ToNot(HaveOccurred())
CreateObject(rollout)
By("Creating TrafficRouting...")
traffic := &v1alpha1.TrafficRouting{}
Expect(ReadYamlToObject("./test_data/customNetworkProvider/trafficrouting.yaml", traffic)).ToNot(HaveOccurred())
CreateObject(traffic)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// istio api
vs := &unstructured.Unstructured{}
Expect(ReadYamlToObject("./test_data/customNetworkProvider/virtualservice_without_destinationrule.yaml", vs)).ToNot(HaveOccurred())
vs.SetAPIVersion("networking.istio.io/v1alpha3")
vs.SetKind("VirtualService")
CreateObject(vs)
dr := &unstructured.Unstructured{}
Expect(ReadYamlToObject("./test_data/customNetworkProvider/destinationrule.yaml", dr)).ToNot(HaveOccurred())
dr.SetAPIVersion("networking.istio.io/v1alpha3")
dr.SetKind("DestinationRule")
CreateObject(dr)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(4)
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout and trafficrouting status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(GetObject(traffic.Name, traffic)).NotTo(HaveOccurred())
Expect(traffic.Status.Phase).Should(Equal(v1alpha1.TrafficRoutingPhaseHealthy))
By("check rollout and trafficrouting status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update deployment env NODE_NAME from(version1) -> to(version2), routing traffic with header agent:pc to new version pods")
time.Sleep(time.Second * 2)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeTrue())
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check rollout and trafficrouting status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 1))
Expect(GetObject(traffic.Name, traffic)).NotTo(HaveOccurred())
Expect(traffic.Status.Phase).Should(Equal(v1alpha1.TrafficRoutingPhaseProgressing))
// check virtualservice and destinationrule spec
Expect(GetObject(vs.GetName(), vs)).NotTo(HaveOccurred())
expectedVSSpec := `{"gateways":["nginx-gateway"],"hosts":["*"],"http":[{"match":[{"headers":{"user-agent":{"exact":"pc"}}}],"route":[{"destination":{"host":"echoserver","subset":"canary"}}]},{"route":[{"destination":{"host":"echoserver"}}]}]}`
Expect(util.DumpJSON(vs.Object["spec"])).Should(Equal(expectedVSSpec))
Expect(GetObject(dr.GetName(), dr)).NotTo(HaveOccurred())
expectedDRSpec := `{"host":"svc-demo","subsets":[{"labels":{"version":"base"},"name":"echoserver"},{"labels":{"istio.service.tag":"gray"},"name":"canary"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}`
Expect(util.DumpJSON(dr.Object["spec"])).Should(Equal(expectedDRSpec))
// check original spec annotation
expectedVSAnno := `{"spec":{"gateways":["nginx-gateway"],"hosts":["*"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]}}`
Expect(vs.GetAnnotations()[OriginalSpecAnnotation]).Should(Equal(expectedVSAnno))
expectedDRAnno := `{"spec":{"host":"svc-demo","subsets":[{"labels":{"version":"base"},"name":"echoserver"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}`
Expect(dr.GetAnnotations()[OriginalSpecAnnotation]).Should(Equal(expectedDRAnno))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
Expect(GetObject(traffic.Name, traffic)).NotTo(HaveOccurred())
Expect(traffic.Status.Phase).Should(Equal(v1alpha1.TrafficRoutingPhaseHealthy))
By("rollout completed, and check")
// check service & virtualservice & destinationrule & deployment
// virtualservice and destinationrule
Expect(GetObject(vs.GetName(), vs)).NotTo(HaveOccurred())
expectedVSSpec = `{"gateways":["nginx-gateway"],"hosts":["*"],"http":[{"route":[{"destination":{"host":"echoserver"}}]}]}`
Expect(util.DumpJSON(vs.Object["spec"])).Should(Equal(expectedVSSpec))
Expect(vs.GetAnnotations()[OriginalSpecAnnotation]).Should(Equal(""))
Expect(GetObject(dr.GetName(), dr)).NotTo(HaveOccurred())
expectedDRSpec = `{"host":"svc-demo","subsets":[{"labels":{"version":"base"},"name":"echoserver"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}`
Expect(util.DumpJSON(dr.Object["spec"])).Should(Equal(expectedDRSpec))
Expect(dr.GetAnnotations()[OriginalSpecAnnotation]).Should(Equal(""))
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// deployment
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.Replicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
// check progressing succeed
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
})
KruiseDescribe("CloneSet canary rollout with Ingress", func() {
It("CloneSet V1->V2: Percentage, 20%,60% Succeeded", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:]))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check stable, canary service & ingress
// canary ingress
cIngress = &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[1].Weight)))
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 3))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitCloneSetAllPodsReady(workload)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 5))
Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 0))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevision))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
// scale up replicas 5 -> 6
workload.Spec.Replicas = utilpointer.Int32(6)
UpdateCloneSet(workload)
By("Update cloneSet replicas from(5) -> to(6)")
time.Sleep(time.Second * 2)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage, 20%, and rollback(v1)", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
// check rollout status
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:]))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Image = "echoserver:failed"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
time.Sleep(time.Second * 20)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 0))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(v1alpha1.CanaryStepStateUpgrade))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
time.Sleep(time.Second * 15)
// rollback -> v1
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version1"})
workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:latest"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("Rollback deployment env NODE_NAME from(version2) -> to(version1)")
time.Sleep(time.Second * 2)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitCloneSetAllPodsReady(workload)
By("rollout completed, and check")
// check progressing canceled
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
Expect(string(cond.Status)).Should(Equal("False"))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 5))
Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 0))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(stableRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(stableRevision))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version1"))
}
}
})
It("Cloneset V1->V2: Percentage, 20%,40% and continuous release v3", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:]))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
canaryRevisionV1 := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
time.Sleep(time.Second * 15)
// v1 -> v2 -> v3, continuous release
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version3"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("Update cloneSet env NODE_NAME from(version2) -> to(version3)")
time.Sleep(time.Second * 10)
// wait step 0 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
//Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
//Expect(rollout.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).ShouldNot(Equal(canaryRevisionV1))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
canaryRevisionV2 := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevisionV2))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitCloneSetAllPodsReady(workload)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 5))
Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 0))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevisionV2))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevisionV2))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version3"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: disable quickly rollback policy without traffic routing", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
rollout.Annotations = map[string]string{
v1alpha1.RollbackInBatchAnnotation: "true",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// workload
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:]))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// v1 -> v2 -> v1, continuous release
By("Update cloneSet env NODE_NAME from(version2) -> to(version1)")
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 3)
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version1"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
// make sure CloneSet is rolling back in batch
By("Wait step 1 paused")
WaitRolloutCanaryStepPaused(rollout.Name, 1)
By("Wait step 2 paused")
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitCloneSetAllPodsReady(workload)
By("rollout completed, and check")
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 5))
Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 0))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version1"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("CloneSet V1->V2: Percentage, 20%,40%,60%,80%,100%, no traffic, Succeeded", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.UpdateStrategy.Type = appsv1alpha1.InPlaceOnlyCloneSetUpdateStrategyType
workload.Spec.UpdateStrategy.MaxUnavailable = &intstr.IntOrString{
Type: intstr.Int,
IntVal: 1,
}
workload.Spec.UpdateStrategy.MaxSurge = nil
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision[strings.LastIndex(workload.Status.CurrentRevision, "-")+1:]))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
//newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:1.10.2"
UpdateCloneSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision[strings.LastIndex(workload.Status.UpdateRevision, "-")+1:]))
canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitCloneSetAllPodsReady(workload)
By("rollout completed, and check")
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.UpdatedReadyReplicas).Should(BeNumerically("==", 5))
Expect(workload.Spec.UpdateStrategy.Partition.IntVal).Should(BeNumerically("==", 0))
Expect(workload.Spec.UpdateStrategy.Paused).Should(BeFalse())
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevision))
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
// scale up replicas 5 -> 6
workload.Spec.Replicas = utilpointer.Int32(6)
UpdateCloneSet(workload)
By("Update cloneSet replicas from(5) -> to(6)")
time.Sleep(time.Second * 2)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
})
KruiseDescribe("StatefulSet canary rollout with Ingress", func() {
KruiseDescribe("Native StatefulSet rollout canary with Ingress", func() {
It("V1->V2: Percentage, 20%,60% Succeeded", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "StatefulSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// headless service
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/native_statefulset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitNativeStatefulSetPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
By("Update statefulset env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateNativeStatefulSet(workload)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Partition).Should(BeNumerically("==", *workload.Spec.Replicas-1))
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check stable, canary service & ingress
// canary ingress
cIngress = &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[1].Weight)))
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Partition).Should(BeNumerically("==", *workload.Spec.Replicas-3))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitNativeStatefulSetPodsReady(workload)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevision))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
// scale up replicas 5 -> 6
workload.Spec.Replicas = utilpointer.Int32(6)
UpdateNativeStatefulSet(workload)
By("Update cloneSet replicas from(5) -> to(6)")
time.Sleep(time.Second * 2)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage, 20%,40% and continuous release v3", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "StatefulSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/native_statefulset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitNativeStatefulSetPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateNativeStatefulSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
canaryRevisionV1 := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
time.Sleep(time.Second * 15)
// v1 -> v2 -> v3, continuous release
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version3"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateNativeStatefulSet(workload)
By("Update cloneSet env NODE_NAME from(version2) -> to(version3)")
time.Sleep(time.Second * 10)
// wait step 0 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).ShouldNot(Equal(canaryRevisionV1))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
canaryRevisionV2 := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(canaryRevisionV2))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitNativeStatefulSetPodsReady(workload)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevisionV2))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevisionV2))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version3"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage, 20%, and rollback(v1)", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "StatefulSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/native_statefulset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitNativeStatefulSetPodsReady(workload)
// check rollout status
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Image = "echoserver:failed"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateNativeStatefulSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
time.Sleep(time.Minute * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(v1alpha1.CanaryStepStateUpgrade))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
time.Sleep(time.Second * 15)
// rollback -> v1
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version1"})
workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:latest"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateNativeStatefulSet(workload)
By("Rollback deployment env NODE_NAME from(version2) -> to(version1)")
time.Sleep(time.Second * 2)
// StatefulSet will not remove the broken pod with failed image, we should delete it manually
brokenPod := &v1.Pod{}
Expect(GetObject(fmt.Sprintf("%v-%v", workload.Name, *workload.Spec.Replicas-1), brokenPod)).NotTo(HaveOccurred())
Expect(k8sClient.Delete(context.TODO(), brokenPod)).NotTo(HaveOccurred())
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitNativeStatefulSetPodsReady(workload)
By("rollout completed, and check")
// check progressing canceled
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Partition).Should(BeNumerically("==", 0))
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(stableRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(stableRevision))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version1"))
}
}
})
It("V1->V2: Percentage, 20%,40%,60%,80%,100%, no traffic, Succeeded", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "StatefulSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// headless-service
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/native_statefulset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitNativeStatefulSetPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
//newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:1.10.2"
UpdateNativeStatefulSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitNativeStatefulSetPodsReady(workload)
By("rollout completed, and check")
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevision))
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
// scale up replicas 5 -> 6
workload.Spec.Replicas = utilpointer.Int32(6)
UpdateNativeStatefulSet(workload)
By("Update cloneSet replicas from(5) -> to(6)")
time.Sleep(time.Second * 2)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
})
KruiseDescribe("Advanced StatefulSet rollout canary with Ingress", func() {
It("V1->V2: Percentage, 20%,60% Succeeded", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1beta1",
Kind: "StatefulSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// headless service
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1beta1.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/advanced_statefulset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitAdvancedStatefulSetPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
By("Update statefulset env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateAdvancedStatefulSet(workload)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Partition).Should(BeNumerically("==", *workload.Spec.Replicas-1))
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check stable, canary service & ingress
// canary ingress
cIngress = &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[1].Weight)))
// workload
time.Sleep(time.Second * 10)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Partition).Should(BeNumerically("==", *workload.Spec.Replicas-3))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitAdvancedStatefulSetPodsReady(workload)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.ReadyReplicas).Should(BeNumerically("==", *workload.Spec.Replicas))
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevision))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
// scale up replicas 5 -> 6
workload.Spec.Replicas = utilpointer.Int32(6)
UpdateAdvancedStatefulSet(workload)
By("Update cloneSet replicas from(5) -> to(6)")
time.Sleep(time.Second * 2)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage, 20%,40% and continuous release v3", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1beta1",
Kind: "StatefulSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1beta1.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/advanced_statefulset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitAdvancedStatefulSetPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateAdvancedStatefulSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
canaryRevisionV1 := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
time.Sleep(time.Second * 15)
// v1 -> v2 -> v3, continuous release
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version3"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateAdvancedStatefulSet(workload)
By("Update cloneSet env NODE_NAME from(version2) -> to(version3)")
time.Sleep(time.Second * 10)
// wait step 0 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).ShouldNot(Equal(canaryRevisionV1))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
canaryRevisionV2 := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(canaryRevisionV2))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitAdvancedStatefulSetPodsReady(workload)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevisionV2))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevisionV2))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version3"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage, 20%, and rollback(v1)", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1beta1",
Kind: "StatefulSet",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1beta1.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/advanced_statefulset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitAdvancedStatefulSetPodsReady(workload)
// check rollout status
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Image = "echoserver:failed"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateAdvancedStatefulSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
time.Sleep(time.Minute * 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.CurrentStepState).Should(Equal(v1alpha1.CanaryStepStateUpgrade))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
time.Sleep(time.Second * 15)
// rollback -> v1
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version1"})
workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:latest"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateAdvancedStatefulSet(workload)
By("Rollback deployment env NODE_NAME from(version2) -> to(version1)")
time.Sleep(time.Second * 2)
// StatefulSet will not remove the broken pod with failed image, we should delete it manually
brokenPod := &v1.Pod{}
Expect(GetObject(fmt.Sprintf("%v-%v", workload.Name, *workload.Spec.Replicas-1), brokenPod)).NotTo(HaveOccurred())
Expect(k8sClient.Delete(context.TODO(), brokenPod)).NotTo(HaveOccurred())
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitAdvancedStatefulSetPodsReady(workload)
By("rollout completed, and check")
// check progressing canceled
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress := &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.ControllerRevisionHashLabelKey]).Should(Equal(""))
cService := &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Partition).Should(BeNumerically("==", 0))
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(stableRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(stableRevision))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version1"))
}
}
})
It("V1->V2: Percentage, 20%,40%,60%,80%,100%, no traffic, Succeeded", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1beta1",
Kind: "StatefulSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// headless-service
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1beta1.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/advanced_statefulset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitAdvancedStatefulSetPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(workload.Status.CurrentRevision))
stableRevision := rollout.Status.CanaryStatus.StableRevision
By("check rollout status & paused success")
// v1 -> v2, start rollout action
//newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Image = "cilium/echoserver:1.10.2"
UpdateAdvancedStatefulSet(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(workload.Status.UpdateRevision))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(workload.Status.UpdateRevision))
canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitAdvancedStatefulSetPodsReady(workload)
By("rollout completed, and check")
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.CurrentRevision).Should(ContainSubstring(canaryRevision))
Expect(workload.Status.UpdateRevision).Should(ContainSubstring(canaryRevision))
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
// scale up replicas 5 -> 6
workload.Spec.Replicas = utilpointer.Int32(6)
UpdateAdvancedStatefulSet(workload)
By("Update cloneSet replicas from(5) -> to(6)")
time.Sleep(time.Second * 2)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
})
})
KruiseDescribe("Others", func() {
It("Patch batch id to pods: normal case", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1beta1",
Kind: "StatefulSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// headless-service
headlessService := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/headless_service.yaml", headlessService)).ToNot(HaveOccurred())
CreateObject(headlessService)
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1beta1.StatefulSet{}
Expect(ReadYamlToObject("./test_data/rollout/advanced_statefulset.yaml", workload)).ToNot(HaveOccurred())
workload.Labels[v1alpha1.RolloutIDLabel] = "1"
CreateObject(workload)
WaitAdvancedStatefulSetPodsReady(workload)
By("Update statefulset env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateAdvancedStatefulSet(workload)
// wait step 1 complete
By("wait step(1) pause")
WaitRolloutCanaryStepPaused(rollout.Name, 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1)
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 1)
// resume rollout
ResumeRolloutCanary(rollout.Name)
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitAdvancedStatefulSetPodsReady(workload)
// check batch id after rollout
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", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "3", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "4", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "5", 1)
})
It("patch batch id to pods: scaling case", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(10),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
workload.Labels[v1alpha1.RolloutIDLabel] = "1"
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
// v1 -> v2, start rollout action
By("Update cloneset env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
time.Sleep(time.Second * 2)
// wait step 2 complete
By("wait step(2) pause")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 1)
// scale up replicas, 5 -> 10
By("scaling up CloneSet from 5 -> 10")
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(10)
UpdateCloneSet(workload)
Eventually(func() bool {
object := &v1alpha1.Rollout{}
Expect(GetObject(rollout.Name, object)).NotTo(HaveOccurred())
return object.Status.CanaryStatus.CanaryReadyReplicas == 4
}, 5*time.Minute, time.Second).Should(BeTrue())
// 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)
// resume rollout canary
By("check rollout canary status success, resume rollout, and wait rollout canary complete")
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
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", "3", 2)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "4", 4)
})
It("patch batch id to pods: rollback case", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
rollout.Annotations = map[string]string{
v1alpha1.RollbackInBatchAnnotation: "true",
}
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(80),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(0),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
workload.Labels[v1alpha1.RolloutIDLabel] = "1"
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
// v1 -> v2, start rollout action
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("wait step(1) pause")
WaitRolloutCanaryStepPaused(rollout.Name, 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1)
By("wait step(2) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 2)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 1)
By("wait step(3) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 3)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "3", 1)
By("Update cloneSet env NODE_NAME from(version2) -> to(version1)")
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version1"})
workload.Labels[v1alpha1.RolloutIDLabel] = "2"
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
time.Sleep(10 * time.Second)
// make sure disable quickly rollback policy
By("Wait step (1) paused")
WaitRolloutCanaryStepPaused(rollout.Name, 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "1", 1)
By("wait step(2) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 2)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "2", 1)
By("wait step(3) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 3)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "3", 1)
By("wait step(4) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 4)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "4", 1)
By("Wait rollout complete")
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "1", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "2", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "3", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "4", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "5", 1)
})
It("patch batch id to pods: only rollout-id changes", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
rollout.Annotations = map[string]string{
v1alpha1.RollbackInBatchAnnotation: "true",
}
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(80),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(0),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
By("Only update rollout id = '1', and start rollout")
workload.Labels[v1alpha1.RolloutIDLabel] = "1"
workload.Annotations[util.InRolloutProgressingAnnotation] = "true"
UpdateCloneSet(workload)
By("wait step(1) pause")
WaitRolloutCanaryStepPaused(rollout.Name, 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1)
By("wait step(2) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 2)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 1)
By("wait step(3) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 3)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "3", 1)
By("Only update rollout id = '2', and check batch label again")
workload.Labels[v1alpha1.RolloutIDLabel] = "2"
UpdateCloneSet(workload)
By("wait step(3) pause again")
WaitRolloutCanaryStepPaused(rollout.Name, 3)
time.Sleep(30 * time.Second)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "1", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "2", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "3", 1)
By("wait step(4) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 4)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "4", 1)
By("Wait rollout complete")
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "1", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "2", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "3", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "4", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "5", 1)
})
It("patch batch id to pods: only change rollout-id after rolling the first step", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
rollout.Annotations = map[string]string{
v1alpha1.RollbackInBatchAnnotation: "true",
}
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(40),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(80),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{
Duration: utilpointer.Int32(0),
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
By("Only update rollout id = '1', and start rollout")
workload.Labels[v1alpha1.RolloutIDLabel] = "1"
workload.Annotations[util.InRolloutProgressingAnnotation] = "true"
UpdateCloneSet(workload)
By("wait step(1) pause")
WaitRolloutCanaryStepPaused(rollout.Name, 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1)
By("Only update rollout id = '2', and check batch label again")
workload.Labels[v1alpha1.RolloutIDLabel] = "2"
UpdateCloneSet(workload)
By("wait 30s")
time.Sleep(30 * time.Second)
By("wait step(1) pause")
WaitRolloutCanaryStepPaused(rollout.Name, 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "1", 1)
By("wait step(2) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 2)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "2", 1)
By("wait step(3) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 3)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "3", 1)
By("wait step(4) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 4)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "4", 1)
By("Wait rollout complete")
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "1", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "2", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "3", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "4", 1)
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "2", "5", 1)
})
})
KruiseDescribe("Test", func() {
It("failure threshold", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "echoserver",
}
rollout.Spec.Strategy.Canary = &v1alpha1.CanaryStrategy{
FailureThreshold: &intstr.IntOrString{Type: intstr.String, StrVal: "20%"},
Steps: []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(10),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(30),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{},
},
},
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
workload := &appsv1alpha1.CloneSet{}
Expect(ReadYamlToObject("./test_data/rollout/cloneset.yaml", workload)).ToNot(HaveOccurred())
workload.Spec.Replicas = utilpointer.Int32(10)
workload.Spec.UpdateStrategy.MaxUnavailable = &intstr.IntOrString{Type: intstr.String, StrVal: "100%"}
CreateObject(workload)
WaitCloneSetAllPodsReady(workload)
checkUpdateReadyPods := func(lower, upper int32) bool {
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
return lower <= workload.Status.UpdatedReadyReplicas && workload.Status.UpdatedReadyReplicas <= upper
}
By("start rollout")
workload.Labels[v1alpha1.RolloutIDLabel] = "1"
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateCloneSet(workload)
By("wait step(1) pause")
WaitRolloutCanaryStepPaused(rollout.Name, 1)
Expect(checkUpdateReadyPods(1, 1)).Should(BeTrue())
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "1", 1)
By("wait step(2) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 2)
Expect(checkUpdateReadyPods(2, 3)).Should(BeTrue())
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "2", 2)
By("wait step(3) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 3)
Expect(checkUpdateReadyPods(4, 6)).Should(BeTrue())
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "3", 3)
By("wait step(4) pause")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 4)
Expect(checkUpdateReadyPods(8, 10)).Should(BeTrue())
CheckPodBatchLabel(workload.Namespace, workload.Spec.Selector, "1", "4", 4)
})
})
KruiseDescribe("Advanced Deployment canary rollout with Ingress", func() {
It("advanced deployment rolling with traffic case", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Annotations = map[string]string{
v1alpha1.RolloutStyleAnnotation: string(v1alpha1.PartitionRollingStyle),
}
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// service
service := &v1.Service{}
Expect(ReadYamlToObject("./test_data/rollout/service.yaml", service)).ToNot(HaveOccurred())
CreateObject(service)
// ingress
ingress := &netv1.Ingress{}
Expect(ReadYamlToObject("./test_data/rollout/nginx_ingress.yaml", ingress)).ToNot(HaveOccurred())
CreateObject(ingress)
// workload
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
By("Update cloneSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
stableRevision := GetStableRSRevision(workload)
By(stableRevision)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
strategy := util.GetDeploymentStrategy(workload)
extraStatus := util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(strategy.Paused).Should(BeFalse())
By("check cloneSet status & paused success")
// check rollout status
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
Expect(rollout.Status.CanaryStatus.CanaryRevision).Should(Equal(util.ComputeHash(&workload.Spec.Template, nil)))
Expect(rollout.Status.CanaryStatus.PodTemplateHash).Should(Equal(GetCanaryRSRevision(workload)))
canaryRevision := rollout.Status.CanaryStatus.PodTemplateHash
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// check stable, canary service & ingress
// stable service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(stableRevision))
//canary service
cService := &v1.Service{}
Expect(GetObject(service.Name+"-canary", cService)).NotTo(HaveOccurred())
Expect(cService.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(canaryRevision))
// canary ingress
cIngress := &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary", nginxIngressAnnotationDefaultPrefix)]).Should(Equal("true"))
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[0].Weight)))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check stable, canary service & ingress
// canary ingress
cIngress = &netv1.Ingress{}
Expect(GetObject(service.Name+"-canary", cIngress)).NotTo(HaveOccurred())
Expect(cIngress.Annotations[fmt.Sprintf("%s/canary-weight", nginxIngressAnnotationDefaultPrefix)]).Should(Equal(fmt.Sprintf("%d", *rollout.Spec.Strategy.Canary.Steps[1].Weight)))
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3))
strategy = util.GetDeploymentStrategy(workload)
extraStatus = util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 3))
Expect(strategy.Paused).Should(BeFalse())
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitDeploymentAllPodsReady(workload)
By("rollout completed, and check")
// check service & ingress & deployment
// ingress
Expect(GetObject(ingress.Name, ingress)).NotTo(HaveOccurred())
cIngress = &netv1.Ingress{}
Expect(GetObject(fmt.Sprintf("%s-canary", ingress.Name), cIngress)).To(HaveOccurred())
// service
Expect(GetObject(service.Name, service)).NotTo(HaveOccurred())
Expect(service.Spec.Selector[apps.DefaultDeploymentUniqueLabelKey]).Should(Equal(""))
cService = &v1.Service{}
Expect(GetObject(fmt.Sprintf("%s-canary", service.Name), cService)).To(HaveOccurred())
// cloneset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 5))
Expect(workload.Status.AvailableReplicas).Should(BeNumerically("==", 5))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
//Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(canaryRevision))
// scale up replicas 5 -> 6
workload.Spec.Replicas = utilpointer.Int32(6)
UpdateDeployment(workload)
By("Update cloneSet replicas from(5) -> to(6)")
time.Sleep(time.Second * 2)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("advanced deployment continuous rolling case", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Annotations = map[string]string{
v1alpha1.RolloutStyleAnnotation: string(v1alpha1.PartitionRollingStyle),
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{Duration: utilpointer.Int32(0)},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
By("update workload env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
stableRevision := GetStableRSRevision(workload)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
strategy := util.GetDeploymentStrategy(workload)
extraStatus := util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(strategy.Paused).Should(BeFalse())
By("check workload status & paused success")
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3))
strategy = util.GetDeploymentStrategy(workload)
extraStatus = util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 3))
Expect(strategy.Paused).Should(BeFalse())
By("update workload env NODE_NAME from(version2) -> to(version3)")
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version3"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
WaitRolloutCanaryStepPaused(rollout.Name, 1)
stableRevision = workload.Labels[v1alpha1.DeploymentStableRevisionLabel]
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
strategy = util.GetDeploymentStrategy(workload)
extraStatus = util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(strategy.Paused).Should(BeFalse())
By("check workload status & paused success")
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3))
strategy = util.GetDeploymentStrategy(workload)
extraStatus = util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 3))
Expect(strategy.Paused).Should(BeFalse())
})
It("advanced deployment rollback case", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Annotations = map[string]string{
v1alpha1.RolloutStyleAnnotation: string(v1alpha1.PartitionRollingStyle),
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{Duration: utilpointer.Int32(0)},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
By("update cloneSet env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
stableRevision := GetStableRSRevision(workload)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
strategy := util.GetDeploymentStrategy(workload)
extraStatus := util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(strategy.Paused).Should(BeFalse())
By("check workload status & paused success")
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 3))
strategy = util.GetDeploymentStrategy(workload)
extraStatus = util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 3))
Expect(strategy.Paused).Should(BeFalse())
By("update workload env NODE_NAME from(version2) -> to(version1)")
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version1"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitDeploymentAllPodsReady(workload)
})
It("advanced deployment delete rollout case", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Annotations = map[string]string{
v1alpha1.RolloutStyleAnnotation: string(v1alpha1.PartitionRollingStyle),
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{Duration: utilpointer.Int32(0)},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
By("update workload env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
stableRevision := GetStableRSRevision(workload)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
strategy := util.GetDeploymentStrategy(workload)
extraStatus := util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(strategy.Paused).Should(BeFalse())
By("check workload status & paused success")
By("delete rollout and check deployment")
k8sClient.Delete(context.TODO(), rollout)
WaitRolloutNotFound(rollout.Name)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Spec.Strategy.Type).Should(Equal(apps.RollingUpdateDeploymentStrategyType))
Expect(workload.Spec.Paused).Should(BeFalse())
WaitDeploymentAllPodsReady(workload)
})
It("advanced deployment scaling case", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Annotations = map[string]string{
v1alpha1.RolloutStyleAnnotation: string(v1alpha1.PartitionRollingStyle),
}
rollout.Spec.Strategy.Canary.TrafficRoutings = nil
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(20),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(60),
},
Pause: v1alpha1.RolloutPause{},
},
{
TrafficRoutingStrategy: v1alpha1.TrafficRoutingStrategy{
Weight: utilpointer.Int32(100),
},
Pause: v1alpha1.RolloutPause{Duration: utilpointer.Int32(0)},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "echoserver",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
workload := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDeploymentAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
By("update workload env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(workload)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
stableRevision := GetStableRSRevision(workload)
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.CanaryStatus.StableRevision).Should(Equal(stableRevision))
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedReplicas).Should(BeNumerically("==", 1))
strategy := util.GetDeploymentStrategy(workload)
extraStatus := util.GetDeploymentExtraStatus(workload)
Expect(extraStatus.UpdatedReadyReplicas).Should(BeNumerically("==", 1))
Expect(strategy.Paused).Should(BeFalse())
By("check workload status & paused success")
By("scale up workload from 5 to 10, and check")
workload.Spec.Replicas = utilpointer.Int32(10)
UpdateDeployment(workload)
Eventually(func() bool {
object := &v1alpha1.Rollout{}
Expect(GetObject(rollout.Name, object)).NotTo(HaveOccurred())
return object.Status.CanaryStatus.CanaryReadyReplicas == 2
}, 5*time.Minute, time.Second).Should(BeTrue())
By("scale down workload from 10 to 5, and check")
workload.Spec.Replicas = utilpointer.Int32(5)
UpdateDeployment(workload)
Eventually(func() bool {
object := &v1alpha1.Rollout{}
Expect(GetObject(rollout.Name, object)).NotTo(HaveOccurred())
return object.Status.CanaryStatus.CanaryReadyReplicas == 1
}, 5*time.Minute, time.Second).Should(BeTrue())
By("rolling deployment to be completed")
ResumeRolloutCanary(rollout.Name)
WaitRolloutCanaryStepPaused(rollout.Name, 2)
ResumeRolloutCanary(rollout.Name)
WaitDeploymentAllPodsReady(workload)
})
})
KruiseDescribe("DaemonSet canary rollout", func() {
It("DaemonSet V1->V2: 1,100% Succeeded", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_daemonset_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
Replicas: &intstr.IntOrString{IntVal: int32(*utilpointer.Int32(1)), Type: intstr.Int},
Pause: v1alpha1.RolloutPause{},
},
{
Replicas: &intstr.IntOrString{IntVal: int32(*utilpointer.Int32Ptr(100)), Type: intstr.Int},
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "DaemonSet",
Name: "fluentd-elasticsearch",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// workload
workload := &appsv1alpha1.DaemonSet{}
Expect(ReadYamlToObject("./test_data/rollout/daemonset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDaemonSetAllPodsReady(workload)
// check rollout status
By("check rollout status & paused success")
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
// v1 -> v2, start rollout action
By("Update daemonset env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDaemonSet(workload)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedNumberScheduled).Should(BeNumerically("==", 1))
Expect(workload.Status.NumberReady).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Paused).Should(BeFalse())
By("check daemonset status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitDaemonSetAllPodsReady(workload)
By("rollout completed, and check")
// check daemonset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedNumberScheduled).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(workload.Status.NumberReady).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: Percentage, 1, 2 and continuous release v3", func() {
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_daemonset_interrupt.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
Replicas: &intstr.IntOrString{IntVal: int32(*utilpointer.Int32(1)), Type: intstr.Int},
Pause: v1alpha1.RolloutPause{},
},
{
Replicas: &intstr.IntOrString{IntVal: int32(*utilpointer.Int32Ptr(2)), Type: intstr.Int},
Pause: v1alpha1.RolloutPause{},
},
{
Replicas: &intstr.IntOrString{IntVal: int32(*utilpointer.Int32Ptr(100)), Type: intstr.Int},
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "DaemonSet",
Name: "fluentd-elasticsearch",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// workload
workload := &appsv1alpha1.DaemonSet{}
Expect(ReadYamlToObject("./test_data/rollout/daemonset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDaemonSetAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDaemonSet(workload)
By("Update daemonSet env NODE_NAME from(version1) -> to(version2)")
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedNumberScheduled).Should(BeNumerically("==", 1))
Expect(workload.Status.NumberReady).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Paused).Should(BeFalse())
By("check daemonSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
Expect(rollout.Status.CanaryStatus.RolloutHash).Should(Equal(rollout.Annotations[util.RolloutHashAnnotation]))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// v1 -> v2 -> v3, continuous release
By("Update daemonSet env NODE_NAME from(version2) -> to(version3)")
newEnvs = mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version3"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDaemonSet(workload)
// wait step 1 complete
WaitRolloutCanaryStepPaused(rollout.Name, 1)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedNumberScheduled).Should(BeNumerically("==", 1))
Expect(workload.Status.NumberReady).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Paused).Should(BeFalse())
By("check daemonSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 1))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(2)")
WaitRolloutCanaryStepPaused(rollout.Name, 2)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedNumberScheduled).Should(BeNumerically("==", 2))
Expect(workload.Status.NumberReady).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Paused).Should(BeFalse())
By("check daemonSet status & paused success")
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseProgressing))
Expect(rollout.Status.CanaryStatus.CurrentStepIndex).Should(BeNumerically("==", 2))
// resume rollout canary
ResumeRolloutCanary(rollout.Name)
By("resume rollout, and wait next step(3)")
WaitRolloutCanaryStepPaused(rollout.Name, 3)
// resume rollout
ResumeRolloutCanary(rollout.Name)
WaitRolloutStatusPhase(rollout.Name, v1alpha1.RolloutPhaseHealthy)
WaitDaemonSetAllPodsReady(workload)
By("rollout completed, and check")
// check daemonset
// daemonset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedNumberScheduled).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(workload.Status.NumberReady).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version3"))
}
}
time.Sleep(time.Second * 3)
// check progressing succeed
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
cond := util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionProgressing)
Expect(cond.Reason).Should(Equal(v1alpha1.ProgressingReasonCompleted))
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionFalse)))
cond = util.GetRolloutCondition(rollout.Status, v1alpha1.RolloutConditionSucceeded)
Expect(string(cond.Status)).Should(Equal(string(metav1.ConditionTrue)))
WaitRolloutWorkloadGeneration(rollout.Name, workload.Generation)
})
It("V1->V2: 1,100%, but delete rollout crd", func() {
// finder := util.NewControllerFinder(k8sClient)
By("Creating Rollout...")
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_canary_daemonset_base.yaml", rollout)).ToNot(HaveOccurred())
rollout.Spec.Strategy.Canary.Steps = []v1alpha1.CanaryStep{
{
Replicas: &intstr.IntOrString{IntVal: int32(*utilpointer.Int32(1)), Type: intstr.Int},
Pause: v1alpha1.RolloutPause{},
},
{
Replicas: &intstr.IntOrString{IntVal: int32(*utilpointer.Int32Ptr(100)), Type: intstr.Int},
Pause: v1alpha1.RolloutPause{},
},
}
rollout.Spec.ObjectRef.WorkloadRef = &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "DaemonSet",
Name: "fluentd-elasticsearch",
}
CreateObject(rollout)
By("Creating workload and waiting for all pods ready...")
// workload
workload := &appsv1alpha1.DaemonSet{}
Expect(ReadYamlToObject("./test_data/rollout/daemonset.yaml", workload)).ToNot(HaveOccurred())
CreateObject(workload)
WaitDaemonSetAllPodsReady(workload)
// check rollout status
Expect(GetObject(rollout.Name, rollout)).NotTo(HaveOccurred())
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(rollout.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("check rollout status & paused success")
// v1 -> v2, start rollout action
By("Update DaemonSet env NODE_NAME from(version1) -> to(version2)")
newEnvs := mergeEnvVar(workload.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "NODE_NAME", Value: "version2"})
workload.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDaemonSet(workload)
WaitRolloutCanaryStepPaused(rollout.Name, 1)
time.Sleep(time.Second * 3)
// check workload status & paused
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(workload.Status.UpdatedNumberScheduled).Should(BeNumerically("==", 1))
Expect(workload.Status.NumberReady).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Paused).Should(BeFalse())
By("check DaemonSet status & paused success")
// delete rollout
By("Delete rollout crd, and wait DaemonSet ready")
Expect(k8sClient.DeleteAllOf(context.TODO(), &v1alpha1.Rollout{}, client.InNamespace(namespace), client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
WaitRolloutNotFound(rollout.Name)
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
workload.Spec.UpdateStrategy.RollingUpdate.Partition = utilpointer.Int32(0)
UpdateDaemonSet(workload)
WaitDaemonSetAllPodsReady(workload)
// check daemonset
// daemonset
Expect(GetObject(workload.Name, workload)).NotTo(HaveOccurred())
Expect(*workload.Spec.UpdateStrategy.RollingUpdate.Paused).Should(BeFalse())
Expect(workload.Status.UpdatedNumberScheduled).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(workload.Status.NumberReady).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
Expect(workload.Status.CurrentNumberScheduled).Should(BeNumerically("==", workload.Status.DesiredNumberScheduled))
for _, env := range workload.Spec.Template.Spec.Containers[0].Env {
if env.Name == "NODE_NAME" {
Expect(env.Value).Should(Equal("version2"))
}
}
})
})
KruiseDescribe("Disabled rollout tests", func() {
rollout := &v1alpha1.Rollout{}
Expect(ReadYamlToObject("./test_data/rollout/rollout_disabled.yaml", rollout)).ToNot(HaveOccurred())
It("Rollout status tests", func() {
By("Create an enabled rollout")
rollout1 := rollout.DeepCopy()
rollout1.Name = "rollout-demo1"
rollout1.Spec.Disabled = false
CreateObject(rollout1)
time.Sleep(1 * time.Second)
By("Create another enabled rollout")
rollout2 := rollout.DeepCopy()
rollout2.Name = "rollout-demo2"
rollout2.Spec.Disabled = false
rollout2.SetNamespace(namespace)
Expect(k8sClient.Create(context.TODO(), rollout2)).Should(HaveOccurred())
By("Creating a disabled rollout")
rollout3 := rollout.DeepCopy()
rollout3.Name = "rollout-demo3"
rollout3.Spec.Disabled = true
rollout2.SetNamespace(namespace)
Expect(k8sClient.Create(context.TODO(), rollout2)).Should(HaveOccurred())
// wait for reconciling
time.Sleep(3 * time.Second)
Expect(GetObject(rollout1.Name, rollout1)).NotTo(HaveOccurred())
Expect(rollout1.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseInitial))
By("Create workload")
deploy := &apps.Deployment{}
Expect(ReadYamlToObject("./test_data/rollout/deployment_disabled.yaml", deploy)).ToNot(HaveOccurred())
CreateObject(deploy)
WaitDeploymentAllPodsReady(deploy)
Expect(GetObject(rollout1.Name, rollout1)).NotTo(HaveOccurred())
Expect(rollout1.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
By("Updating deployment version-1 to version-2")
Expect(GetObject(deploy.Name, deploy)).NotTo(HaveOccurred())
newEnvs := mergeEnvVar(deploy.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "VERSION", Value: "version-2"})
deploy.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(deploy)
WaitRolloutCanaryStepPaused(rollout1.Name, 1)
Expect(GetObject(rollout1.Name, rollout1)).NotTo(HaveOccurred())
Expect(rollout1.Status.CanaryStatus.CanaryReplicas).Should(BeNumerically("==", 2))
Expect(rollout1.Status.CanaryStatus.CanaryReadyReplicas).Should(BeNumerically("==", 2))
Expect(GetObject(deploy.Name, deploy)).NotTo(HaveOccurred())
Expect(deploy.Spec.Paused).Should(BeTrue())
By("Disable a rolling rollout")
rollout1.Spec.Disabled = true
UpdateRollout(rollout1)
time.Sleep(5 * time.Second)
By("Rolling should be resumed")
Expect(GetObject(deploy.Name, deploy)).NotTo(HaveOccurred())
Expect(deploy.Spec.Paused).Should(BeFalse())
By("Batchrelease should be deleted")
key := types.NamespacedName{Namespace: namespace, Name: rollout1.Name}
Expect(k8sClient.Get(context.TODO(), key, &v1alpha1.BatchRelease{})).Should(HaveOccurred())
Expect(GetObject(rollout1.Name, rollout1)).NotTo(HaveOccurred())
Expect(rollout1.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseDisabled))
By("Updating deployment version-2 to version-3")
Expect(GetObject(deploy.Name, deploy)).NotTo(HaveOccurred())
newEnvs = mergeEnvVar(deploy.Spec.Template.Spec.Containers[0].Env, v1.EnvVar{Name: "VERSION", Value: "version-3"})
deploy.Spec.Template.Spec.Containers[0].Env = newEnvs
UpdateDeployment(deploy)
time.Sleep(3 * time.Second)
Expect(GetObject(deploy.Name, deploy)).NotTo(HaveOccurred())
Expect(deploy.Spec.Paused).Should(BeFalse())
By("Enable a disabled rollout")
rollout1.Spec.Disabled = false
UpdateRollout(rollout1)
time.Sleep(3 * time.Second)
Expect(GetObject(rollout1.Name, rollout1)).NotTo(HaveOccurred())
Expect(rollout1.Status.Phase).Should(Equal(v1alpha1.RolloutPhaseHealthy))
})
})
})
func mergeEnvVar(original []v1.EnvVar, add v1.EnvVar) []v1.EnvVar {
newEnvs := make([]v1.EnvVar, 0)
for _, env := range original {
if add.Name == env.Name {
continue
}
newEnvs = append(newEnvs, env)
}
newEnvs = append(newEnvs, add)
return newEnvs
}
func mergeMap(dst, patch map[string]string) map[string]string {
for k1, v1 := range patch {
dst[k1] = v1
}
return dst
}
func getHTTPRouteWeight(route gatewayv1alpha2.HTTPRoute) (int32, int32) {
var stable, canary int32
for i := range route.Spec.Rules {
rules := route.Spec.Rules[i]
for j := range rules.BackendRefs {
if strings.HasSuffix(string(rules.BackendRefs[j].Name), "-canary") {
canary = *rules.BackendRefs[j].Weight
} else {
stable = *rules.BackendRefs[j].Weight
}
}
}
if canary == 0 {
canary = -1
}
return stable, canary
}