k8s.io/kubernetes@v1.29.3/test/e2e/kubectl/rollout.go (about)

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // OWNER = sig/cli
    18  
    19  package kubectl
    20  
    21  import (
    22  	"context"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/google/go-cmp/cmp/cmpopts"
    26  	"github.com/onsi/ginkgo/v2"
    27  
    28  	appsv1 "k8s.io/api/apps/v1"
    29  	v1 "k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	clientset "k8s.io/client-go/kubernetes"
    32  	commonutils "k8s.io/kubernetes/test/e2e/common"
    33  	"k8s.io/kubernetes/test/e2e/framework"
    34  	e2edeployment "k8s.io/kubernetes/test/e2e/framework/deployment"
    35  	e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"
    36  	imageutils "k8s.io/kubernetes/test/utils/image"
    37  	admissionapi "k8s.io/pod-security-admission/api"
    38  )
    39  
    40  var _ = SIGDescribe("Kubectl rollout", func() {
    41  	defer ginkgo.GinkgoRecover()
    42  	var deploymentYaml string
    43  	f := framework.NewDefaultFramework("kubectl-rollout")
    44  	f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
    45  
    46  	var c clientset.Interface
    47  	var ns string
    48  	ginkgo.BeforeEach(func() {
    49  		c = f.ClientSet
    50  		ns = f.Namespace.Name
    51  		deploymentYaml = commonutils.SubstituteImageName(string(readTestFileOrDie(httpdDeployment1Filename)))
    52  	})
    53  
    54  	ginkgo.Describe("undo", func() {
    55  		ginkgo.AfterEach(func() {
    56  			cleanupKubectlInputs(deploymentYaml, ns, "app=httpd")
    57  		})
    58  		ginkgo.It("undo should rollback and update deployment env", func(ctx context.Context) {
    59  			var err error
    60  			// create deployment
    61  			e2ekubectl.RunKubectlOrDieInput(ns, deploymentYaml, "apply", "-f", "-")
    62  
    63  			if err = e2edeployment.WaitForDeploymentRevisionAndImage(c, ns, "httpd-deployment", "1", imageutils.GetE2EImage(imageutils.HttpdNew)); err != nil {
    64  				framework.Failf("created deployment not ready")
    65  			}
    66  
    67  			var d *appsv1.Deployment
    68  			if d, err = c.AppsV1().Deployments(ns).Get(ctx, "httpd-deployment", metav1.GetOptions{}); err != nil {
    69  				framework.Failf("get deployment failed")
    70  			}
    71  
    72  			origEnv := d.Spec.Template.Spec.Containers[0].Env
    73  			for _, env := range origEnv {
    74  				if env.Name == "foo" && env.Value == "bar" {
    75  					framework.Failf("labeled deployment should not have an env named foo and valued bar at the beginning")
    76  				}
    77  			}
    78  
    79  			origLabels := d.Spec.Template.Labels
    80  			if len(origLabels) == 0 {
    81  				framework.Failf("original labels should not be empty in kubectl rollout test")
    82  			}
    83  
    84  			origAnnotations := d.Spec.Template.Annotations
    85  			if len(origAnnotations) == 0 {
    86  				framework.Failf("original annotations should not be empty in kubectl rollout test")
    87  			}
    88  
    89  			// do a small update
    90  			if _, err = e2ekubectl.RunKubectl(ns, "set", "env", "deployment/httpd-deployment", "foo=bar"); err != nil {
    91  				framework.Failf("kubectl failed set env for deployment")
    92  			}
    93  			// wait for env to be set
    94  			if err = e2edeployment.WaitForDeploymentComplete(c, d); err != nil {
    95  				framework.Failf("update deployment failed")
    96  			}
    97  			if d, err = c.AppsV1().Deployments(ns).Get(ctx, "httpd-deployment", metav1.GetOptions{}); err != nil {
    98  				framework.Failf("get deployment failed")
    99  			}
   100  			envs := d.Spec.Template.Spec.Containers[0].Env
   101  
   102  			envUpdated := false
   103  			for _, env := range envs {
   104  				if env.Name == "foo" && env.Value == "bar" {
   105  					envUpdated = true
   106  					break
   107  				}
   108  			}
   109  			if !envUpdated {
   110  				framework.Failf("update deployment's env failed")
   111  			}
   112  
   113  			// rollback
   114  			if _, err = e2ekubectl.RunKubectl(ns, "rollout", "undo", "deployment/httpd-deployment"); err != nil {
   115  				framework.Failf("kubectl failed to rollback deployment")
   116  			}
   117  			// wait for rollback finished
   118  			if err = e2edeployment.WaitForDeploymentComplete(c, d); err != nil {
   119  				framework.Failf("rollback deployment failed")
   120  			}
   121  			if d, err = c.AppsV1().Deployments(ns).Get(ctx, "httpd-deployment", metav1.GetOptions{}); err != nil {
   122  				framework.Failf("get deployment failed")
   123  			}
   124  
   125  			rollbackedEnv := d.Spec.Template.Spec.Containers[0].Env
   126  			rollbackedLabels := d.Spec.Template.Labels
   127  			rollbackedAnnotations := d.Spec.Template.Annotations
   128  
   129  			if diff := cmp.Diff(origEnv, rollbackedEnv, cmpopts.SortSlices(func(a, b v1.EnvVar) bool {
   130  				return a.Name < b.Name
   131  			})); diff != "" {
   132  				framework.Failf("inconsistent env after rolled back: %s", diff)
   133  			}
   134  			if diff := cmp.Diff(origLabels, rollbackedLabels); diff != "" {
   135  				framework.Failf("inconsistent labels after rolled back: %s", diff)
   136  			}
   137  			if diff := cmp.Diff(origAnnotations, rollbackedAnnotations); diff != "" {
   138  				framework.Failf("inconsistent annotations after rolled back: %s", diff)
   139  			}
   140  		})
   141  	})
   142  })