k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/integration/deployment/deployment_test.go (about) 1 /* 2 Copyright 2017 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 package deployment 18 19 import ( 20 "context" 21 "fmt" 22 "strings" 23 "testing" 24 25 apps "k8s.io/api/apps/v1" 26 v1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/util/intstr" 29 "k8s.io/apimachinery/pkg/util/uuid" 30 "k8s.io/apimachinery/pkg/util/wait" 31 "k8s.io/client-go/util/retry" 32 "k8s.io/klog/v2/ktesting" 33 deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" 34 "k8s.io/kubernetes/test/integration/framework" 35 testutil "k8s.io/kubernetes/test/utils" 36 "k8s.io/utils/ptr" 37 ) 38 39 func TestNewDeployment(t *testing.T) { 40 _, ctx := ktesting.NewTestContext(t) 41 ctx, cancel := context.WithCancel(ctx) 42 defer cancel() 43 44 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 45 defer closeFn() 46 name := "test-new-deployment" 47 48 ns := framework.CreateNamespaceOrDie(c, name, t) 49 defer framework.DeleteNamespaceOrDie(c, ns, t) 50 51 replicas := int32(20) 52 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(name, ns.Name, replicas)} 53 tester.deployment.Spec.MinReadySeconds = 4 54 55 tester.deployment.Annotations = map[string]string{"test": "should-copy-to-replica-set", v1.LastAppliedConfigAnnotation: "should-not-copy-to-replica-set"} 56 var err error 57 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 58 if err != nil { 59 t.Fatalf("failed to create deployment %s: %v", tester.deployment.Name, err) 60 } 61 62 // Start informer and controllers 63 stopControllers := runControllersAndInformers(t, rm, dc, informers) 64 defer stopControllers() 65 66 // Wait for the Deployment to be updated to revision 1 67 if err := tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 68 t.Fatal(err) 69 } 70 71 // Make sure the Deployment completes while manually marking Deployment pods as ready at the same time. 72 // Use soft check because this deployment was just created and rolling update strategy might be violated. 73 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 74 t.Fatal(err) 75 } 76 77 // Check new RS annotations 78 newRS, err := tester.expectNewReplicaSet() 79 if err != nil { 80 t.Fatal(err) 81 } 82 if newRS.Annotations["test"] != "should-copy-to-replica-set" { 83 t.Errorf("expected new ReplicaSet annotations copied from Deployment %s, got: %v", tester.deployment.Name, newRS.Annotations) 84 } 85 if newRS.Annotations[v1.LastAppliedConfigAnnotation] != "" { 86 t.Errorf("expected new ReplicaSet last-applied annotation not copied from Deployment %s", tester.deployment.Name) 87 } 88 89 // New RS should contain pod-template-hash in its selector, label, and template label 90 rsHash, err := checkRSHashLabels(newRS) 91 if err != nil { 92 t.Error(err) 93 } 94 95 // All pods targeted by the deployment should contain pod-template-hash in their labels 96 selector, err := metav1.LabelSelectorAsSelector(tester.deployment.Spec.Selector) 97 if err != nil { 98 t.Fatalf("failed to parse deployment %s selector: %v", name, err) 99 } 100 pods, err := c.CoreV1().Pods(ns.Name).List(context.TODO(), metav1.ListOptions{LabelSelector: selector.String()}) 101 if err != nil { 102 t.Fatalf("failed to list pods of deployment %s: %v", name, err) 103 } 104 if len(pods.Items) != int(replicas) { 105 t.Errorf("expected %d pods, got %d pods", replicas, len(pods.Items)) 106 } 107 podHash, err := checkPodsHashLabel(pods) 108 if err != nil { 109 t.Error(err) 110 } 111 if rsHash != podHash { 112 t.Errorf("found mismatching pod-template-hash value: rs hash = %s whereas pod hash = %s", rsHash, podHash) 113 } 114 } 115 116 // Deployments should support roll out, roll back, and roll over. 117 // TODO: drop the rollback portions of this test when extensions/v1beta1 is no longer served 118 // and rollback endpoint is no longer supported. 119 func TestDeploymentRollingUpdate(t *testing.T) { 120 _, ctx := ktesting.NewTestContext(t) 121 ctx, cancel := context.WithCancel(ctx) 122 defer cancel() 123 124 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 125 defer closeFn() 126 127 name := "test-rolling-update-deployment" 128 ns := framework.CreateNamespaceOrDie(c, name, t) 129 defer framework.DeleteNamespaceOrDie(c, ns, t) 130 131 // Start informer and controllers 132 stopControllers := runControllersAndInformers(t, rm, dc, informers) 133 defer stopControllers() 134 135 replicas := int32(20) 136 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(name, ns.Name, replicas)} 137 tester.deployment.Spec.MinReadySeconds = 4 138 quarter := intstr.FromString("25%") 139 tester.deployment.Spec.Strategy.RollingUpdate = &apps.RollingUpdateDeployment{ 140 MaxUnavailable: &quarter, 141 MaxSurge: &quarter, 142 } 143 144 // Create a deployment. 145 var err error 146 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 147 if err != nil { 148 t.Fatalf("failed to create deployment %s: %v", tester.deployment.Name, err) 149 } 150 oriImage := tester.deployment.Spec.Template.Spec.Containers[0].Image 151 if err := tester.waitForDeploymentRevisionAndImage("1", oriImage); err != nil { 152 t.Fatal(err) 153 } 154 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 155 t.Fatal(err) 156 } 157 158 // 1. Roll out a new image. 159 image := "new-image" 160 if oriImage == image { 161 t.Fatalf("bad test setup, deployment %s roll out with the same image", tester.deployment.Name) 162 } 163 imageFn := func(update *apps.Deployment) { 164 update.Spec.Template.Spec.Containers[0].Image = image 165 } 166 tester.deployment, err = tester.updateDeployment(imageFn) 167 if err != nil { 168 t.Fatalf("failed to update deployment %s: %v", tester.deployment.Name, err) 169 } 170 if err := tester.waitForDeploymentRevisionAndImage("2", image); err != nil { 171 t.Fatal(err) 172 } 173 if err := tester.waitForDeploymentCompleteAndCheckRollingAndMarkPodsReady(); err != nil { 174 t.Fatal(err) 175 } 176 177 // 2. Roll over a deployment before the previous rolling update finishes. 178 image = "dont-finish" 179 imageFn = func(update *apps.Deployment) { 180 update.Spec.Template.Spec.Containers[0].Image = image 181 } 182 tester.deployment, err = tester.updateDeployment(imageFn) 183 if err != nil { 184 t.Fatalf("failed to update deployment %s: %v", tester.deployment.Name, err) 185 } 186 if err := tester.waitForDeploymentRevisionAndImage("3", image); err != nil { 187 t.Fatal(err) 188 } 189 190 // We don't mark pods as ready so that rollout won't finish. 191 // Before the rollout finishes, trigger another rollout. 192 image = "rollover" 193 imageFn = func(update *apps.Deployment) { 194 update.Spec.Template.Spec.Containers[0].Image = image 195 } 196 tester.deployment, err = tester.updateDeployment(imageFn) 197 if err != nil { 198 t.Fatalf("failed to update deployment %s: %v", tester.deployment.Name, err) 199 } 200 if err := tester.waitForDeploymentRevisionAndImage("4", image); err != nil { 201 t.Fatal(err) 202 } 203 if err := tester.waitForDeploymentCompleteAndCheckRollingAndMarkPodsReady(); err != nil { 204 t.Fatal(err) 205 } 206 _, allOldRSs, err := testutil.GetOldReplicaSets(tester.deployment, c) 207 if err != nil { 208 t.Fatalf("failed retrieving old replicasets of deployment %s: %v", tester.deployment.Name, err) 209 } 210 for _, oldRS := range allOldRSs { 211 if *oldRS.Spec.Replicas != 0 { 212 t.Errorf("expected old replicaset %s of deployment %s to have 0 replica, got %d", oldRS.Name, tester.deployment.Name, *oldRS.Spec.Replicas) 213 } 214 } 215 } 216 217 // selectors are IMMUTABLE for all API versions except apps/v1beta1 and extensions/v1beta1 218 func TestDeploymentSelectorImmutability(t *testing.T) { 219 closeFn, c := dcSimpleSetup(t) 220 defer closeFn() 221 222 name := "test-deployment-selector-immutability" 223 ns := framework.CreateNamespaceOrDie(c, name, t) 224 defer framework.DeleteNamespaceOrDie(c, ns, t) 225 226 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(name, ns.Name, int32(20))} 227 var err error 228 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 229 if err != nil { 230 t.Fatalf("failed to create apps/v1 deployment %s: %v", tester.deployment.Name, err) 231 } 232 233 // test to ensure apps/v1 selector is immutable 234 deploymentAppsV1, err := c.AppsV1().Deployments(ns.Name).Get(context.TODO(), name, metav1.GetOptions{}) 235 if err != nil { 236 t.Fatalf("failed to get apps/v1 deployment %s: %v", name, err) 237 } 238 newSelectorLabels := map[string]string{"name_apps_v1": "test_apps_v1"} 239 deploymentAppsV1.Spec.Selector.MatchLabels = newSelectorLabels 240 deploymentAppsV1.Spec.Template.Labels = newSelectorLabels 241 _, err = c.AppsV1().Deployments(ns.Name).Update(context.TODO(), deploymentAppsV1, metav1.UpdateOptions{}) 242 if err == nil { 243 t.Fatalf("failed to provide validation error when changing immutable selector when updating apps/v1 deployment %s", deploymentAppsV1.Name) 244 } 245 expectedErrType := "Invalid value" 246 expectedErrDetail := "field is immutable" 247 if !strings.Contains(err.Error(), expectedErrType) || !strings.Contains(err.Error(), expectedErrDetail) { 248 t.Errorf("error message does not match, expected type: %s, expected detail: %s, got: %s", expectedErrType, expectedErrDetail, err.Error()) 249 } 250 } 251 252 // Paused deployment should not start new rollout 253 func TestPausedDeployment(t *testing.T) { 254 _, ctx := ktesting.NewTestContext(t) 255 ctx, cancel := context.WithCancel(ctx) 256 defer cancel() 257 258 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 259 defer closeFn() 260 261 name := "test-paused-deployment" 262 ns := framework.CreateNamespaceOrDie(c, name, t) 263 defer framework.DeleteNamespaceOrDie(c, ns, t) 264 265 replicas := int32(1) 266 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(name, ns.Name, replicas)} 267 tester.deployment.Spec.Paused = true 268 tgps := int64(1) 269 tester.deployment.Spec.Template.Spec.TerminationGracePeriodSeconds = &tgps 270 271 var err error 272 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 273 if err != nil { 274 t.Fatalf("failed to create deployment %s: %v", tester.deployment.Name, err) 275 } 276 277 // Start informer and controllers 278 stopControllers := runControllersAndInformers(t, rm, dc, informers) 279 defer stopControllers() 280 281 // Verify that the paused deployment won't create new replica set. 282 if err := tester.expectNoNewReplicaSet(); err != nil { 283 t.Fatal(err) 284 } 285 286 // Resume the deployment 287 tester.deployment, err = tester.updateDeployment(resumeFn) 288 if err != nil { 289 t.Fatalf("failed to resume deployment %s: %v", tester.deployment.Name, err) 290 } 291 292 // Wait for the controller to notice the resume. 293 if err := tester.waitForObservedDeployment(tester.deployment.Generation); err != nil { 294 t.Fatal(err) 295 } 296 297 // Wait for the Deployment to be updated to revision 1 298 if err := tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 299 t.Fatal(err) 300 } 301 302 // Make sure the Deployment completes while manually marking Deployment pods as ready at the same time. 303 // Use soft check because this deployment was just created and rolling update strategy might be violated. 304 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 305 t.Fatal(err) 306 } 307 308 // A new replicaset should be created. 309 if _, err := tester.expectNewReplicaSet(); err != nil { 310 t.Fatal(err) 311 } 312 313 // Pause the deployment. 314 // The paused deployment shouldn't trigger a new rollout. 315 tester.deployment, err = tester.updateDeployment(pauseFn) 316 if err != nil { 317 t.Fatalf("failed to pause deployment %s: %v", tester.deployment.Name, err) 318 } 319 320 // Wait for the controller to notice the pause. 321 if err := tester.waitForObservedDeployment(tester.deployment.Generation); err != nil { 322 t.Fatal(err) 323 } 324 325 // Update the deployment template 326 newTGPS := int64(0) 327 tester.deployment, err = tester.updateDeployment(func(update *apps.Deployment) { 328 update.Spec.Template.Spec.TerminationGracePeriodSeconds = &newTGPS 329 }) 330 if err != nil { 331 t.Fatalf("failed updating template of deployment %s: %v", tester.deployment.Name, err) 332 } 333 334 // Wait for the controller to notice the rollout. 335 if err := tester.waitForObservedDeployment(tester.deployment.Generation); err != nil { 336 t.Fatal(err) 337 } 338 339 // Verify that the paused deployment won't create new replica set. 340 if err := tester.expectNoNewReplicaSet(); err != nil { 341 t.Fatal(err) 342 } 343 344 _, allOldRs, err := testutil.GetOldReplicaSets(tester.deployment, c) 345 if err != nil { 346 t.Fatalf("failed retrieving old replicasets of deployment %s: %v", tester.deployment.Name, err) 347 } 348 if len(allOldRs) != 1 { 349 t.Errorf("expected an old replica set, got %v", allOldRs) 350 } 351 if *allOldRs[0].Spec.Template.Spec.TerminationGracePeriodSeconds == newTGPS { 352 t.Errorf("TerminationGracePeriodSeconds on the replica set should be %d, got %d", tgps, newTGPS) 353 } 354 } 355 356 // Paused deployment can be scaled 357 func TestScalePausedDeployment(t *testing.T) { 358 _, ctx := ktesting.NewTestContext(t) 359 ctx, cancel := context.WithCancel(ctx) 360 defer cancel() 361 362 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 363 defer closeFn() 364 365 name := "test-scale-paused-deployment" 366 ns := framework.CreateNamespaceOrDie(c, name, t) 367 defer framework.DeleteNamespaceOrDie(c, ns, t) 368 369 replicas := int32(1) 370 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(name, ns.Name, replicas)} 371 tgps := int64(1) 372 tester.deployment.Spec.Template.Spec.TerminationGracePeriodSeconds = &tgps 373 374 var err error 375 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 376 if err != nil { 377 t.Fatalf("failed to create deployment %s: %v", tester.deployment.Name, err) 378 } 379 380 // Start informer and controllers 381 stopControllers := runControllersAndInformers(t, rm, dc, informers) 382 defer stopControllers() 383 384 // Wait for the Deployment to be updated to revision 1 385 if err := tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 386 t.Fatal(err) 387 } 388 389 // Make sure the Deployment completes while manually marking Deployment pods as ready at the same time. 390 // Use soft check because this deployment was just created and rolling update strategy might be violated. 391 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 392 t.Fatal(err) 393 } 394 395 // A new replicaset should be created. 396 if _, err := tester.expectNewReplicaSet(); err != nil { 397 t.Fatal(err) 398 } 399 400 // Pause the deployment. 401 tester.deployment, err = tester.updateDeployment(pauseFn) 402 if err != nil { 403 t.Fatalf("failed to pause deployment %s: %v", tester.deployment.Name, err) 404 } 405 406 // Wait for the controller to notice the scale. 407 if err := tester.waitForObservedDeployment(tester.deployment.Generation); err != nil { 408 t.Fatal(err) 409 } 410 411 // Scale the paused deployment. 412 newReplicas := int32(10) 413 tester.deployment, err = tester.updateDeployment(func(update *apps.Deployment) { 414 update.Spec.Replicas = &newReplicas 415 }) 416 if err != nil { 417 t.Fatalf("failed updating deployment %s: %v", tester.deployment.Name, err) 418 } 419 420 // Wait for the controller to notice the scale. 421 if err := tester.waitForObservedDeployment(tester.deployment.Generation); err != nil { 422 t.Fatal(err) 423 } 424 425 // Verify that the new replicaset is scaled. 426 rs, err := tester.expectNewReplicaSet() 427 if err != nil { 428 t.Fatal(err) 429 } 430 if *rs.Spec.Replicas != newReplicas { 431 t.Errorf("expected new replicaset replicas = %d, got %d", newReplicas, *rs.Spec.Replicas) 432 } 433 434 // Make sure the Deployment completes while manually marking Deployment pods as ready at the same time. 435 // Use soft check because this deployment was just scaled and rolling update strategy might be violated. 436 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 437 t.Fatal(err) 438 } 439 } 440 441 // Deployment rollout shouldn't be blocked on hash collisions 442 func TestDeploymentHashCollision(t *testing.T) { 443 _, ctx := ktesting.NewTestContext(t) 444 ctx, cancel := context.WithCancel(ctx) 445 defer cancel() 446 447 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 448 defer closeFn() 449 450 name := "test-hash-collision-deployment" 451 ns := framework.CreateNamespaceOrDie(c, name, t) 452 defer framework.DeleteNamespaceOrDie(c, ns, t) 453 454 replicas := int32(1) 455 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(name, ns.Name, replicas)} 456 457 var err error 458 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 459 if err != nil { 460 t.Fatalf("failed to create deployment %s: %v", tester.deployment.Name, err) 461 } 462 463 // Start informer and controllers 464 stopControllers := runControllersAndInformers(t, rm, dc, informers) 465 defer stopControllers() 466 467 // Wait for the Deployment to be updated to revision 1 468 if err := tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 469 t.Fatal(err) 470 } 471 472 // Mock a hash collision 473 newRS, err := testutil.GetNewReplicaSet(tester.deployment, c) 474 if err != nil { 475 t.Fatalf("failed getting new replicaset of deployment %s: %v", tester.deployment.Name, err) 476 } 477 if newRS == nil { 478 t.Fatalf("unable to find new replicaset of deployment %s", tester.deployment.Name) 479 } 480 _, err = tester.updateReplicaSet(newRS.Name, func(update *apps.ReplicaSet) { 481 *update.Spec.Template.Spec.TerminationGracePeriodSeconds = int64(5) 482 }) 483 if err != nil { 484 t.Fatalf("failed updating replicaset %s template: %v", newRS.Name, err) 485 } 486 487 // Expect deployment collision counter to increment 488 if err := wait.PollImmediate(pollInterval, pollTimeout, func() (bool, error) { 489 d, err := c.AppsV1().Deployments(ns.Name).Get(context.TODO(), tester.deployment.Name, metav1.GetOptions{}) 490 if err != nil { 491 return false, nil 492 } 493 return d.Status.CollisionCount != nil && *d.Status.CollisionCount == int32(1), nil 494 }); err != nil { 495 t.Fatalf("Failed to increment collision counter for deployment %q: %v", tester.deployment.Name, err) 496 } 497 498 // Expect a new ReplicaSet to be created 499 if err := tester.waitForDeploymentRevisionAndImage("2", fakeImage); err != nil { 500 t.Fatal(err) 501 } 502 } 503 504 func checkRSHashLabels(rs *apps.ReplicaSet) (string, error) { 505 hash := rs.Labels[apps.DefaultDeploymentUniqueLabelKey] 506 selectorHash := rs.Spec.Selector.MatchLabels[apps.DefaultDeploymentUniqueLabelKey] 507 templateLabelHash := rs.Spec.Template.Labels[apps.DefaultDeploymentUniqueLabelKey] 508 509 if hash != selectorHash || selectorHash != templateLabelHash { 510 return "", fmt.Errorf("mismatching hash value found in replicaset %s: %#v", rs.Name, rs) 511 } 512 if len(hash) == 0 { 513 return "", fmt.Errorf("unexpected replicaset %s missing required pod-template-hash labels", rs.Name) 514 } 515 516 if !strings.HasSuffix(rs.Name, hash) { 517 return "", fmt.Errorf("unexpected replicaset %s name suffix doesn't match hash %s", rs.Name, hash) 518 } 519 520 return hash, nil 521 } 522 523 func checkPodsHashLabel(pods *v1.PodList) (string, error) { 524 if len(pods.Items) == 0 { 525 return "", fmt.Errorf("no pods given") 526 } 527 var hash string 528 for _, pod := range pods.Items { 529 podHash := pod.Labels[apps.DefaultDeploymentUniqueLabelKey] 530 if len(podHash) == 0 { 531 return "", fmt.Errorf("found pod %s missing pod-template-hash label: %#v", pod.Name, pods) 532 } 533 // Save the first valid hash 534 if len(hash) == 0 { 535 hash = podHash 536 } 537 if podHash != hash { 538 return "", fmt.Errorf("found pod %s with mismatching pod-template-hash value %s: %#v", pod.Name, podHash, pods) 539 } 540 } 541 return hash, nil 542 } 543 544 // Deployment should have a timeout condition when it fails to progress after given deadline. 545 func TestFailedDeployment(t *testing.T) { 546 _, ctx := ktesting.NewTestContext(t) 547 ctx, cancel := context.WithCancel(ctx) 548 defer cancel() 549 550 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 551 defer closeFn() 552 553 name := "test-failed-deployment" 554 ns := framework.CreateNamespaceOrDie(c, name, t) 555 defer framework.DeleteNamespaceOrDie(c, ns, t) 556 557 deploymentName := "progress-check" 558 replicas := int32(1) 559 three := int32(3) 560 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(deploymentName, ns.Name, replicas)} 561 tester.deployment.Spec.ProgressDeadlineSeconds = &three 562 var err error 563 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 564 if err != nil { 565 t.Fatalf("failed to create deployment %q: %v", deploymentName, err) 566 } 567 568 // Start informer and controllers 569 stopControllers := runControllersAndInformers(t, rm, dc, informers) 570 defer stopControllers() 571 572 if err = tester.waitForDeploymentUpdatedReplicasGTE(replicas); err != nil { 573 t.Fatal(err) 574 } 575 576 // Pods are not marked as Ready, therefore the deployment progress will eventually timeout after progressDeadlineSeconds has passed. 577 // Wait for the deployment to have a progress timeout condition. 578 if err = tester.waitForDeploymentWithCondition(deploymentutil.TimedOutReason, apps.DeploymentProgressing); err != nil { 579 t.Fatal(err) 580 } 581 582 // Manually mark pods as Ready and wait for deployment to complete. 583 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 584 t.Fatalf("deployment %q fails to have its status becoming valid: %v", deploymentName, err) 585 } 586 587 // Wait for the deployment to have a progress complete condition. 588 if err = tester.waitForDeploymentWithCondition(deploymentutil.NewRSAvailableReason, apps.DeploymentProgressing); err != nil { 589 t.Fatal(err) 590 } 591 } 592 593 func TestOverlappingDeployments(t *testing.T) { 594 _, ctx := ktesting.NewTestContext(t) 595 ctx, cancel := context.WithCancel(ctx) 596 defer cancel() 597 598 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 599 defer closeFn() 600 601 name := "test-overlapping-deployments" 602 ns := framework.CreateNamespaceOrDie(c, name, t) 603 defer framework.DeleteNamespaceOrDie(c, ns, t) 604 605 replicas := int32(1) 606 firstDeploymentName := "first-deployment" 607 secondDeploymentName := "second-deployment" 608 testers := []*deploymentTester{ 609 {t: t, c: c, deployment: newDeployment(firstDeploymentName, ns.Name, replicas)}, 610 {t: t, c: c, deployment: newDeployment(secondDeploymentName, ns.Name, replicas)}, 611 } 612 613 // Start informer and controllers 614 stopControllers := runControllersAndInformers(t, rm, dc, informers) 615 defer stopControllers() 616 617 // Create 2 deployments with overlapping selectors 618 var err error 619 var rss []*apps.ReplicaSet 620 for _, tester := range testers { 621 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 622 dname := tester.deployment.Name 623 if err != nil { 624 t.Fatalf("failed to create deployment %q: %v", dname, err) 625 } 626 // Wait for the deployment to be updated to revision 1 627 if err = tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 628 t.Fatalf("failed to update deployment %q to revision 1: %v", dname, err) 629 } 630 // Make sure the deployment completes while manually marking its pods as ready at the same time 631 if err = tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 632 t.Fatalf("deployment %q failed to complete: %v", dname, err) 633 } 634 // Get replicaset of the deployment 635 newRS, err := tester.getNewReplicaSet() 636 if err != nil { 637 t.Fatalf("failed to get new replicaset of deployment %q: %v", dname, err) 638 } 639 if newRS == nil { 640 t.Fatalf("unable to find new replicaset of deployment %q", dname) 641 } 642 // Store the replicaset for future usage 643 rss = append(rss, newRS) 644 } 645 646 // Both deployments should proceed independently, so their respective replicaset should not be the same replicaset 647 if rss[0].UID == rss[1].UID { 648 t.Fatalf("overlapping deployments should not share the same replicaset") 649 } 650 651 // Scale only the first deployment by 1 652 newReplicas := replicas + 1 653 testers[0].deployment, err = testers[0].updateDeployment(func(update *apps.Deployment) { 654 update.Spec.Replicas = &newReplicas 655 }) 656 if err != nil { 657 t.Fatalf("failed updating deployment %q: %v", firstDeploymentName, err) 658 } 659 660 // Make sure the deployment completes after scaling 661 if err := testers[0].waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 662 t.Fatalf("deployment %q failed to complete after scaling: %v", firstDeploymentName, err) 663 } 664 665 // Verify replicaset of both deployments has updated number of replicas 666 for i, tester := range testers { 667 rs, err := c.AppsV1().ReplicaSets(ns.Name).Get(context.TODO(), rss[i].Name, metav1.GetOptions{}) 668 if err != nil { 669 t.Fatalf("failed to get replicaset %q: %v", rss[i].Name, err) 670 } 671 if *rs.Spec.Replicas != *tester.deployment.Spec.Replicas { 672 t.Errorf("expected replicaset %q of deployment %q has %d replicas, but found %d replicas", rs.Name, firstDeploymentName, *tester.deployment.Spec.Replicas, *rs.Spec.Replicas) 673 } 674 } 675 } 676 677 // Deployment should not block rollout when updating spec replica number and template at the same time. 678 func TestScaledRolloutDeployment(t *testing.T) { 679 logger, ctx := ktesting.NewTestContext(t) 680 ctx, cancel := context.WithCancel(ctx) 681 defer cancel() 682 683 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 684 defer closeFn() 685 686 name := "test-scaled-rollout-deployment" 687 ns := framework.CreateNamespaceOrDie(c, name, t) 688 defer framework.DeleteNamespaceOrDie(c, ns, t) 689 690 // Start informer and controllers 691 stopControllers := runControllersAndInformers(t, rm, dc, informers) 692 defer stopControllers() 693 694 // Create a deployment with rolling update strategy, max surge = 3, and max unavailable = 2 695 var err error 696 replicas := int32(10) 697 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(name, ns.Name, replicas)} 698 tester.deployment.Spec.Strategy.RollingUpdate.MaxSurge = ptr.To(intstr.FromInt32(3)) 699 tester.deployment.Spec.Strategy.RollingUpdate.MaxUnavailable = ptr.To(intstr.FromInt32(2)) 700 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 701 if err != nil { 702 t.Fatalf("failed to create deployment %q: %v", name, err) 703 } 704 if err = tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 705 t.Fatal(err) 706 } 707 if err = tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 708 t.Fatalf("deployment %q failed to complete: %v", name, err) 709 } 710 711 // Record current replicaset before starting new rollout 712 firstRS, err := tester.expectNewReplicaSet() 713 if err != nil { 714 t.Fatal(err) 715 } 716 717 // Update the deployment with another new image but do not mark the pods as ready to block new replicaset 718 fakeImage2 := "fakeimage2" 719 tester.deployment, err = tester.updateDeployment(func(update *apps.Deployment) { 720 update.Spec.Template.Spec.Containers[0].Image = fakeImage2 721 }) 722 if err != nil { 723 t.Fatalf("failed updating deployment %q: %v", name, err) 724 } 725 if err = tester.waitForDeploymentRevisionAndImage("2", fakeImage2); err != nil { 726 t.Fatal(err) 727 } 728 729 // Verify the deployment has minimum available replicas after 2nd rollout 730 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Get(context.TODO(), name, metav1.GetOptions{}) 731 if err != nil { 732 t.Fatalf("failed to get deployment %q: %v", name, err) 733 } 734 minAvailableReplicas := deploymentutil.MinAvailable(tester.deployment) 735 if tester.deployment.Status.AvailableReplicas < minAvailableReplicas { 736 t.Fatalf("deployment %q does not have minimum number of available replicas after 2nd rollout", name) 737 } 738 739 // Wait for old replicaset of 1st rollout to have desired replicas 740 firstRS, err = c.AppsV1().ReplicaSets(ns.Name).Get(context.TODO(), firstRS.Name, metav1.GetOptions{}) 741 if err != nil { 742 t.Fatalf("failed to get replicaset %q: %v", firstRS.Name, err) 743 } 744 if err = tester.waitRSStable(firstRS); err != nil { 745 t.Fatal(err) 746 } 747 748 // Wait for new replicaset of 2nd rollout to have desired replicas 749 secondRS, err := tester.expectNewReplicaSet() 750 if err != nil { 751 t.Fatal(err) 752 } 753 if err = tester.waitRSStable(secondRS); err != nil { 754 t.Fatal(err) 755 } 756 757 // Scale up the deployment and update its image to another new image simultaneously (this time marks all pods as ready) 758 newReplicas := int32(20) 759 fakeImage3 := "fakeimage3" 760 tester.deployment, err = tester.updateDeployment(func(update *apps.Deployment) { 761 update.Spec.Replicas = &newReplicas 762 update.Spec.Template.Spec.Containers[0].Image = fakeImage3 763 }) 764 if err != nil { 765 t.Fatalf("failed updating deployment %q: %v", name, err) 766 } 767 if err = tester.waitForDeploymentRevisionAndImage("3", fakeImage3); err != nil { 768 t.Fatal(err) 769 } 770 if err = tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 771 t.Fatalf("deployment %q failed to complete: %v", name, err) 772 } 773 774 // Verify every replicaset has correct desiredReplicas annotation after 3rd rollout 775 thirdRS, err := testutil.GetNewReplicaSet(tester.deployment, c) 776 if err != nil { 777 t.Fatalf("failed getting new revision 3 replicaset for deployment %q: %v", name, err) 778 } 779 rss := []*apps.ReplicaSet{firstRS, secondRS, thirdRS} 780 for _, curRS := range rss { 781 curRS, err = c.AppsV1().ReplicaSets(ns.Name).Get(context.TODO(), curRS.Name, metav1.GetOptions{}) 782 if err != nil { 783 t.Fatalf("failed to get replicaset when checking desired replicas annotation: %v", err) 784 } 785 desired, ok := deploymentutil.GetDesiredReplicasAnnotation(logger, curRS) 786 if !ok { 787 t.Fatalf("failed to retrieve desiredReplicas annotation for replicaset %q", curRS.Name) 788 } 789 if desired != *(tester.deployment.Spec.Replicas) { 790 t.Fatalf("unexpected desiredReplicas annotation for replicaset %q: expected %d, got %d", curRS.Name, *(tester.deployment.Spec.Replicas), desired) 791 } 792 } 793 794 // Update the deployment with another new image but do not mark the pods as ready to block new replicaset 795 fakeImage4 := "fakeimage4" 796 tester.deployment, err = tester.updateDeployment(func(update *apps.Deployment) { 797 update.Spec.Template.Spec.Containers[0].Image = fakeImage4 798 }) 799 if err != nil { 800 t.Fatalf("failed updating deployment %q: %v", name, err) 801 } 802 if err = tester.waitForDeploymentRevisionAndImage("4", fakeImage4); err != nil { 803 t.Fatal(err) 804 } 805 806 // Verify the deployment has minimum available replicas after 4th rollout 807 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Get(context.TODO(), name, metav1.GetOptions{}) 808 if err != nil { 809 t.Fatalf("failed to get deployment %q: %v", name, err) 810 } 811 minAvailableReplicas = deploymentutil.MinAvailable(tester.deployment) 812 if tester.deployment.Status.AvailableReplicas < minAvailableReplicas { 813 t.Fatalf("deployment %q does not have minimum number of available replicas after 4th rollout", name) 814 } 815 816 // Wait for old replicaset of 3rd rollout to have desired replicas 817 thirdRS, err = c.AppsV1().ReplicaSets(ns.Name).Get(context.TODO(), thirdRS.Name, metav1.GetOptions{}) 818 if err != nil { 819 t.Fatalf("failed to get replicaset %q: %v", thirdRS.Name, err) 820 } 821 if err = tester.waitRSStable(thirdRS); err != nil { 822 t.Fatal(err) 823 } 824 825 // Wait for new replicaset of 4th rollout to have desired replicas 826 fourthRS, err := tester.expectNewReplicaSet() 827 if err != nil { 828 t.Fatal(err) 829 } 830 if err = tester.waitRSStable(fourthRS); err != nil { 831 t.Fatal(err) 832 } 833 834 // Scale down the deployment and update its image to another new image simultaneously (this time marks all pods as ready) 835 newReplicas = int32(5) 836 fakeImage5 := "fakeimage5" 837 tester.deployment, err = tester.updateDeployment(func(update *apps.Deployment) { 838 update.Spec.Replicas = &newReplicas 839 update.Spec.Template.Spec.Containers[0].Image = fakeImage5 840 }) 841 if err != nil { 842 t.Fatalf("failed updating deployment %q: %v", name, err) 843 } 844 if err = tester.waitForDeploymentRevisionAndImage("5", fakeImage5); err != nil { 845 t.Fatal(err) 846 } 847 if err = tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 848 t.Fatalf("deployment %q failed to complete: %v", name, err) 849 } 850 851 // Verify every replicaset has correct desiredReplicas annotation after 5th rollout 852 fifthRS, err := testutil.GetNewReplicaSet(tester.deployment, c) 853 if err != nil { 854 t.Fatalf("failed getting new revision 5 replicaset for deployment %q: %v", name, err) 855 } 856 rss = []*apps.ReplicaSet{thirdRS, fourthRS, fifthRS} 857 for _, curRS := range rss { 858 curRS, err = c.AppsV1().ReplicaSets(ns.Name).Get(context.TODO(), curRS.Name, metav1.GetOptions{}) 859 if err != nil { 860 t.Fatalf("failed to get replicaset when checking desired replicas annotation: %v", err) 861 } 862 desired, ok := deploymentutil.GetDesiredReplicasAnnotation(logger, curRS) 863 if !ok { 864 t.Fatalf("failed to retrieve desiredReplicas annotation for replicaset %q", curRS.Name) 865 } 866 if desired != *(tester.deployment.Spec.Replicas) { 867 t.Fatalf("unexpected desiredReplicas annotation for replicaset %q: expected %d, got %d", curRS.Name, *(tester.deployment.Spec.Replicas), desired) 868 } 869 } 870 } 871 872 func TestSpecReplicasChange(t *testing.T) { 873 _, ctx := ktesting.NewTestContext(t) 874 ctx, cancel := context.WithCancel(ctx) 875 defer cancel() 876 877 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 878 defer closeFn() 879 880 name := "test-spec-replicas-change" 881 ns := framework.CreateNamespaceOrDie(c, name, t) 882 defer framework.DeleteNamespaceOrDie(c, ns, t) 883 884 deploymentName := "deployment" 885 replicas := int32(1) 886 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(deploymentName, ns.Name, replicas)} 887 tester.deployment.Spec.Strategy.Type = apps.RecreateDeploymentStrategyType 888 tester.deployment.Spec.Strategy.RollingUpdate = nil 889 var err error 890 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 891 if err != nil { 892 t.Fatalf("failed to create deployment %q: %v", deploymentName, err) 893 } 894 895 // Start informer and controllers 896 stopControllers := runControllersAndInformers(t, rm, dc, informers) 897 defer stopControllers() 898 899 // Scale up/down deployment and verify its replicaset has matching .spec.replicas 900 if err = tester.scaleDeployment(2); err != nil { 901 t.Fatal(err) 902 } 903 if err = tester.scaleDeployment(0); err != nil { 904 t.Fatal(err) 905 } 906 if err = tester.scaleDeployment(1); err != nil { 907 t.Fatal(err) 908 } 909 910 // Add a template annotation change to test deployment's status does update 911 // without .spec.replicas change 912 var oldGeneration int64 913 tester.deployment, err = tester.updateDeployment(func(update *apps.Deployment) { 914 oldGeneration = update.Generation 915 update.Spec.RevisionHistoryLimit = ptr.To[int32](4) 916 }) 917 if err != nil { 918 t.Fatalf("failed updating deployment %q: %v", tester.deployment.Name, err) 919 } 920 921 savedGeneration := tester.deployment.Generation 922 if savedGeneration == oldGeneration { 923 t.Fatalf("Failed to verify .Generation has incremented for deployment %q", deploymentName) 924 } 925 if err = tester.waitForObservedDeployment(savedGeneration); err != nil { 926 t.Fatal(err) 927 } 928 } 929 930 func TestDeploymentAvailableCondition(t *testing.T) { 931 _, ctx := ktesting.NewTestContext(t) 932 ctx, cancel := context.WithCancel(ctx) 933 defer cancel() 934 935 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 936 defer closeFn() 937 938 name := "test-deployment-available-condition" 939 ns := framework.CreateNamespaceOrDie(c, name, t) 940 defer framework.DeleteNamespaceOrDie(c, ns, t) 941 942 deploymentName := "deployment" 943 replicas := int32(10) 944 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(deploymentName, ns.Name, replicas)} 945 // Assign a high value to the deployment's minReadySeconds 946 tester.deployment.Spec.MinReadySeconds = 3600 947 // progressDeadlineSeconds must be greater than minReadySeconds 948 tester.deployment.Spec.ProgressDeadlineSeconds = ptr.To[int32](7200) 949 var err error 950 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 951 if err != nil { 952 t.Fatalf("failed to create deployment %q: %v", deploymentName, err) 953 } 954 955 // Start informer and controllers 956 stopControllers := runControllersAndInformers(t, rm, dc, informers) 957 defer stopControllers() 958 959 // Wait for the deployment to be observed by the controller and has at least specified number of updated replicas 960 if err = tester.waitForDeploymentUpdatedReplicasGTE(replicas); err != nil { 961 t.Fatal(err) 962 } 963 964 // Wait for the deployment to have MinimumReplicasUnavailable reason because the pods are not marked as ready 965 if err = tester.waitForDeploymentWithCondition(deploymentutil.MinimumReplicasUnavailable, apps.DeploymentAvailable); err != nil { 966 t.Fatal(err) 967 } 968 969 // Verify all replicas fields of DeploymentStatus have desired counts 970 if err = tester.checkDeploymentStatusReplicasFields(10, 10, 0, 0, 10); err != nil { 971 t.Fatal(err) 972 } 973 974 // Mark the pods as ready without waiting for the deployment to complete 975 if err = tester.markUpdatedPodsReadyWithoutComplete(); err != nil { 976 t.Fatal(err) 977 } 978 979 // Wait for number of ready replicas to equal number of replicas. 980 if err = tester.waitForReadyReplicas(); err != nil { 981 t.Fatal(err) 982 } 983 984 // Wait for the deployment to still have MinimumReplicasUnavailable reason within minReadySeconds period 985 if err = tester.waitForDeploymentWithCondition(deploymentutil.MinimumReplicasUnavailable, apps.DeploymentAvailable); err != nil { 986 t.Fatal(err) 987 } 988 989 // Verify all replicas fields of DeploymentStatus have desired counts 990 if err = tester.checkDeploymentStatusReplicasFields(10, 10, 10, 0, 10); err != nil { 991 t.Fatal(err) 992 } 993 994 // Update the deployment's minReadySeconds to a small value 995 tester.deployment, err = tester.updateDeployment(func(update *apps.Deployment) { 996 update.Spec.MinReadySeconds = 1 997 }) 998 if err != nil { 999 t.Fatalf("failed updating deployment %q: %v", deploymentName, err) 1000 } 1001 1002 // Wait for the deployment to notice minReadySeconds has changed 1003 if err := tester.waitForObservedDeployment(tester.deployment.Generation); err != nil { 1004 t.Fatal(err) 1005 } 1006 1007 // Wait for the deployment to have MinimumReplicasAvailable reason after minReadySeconds period 1008 if err = tester.waitForDeploymentWithCondition(deploymentutil.MinimumReplicasAvailable, apps.DeploymentAvailable); err != nil { 1009 t.Fatal(err) 1010 } 1011 1012 // Verify all replicas fields of DeploymentStatus have desired counts 1013 if err = tester.checkDeploymentStatusReplicasFields(10, 10, 10, 10, 0); err != nil { 1014 t.Fatal(err) 1015 } 1016 } 1017 1018 // Wait for deployment to automatically patch incorrect ControllerRef of RS 1019 func testRSControllerRefPatch(t *testing.T, tester *deploymentTester, rs *apps.ReplicaSet, ownerReference *metav1.OwnerReference, expectedOwnerReferenceNum int) { 1020 ns := rs.Namespace 1021 rsClient := tester.c.AppsV1().ReplicaSets(ns) 1022 rs, err := tester.updateReplicaSet(rs.Name, func(update *apps.ReplicaSet) { 1023 update.OwnerReferences = []metav1.OwnerReference{*ownerReference} 1024 }) 1025 if err != nil { 1026 t.Fatalf("failed to update replicaset %q: %v", rs.Name, err) 1027 } 1028 1029 if err := wait.PollImmediate(pollInterval, pollTimeout, func() (bool, error) { 1030 newRS, err := rsClient.Get(context.TODO(), rs.Name, metav1.GetOptions{}) 1031 if err != nil { 1032 return false, err 1033 } 1034 return metav1.GetControllerOf(newRS) != nil, nil 1035 }); err != nil { 1036 t.Fatalf("failed to wait for controllerRef of the replicaset %q to become nil: %v", rs.Name, err) 1037 } 1038 1039 newRS, err := rsClient.Get(context.TODO(), rs.Name, metav1.GetOptions{}) 1040 if err != nil { 1041 t.Fatalf("failed to obtain replicaset %q: %v", rs.Name, err) 1042 } 1043 controllerRef := metav1.GetControllerOf(newRS) 1044 if controllerRef.UID != tester.deployment.UID { 1045 t.Fatalf("controllerRef of replicaset %q has a different UID: Expected %v, got %v", newRS.Name, tester.deployment.UID, controllerRef.UID) 1046 } 1047 ownerReferenceNum := len(newRS.GetOwnerReferences()) 1048 if ownerReferenceNum != expectedOwnerReferenceNum { 1049 t.Fatalf("unexpected number of owner references for replicaset %q: Expected %d, got %d", newRS.Name, expectedOwnerReferenceNum, ownerReferenceNum) 1050 } 1051 } 1052 1053 func TestGeneralReplicaSetAdoption(t *testing.T) { 1054 _, ctx := ktesting.NewTestContext(t) 1055 ctx, cancel := context.WithCancel(ctx) 1056 defer cancel() 1057 1058 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 1059 defer closeFn() 1060 1061 name := "test-general-replicaset-adoption" 1062 ns := framework.CreateNamespaceOrDie(c, name, t) 1063 defer framework.DeleteNamespaceOrDie(c, ns, t) 1064 1065 deploymentName := "deployment" 1066 replicas := int32(1) 1067 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(deploymentName, ns.Name, replicas)} 1068 var err error 1069 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 1070 if err != nil { 1071 t.Fatalf("failed to create deployment %q: %v", deploymentName, err) 1072 } 1073 1074 // Start informer and controllers 1075 stopControllers := runControllersAndInformers(t, rm, dc, informers) 1076 defer stopControllers() 1077 1078 // Wait for the Deployment to be updated to revision 1 1079 if err := tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 1080 t.Fatal(err) 1081 } 1082 1083 // Ensure the deployment completes while marking its pods as ready simultaneously 1084 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 1085 t.Fatal(err) 1086 } 1087 1088 // Get replicaset of the deployment 1089 rs, err := testutil.GetNewReplicaSet(tester.deployment, c) 1090 if err != nil { 1091 t.Fatalf("failed to get replicaset of deployment %q: %v", deploymentName, err) 1092 } 1093 if rs == nil { 1094 t.Fatalf("unable to find replicaset of deployment %q", deploymentName) 1095 } 1096 1097 // When the only OwnerReference of the RS points to another type of API object such as statefulset 1098 // with Controller=false, the deployment should add a second OwnerReference (ControllerRef) pointing to itself 1099 // with Controller=true 1100 var falseVar = false 1101 ownerReference := metav1.OwnerReference{UID: uuid.NewUUID(), APIVersion: "apps/v1", Kind: "StatefulSet", Name: deploymentName, Controller: &falseVar} 1102 testRSControllerRefPatch(t, tester, rs, &ownerReference, 2) 1103 1104 // When the only OwnerReference of the RS points to the deployment with Controller=false, 1105 // the deployment should set Controller=true for the only OwnerReference 1106 ownerReference = metav1.OwnerReference{UID: tester.deployment.UID, APIVersion: "apps/v1", Kind: "Deployment", Name: deploymentName, Controller: &falseVar} 1107 testRSControllerRefPatch(t, tester, rs, &ownerReference, 1) 1108 } 1109 1110 func testScalingUsingScaleSubresource(t *testing.T, tester *deploymentTester, replicas int32) { 1111 ns := tester.deployment.Namespace 1112 deploymentName := tester.deployment.Name 1113 deploymentClient := tester.c.AppsV1().Deployments(ns) 1114 deployment, err := deploymentClient.Get(context.TODO(), deploymentName, metav1.GetOptions{}) 1115 if err != nil { 1116 t.Fatalf("Failed to obtain deployment %q: %v", deploymentName, err) 1117 } 1118 scale, err := tester.c.AppsV1().Deployments(ns).GetScale(context.TODO(), deploymentName, metav1.GetOptions{}) 1119 if err != nil { 1120 t.Fatalf("Failed to obtain scale subresource for deployment %q: %v", deploymentName, err) 1121 } 1122 if scale.Spec.Replicas != *deployment.Spec.Replicas { 1123 t.Fatalf("Scale subresource for deployment %q does not match .Spec.Replicas: expected %d, got %d", deploymentName, *deployment.Spec.Replicas, scale.Spec.Replicas) 1124 } 1125 1126 if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { 1127 scale, err := tester.c.AppsV1().Deployments(ns).GetScale(context.TODO(), deploymentName, metav1.GetOptions{}) 1128 if err != nil { 1129 return err 1130 } 1131 scale.Spec.Replicas = replicas 1132 _, err = tester.c.AppsV1().Deployments(ns).UpdateScale(context.TODO(), deploymentName, scale, metav1.UpdateOptions{}) 1133 return err 1134 }); err != nil { 1135 t.Fatalf("Failed to set .Spec.Replicas of scale subresource for deployment %q: %v", deploymentName, err) 1136 } 1137 1138 deployment, err = deploymentClient.Get(context.TODO(), deploymentName, metav1.GetOptions{}) 1139 if err != nil { 1140 t.Fatalf("Failed to obtain deployment %q: %v", deploymentName, err) 1141 } 1142 if *deployment.Spec.Replicas != replicas { 1143 t.Fatalf(".Spec.Replicas of deployment %q does not match its scale subresource: expected %d, got %d", deploymentName, replicas, *deployment.Spec.Replicas) 1144 } 1145 } 1146 1147 func TestDeploymentScaleSubresource(t *testing.T) { 1148 _, ctx := ktesting.NewTestContext(t) 1149 ctx, cancel := context.WithCancel(ctx) 1150 defer cancel() 1151 1152 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 1153 defer closeFn() 1154 1155 name := "test-deployment-scale-subresource" 1156 ns := framework.CreateNamespaceOrDie(c, name, t) 1157 defer framework.DeleteNamespaceOrDie(c, ns, t) 1158 1159 deploymentName := "deployment" 1160 replicas := int32(2) 1161 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(deploymentName, ns.Name, replicas)} 1162 var err error 1163 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 1164 if err != nil { 1165 t.Fatalf("failed to create deployment %q: %v", deploymentName, err) 1166 } 1167 1168 // Start informer and controllers 1169 stopControllers := runControllersAndInformers(t, rm, dc, informers) 1170 defer stopControllers() 1171 1172 // Wait for the Deployment to be updated to revision 1 1173 if err := tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 1174 t.Fatal(err) 1175 } 1176 1177 // Ensure the deployment completes while marking its pods as ready simultaneously 1178 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 1179 t.Fatal(err) 1180 } 1181 1182 // Use scale subresource to scale the deployment up to 3 1183 testScalingUsingScaleSubresource(t, tester, 3) 1184 // Use the scale subresource to scale the deployment down to 0 1185 testScalingUsingScaleSubresource(t, tester, 0) 1186 } 1187 1188 // This test verifies that the Deployment does orphan a ReplicaSet when the ReplicaSet's 1189 // .Labels field is changed to no longer match the Deployment's selector. It also partially 1190 // verifies that collision avoidance mechanism is triggered when a Deployment's new ReplicaSet 1191 // is orphaned, even without PodTemplateSpec change. Refer comment below for more info: 1192 // https://github.com/kubernetes/kubernetes/pull/59212#discussion_r166465113 1193 func TestReplicaSetOrphaningAndAdoptionWhenLabelsChange(t *testing.T) { 1194 _, ctx := ktesting.NewTestContext(t) 1195 ctx, cancel := context.WithCancel(ctx) 1196 defer cancel() 1197 1198 closeFn, rm, dc, informers, c := dcSetup(ctx, t) 1199 defer closeFn() 1200 1201 name := "test-replicaset-orphaning-and-adoption-when-labels-change" 1202 ns := framework.CreateNamespaceOrDie(c, name, t) 1203 defer framework.DeleteNamespaceOrDie(c, ns, t) 1204 1205 deploymentName := "deployment" 1206 replicas := int32(1) 1207 tester := &deploymentTester{t: t, c: c, deployment: newDeployment(deploymentName, ns.Name, replicas)} 1208 var err error 1209 tester.deployment, err = c.AppsV1().Deployments(ns.Name).Create(context.TODO(), tester.deployment, metav1.CreateOptions{}) 1210 if err != nil { 1211 t.Fatalf("failed to create deployment %q: %v", deploymentName, err) 1212 } 1213 1214 // Start informer and controllers 1215 stopControllers := runControllersAndInformers(t, rm, dc, informers) 1216 defer stopControllers() 1217 1218 // Wait for the Deployment to be updated to revision 1 1219 if err := tester.waitForDeploymentRevisionAndImage("1", fakeImage); err != nil { 1220 t.Fatal(err) 1221 } 1222 1223 // Ensure the deployment completes while marking its pods as ready simultaneously 1224 if err := tester.waitForDeploymentCompleteAndMarkPodsReady(); err != nil { 1225 t.Fatal(err) 1226 } 1227 1228 // Orphaning: deployment should remove OwnerReference from a RS when the RS's labels change to not match its labels 1229 1230 // Get replicaset of the deployment 1231 rs, err := testutil.GetNewReplicaSet(tester.deployment, c) 1232 if err != nil { 1233 t.Fatalf("failed to get replicaset of deployment %q: %v", deploymentName, err) 1234 } 1235 if rs == nil { 1236 t.Fatalf("unable to find replicaset of deployment %q", deploymentName) 1237 } 1238 1239 // Verify controllerRef of the replicaset is not nil and pointing to the deployment 1240 controllerRef := metav1.GetControllerOf(rs) 1241 if controllerRef == nil { 1242 t.Fatalf("controllerRef of replicaset %q is nil", rs.Name) 1243 } 1244 if controllerRef.UID != tester.deployment.UID { 1245 t.Fatalf("controllerRef of replicaset %q has a different UID: Expected %v, got %v", rs.Name, tester.deployment.UID, controllerRef.UID) 1246 } 1247 1248 // Change the replicaset's labels to not match the deployment's labels 1249 labelMap := map[string]string{"new-name": "new-test"} 1250 rs, err = tester.updateReplicaSet(rs.Name, func(update *apps.ReplicaSet) { 1251 update.Labels = labelMap 1252 }) 1253 if err != nil { 1254 t.Fatalf("failed to update replicaset %q: %v", rs.Name, err) 1255 } 1256 1257 // Wait for the controllerRef of the replicaset to become nil 1258 rsClient := tester.c.AppsV1().ReplicaSets(ns.Name) 1259 if err = wait.PollImmediate(pollInterval, pollTimeout, func() (bool, error) { 1260 rs, err = rsClient.Get(context.TODO(), rs.Name, metav1.GetOptions{}) 1261 if err != nil { 1262 return false, err 1263 } 1264 return metav1.GetControllerOf(rs) == nil, nil 1265 }); err != nil { 1266 t.Fatalf("failed to wait for controllerRef of replicaset %q to become nil: %v", rs.Name, err) 1267 } 1268 1269 // Wait for the deployment to create a new replicaset 1270 // This will trigger collision avoidance due to deterministic nature of replicaset name 1271 // i.e., the new replicaset will have a name with different hash to preserve name uniqueness 1272 var newRS *apps.ReplicaSet 1273 if err = wait.PollImmediate(pollInterval, pollTimeout, func() (bool, error) { 1274 newRS, err = testutil.GetNewReplicaSet(tester.deployment, c) 1275 if err != nil { 1276 return false, fmt.Errorf("failed to get new replicaset of deployment %q after orphaning: %v", deploymentName, err) 1277 } 1278 return newRS != nil, nil 1279 }); err != nil { 1280 t.Fatalf("failed to wait for deployment %q to create a new replicaset after orphaning: %v", deploymentName, err) 1281 } 1282 if newRS.UID == rs.UID { 1283 t.Fatalf("expect deployment %q to create a new replicaset different from the orphaned one, but it isn't", deploymentName) 1284 } 1285 1286 // Adoption: deployment should add controllerRef to a RS when the RS's labels change to match its labels 1287 1288 // Change the old replicaset's labels to match the deployment's labels 1289 rs, err = tester.updateReplicaSet(rs.Name, func(update *apps.ReplicaSet) { 1290 update.Labels = testLabels() 1291 }) 1292 if err != nil { 1293 t.Fatalf("failed to update replicaset %q: %v", rs.Name, err) 1294 } 1295 1296 // Wait for the deployment to adopt the old replicaset 1297 if err = wait.PollImmediate(pollInterval, pollTimeout, func() (bool, error) { 1298 rs, err := rsClient.Get(context.TODO(), rs.Name, metav1.GetOptions{}) 1299 if err != nil { 1300 return false, err 1301 } 1302 controllerRef = metav1.GetControllerOf(rs) 1303 return controllerRef != nil && controllerRef.UID == tester.deployment.UID, nil 1304 }); err != nil { 1305 t.Fatalf("failed waiting for replicaset adoption by deployment %q to complete: %v", deploymentName, err) 1306 } 1307 }