k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/controller/statefulset/stateful_set_test.go (about) 1 /* 2 Copyright 2016 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 statefulset 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "fmt" 24 "sort" 25 "testing" 26 27 apps "k8s.io/api/apps/v1" 28 v1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/apimachinery/pkg/labels" 31 "k8s.io/apimachinery/pkg/runtime" 32 "k8s.io/apimachinery/pkg/types" 33 "k8s.io/apimachinery/pkg/util/sets" 34 "k8s.io/apimachinery/pkg/util/strategicpatch" 35 utilfeature "k8s.io/apiserver/pkg/util/feature" 36 "k8s.io/client-go/informers" 37 "k8s.io/client-go/kubernetes/fake" 38 core "k8s.io/client-go/testing" 39 "k8s.io/client-go/tools/cache" 40 featuregatetesting "k8s.io/component-base/featuregate/testing" 41 "k8s.io/klog/v2" 42 "k8s.io/klog/v2/ktesting" 43 "k8s.io/kubernetes/pkg/controller" 44 "k8s.io/kubernetes/pkg/controller/history" 45 "k8s.io/kubernetes/pkg/features" 46 ) 47 48 var parentKind = apps.SchemeGroupVersion.WithKind("StatefulSet") 49 50 func alwaysReady() bool { return true } 51 52 func TestStatefulSetControllerCreates(t *testing.T) { 53 set := newStatefulSet(3) 54 logger, ctx := ktesting.NewTestContext(t) 55 ssc, spc, om, _ := newFakeStatefulSetController(ctx, set) 56 if err := scaleUpStatefulSetController(logger, set, ssc, spc, om); err != nil { 57 t.Errorf("Failed to turn up StatefulSet : %s", err) 58 } 59 if obj, _, err := om.setsIndexer.Get(set); err != nil { 60 t.Error(err) 61 } else { 62 set = obj.(*apps.StatefulSet) 63 } 64 if set.Status.Replicas != 3 { 65 t.Errorf("set.Status.Replicas = %v; want 3", set.Status.Replicas) 66 } 67 } 68 69 func TestStatefulSetControllerDeletes(t *testing.T) { 70 set := newStatefulSet(3) 71 logger, ctx := ktesting.NewTestContext(t) 72 ssc, spc, om, _ := newFakeStatefulSetController(ctx, set) 73 if err := scaleUpStatefulSetController(logger, set, ssc, spc, om); err != nil { 74 t.Errorf("Failed to turn up StatefulSet : %s", err) 75 } 76 if obj, _, err := om.setsIndexer.Get(set); err != nil { 77 t.Error(err) 78 } else { 79 set = obj.(*apps.StatefulSet) 80 } 81 if set.Status.Replicas != 3 { 82 t.Errorf("set.Status.Replicas = %v; want 3", set.Status.Replicas) 83 } 84 *set.Spec.Replicas = 0 85 if err := scaleDownStatefulSetController(logger, set, ssc, spc, om); err != nil { 86 t.Errorf("Failed to turn down StatefulSet : %s", err) 87 } 88 if obj, _, err := om.setsIndexer.Get(set); err != nil { 89 t.Error(err) 90 } else { 91 set = obj.(*apps.StatefulSet) 92 } 93 if set.Status.Replicas != 0 { 94 t.Errorf("set.Status.Replicas = %v; want 0", set.Status.Replicas) 95 } 96 } 97 98 func TestStatefulSetControllerRespectsTermination(t *testing.T) { 99 set := newStatefulSet(3) 100 logger, ctx := ktesting.NewTestContext(t) 101 ssc, spc, om, _ := newFakeStatefulSetController(ctx, set) 102 if err := scaleUpStatefulSetController(logger, set, ssc, spc, om); err != nil { 103 t.Errorf("Failed to turn up StatefulSet : %s", err) 104 } 105 if obj, _, err := om.setsIndexer.Get(set); err != nil { 106 t.Error(err) 107 } else { 108 set = obj.(*apps.StatefulSet) 109 } 110 if set.Status.Replicas != 3 { 111 t.Errorf("set.Status.Replicas = %v; want 3", set.Status.Replicas) 112 } 113 _, err := om.addTerminatingPod(set, 3) 114 if err != nil { 115 t.Error(err) 116 } 117 pods, err := om.addTerminatingPod(set, 4) 118 if err != nil { 119 t.Error(err) 120 } 121 ssc.syncStatefulSet(ctx, set, pods) 122 selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) 123 if err != nil { 124 t.Error(err) 125 } 126 pods, err = om.podsLister.Pods(set.Namespace).List(selector) 127 if err != nil { 128 t.Error(err) 129 } 130 if len(pods) != 5 { 131 t.Error("StatefulSet does not respect termination") 132 } 133 sort.Sort(ascendingOrdinal(pods)) 134 spc.DeleteStatefulPod(set, pods[3]) 135 spc.DeleteStatefulPod(set, pods[4]) 136 *set.Spec.Replicas = 0 137 if err := scaleDownStatefulSetController(logger, set, ssc, spc, om); err != nil { 138 t.Errorf("Failed to turn down StatefulSet : %s", err) 139 } 140 if obj, _, err := om.setsIndexer.Get(set); err != nil { 141 t.Error(err) 142 } else { 143 set = obj.(*apps.StatefulSet) 144 } 145 if set.Status.Replicas != 0 { 146 t.Errorf("set.Status.Replicas = %v; want 0", set.Status.Replicas) 147 } 148 } 149 150 func TestStatefulSetControllerBlocksScaling(t *testing.T) { 151 logger, ctx := ktesting.NewTestContext(t) 152 set := newStatefulSet(3) 153 ssc, spc, om, _ := newFakeStatefulSetController(ctx, set) 154 if err := scaleUpStatefulSetController(logger, set, ssc, spc, om); err != nil { 155 t.Errorf("Failed to turn up StatefulSet : %s", err) 156 } 157 if obj, _, err := om.setsIndexer.Get(set); err != nil { 158 t.Error(err) 159 } else { 160 set = obj.(*apps.StatefulSet) 161 } 162 if set.Status.Replicas != 3 { 163 t.Errorf("set.Status.Replicas = %v; want 3", set.Status.Replicas) 164 } 165 *set.Spec.Replicas = 5 166 fakeResourceVersion(set) 167 om.setsIndexer.Update(set) 168 _, err := om.setPodTerminated(set, 0) 169 if err != nil { 170 t.Error("Failed to set pod terminated at ordinal 0") 171 } 172 ssc.enqueueStatefulSet(set) 173 fakeWorker(ssc) 174 selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) 175 if err != nil { 176 t.Error(err) 177 } 178 pods, err := om.podsLister.Pods(set.Namespace).List(selector) 179 if err != nil { 180 t.Error(err) 181 } 182 if len(pods) != 3 { 183 t.Error("StatefulSet does not block scaling") 184 } 185 sort.Sort(ascendingOrdinal(pods)) 186 spc.DeleteStatefulPod(set, pods[0]) 187 ssc.enqueueStatefulSet(set) 188 fakeWorker(ssc) 189 pods, err = om.podsLister.Pods(set.Namespace).List(selector) 190 if err != nil { 191 t.Error(err) 192 } 193 if len(pods) != 3 { 194 t.Error("StatefulSet does not resume when terminated Pod is removed") 195 } 196 } 197 198 func TestStatefulSetControllerDeletionTimestamp(t *testing.T) { 199 _, ctx := ktesting.NewTestContext(t) 200 set := newStatefulSet(3) 201 set.DeletionTimestamp = new(metav1.Time) 202 ssc, _, om, _ := newFakeStatefulSetController(ctx, set) 203 204 om.setsIndexer.Add(set) 205 206 // Force a sync. It should not try to create any Pods. 207 ssc.enqueueStatefulSet(set) 208 fakeWorker(ssc) 209 210 selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) 211 if err != nil { 212 t.Fatal(err) 213 } 214 pods, err := om.podsLister.Pods(set.Namespace).List(selector) 215 if err != nil { 216 t.Fatal(err) 217 } 218 if got, want := len(pods), 0; got != want { 219 t.Errorf("len(pods) = %v, want %v", got, want) 220 } 221 } 222 223 func TestStatefulSetControllerDeletionTimestampRace(t *testing.T) { 224 _, ctx := ktesting.NewTestContext(t) 225 set := newStatefulSet(3) 226 // The bare client says it IS deleted. 227 set.DeletionTimestamp = new(metav1.Time) 228 ssc, _, om, ssh := newFakeStatefulSetController(ctx, set) 229 230 // The lister (cache) says it's NOT deleted. 231 set2 := *set 232 set2.DeletionTimestamp = nil 233 om.setsIndexer.Add(&set2) 234 235 // The recheck occurs in the presence of a matching orphan. 236 pod := newStatefulSetPod(set, 1) 237 pod.OwnerReferences = nil 238 om.podsIndexer.Add(pod) 239 set.Status.CollisionCount = new(int32) 240 revision, err := newRevision(set, 1, set.Status.CollisionCount) 241 if err != nil { 242 t.Fatal(err) 243 } 244 revision.OwnerReferences = nil 245 _, err = ssh.CreateControllerRevision(set, revision, set.Status.CollisionCount) 246 if err != nil { 247 t.Fatal(err) 248 } 249 250 // Force a sync. It should not try to create any Pods. 251 ssc.enqueueStatefulSet(set) 252 fakeWorker(ssc) 253 254 selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) 255 if err != nil { 256 t.Fatal(err) 257 } 258 pods, err := om.podsLister.Pods(set.Namespace).List(selector) 259 if err != nil { 260 t.Fatal(err) 261 } 262 if got, want := len(pods), 1; got != want { 263 t.Errorf("len(pods) = %v, want %v", got, want) 264 } 265 266 // It should not adopt pods. 267 for _, pod := range pods { 268 if len(pod.OwnerReferences) > 0 { 269 t.Errorf("unexpected pod owner references: %v", pod.OwnerReferences) 270 } 271 } 272 273 // It should not adopt revisions. 274 revisions, err := ssh.ListControllerRevisions(set, selector) 275 if err != nil { 276 t.Fatal(err) 277 } 278 if got, want := len(revisions), 1; got != want { 279 t.Errorf("len(revisions) = %v, want %v", got, want) 280 } 281 for _, revision := range revisions { 282 if len(revision.OwnerReferences) > 0 { 283 t.Errorf("unexpected revision owner references: %v", revision.OwnerReferences) 284 } 285 } 286 } 287 288 func TestStatefulSetControllerAddPod(t *testing.T) { 289 logger, ctx := ktesting.NewTestContext(t) 290 ssc, _, om, _ := newFakeStatefulSetController(ctx) 291 set1 := newStatefulSet(3) 292 set2 := newStatefulSet(3) 293 pod1 := newStatefulSetPod(set1, 0) 294 pod2 := newStatefulSetPod(set2, 0) 295 om.setsIndexer.Add(set1) 296 om.setsIndexer.Add(set2) 297 298 ssc.addPod(logger, pod1) 299 key, done := ssc.queue.Get() 300 if key == "" || done { 301 t.Error("failed to enqueue StatefulSet") 302 } else if expectedKey, _ := controller.KeyFunc(set1); expectedKey != key { 303 t.Errorf("expected StatefulSet key %s found %s", expectedKey, key) 304 } 305 ssc.queue.Done(key) 306 307 ssc.addPod(logger, pod2) 308 key, done = ssc.queue.Get() 309 if key == "" || done { 310 t.Error("failed to enqueue StatefulSet") 311 } else if expectedKey, _ := controller.KeyFunc(set2); expectedKey != key { 312 t.Errorf("expected StatefulSet key %s found %s", expectedKey, key) 313 } 314 ssc.queue.Done(key) 315 } 316 317 func TestStatefulSetControllerAddPodOrphan(t *testing.T) { 318 logger, ctx := ktesting.NewTestContext(t) 319 ssc, _, om, _ := newFakeStatefulSetController(ctx) 320 set1 := newStatefulSet(3) 321 set2 := newStatefulSet(3) 322 set2.Name = "foo2" 323 set3 := newStatefulSet(3) 324 set3.Name = "foo3" 325 set3.Spec.Selector.MatchLabels = map[string]string{"foo3": "bar"} 326 pod := newStatefulSetPod(set1, 0) 327 om.setsIndexer.Add(set1) 328 om.setsIndexer.Add(set2) 329 om.setsIndexer.Add(set3) 330 331 // Make pod an orphan. Expect matching sets to be queued. 332 pod.OwnerReferences = nil 333 ssc.addPod(logger, pod) 334 if got, want := ssc.queue.Len(), 2; got != want { 335 t.Errorf("queue.Len() = %v, want %v", got, want) 336 } 337 } 338 339 func TestStatefulSetControllerAddPodNoSet(t *testing.T) { 340 logger, ctx := ktesting.NewTestContext(t) 341 ssc, _, _, _ := newFakeStatefulSetController(ctx) 342 set := newStatefulSet(3) 343 pod := newStatefulSetPod(set, 0) 344 ssc.addPod(logger, pod) 345 ssc.queue.ShutDown() 346 key, _ := ssc.queue.Get() 347 if key != "" { 348 t.Errorf("StatefulSet enqueued key for Pod with no Set %s", key) 349 } 350 } 351 352 func TestStatefulSetControllerUpdatePod(t *testing.T) { 353 logger, ctx := ktesting.NewTestContext(t) 354 ssc, _, om, _ := newFakeStatefulSetController(ctx) 355 set1 := newStatefulSet(3) 356 set2 := newStatefulSet(3) 357 set2.Name = "foo2" 358 pod1 := newStatefulSetPod(set1, 0) 359 pod2 := newStatefulSetPod(set2, 0) 360 om.setsIndexer.Add(set1) 361 om.setsIndexer.Add(set2) 362 363 prev := *pod1 364 fakeResourceVersion(pod1) 365 ssc.updatePod(logger, &prev, pod1) 366 key, done := ssc.queue.Get() 367 if key == "" || done { 368 t.Error("failed to enqueue StatefulSet") 369 } else if expectedKey, _ := controller.KeyFunc(set1); expectedKey != key { 370 t.Errorf("expected StatefulSet key %s found %s", expectedKey, key) 371 } 372 373 prev = *pod2 374 fakeResourceVersion(pod2) 375 ssc.updatePod(logger, &prev, pod2) 376 key, done = ssc.queue.Get() 377 if key == "" || done { 378 t.Error("failed to enqueue StatefulSet") 379 } else if expectedKey, _ := controller.KeyFunc(set2); expectedKey != key { 380 t.Errorf("expected StatefulSet key %s found %s", expectedKey, key) 381 } 382 } 383 384 func TestStatefulSetControllerUpdatePodWithNoSet(t *testing.T) { 385 logger, ctx := ktesting.NewTestContext(t) 386 ssc, _, _, _ := newFakeStatefulSetController(ctx) 387 set := newStatefulSet(3) 388 pod := newStatefulSetPod(set, 0) 389 prev := *pod 390 fakeResourceVersion(pod) 391 ssc.updatePod(logger, &prev, pod) 392 ssc.queue.ShutDown() 393 key, _ := ssc.queue.Get() 394 if key != "" { 395 t.Errorf("StatefulSet enqueued key for Pod with no Set %s", key) 396 } 397 } 398 399 func TestStatefulSetControllerUpdatePodWithSameVersion(t *testing.T) { 400 logger, ctx := ktesting.NewTestContext(t) 401 ssc, _, om, _ := newFakeStatefulSetController(ctx) 402 set := newStatefulSet(3) 403 pod := newStatefulSetPod(set, 0) 404 om.setsIndexer.Add(set) 405 ssc.updatePod(logger, pod, pod) 406 ssc.queue.ShutDown() 407 key, _ := ssc.queue.Get() 408 if key != "" { 409 t.Errorf("StatefulSet enqueued key for Pod with no Set %s", key) 410 } 411 } 412 413 func TestStatefulSetControllerUpdatePodOrphanWithNewLabels(t *testing.T) { 414 logger, ctx := ktesting.NewTestContext(t) 415 ssc, _, om, _ := newFakeStatefulSetController(ctx) 416 set := newStatefulSet(3) 417 pod := newStatefulSetPod(set, 0) 418 pod.OwnerReferences = nil 419 set2 := newStatefulSet(3) 420 set2.Name = "foo2" 421 om.setsIndexer.Add(set) 422 om.setsIndexer.Add(set2) 423 clone := *pod 424 clone.Labels = map[string]string{"foo2": "bar2"} 425 fakeResourceVersion(&clone) 426 ssc.updatePod(logger, &clone, pod) 427 if got, want := ssc.queue.Len(), 2; got != want { 428 t.Errorf("queue.Len() = %v, want %v", got, want) 429 } 430 } 431 432 func TestStatefulSetControllerUpdatePodChangeControllerRef(t *testing.T) { 433 logger, ctx := ktesting.NewTestContext(t) 434 ssc, _, om, _ := newFakeStatefulSetController(ctx) 435 set := newStatefulSet(3) 436 set2 := newStatefulSet(3) 437 set2.Name = "foo2" 438 pod := newStatefulSetPod(set, 0) 439 pod2 := newStatefulSetPod(set2, 0) 440 om.setsIndexer.Add(set) 441 om.setsIndexer.Add(set2) 442 clone := *pod 443 clone.OwnerReferences = pod2.OwnerReferences 444 fakeResourceVersion(&clone) 445 ssc.updatePod(logger, &clone, pod) 446 if got, want := ssc.queue.Len(), 2; got != want { 447 t.Errorf("queue.Len() = %v, want %v", got, want) 448 } 449 } 450 451 func TestStatefulSetControllerUpdatePodRelease(t *testing.T) { 452 logger, ctx := ktesting.NewTestContext(t) 453 ssc, _, om, _ := newFakeStatefulSetController(ctx) 454 set := newStatefulSet(3) 455 set2 := newStatefulSet(3) 456 set2.Name = "foo2" 457 pod := newStatefulSetPod(set, 0) 458 om.setsIndexer.Add(set) 459 om.setsIndexer.Add(set2) 460 clone := *pod 461 clone.OwnerReferences = nil 462 fakeResourceVersion(&clone) 463 ssc.updatePod(logger, pod, &clone) 464 if got, want := ssc.queue.Len(), 2; got != want { 465 t.Errorf("queue.Len() = %v, want %v", got, want) 466 } 467 } 468 469 func TestStatefulSetControllerDeletePod(t *testing.T) { 470 logger, ctx := ktesting.NewTestContext(t) 471 ssc, _, om, _ := newFakeStatefulSetController(ctx) 472 set1 := newStatefulSet(3) 473 set2 := newStatefulSet(3) 474 set2.Name = "foo2" 475 pod1 := newStatefulSetPod(set1, 0) 476 pod2 := newStatefulSetPod(set2, 0) 477 om.setsIndexer.Add(set1) 478 om.setsIndexer.Add(set2) 479 480 ssc.deletePod(logger, pod1) 481 key, done := ssc.queue.Get() 482 if key == "" || done { 483 t.Error("failed to enqueue StatefulSet") 484 } else if expectedKey, _ := controller.KeyFunc(set1); expectedKey != key { 485 t.Errorf("expected StatefulSet key %s found %s", expectedKey, key) 486 } 487 488 ssc.deletePod(logger, pod2) 489 key, done = ssc.queue.Get() 490 if key == "" || done { 491 t.Error("failed to enqueue StatefulSet") 492 } else if expectedKey, _ := controller.KeyFunc(set2); expectedKey != key { 493 t.Errorf("expected StatefulSet key %s found %s", expectedKey, key) 494 } 495 } 496 497 func TestStatefulSetControllerDeletePodOrphan(t *testing.T) { 498 logger, ctx := ktesting.NewTestContext(t) 499 ssc, _, om, _ := newFakeStatefulSetController(ctx) 500 set1 := newStatefulSet(3) 501 set2 := newStatefulSet(3) 502 set2.Name = "foo2" 503 pod1 := newStatefulSetPod(set1, 0) 504 om.setsIndexer.Add(set1) 505 om.setsIndexer.Add(set2) 506 507 pod1.OwnerReferences = nil 508 ssc.deletePod(logger, pod1) 509 if got, want := ssc.queue.Len(), 0; got != want { 510 t.Errorf("queue.Len() = %v, want %v", got, want) 511 } 512 } 513 514 func TestStatefulSetControllerDeletePodTombstone(t *testing.T) { 515 logger, ctx := ktesting.NewTestContext(t) 516 ssc, _, om, _ := newFakeStatefulSetController(ctx) 517 set := newStatefulSet(3) 518 pod := newStatefulSetPod(set, 0) 519 om.setsIndexer.Add(set) 520 tombstoneKey, _ := controller.KeyFunc(pod) 521 tombstone := cache.DeletedFinalStateUnknown{Key: tombstoneKey, Obj: pod} 522 ssc.deletePod(logger, tombstone) 523 key, done := ssc.queue.Get() 524 if key == "" || done { 525 t.Error("failed to enqueue StatefulSet") 526 } else if expectedKey, _ := controller.KeyFunc(set); expectedKey != key { 527 t.Errorf("expected StatefulSet key %s found %s", expectedKey, key) 528 } 529 } 530 531 func TestStatefulSetControllerGetStatefulSetsForPod(t *testing.T) { 532 _, ctx := ktesting.NewTestContext(t) 533 ssc, _, om, _ := newFakeStatefulSetController(ctx) 534 set1 := newStatefulSet(3) 535 set2 := newStatefulSet(3) 536 set2.Name = "foo2" 537 pod := newStatefulSetPod(set1, 0) 538 om.setsIndexer.Add(set1) 539 om.setsIndexer.Add(set2) 540 om.podsIndexer.Add(pod) 541 sets := ssc.getStatefulSetsForPod(pod) 542 if got, want := len(sets), 2; got != want { 543 t.Errorf("len(sets) = %v, want %v", got, want) 544 } 545 } 546 547 func TestGetPodsForStatefulSetAdopt(t *testing.T) { 548 set := newStatefulSet(5) 549 pod1 := newStatefulSetPod(set, 1) 550 // pod2 is an orphan with matching labels and name. 551 pod2 := newStatefulSetPod(set, 2) 552 pod2.OwnerReferences = nil 553 // pod3 has wrong labels. 554 pod3 := newStatefulSetPod(set, 3) 555 pod3.OwnerReferences = nil 556 pod3.Labels = nil 557 // pod4 has wrong name. 558 pod4 := newStatefulSetPod(set, 4) 559 pod4.OwnerReferences = nil 560 pod4.Name = "x" + pod4.Name 561 562 _, ctx := ktesting.NewTestContext(t) 563 ssc, _, om, _ := newFakeStatefulSetController(ctx, set, pod1, pod2, pod3, pod4) 564 565 om.podsIndexer.Add(pod1) 566 om.podsIndexer.Add(pod2) 567 om.podsIndexer.Add(pod3) 568 om.podsIndexer.Add(pod4) 569 selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) 570 if err != nil { 571 t.Fatal(err) 572 } 573 pods, err := ssc.getPodsForStatefulSet(context.TODO(), set, selector) 574 if err != nil { 575 t.Fatalf("getPodsForStatefulSet() error: %v", err) 576 } 577 got := sets.NewString() 578 for _, pod := range pods { 579 got.Insert(pod.Name) 580 } 581 // pod2 should be claimed, pod3 and pod4 ignored 582 want := sets.NewString(pod1.Name, pod2.Name) 583 if !got.Equal(want) { 584 t.Errorf("getPodsForStatefulSet() = %v, want %v", got, want) 585 } 586 } 587 588 func TestAdoptOrphanRevisions(t *testing.T) { 589 ss1 := newStatefulSetWithLabels(3, "ss1", types.UID("ss1"), map[string]string{"foo": "bar"}) 590 ss1.Status.CollisionCount = new(int32) 591 ss1Rev1, err := history.NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 1, ss1.Status.CollisionCount) 592 if err != nil { 593 t.Fatal(err) 594 } 595 ss1Rev1.Namespace = ss1.Namespace 596 ss1.Spec.Template.Annotations = make(map[string]string) 597 ss1.Spec.Template.Annotations["ss1"] = "ss1" 598 ss1Rev2, err := history.NewControllerRevision(ss1, parentKind, ss1.Spec.Template.Labels, rawTemplate(&ss1.Spec.Template), 2, ss1.Status.CollisionCount) 599 if err != nil { 600 t.Fatal(err) 601 } 602 ss1Rev2.Namespace = ss1.Namespace 603 ss1Rev2.OwnerReferences = []metav1.OwnerReference{} 604 605 _, ctx := ktesting.NewTestContext(t) 606 ssc, _, om, _ := newFakeStatefulSetController(ctx, ss1, ss1Rev1, ss1Rev2) 607 608 om.revisionsIndexer.Add(ss1Rev1) 609 om.revisionsIndexer.Add(ss1Rev2) 610 611 err = ssc.adoptOrphanRevisions(context.TODO(), ss1) 612 if err != nil { 613 t.Errorf("adoptOrphanRevisions() error: %v", err) 614 } 615 616 if revisions, err := ssc.control.ListRevisions(ss1); err != nil { 617 t.Errorf("ListRevisions() error: %v", err) 618 } else { 619 var adopted bool 620 for i := range revisions { 621 if revisions[i].Name == ss1Rev2.Name && metav1.GetControllerOf(revisions[i]) != nil { 622 adopted = true 623 } 624 } 625 if !adopted { 626 t.Error("adoptOrphanRevisions() not adopt orphan revisions") 627 } 628 } 629 } 630 631 func TestGetPodsForStatefulSetRelease(t *testing.T) { 632 _, ctx := ktesting.NewTestContext(t) 633 set := newStatefulSet(3) 634 ssc, _, om, _ := newFakeStatefulSetController(ctx, set) 635 pod1 := newStatefulSetPod(set, 1) 636 // pod2 is owned but has wrong name. 637 pod2 := newStatefulSetPod(set, 2) 638 pod2.Name = "x" + pod2.Name 639 // pod3 is owned but has wrong labels. 640 pod3 := newStatefulSetPod(set, 3) 641 pod3.Labels = nil 642 // pod4 is an orphan that doesn't match. 643 pod4 := newStatefulSetPod(set, 4) 644 pod4.OwnerReferences = nil 645 pod4.Labels = nil 646 647 om.podsIndexer.Add(pod1) 648 om.podsIndexer.Add(pod2) 649 om.podsIndexer.Add(pod3) 650 om.podsIndexer.Add(pod4) 651 selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) 652 if err != nil { 653 t.Fatal(err) 654 } 655 pods, err := ssc.getPodsForStatefulSet(context.TODO(), set, selector) 656 if err != nil { 657 t.Fatalf("getPodsForStatefulSet() error: %v", err) 658 } 659 got := sets.NewString() 660 for _, pod := range pods { 661 got.Insert(pod.Name) 662 } 663 664 // Expect only pod1 (pod2 and pod3 should be released, pod4 ignored). 665 want := sets.NewString(pod1.Name) 666 if !got.Equal(want) { 667 t.Errorf("getPodsForStatefulSet() = %v, want %v", got, want) 668 } 669 } 670 671 func TestOrphanedPodsWithPVCDeletePolicy(t *testing.T) { 672 featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StatefulSetAutoDeletePVC, true) 673 674 testFn := func(t *testing.T, scaledownPolicy, deletionPolicy apps.PersistentVolumeClaimRetentionPolicyType) { 675 set := newStatefulSet(4) 676 *set.Spec.Replicas = 2 677 set.Spec.PersistentVolumeClaimRetentionPolicy.WhenScaled = scaledownPolicy 678 set.Spec.PersistentVolumeClaimRetentionPolicy.WhenDeleted = deletionPolicy 679 _, ctx := ktesting.NewTestContext(t) 680 ssc, _, om, _ := newFakeStatefulSetController(ctx, set) 681 om.setsIndexer.Add(set) 682 683 pods := []*v1.Pod{} 684 pods = append(pods, newStatefulSetPod(set, 0)) 685 // pod1 is orphaned 686 pods = append(pods, newStatefulSetPod(set, 1)) 687 pods[1].OwnerReferences = nil 688 // pod2 is owned but has wrong name. 689 pods = append(pods, newStatefulSetPod(set, 2)) 690 pods[2].Name = "x" + pods[2].Name 691 692 ssc.kubeClient.(*fake.Clientset).PrependReactor("patch", "pods", func(action core.Action) (bool, runtime.Object, error) { 693 patch := action.(core.PatchAction).GetPatch() 694 target := action.(core.PatchAction).GetName() 695 var pod *v1.Pod 696 for _, p := range pods { 697 if p.Name == target { 698 pod = p 699 break 700 } 701 } 702 if pod == nil { 703 t.Fatalf("Can't find patch target %s", target) 704 } 705 original, err := json.Marshal(pod) 706 if err != nil { 707 t.Fatalf("failed to marshal original pod %s: %v", pod.Name, err) 708 } 709 updated, err := strategicpatch.StrategicMergePatch(original, patch, v1.Pod{}) 710 if err != nil { 711 t.Fatalf("failed to apply strategic merge patch %q on node %s: %v", patch, pod.Name, err) 712 } 713 if err := json.Unmarshal(updated, pod); err != nil { 714 t.Fatalf("failed to unmarshal updated pod %s: %v", pod.Name, err) 715 } 716 717 return true, pod, nil 718 }) 719 720 for _, pod := range pods { 721 om.podsIndexer.Add(pod) 722 claims := getPersistentVolumeClaims(set, pod) 723 for _, claim := range claims { 724 om.CreateClaim(&claim) 725 } 726 } 727 728 for i := range pods { 729 if _, err := om.setPodReady(set, i); err != nil { 730 t.Errorf("%d: %v", i, err) 731 } 732 if _, err := om.setPodRunning(set, i); err != nil { 733 t.Errorf("%d: %v", i, err) 734 } 735 } 736 737 // First sync to manage orphaned pod, then set replicas. 738 ssc.enqueueStatefulSet(set) 739 fakeWorker(ssc) 740 *set.Spec.Replicas = 0 // Put an ownerRef for all scale-down deleted PVCs. 741 ssc.enqueueStatefulSet(set) 742 fakeWorker(ssc) 743 744 hasNamedOwnerRef := func(claim *v1.PersistentVolumeClaim, name string) bool { 745 for _, ownerRef := range claim.GetOwnerReferences() { 746 if ownerRef.Name == name { 747 return true 748 } 749 } 750 return false 751 } 752 verifyOwnerRefs := func(claim *v1.PersistentVolumeClaim, condemned bool) { 753 podName := getClaimPodName(set, claim) 754 const retain = apps.RetainPersistentVolumeClaimRetentionPolicyType 755 const delete = apps.DeletePersistentVolumeClaimRetentionPolicyType 756 switch { 757 case scaledownPolicy == retain && deletionPolicy == retain: 758 if hasNamedOwnerRef(claim, podName) || hasNamedOwnerRef(claim, set.Name) { 759 t.Errorf("bad claim ownerRefs: %s: %v", claim.Name, claim.GetOwnerReferences()) 760 } 761 case scaledownPolicy == retain && deletionPolicy == delete: 762 if hasNamedOwnerRef(claim, podName) || !hasNamedOwnerRef(claim, set.Name) { 763 t.Errorf("bad claim ownerRefs: %s: %v", claim.Name, claim.GetOwnerReferences()) 764 } 765 case scaledownPolicy == delete && deletionPolicy == retain: 766 if hasNamedOwnerRef(claim, podName) != condemned || hasNamedOwnerRef(claim, set.Name) { 767 t.Errorf("bad claim ownerRefs: %s: %v", claim.Name, claim.GetOwnerReferences()) 768 } 769 case scaledownPolicy == delete && deletionPolicy == delete: 770 if hasNamedOwnerRef(claim, podName) != condemned || !hasNamedOwnerRef(claim, set.Name) { 771 t.Errorf("bad claim ownerRefs: %s: %v", claim.Name, claim.GetOwnerReferences()) 772 } 773 } 774 } 775 776 claims, _ := om.claimsLister.PersistentVolumeClaims(set.Namespace).List(labels.Everything()) 777 if len(claims) != len(pods) { 778 t.Errorf("Unexpected number of claims: %d", len(claims)) 779 } 780 for _, claim := range claims { 781 // Only the first pod and the reclaimed orphan pod should have owner refs. 782 switch claim.Name { 783 case "datadir-foo-0", "datadir-foo-1": 784 verifyOwnerRefs(claim, false) 785 case "datadir-foo-2": 786 if hasNamedOwnerRef(claim, getClaimPodName(set, claim)) || hasNamedOwnerRef(claim, set.Name) { 787 t.Errorf("unexpected ownerRefs for %s: %v", claim.Name, claim.GetOwnerReferences()) 788 } 789 default: 790 t.Errorf("Unexpected claim %s", claim.Name) 791 } 792 } 793 } 794 policies := []apps.PersistentVolumeClaimRetentionPolicyType{ 795 apps.RetainPersistentVolumeClaimRetentionPolicyType, 796 apps.DeletePersistentVolumeClaimRetentionPolicyType, 797 } 798 for _, scaledownPolicy := range policies { 799 for _, deletionPolicy := range policies { 800 testName := fmt.Sprintf("ScaleDown:%s/SetDeletion:%s", scaledownPolicy, deletionPolicy) 801 t.Run(testName, func(t *testing.T) { testFn(t, scaledownPolicy, deletionPolicy) }) 802 } 803 } 804 } 805 806 func TestStaleOwnerRefOnScaleup(t *testing.T) { 807 featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StatefulSetAutoDeletePVC, true) 808 809 for _, policy := range []*apps.StatefulSetPersistentVolumeClaimRetentionPolicy{ 810 { 811 WhenScaled: apps.DeletePersistentVolumeClaimRetentionPolicyType, 812 WhenDeleted: apps.RetainPersistentVolumeClaimRetentionPolicyType, 813 }, 814 { 815 WhenScaled: apps.DeletePersistentVolumeClaimRetentionPolicyType, 816 WhenDeleted: apps.DeletePersistentVolumeClaimRetentionPolicyType, 817 }, 818 } { 819 onPolicy := func(msg string, args ...interface{}) string { 820 return fmt.Sprintf(fmt.Sprintf("(%s) %s", policy, msg), args...) 821 } 822 set := newStatefulSet(3) 823 set.Spec.PersistentVolumeClaimRetentionPolicy = policy 824 logger, ctx := ktesting.NewTestContext(t) 825 ssc, spc, om, _ := newFakeStatefulSetController(ctx, set) 826 if err := scaleUpStatefulSetController(logger, set, ssc, spc, om); err != nil { 827 t.Errorf(onPolicy("Failed to turn up StatefulSet : %s", err)) 828 } 829 var err error 830 if set, err = om.setsLister.StatefulSets(set.Namespace).Get(set.Name); err != nil { 831 t.Errorf(onPolicy("Could not get scaled up set: %v", err)) 832 } 833 if set.Status.Replicas != 3 { 834 t.Errorf(onPolicy("set.Status.Replicas = %v; want 3", set.Status.Replicas)) 835 } 836 *set.Spec.Replicas = 2 837 if err := scaleDownStatefulSetController(logger, set, ssc, spc, om); err != nil { 838 t.Errorf(onPolicy("Failed to scale down StatefulSet : msg, %s", err)) 839 } 840 set, err = om.setsLister.StatefulSets(set.Namespace).Get(set.Name) 841 if err != nil { 842 t.Errorf(onPolicy("Could not get scaled down StatefulSet: %v", err)) 843 } 844 if set.Status.Replicas != 2 { 845 t.Errorf(onPolicy("Failed to scale statefulset to 2 replicas")) 846 } 847 848 var claim *v1.PersistentVolumeClaim 849 claim, err = om.claimsLister.PersistentVolumeClaims(set.Namespace).Get("datadir-foo-2") 850 if err != nil { 851 t.Errorf(onPolicy("Could not find expected pvc datadir-foo-2")) 852 } 853 refs := claim.GetOwnerReferences() 854 if len(refs) != 1 { 855 t.Errorf(onPolicy("Expected only one refs: %v", refs)) 856 } 857 // Make the pod ref stale. 858 for i := range refs { 859 if refs[i].Name == "foo-2" { 860 refs[i].UID = "stale" 861 break 862 } 863 } 864 claim.SetOwnerReferences(refs) 865 if err = om.claimsIndexer.Update(claim); err != nil { 866 t.Errorf(onPolicy("Could not update claim with new owner ref: %v", err)) 867 } 868 869 *set.Spec.Replicas = 3 870 // Until the stale PVC goes away, the scale up should never finish. Run 10 iterations, then delete the PVC. 871 if err := scaleUpStatefulSetControllerBounded(logger, set, ssc, spc, om, 10); err != nil { 872 t.Errorf(onPolicy("Failed attempt to scale StatefulSet back up: %v", err)) 873 } 874 set, err = om.setsLister.StatefulSets(set.Namespace).Get(set.Name) 875 if err != nil { 876 t.Errorf(onPolicy("Could not get scaled down StatefulSet: %v", err)) 877 } 878 if set.Status.Replicas != 2 { 879 t.Errorf(onPolicy("Expected set to stay at two replicas")) 880 } 881 882 claim, err = om.claimsLister.PersistentVolumeClaims(set.Namespace).Get("datadir-foo-2") 883 if err != nil { 884 t.Errorf(onPolicy("Could not find expected pvc datadir-foo-2")) 885 } 886 refs = claim.GetOwnerReferences() 887 if len(refs) != 1 { 888 t.Errorf(onPolicy("Unexpected change to condemned pvc ownerRefs: %v", refs)) 889 } 890 foundPodRef := false 891 for i := range refs { 892 if refs[i].UID == "stale" { 893 foundPodRef = true 894 break 895 } 896 } 897 if !foundPodRef { 898 t.Errorf(onPolicy("Claim ref unexpectedly changed: %v", refs)) 899 } 900 if err = om.claimsIndexer.Delete(claim); err != nil { 901 t.Errorf(onPolicy("Could not delete stale pvc: %v", err)) 902 } 903 904 if err := scaleUpStatefulSetController(logger, set, ssc, spc, om); err != nil { 905 t.Errorf(onPolicy("Failed to scale StatefulSet back up: %v", err)) 906 } 907 set, err = om.setsLister.StatefulSets(set.Namespace).Get(set.Name) 908 if err != nil { 909 t.Errorf(onPolicy("Could not get scaled down StatefulSet: %v", err)) 910 } 911 if set.Status.Replicas != 3 { 912 t.Errorf(onPolicy("Failed to scale set back up once PVC was deleted")) 913 } 914 } 915 } 916 917 func newFakeStatefulSetController(ctx context.Context, initialObjects ...runtime.Object) (*StatefulSetController, *StatefulPodControl, *fakeObjectManager, history.Interface) { 918 client := fake.NewSimpleClientset(initialObjects...) 919 informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc()) 920 om := newFakeObjectManager(informerFactory) 921 spc := NewStatefulPodControlFromManager(om, &noopRecorder{}) 922 ssu := newFakeStatefulSetStatusUpdater(informerFactory.Apps().V1().StatefulSets()) 923 ssc := NewStatefulSetController( 924 ctx, 925 informerFactory.Core().V1().Pods(), 926 informerFactory.Apps().V1().StatefulSets(), 927 informerFactory.Core().V1().PersistentVolumeClaims(), 928 informerFactory.Apps().V1().ControllerRevisions(), 929 client, 930 ) 931 ssh := history.NewFakeHistory(informerFactory.Apps().V1().ControllerRevisions()) 932 ssc.podListerSynced = alwaysReady 933 ssc.setListerSynced = alwaysReady 934 ssc.control = NewDefaultStatefulSetControl(spc, ssu, ssh) 935 936 return ssc, spc, om, ssh 937 } 938 939 func fakeWorker(ssc *StatefulSetController) { 940 if obj, done := ssc.queue.Get(); !done { 941 _ = ssc.sync(context.TODO(), obj) 942 ssc.queue.Done(obj) 943 } 944 } 945 946 func getPodAtOrdinal(pods []*v1.Pod, ordinal int) *v1.Pod { 947 if 0 > ordinal || ordinal >= len(pods) { 948 return nil 949 } 950 sort.Sort(ascendingOrdinal(pods)) 951 return pods[ordinal] 952 } 953 954 func scaleUpStatefulSetController(logger klog.Logger, set *apps.StatefulSet, ssc *StatefulSetController, spc *StatefulPodControl, om *fakeObjectManager) error { 955 return scaleUpStatefulSetControllerBounded(logger, set, ssc, spc, om, -1) 956 } 957 958 func scaleUpStatefulSetControllerBounded(logger klog.Logger, set *apps.StatefulSet, ssc *StatefulSetController, spc *StatefulPodControl, om *fakeObjectManager, maxIterations int) error { 959 om.setsIndexer.Add(set) 960 ssc.enqueueStatefulSet(set) 961 fakeWorker(ssc) 962 selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) 963 if err != nil { 964 return err 965 } 966 iterations := 0 967 for (maxIterations < 0 || iterations < maxIterations) && set.Status.ReadyReplicas < *set.Spec.Replicas { 968 iterations++ 969 pods, err := om.podsLister.Pods(set.Namespace).List(selector) 970 if err != nil { 971 return err 972 } 973 ord := len(pods) - 1 974 if pods, err = om.setPodPending(set, ord); err != nil { 975 return err 976 } 977 pod := getPodAtOrdinal(pods, ord) 978 ssc.addPod(logger, pod) 979 fakeWorker(ssc) 980 pod = getPodAtOrdinal(pods, ord) 981 prev := *pod 982 if pods, err = om.setPodRunning(set, ord); err != nil { 983 return err 984 } 985 pod = getPodAtOrdinal(pods, ord) 986 ssc.updatePod(logger, &prev, pod) 987 fakeWorker(ssc) 988 pod = getPodAtOrdinal(pods, ord) 989 prev = *pod 990 if pods, err = om.setPodReady(set, ord); err != nil { 991 return err 992 } 993 pod = getPodAtOrdinal(pods, ord) 994 ssc.updatePod(logger, &prev, pod) 995 fakeWorker(ssc) 996 if err := assertMonotonicInvariants(set, om); err != nil { 997 return err 998 } 999 obj, _, err := om.setsIndexer.Get(set) 1000 if err != nil { 1001 return err 1002 } 1003 set = obj.(*apps.StatefulSet) 1004 1005 } 1006 return assertMonotonicInvariants(set, om) 1007 } 1008 1009 func scaleDownStatefulSetController(logger klog.Logger, set *apps.StatefulSet, ssc *StatefulSetController, spc *StatefulPodControl, om *fakeObjectManager) error { 1010 selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) 1011 if err != nil { 1012 return err 1013 } 1014 pods, err := om.podsLister.Pods(set.Namespace).List(selector) 1015 if err != nil { 1016 return err 1017 } 1018 ord := len(pods) - 1 1019 pod := getPodAtOrdinal(pods, ord) 1020 prev := *pod 1021 fakeResourceVersion(set) 1022 om.setsIndexer.Add(set) 1023 ssc.enqueueStatefulSet(set) 1024 fakeWorker(ssc) 1025 pods, err = om.addTerminatingPod(set, ord) 1026 if err != nil { 1027 return err 1028 } 1029 pod = getPodAtOrdinal(pods, ord) 1030 ssc.updatePod(logger, &prev, pod) 1031 fakeWorker(ssc) 1032 spc.DeleteStatefulPod(set, pod) 1033 ssc.deletePod(logger, pod) 1034 fakeWorker(ssc) 1035 for set.Status.Replicas > *set.Spec.Replicas { 1036 pods, err = om.podsLister.Pods(set.Namespace).List(selector) 1037 if err != nil { 1038 return err 1039 } 1040 1041 ord := len(pods) 1042 pods, err = om.addTerminatingPod(set, ord) 1043 if err != nil { 1044 return err 1045 } 1046 pod = getPodAtOrdinal(pods, ord) 1047 ssc.updatePod(logger, &prev, pod) 1048 fakeWorker(ssc) 1049 spc.DeleteStatefulPod(set, pod) 1050 ssc.deletePod(logger, pod) 1051 fakeWorker(ssc) 1052 obj, _, err := om.setsIndexer.Get(set) 1053 if err != nil { 1054 return err 1055 } 1056 set = obj.(*apps.StatefulSet) 1057 1058 } 1059 return assertMonotonicInvariants(set, om) 1060 } 1061 1062 func rawTemplate(template *v1.PodTemplateSpec) runtime.RawExtension { 1063 buf := new(bytes.Buffer) 1064 enc := json.NewEncoder(buf) 1065 if err := enc.Encode(template); err != nil { 1066 panic(err) 1067 } 1068 return runtime.RawExtension{Raw: buf.Bytes()} 1069 }