1
16
17 package apps
18
19 import (
20 "context"
21 "fmt"
22 "time"
23
24 appsv1 "k8s.io/api/apps/v1"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/types"
27 "k8s.io/apimachinery/pkg/util/wait"
28 clientset "k8s.io/client-go/kubernetes"
29 deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
30 "k8s.io/kubernetes/test/e2e/framework"
31 e2edeployment "k8s.io/kubernetes/test/e2e/framework/deployment"
32 "k8s.io/kubernetes/test/e2e/upgrades"
33
34 "github.com/onsi/ginkgo/v2"
35 "github.com/onsi/gomega"
36
37 imageutils "k8s.io/kubernetes/test/utils/image"
38 )
39
40 const (
41 deploymentName = "dp"
42
43 poll = 2 * time.Second
44 pollLongTimeout = 5 * time.Minute
45 )
46
47
48
49
50
51
52 type DeploymentUpgradeTest struct {
53 oldDeploymentUID types.UID
54 oldRSUID types.UID
55 newRSUID types.UID
56 }
57
58
59 func (DeploymentUpgradeTest) Name() string { return "[sig-apps] deployment-upgrade" }
60
61
62 func (t *DeploymentUpgradeTest) Setup(ctx context.Context, f *framework.Framework) {
63 c := f.ClientSet
64 nginxImage := imageutils.GetE2EImage(imageutils.Nginx)
65
66 ns := f.Namespace.Name
67 deploymentClient := c.AppsV1().Deployments(ns)
68 rsClient := c.AppsV1().ReplicaSets(ns)
69
70 ginkgo.By(fmt.Sprintf("Creating a deployment %q with 1 replica in namespace %q", deploymentName, ns))
71 d := e2edeployment.NewDeployment(deploymentName, int32(1), map[string]string{"test": "upgrade"}, "nginx", nginxImage, appsv1.RollingUpdateDeploymentStrategyType)
72 deployment, err := deploymentClient.Create(ctx, d, metav1.CreateOptions{})
73 framework.ExpectNoError(err)
74
75 ginkgo.By(fmt.Sprintf("Waiting deployment %q to complete", deploymentName))
76 framework.ExpectNoError(e2edeployment.WaitForDeploymentComplete(c, deployment))
77
78 ginkgo.By(fmt.Sprintf("Getting replicaset revision 1 of deployment %q", deploymentName))
79 rsSelector, err := metav1.LabelSelectorAsSelector(d.Spec.Selector)
80 framework.ExpectNoError(err)
81 rsList, err := rsClient.List(ctx, metav1.ListOptions{LabelSelector: rsSelector.String()})
82 framework.ExpectNoError(err)
83 rss := rsList.Items
84 gomega.Expect(rss).To(gomega.HaveLen(1), "expected one replicaset, got %d", len(rss))
85 t.oldRSUID = rss[0].UID
86
87 ginkgo.By(fmt.Sprintf("Waiting for revision of the deployment %q to become 1", deploymentName))
88 framework.ExpectNoError(waitForDeploymentRevision(ctx, c, deployment, "1"))
89
90
91 ginkgo.By(fmt.Sprintf("Triggering a new rollout for deployment %q", deploymentName))
92 deployment, err = e2edeployment.UpdateDeploymentWithRetries(c, ns, deploymentName, func(update *appsv1.Deployment) {
93 update.Spec.Template.Spec.Containers[0].Name = "updated-name"
94 })
95 framework.ExpectNoError(err)
96
97 ginkgo.By(fmt.Sprintf("Waiting deployment %q to complete", deploymentName))
98 framework.ExpectNoError(e2edeployment.WaitForDeploymentComplete(c, deployment))
99
100 ginkgo.By(fmt.Sprintf("Getting replicasets revision 1 and 2 of deployment %q", deploymentName))
101 rsList, err = rsClient.List(ctx, metav1.ListOptions{LabelSelector: rsSelector.String()})
102 framework.ExpectNoError(err)
103 rss = rsList.Items
104 gomega.Expect(rss).To(gomega.HaveLen(2), "expected 2 replicaset, got %d", len(rss))
105
106 ginkgo.By(fmt.Sprintf("Checking replicaset of deployment %q that is created before rollout survives the rollout", deploymentName))
107 switch t.oldRSUID {
108 case rss[0].UID:
109 t.newRSUID = rss[1].UID
110 case rss[1].UID:
111 t.newRSUID = rss[0].UID
112 default:
113 framework.ExpectNoError(fmt.Errorf("old replicaset with UID %q does not survive rollout", t.oldRSUID))
114 }
115
116 ginkgo.By(fmt.Sprintf("Waiting for revision of the deployment %q to become 2", deploymentName))
117 framework.ExpectNoError(waitForDeploymentRevision(ctx, c, deployment, "2"))
118
119 t.oldDeploymentUID = deployment.UID
120 }
121
122
123 func (t *DeploymentUpgradeTest) Test(ctx context.Context, f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) {
124
125 ginkgo.By(fmt.Sprintf("Waiting for upgrade to finish before checking replicasets for deployment %q", deploymentName))
126 <-done
127
128 c := f.ClientSet
129 ns := f.Namespace.Name
130 deploymentClient := c.AppsV1().Deployments(ns)
131 rsClient := c.AppsV1().ReplicaSets(ns)
132
133 deployment, err := deploymentClient.Get(ctx, deploymentName, metav1.GetOptions{})
134 framework.ExpectNoError(err)
135
136 ginkgo.By(fmt.Sprintf("Checking UID to verify deployment %q survives upgrade", deploymentName))
137 gomega.Expect(deployment.UID).To(gomega.Equal(t.oldDeploymentUID))
138
139 ginkgo.By(fmt.Sprintf("Verifying deployment %q does not create new replicasets", deploymentName))
140 rsSelector, err := metav1.LabelSelectorAsSelector(deployment.Spec.Selector)
141 framework.ExpectNoError(err)
142 rsList, err := rsClient.List(ctx, metav1.ListOptions{LabelSelector: rsSelector.String()})
143 framework.ExpectNoError(err)
144 rss := rsList.Items
145 gomega.Expect(rss).To(gomega.HaveLen(2), "expected 2 replicaset, got %d", len(rss))
146
147 switch t.oldRSUID {
148 case rss[0].UID:
149 gomega.Expect(rss[1].UID).To(gomega.Equal(t.newRSUID))
150 case rss[1].UID:
151 gomega.Expect(rss[0].UID).To(gomega.Equal(t.newRSUID))
152 default:
153 framework.ExpectNoError(fmt.Errorf("new replicasets are created during upgrade of deployment %q", deploymentName))
154 }
155
156 ginkgo.By(fmt.Sprintf("Verifying revision of the deployment %q is still 2", deploymentName))
157 gomega.Expect(deployment.Annotations).To(gomega.HaveKeyWithValue(deploymentutil.RevisionAnnotation, "2"))
158
159 ginkgo.By(fmt.Sprintf("Waiting for deployment %q to complete adoption", deploymentName))
160 framework.ExpectNoError(e2edeployment.WaitForDeploymentComplete(c, deployment))
161
162
163 ginkgo.By(fmt.Sprintf("Scaling up replicaset of deployment %q by 1", deploymentName))
164 deploymentWithUpdatedReplicas, err := e2edeployment.UpdateDeploymentWithRetries(c, ns, deploymentName, func(deployment *appsv1.Deployment) {
165 *deployment.Spec.Replicas = *deployment.Spec.Replicas + 1
166 })
167 framework.ExpectNoError(err)
168
169 ginkgo.By(fmt.Sprintf("Waiting for deployment %q to complete after scaling", deploymentName))
170 framework.ExpectNoError(e2edeployment.WaitForDeploymentComplete(c, deploymentWithUpdatedReplicas))
171 }
172
173
174 func (t *DeploymentUpgradeTest) Teardown(ctx context.Context, f *framework.Framework) {
175
176 }
177
178
179 func waitForDeploymentRevision(ctx context.Context, c clientset.Interface, d *appsv1.Deployment, targetRevision string) error {
180 err := wait.PollImmediate(poll, pollLongTimeout, func() (bool, error) {
181 deployment, err := c.AppsV1().Deployments(d.Namespace).Get(ctx, d.Name, metav1.GetOptions{})
182 if err != nil {
183 return false, err
184 }
185 revision := deployment.Annotations[deploymentutil.RevisionAnnotation]
186 return revision == targetRevision, nil
187 })
188 if err != nil {
189 return fmt.Errorf("error waiting for revision to become %q for deployment %q: %w", targetRevision, d.Name, err)
190 }
191 return nil
192 }
193
View as plain text