1
16
17 package replicaset
18
19 import (
20 "context"
21 "fmt"
22 "reflect"
23 "strings"
24 "testing"
25 "time"
26
27 apps "k8s.io/api/apps/v1"
28 v1 "k8s.io/api/core/v1"
29 apierrors "k8s.io/apimachinery/pkg/api/errors"
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 "k8s.io/apimachinery/pkg/labels"
32 "k8s.io/apimachinery/pkg/util/uuid"
33 "k8s.io/apimachinery/pkg/util/wait"
34 utilfeature "k8s.io/apiserver/pkg/util/feature"
35 "k8s.io/client-go/informers"
36 clientset "k8s.io/client-go/kubernetes"
37 appsclient "k8s.io/client-go/kubernetes/typed/apps/v1"
38 typedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
39 restclient "k8s.io/client-go/rest"
40 "k8s.io/client-go/tools/cache"
41 "k8s.io/client-go/util/retry"
42 featuregatetesting "k8s.io/component-base/featuregate/testing"
43 kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
44 podutil "k8s.io/kubernetes/pkg/api/v1/pod"
45 "k8s.io/kubernetes/pkg/apis/core"
46 "k8s.io/kubernetes/pkg/controller/replicaset"
47 "k8s.io/kubernetes/pkg/features"
48 "k8s.io/kubernetes/test/integration/framework"
49 testutil "k8s.io/kubernetes/test/utils"
50 "k8s.io/kubernetes/test/utils/ktesting"
51 "k8s.io/utils/ptr"
52 )
53
54 const (
55 interval = 100 * time.Millisecond
56 timeout = 60 * time.Second
57 )
58
59 func labelMap() map[string]string {
60 return map[string]string{"foo": "bar"}
61 }
62
63 func newRS(name, namespace string, replicas int) *apps.ReplicaSet {
64 replicasCopy := int32(replicas)
65 return &apps.ReplicaSet{
66 TypeMeta: metav1.TypeMeta{
67 Kind: "ReplicaSet",
68 APIVersion: "apps/v1",
69 },
70 ObjectMeta: metav1.ObjectMeta{
71 Namespace: namespace,
72 Name: name,
73 },
74 Spec: apps.ReplicaSetSpec{
75 Selector: &metav1.LabelSelector{
76 MatchLabels: labelMap(),
77 },
78 Replicas: &replicasCopy,
79 Template: v1.PodTemplateSpec{
80 ObjectMeta: metav1.ObjectMeta{
81 Labels: labelMap(),
82 },
83 Spec: v1.PodSpec{
84 Containers: []v1.Container{
85 {
86 Name: "fake-name",
87 Image: "fakeimage",
88 },
89 },
90 },
91 },
92 },
93 }
94 }
95
96 func newMatchingPod(podName, namespace string) *v1.Pod {
97 return &v1.Pod{
98 TypeMeta: metav1.TypeMeta{
99 Kind: "Pod",
100 APIVersion: "v1",
101 },
102 ObjectMeta: metav1.ObjectMeta{
103 Name: podName,
104 Namespace: namespace,
105 Labels: labelMap(),
106 },
107 Spec: v1.PodSpec{
108 Containers: []v1.Container{
109 {
110 Name: "fake-name",
111 Image: "fakeimage",
112 },
113 },
114 },
115 Status: v1.PodStatus{
116 Phase: v1.PodRunning,
117 },
118 }
119 }
120
121 func rmSetup(t *testing.T) (context.Context, kubeapiservertesting.TearDownFunc, *replicaset.ReplicaSetController, informers.SharedInformerFactory, clientset.Interface) {
122 tCtx := ktesting.Init(t)
123
124 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
125
126 config := restclient.CopyConfig(server.ClientConfig)
127 clientSet, err := clientset.NewForConfig(config)
128 if err != nil {
129 t.Fatalf("Error in create clientset: %v", err)
130 }
131 resyncPeriod := 12 * time.Hour
132 informers := informers.NewSharedInformerFactory(clientset.NewForConfigOrDie(restclient.AddUserAgent(config, "rs-informers")), resyncPeriod)
133
134 rm := replicaset.NewReplicaSetController(
135 tCtx,
136 informers.Apps().V1().ReplicaSets(),
137 informers.Core().V1().Pods(),
138 clientset.NewForConfigOrDie(restclient.AddUserAgent(config, "replicaset-controller")),
139 replicaset.BurstReplicas,
140 )
141
142 newTeardown := func() {
143 tCtx.Cancel("tearing down controller")
144 server.TearDownFn()
145 }
146
147 return tCtx, newTeardown, rm, informers, clientSet
148 }
149
150 func rmSimpleSetup(t *testing.T) (kubeapiservertesting.TearDownFunc, clientset.Interface) {
151
152 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
153
154 config := restclient.CopyConfig(server.ClientConfig)
155 clientSet, err := clientset.NewForConfig(config)
156 if err != nil {
157 t.Fatalf("Error in create clientset: %v", err)
158 }
159 return server.TearDownFn, clientSet
160 }
161
162
163 func runControllerAndInformers(t *testing.T, rm *replicaset.ReplicaSetController, informers informers.SharedInformerFactory, podNum int) func() {
164 ctx, cancelFn := context.WithCancel(context.Background())
165 informers.Start(ctx.Done())
166 waitToObservePods(t, informers.Core().V1().Pods().Informer(), podNum)
167 go rm.Run(ctx, 5)
168 return cancelFn
169 }
170
171
172
173
174 func waitToObservePods(t *testing.T, podInformer cache.SharedIndexInformer, podNum int) {
175 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
176 objects := podInformer.GetIndexer().List()
177 return len(objects) == podNum, nil
178 }); err != nil {
179 t.Fatalf("Error encountered when waiting for podInformer to observe the pods: %v", err)
180 }
181 }
182
183 func createRSsPods(t *testing.T, clientSet clientset.Interface, rss []*apps.ReplicaSet, pods []*v1.Pod) ([]*apps.ReplicaSet, []*v1.Pod) {
184 var createdRSs []*apps.ReplicaSet
185 var createdPods []*v1.Pod
186 for _, rs := range rss {
187 createdRS, err := clientSet.AppsV1().ReplicaSets(rs.Namespace).Create(context.TODO(), rs, metav1.CreateOptions{})
188 if err != nil {
189 t.Fatalf("Failed to create replica set %s: %v", rs.Name, err)
190 }
191 createdRSs = append(createdRSs, createdRS)
192 }
193 for _, pod := range pods {
194 createdPod, err := clientSet.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
195 if err != nil {
196 t.Fatalf("Failed to create pod %s: %v", pod.Name, err)
197 }
198 createdPods = append(createdPods, createdPod)
199 }
200
201 return createdRSs, createdPods
202 }
203
204
205 func waitRSStable(t *testing.T, clientSet clientset.Interface, rs *apps.ReplicaSet) {
206 if err := testutil.WaitRSStable(t, clientSet, rs, interval, timeout); err != nil {
207 t.Fatal(err)
208 }
209 }
210
211
212 func scaleRS(t *testing.T, c clientset.Interface, rs *apps.ReplicaSet, replicas int32) {
213 rsClient := c.AppsV1().ReplicaSets(rs.Namespace)
214 rs = updateRS(t, rsClient, rs.Name, func(rs *apps.ReplicaSet) {
215 *rs.Spec.Replicas = replicas
216 })
217 waitRSStable(t, c, rs)
218 }
219
220 func updatePod(t *testing.T, podClient typedv1.PodInterface, podName string, updateFunc func(*v1.Pod)) *v1.Pod {
221 var pod *v1.Pod
222 if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
223 newPod, err := podClient.Get(context.TODO(), podName, metav1.GetOptions{})
224 if err != nil {
225 return err
226 }
227 updateFunc(newPod)
228 pod, err = podClient.Update(context.TODO(), newPod, metav1.UpdateOptions{})
229 return err
230 }); err != nil {
231 t.Fatalf("Failed to update pod %s: %v", podName, err)
232 }
233 return pod
234 }
235
236 func updatePodStatus(t *testing.T, podClient typedv1.PodInterface, podName string, updateStatusFunc func(*v1.Pod)) {
237 if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
238 newPod, err := podClient.Get(context.TODO(), podName, metav1.GetOptions{})
239 if err != nil {
240 return err
241 }
242 updateStatusFunc(newPod)
243 _, err = podClient.UpdateStatus(context.TODO(), newPod, metav1.UpdateOptions{})
244 return err
245 }); err != nil {
246 t.Fatalf("Failed to update status of pod %s: %v", podName, err)
247 }
248 }
249
250 func getPods(t *testing.T, podClient typedv1.PodInterface, labelMap map[string]string) *v1.PodList {
251 podSelector := labels.Set(labelMap).AsSelector()
252 options := metav1.ListOptions{LabelSelector: podSelector.String()}
253 pods, err := podClient.List(context.TODO(), options)
254 if err != nil {
255 t.Fatalf("Failed obtaining a list of pods that match the pod labels %v: %v", labelMap, err)
256 }
257 return pods
258 }
259
260 func updateRS(t *testing.T, rsClient appsclient.ReplicaSetInterface, rsName string, updateFunc func(*apps.ReplicaSet)) *apps.ReplicaSet {
261 var rs *apps.ReplicaSet
262 if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
263 newRS, err := rsClient.Get(context.TODO(), rsName, metav1.GetOptions{})
264 if err != nil {
265 return err
266 }
267 updateFunc(newRS)
268 rs, err = rsClient.Update(context.TODO(), newRS, metav1.UpdateOptions{})
269 return err
270 }); err != nil {
271 t.Fatalf("Failed to update rs %s: %v", rsName, err)
272 }
273 return rs
274 }
275
276
277 func testPodControllerRefPatch(t *testing.T, c clientset.Interface, pod *v1.Pod, ownerReference *metav1.OwnerReference, rs *apps.ReplicaSet, expectedOwnerReferenceNum int) {
278 ns := rs.Namespace
279 podClient := c.CoreV1().Pods(ns)
280 updatePod(t, podClient, pod.Name, func(pod *v1.Pod) {
281 pod.OwnerReferences = []metav1.OwnerReference{*ownerReference}
282 })
283
284 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
285 newPod, err := podClient.Get(context.TODO(), pod.Name, metav1.GetOptions{})
286 if err != nil {
287 return false, err
288 }
289 return metav1.GetControllerOf(newPod) != nil, nil
290 }); err != nil {
291 t.Fatalf("Failed to verify ControllerRef for the pod %s is not nil: %v", pod.Name, err)
292 }
293
294 newPod, err := podClient.Get(context.TODO(), pod.Name, metav1.GetOptions{})
295 if err != nil {
296 t.Fatalf("Failed to obtain pod %s: %v", pod.Name, err)
297 }
298 controllerRef := metav1.GetControllerOf(newPod)
299 if controllerRef.UID != rs.UID {
300 t.Fatalf("RS owner of the pod %s has a different UID: Expected %v, got %v", newPod.Name, rs.UID, controllerRef.UID)
301 }
302 ownerReferenceNum := len(newPod.GetOwnerReferences())
303 if ownerReferenceNum != expectedOwnerReferenceNum {
304 t.Fatalf("Unexpected number of owner references for pod %s: Expected %d, got %d", newPod.Name, expectedOwnerReferenceNum, ownerReferenceNum)
305 }
306 }
307
308 func setPodsReadyCondition(t *testing.T, clientSet clientset.Interface, pods *v1.PodList, conditionStatus v1.ConditionStatus, lastTransitionTime time.Time) {
309 replicas := int32(len(pods.Items))
310 var readyPods int32
311 err := wait.PollImmediate(interval, timeout, func() (bool, error) {
312 readyPods = 0
313 for i := range pods.Items {
314 pod := &pods.Items[i]
315 if podutil.IsPodReady(pod) {
316 readyPods++
317 continue
318 }
319 pod.Status.Phase = v1.PodRunning
320 _, condition := podutil.GetPodCondition(&pod.Status, v1.PodReady)
321 if condition != nil {
322 condition.Status = conditionStatus
323 condition.LastTransitionTime = metav1.Time{Time: lastTransitionTime}
324 } else {
325 condition = &v1.PodCondition{
326 Type: v1.PodReady,
327 Status: conditionStatus,
328 LastTransitionTime: metav1.Time{Time: lastTransitionTime},
329 }
330 pod.Status.Conditions = append(pod.Status.Conditions, *condition)
331 }
332 _, err := clientSet.CoreV1().Pods(pod.Namespace).UpdateStatus(context.TODO(), pod, metav1.UpdateOptions{})
333 if err != nil {
334
335 continue
336 }
337 readyPods++
338 }
339 return readyPods >= replicas, nil
340 })
341 if err != nil {
342 t.Fatalf("failed to mark all ReplicaSet pods to ready: %v", err)
343 }
344 }
345
346 func testScalingUsingScaleSubresource(t *testing.T, c clientset.Interface, rs *apps.ReplicaSet, replicas int32) {
347 ns := rs.Namespace
348 rsClient := c.AppsV1().ReplicaSets(ns)
349 newRS, err := rsClient.Get(context.TODO(), rs.Name, metav1.GetOptions{})
350 if err != nil {
351 t.Fatalf("Failed to obtain rs %s: %v", rs.Name, err)
352 }
353 scale, err := c.AppsV1().ReplicaSets(ns).GetScale(context.TODO(), rs.Name, metav1.GetOptions{})
354 if err != nil {
355 t.Fatalf("Failed to obtain scale subresource for rs %s: %v", rs.Name, err)
356 }
357 if scale.Spec.Replicas != *newRS.Spec.Replicas {
358 t.Fatalf("Scale subresource for rs %s does not match .Spec.Replicas: expected %d, got %d", rs.Name, *newRS.Spec.Replicas, scale.Spec.Replicas)
359 }
360
361 if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
362 scale, err := c.AppsV1().ReplicaSets(ns).GetScale(context.TODO(), rs.Name, metav1.GetOptions{})
363 if err != nil {
364 return err
365 }
366 scale.Spec.Replicas = replicas
367 _, err = c.AppsV1().ReplicaSets(ns).UpdateScale(context.TODO(), rs.Name, scale, metav1.UpdateOptions{})
368 return err
369 }); err != nil {
370 t.Fatalf("Failed to set .Spec.Replicas of scale subresource for rs %s: %v", rs.Name, err)
371 }
372
373 newRS, err = rsClient.Get(context.TODO(), rs.Name, metav1.GetOptions{})
374 if err != nil {
375 t.Fatalf("Failed to obtain rs %s: %v", rs.Name, err)
376 }
377 if *newRS.Spec.Replicas != replicas {
378 t.Fatalf(".Spec.Replicas of rs %s does not match its scale subresource: expected %d, got %d", rs.Name, replicas, *newRS.Spec.Replicas)
379 }
380 }
381
382 func TestAdoption(t *testing.T) {
383 boolPtr := func(b bool) *bool { return &b }
384 testCases := []struct {
385 name string
386 existingOwnerReferences func(rs *apps.ReplicaSet) []metav1.OwnerReference
387 expectedOwnerReferences func(rs *apps.ReplicaSet) []metav1.OwnerReference
388 }{
389 {
390 "pod refers rs as an owner, not a controller",
391 func(rs *apps.ReplicaSet) []metav1.OwnerReference {
392 return []metav1.OwnerReference{{UID: rs.UID, Name: rs.Name, APIVersion: "apps/v1", Kind: "ReplicaSet"}}
393 },
394 func(rs *apps.ReplicaSet) []metav1.OwnerReference {
395 return []metav1.OwnerReference{{UID: rs.UID, Name: rs.Name, APIVersion: "apps/v1", Kind: "ReplicaSet", Controller: boolPtr(true), BlockOwnerDeletion: boolPtr(true)}}
396 },
397 },
398 {
399 "pod doesn't have owner references",
400 func(rs *apps.ReplicaSet) []metav1.OwnerReference {
401 return []metav1.OwnerReference{}
402 },
403 func(rs *apps.ReplicaSet) []metav1.OwnerReference {
404 return []metav1.OwnerReference{{UID: rs.UID, Name: rs.Name, APIVersion: "apps/v1", Kind: "ReplicaSet", Controller: boolPtr(true), BlockOwnerDeletion: boolPtr(true)}}
405 },
406 },
407 {
408 "pod refers rs as a controller",
409 func(rs *apps.ReplicaSet) []metav1.OwnerReference {
410 return []metav1.OwnerReference{{UID: rs.UID, Name: rs.Name, APIVersion: "apps/v1", Kind: "ReplicaSet", Controller: boolPtr(true)}}
411 },
412 func(rs *apps.ReplicaSet) []metav1.OwnerReference {
413 return []metav1.OwnerReference{{UID: rs.UID, Name: rs.Name, APIVersion: "apps/v1", Kind: "ReplicaSet", Controller: boolPtr(true)}}
414 },
415 },
416 {
417 "pod refers other rs as the controller, refers the rs as an owner",
418 func(rs *apps.ReplicaSet) []metav1.OwnerReference {
419 return []metav1.OwnerReference{
420 {UID: "1", Name: "anotherRS", APIVersion: "apps/v1", Kind: "ReplicaSet", Controller: boolPtr(true)},
421 {UID: rs.UID, Name: rs.Name, APIVersion: "apps/v1", Kind: "ReplicaSet"},
422 }
423 },
424 func(rs *apps.ReplicaSet) []metav1.OwnerReference {
425 return []metav1.OwnerReference{
426 {UID: "1", Name: "anotherRS", APIVersion: "apps/v1", Kind: "ReplicaSet", Controller: boolPtr(true)},
427 {UID: rs.UID, Name: rs.Name, APIVersion: "apps/v1", Kind: "ReplicaSet"},
428 }
429 },
430 },
431 }
432 for i, tc := range testCases {
433 t.Run(tc.name, func(t *testing.T) {
434 tCtx, closeFn, rm, informers, clientSet := rmSetup(t)
435 defer closeFn()
436
437 ns := framework.CreateNamespaceOrDie(clientSet, fmt.Sprintf("rs-adoption-%d", i), t)
438 defer framework.DeleteNamespaceOrDie(clientSet, ns, t)
439
440 rsClient := clientSet.AppsV1().ReplicaSets(ns.Name)
441 podClient := clientSet.CoreV1().Pods(ns.Name)
442 const rsName = "rs"
443 rs, err := rsClient.Create(tCtx, newRS(rsName, ns.Name, 1), metav1.CreateOptions{})
444 if err != nil {
445 t.Fatalf("Failed to create replica set: %v", err)
446 }
447 podName := fmt.Sprintf("pod%d", i)
448 pod := newMatchingPod(podName, ns.Name)
449 pod.OwnerReferences = tc.existingOwnerReferences(rs)
450 _, err = podClient.Create(tCtx, pod, metav1.CreateOptions{})
451 if err != nil {
452 t.Fatalf("Failed to create Pod: %v", err)
453 }
454
455 stopControllers := runControllerAndInformers(t, rm, informers, 1)
456 defer stopControllers()
457 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
458 updatedPod, err := podClient.Get(tCtx, pod.Name, metav1.GetOptions{})
459 if err != nil {
460 return false, err
461 }
462
463 e, a := tc.expectedOwnerReferences(rs), updatedPod.OwnerReferences
464 if reflect.DeepEqual(e, a) {
465 return true, nil
466 }
467
468 t.Logf("ownerReferences don't match, expect %v, got %v", e, a)
469 return false, nil
470 }); err != nil {
471 t.Fatalf("test %q failed: %v", tc.name, err)
472 }
473 })
474 }
475 }
476
477
478 func TestRSSelectorImmutability(t *testing.T) {
479 closeFn, clientSet := rmSimpleSetup(t)
480 defer closeFn()
481 ns := framework.CreateNamespaceOrDie(clientSet, "rs-selector-immutability", t)
482 defer framework.DeleteNamespaceOrDie(clientSet, ns, t)
483 rs := newRS("rs", ns.Name, 0)
484 createRSsPods(t, clientSet, []*apps.ReplicaSet{rs}, []*v1.Pod{})
485
486
487 rsV1, err := clientSet.AppsV1().ReplicaSets(ns.Name).Get(context.TODO(), rs.Name, metav1.GetOptions{})
488 if err != nil {
489 t.Fatalf("failed to get apps/v1 replicaset %s: %v", rs.Name, err)
490 }
491 newSelectorLabels := map[string]string{"changed_name_apps_v1": "changed_test_apps_v1"}
492 rsV1.Spec.Selector.MatchLabels = newSelectorLabels
493 rsV1.Spec.Template.Labels = newSelectorLabels
494 _, err = clientSet.AppsV1().ReplicaSets(ns.Name).Update(context.TODO(), rsV1, metav1.UpdateOptions{})
495 if err == nil {
496 t.Fatalf("failed to provide validation error when changing immutable selector when updating apps/v1 replicaset %s", rsV1.Name)
497 }
498 expectedErrType := "Invalid value"
499 expectedErrDetail := "field is immutable"
500 if !strings.Contains(err.Error(), expectedErrType) || !strings.Contains(err.Error(), expectedErrDetail) {
501 t.Errorf("error message does not match, expected type: %s, expected detail: %s, got: %s", expectedErrType, expectedErrDetail, err.Error())
502 }
503 }
504
505 func TestSpecReplicasChange(t *testing.T) {
506 tCtx, closeFn, rm, informers, c := rmSetup(t)
507 defer closeFn()
508 ns := framework.CreateNamespaceOrDie(c, "test-spec-replicas-change", t)
509 defer framework.DeleteNamespaceOrDie(c, ns, t)
510 stopControllers := runControllerAndInformers(t, rm, informers, 0)
511 defer stopControllers()
512
513 rs := newRS("rs", ns.Name, 2)
514 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
515 rs = rss[0]
516 waitRSStable(t, c, rs)
517
518
519 scaleRS(t, c, rs, 3)
520 scaleRS(t, c, rs, 0)
521 scaleRS(t, c, rs, 2)
522
523
524
525 rsClient := c.AppsV1().ReplicaSets(ns.Name)
526 var oldGeneration int64
527 newRS := updateRS(t, rsClient, rs.Name, func(rs *apps.ReplicaSet) {
528 oldGeneration = rs.Generation
529 rs.Spec.Template.Annotations = map[string]string{"test": "annotation"}
530 })
531 savedGeneration := newRS.Generation
532 if savedGeneration == oldGeneration {
533 t.Fatalf("Failed to verify .Generation has incremented for rs %s", rs.Name)
534 }
535
536 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
537 newRS, err := rsClient.Get(tCtx, rs.Name, metav1.GetOptions{})
538 if err != nil {
539 return false, err
540 }
541 return newRS.Status.ObservedGeneration >= savedGeneration, nil
542 }); err != nil {
543 t.Fatalf("Failed to verify .Status.ObservedGeneration has incremented for rs %s: %v", rs.Name, err)
544 }
545 }
546
547 func TestDeletingAndFailedPods(t *testing.T) {
548 tCtx, closeFn, rm, informers, c := rmSetup(t)
549 defer closeFn()
550
551 ns := framework.CreateNamespaceOrDie(c, "test-deleting-and-failed-pods", t)
552 defer framework.DeleteNamespaceOrDie(c, ns, t)
553 stopControllers := runControllerAndInformers(t, rm, informers, 0)
554 defer stopControllers()
555
556 rs := newRS("rs", ns.Name, 2)
557 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
558 rs = rss[0]
559 waitRSStable(t, c, rs)
560
561
562 podClient := c.CoreV1().Pods(ns.Name)
563 pods := getPods(t, podClient, labelMap())
564 if len(pods.Items) != 2 {
565 t.Fatalf("len(pods) = %d, want 2", len(pods.Items))
566 }
567
568
569
570 deletingPod := &pods.Items[0]
571 updatePod(t, podClient, deletingPod.Name, func(pod *v1.Pod) {
572 pod.Finalizers = []string{"fake.example.com/blockDeletion"}
573 })
574 if err := c.CoreV1().Pods(ns.Name).Delete(tCtx, deletingPod.Name, metav1.DeleteOptions{}); err != nil {
575 t.Fatalf("Error deleting pod %s: %v", deletingPod.Name, err)
576 }
577
578
579 failedPod := &pods.Items[1]
580 updatePodStatus(t, podClient, failedPod.Name, func(pod *v1.Pod) {
581 pod.Status.Phase = v1.PodFailed
582 })
583
584
585 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
586 pods = getPods(t, podClient, labelMap())
587 return len(pods.Items) == 4, nil
588 }); err != nil {
589 t.Fatalf("Failed to verify 2 new pods have been created (expected 4 pods): %v", err)
590 }
591
592
593 foundDeletingPod := false
594 foundFailedPod := false
595 for _, pod := range pods.Items {
596 if pod.UID == deletingPod.UID {
597 foundDeletingPod = true
598 }
599 if pod.UID == failedPod.UID {
600 foundFailedPod = true
601 }
602 }
603
604 if !foundDeletingPod {
605 t.Fatalf("expected deleting pod %s exists, but it is not found", deletingPod.Name)
606 }
607
608 if !foundFailedPod {
609 t.Fatalf("expected failed pod %s exists, but it is not found", failedPod.Name)
610 }
611 }
612
613 func TestPodDeletionCost(t *testing.T) {
614 tests := []struct {
615 name string
616 costs []string
617 restarts []int32
618 enabled bool
619 remainingPodIndex int
620 }{
621 {
622 name: "enabled-with-different-costs",
623 costs: []string{"1000", "100"},
624 restarts: []int32{5, 0},
625 enabled: true,
626 remainingPodIndex: 0,
627 },
628 {
629 name: "enabled-with-same-costs",
630 costs: []string{"100", "100"},
631 restarts: []int32{5, 0},
632 enabled: true,
633 remainingPodIndex: 1,
634 },
635 {
636 name: "enabled-with-no-costs",
637 restarts: []int32{5, 0},
638 enabled: true,
639 remainingPodIndex: 1,
640 },
641 {
642 name: "disabled-with-different-costs",
643 costs: []string{"1000", "100"},
644 restarts: []int32{5, 0},
645 enabled: false,
646 remainingPodIndex: 1,
647 },
648 }
649 for _, tc := range tests {
650 t.Run(tc.name, func(t *testing.T) {
651 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodDeletionCost, tc.enabled)()
652 _, closeFn, rm, informers, c := rmSetup(t)
653 defer closeFn()
654 ns := framework.CreateNamespaceOrDie(c, tc.name, t)
655 defer framework.DeleteNamespaceOrDie(c, ns, t)
656 stopControllers := runControllerAndInformers(t, rm, informers, 0)
657 defer stopControllers()
658
659 rs := newRS("rs", ns.Name, 2)
660 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
661 rs = rss[0]
662 waitRSStable(t, c, rs)
663
664
665 podClient := c.CoreV1().Pods(ns.Name)
666 pods := getPods(t, podClient, labelMap())
667 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
668 pods = getPods(t, podClient, labelMap())
669 return len(pods.Items) == 2, nil
670 }); err != nil {
671 t.Fatalf("Failed to verify replicaset has 2 pods: %v", err)
672 }
673
674
675 remainingPodUID := pods.Items[tc.remainingPodIndex].UID
676 for i := range pods.Items {
677 podName := pods.Items[i].Name
678 if len(tc.costs) != 0 {
679 updatePod(t, podClient, podName, func(pod *v1.Pod) {
680 pod.Annotations = map[string]string{core.PodDeletionCost: tc.costs[i]}
681 })
682 }
683 updatePodStatus(t, podClient, podName, func(pod *v1.Pod) {
684 pod.Status.ContainerStatuses = []v1.ContainerStatus{{RestartCount: tc.restarts[i]}}
685 })
686 }
687
688
689 rsClient := c.AppsV1().ReplicaSets(ns.Name)
690 updateRS(t, rsClient, rs.Name, func(rs *apps.ReplicaSet) {
691 rs.Spec.Replicas = ptr.To[int32](1)
692 })
693
694
695 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
696 pods = getPods(t, podClient, labelMap())
697 return len(pods.Items) == 1, nil
698 }); err != nil {
699 t.Fatalf("Failed to downscale replicaset to 1 pod: %v", err)
700 }
701
702 if pods.Items[0].UID != remainingPodUID {
703 t.Errorf("expected remaining Pod UID %v, got UID %v with container statues %v",
704 remainingPodUID, pods.Items[0].UID, pods.Items[0].Status.ContainerStatuses)
705 }
706 })
707 }
708 }
709
710 func TestOverlappingRSs(t *testing.T) {
711 tCtx, closeFn, rm, informers, c := rmSetup(t)
712 defer closeFn()
713 ns := framework.CreateNamespaceOrDie(c, "test-overlapping-rss", t)
714 defer framework.DeleteNamespaceOrDie(c, ns, t)
715 stopControllers := runControllerAndInformers(t, rm, informers, 0)
716 defer stopControllers()
717
718
719 for i := 0; i < 2; i++ {
720
721 rs := newRS(fmt.Sprintf("rs-%d", i+1), ns.Name, i+1)
722 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
723 waitRSStable(t, c, rss[0])
724 }
725
726
727 podClient := c.CoreV1().Pods(ns.Name)
728 pods := getPods(t, podClient, labelMap())
729 if len(pods.Items) != 3 {
730 t.Errorf("len(pods) = %d, want 3", len(pods.Items))
731 }
732
733
734 for i := 0; i < 2; i++ {
735 newRS, err := c.AppsV1().ReplicaSets(ns.Name).Get(tCtx, fmt.Sprintf("rs-%d", i+1), metav1.GetOptions{})
736 if err != nil {
737 t.Fatalf("failed to obtain rs rs-%d: %v", i+1, err)
738 }
739 if newRS.Status.Replicas != *newRS.Spec.Replicas {
740 t.Fatalf(".Status.Replicas %d is not equal to .Spec.Replicas %d", newRS.Status.Replicas, *newRS.Spec.Replicas)
741 }
742 }
743 }
744
745 func TestPodOrphaningAndAdoptionWhenLabelsChange(t *testing.T) {
746 tCtx, closeFn, rm, informers, c := rmSetup(t)
747 defer closeFn()
748 ns := framework.CreateNamespaceOrDie(c, "test-pod-orphaning-and-adoption-when-labels-change", t)
749 defer framework.DeleteNamespaceOrDie(c, ns, t)
750 stopControllers := runControllerAndInformers(t, rm, informers, 0)
751 defer stopControllers()
752
753 rs := newRS("rs", ns.Name, 1)
754 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
755 rs = rss[0]
756 waitRSStable(t, c, rs)
757
758
759 podClient := c.CoreV1().Pods(ns.Name)
760 pods := getPods(t, podClient, labelMap())
761 if len(pods.Items) != 1 {
762 t.Fatalf("len(pods) = %d, want 1", len(pods.Items))
763 }
764 pod := &pods.Items[0]
765
766
767 if metav1.GetControllerOf(pod) == nil {
768 t.Fatalf("ControllerRef of pod %s is nil", pod.Name)
769 }
770 newLabelMap := map[string]string{"new-foo": "new-bar"}
771 updatePod(t, podClient, pod.Name, func(pod *v1.Pod) {
772 pod.Labels = newLabelMap
773 })
774 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
775 newPod, err := podClient.Get(tCtx, pod.Name, metav1.GetOptions{})
776 if err != nil {
777 return false, err
778 }
779 pod = newPod
780 return metav1.GetControllerOf(newPod) == nil, nil
781 }); err != nil {
782 t.Fatalf("Failed to verify ControllerRef for the pod %s is nil: %v", pod.Name, err)
783 }
784
785
786 updatePod(t, podClient, pod.Name, func(pod *v1.Pod) {
787 pod.Labels = labelMap()
788 })
789 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
790 newPod, err := podClient.Get(tCtx, pod.Name, metav1.GetOptions{})
791 if err != nil {
792
793
794 if !apierrors.IsNotFound(err) {
795 return false, err
796 }
797
798 pods := getPods(t, podClient, labelMap())
799 if len(pods.Items) != 1 {
800 return false, fmt.Errorf("Expected 1 pod in current namespace, got %d", len(pods.Items))
801 }
802
803 pod = &pods.Items[0]
804 return true, nil
805 }
806
807 pod = newPod
808
809 return metav1.GetControllerOf(newPod) != nil, nil
810 }); err != nil {
811 t.Fatalf("Failed to verify ControllerRef for pod %s is not nil: %v", pod.Name, err)
812 }
813
814
815 if pod != nil {
816 controllerRef := metav1.GetControllerOf(pod)
817 if controllerRef.UID != rs.UID {
818 t.Fatalf("RS owner of the pod %s has a different UID: Expected %v, got %v", pod.Name, rs.UID, controllerRef.UID)
819 }
820 }
821 }
822
823 func TestGeneralPodAdoption(t *testing.T) {
824 _, closeFn, rm, informers, c := rmSetup(t)
825 defer closeFn()
826 ns := framework.CreateNamespaceOrDie(c, "test-general-pod-adoption", t)
827 defer framework.DeleteNamespaceOrDie(c, ns, t)
828 stopControllers := runControllerAndInformers(t, rm, informers, 0)
829 defer stopControllers()
830
831 rs := newRS("rs", ns.Name, 1)
832 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
833 rs = rss[0]
834 waitRSStable(t, c, rs)
835
836 podClient := c.CoreV1().Pods(ns.Name)
837 pods := getPods(t, podClient, labelMap())
838 if len(pods.Items) != 1 {
839 t.Fatalf("len(pods) = %d, want 1", len(pods.Items))
840 }
841 pod := &pods.Items[0]
842 var falseVar = false
843
844
845
846
847 ownerReference := metav1.OwnerReference{UID: uuid.NewUUID(), APIVersion: "apps/v1", Kind: "StatefulSet", Name: rs.Name, Controller: &falseVar}
848 testPodControllerRefPatch(t, c, pod, &ownerReference, rs, 2)
849
850
851 ownerReference = metav1.OwnerReference{UID: rs.UID, APIVersion: "apps/v1", Kind: "ReplicaSet", Name: rs.Name, Controller: &falseVar}
852 testPodControllerRefPatch(t, c, pod, &ownerReference, rs, 1)
853 }
854
855 func TestReadyAndAvailableReplicas(t *testing.T) {
856 tCtx, closeFn, rm, informers, c := rmSetup(t)
857 defer closeFn()
858 ns := framework.CreateNamespaceOrDie(c, "test-ready-and-available-replicas", t)
859 defer framework.DeleteNamespaceOrDie(c, ns, t)
860 stopControllers := runControllerAndInformers(t, rm, informers, 0)
861 defer stopControllers()
862
863 rs := newRS("rs", ns.Name, 3)
864 rs.Spec.MinReadySeconds = 3600
865 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
866 rs = rss[0]
867 waitRSStable(t, c, rs)
868
869
870 if rs.Status.AvailableReplicas != 0 {
871 t.Fatalf("Unexpected .Status.AvailableReplicas: Expected 0, saw %d", rs.Status.AvailableReplicas)
872 }
873
874 podClient := c.CoreV1().Pods(ns.Name)
875 pods := getPods(t, podClient, labelMap())
876 if len(pods.Items) != 3 {
877 t.Fatalf("len(pods) = %d, want 3", len(pods.Items))
878 }
879
880
881 firstPodList := &v1.PodList{Items: pods.Items[:1]}
882 secondPodList := &v1.PodList{Items: pods.Items[1:2]}
883 thirdPodList := &v1.PodList{Items: pods.Items[2:]}
884
885
886 setPodsReadyCondition(t, c, firstPodList, v1.ConditionFalse, time.Now())
887
888
889 setPodsReadyCondition(t, c, secondPodList, v1.ConditionTrue, time.Now())
890
891
892 setPodsReadyCondition(t, c, thirdPodList, v1.ConditionTrue, time.Now().Add(-120*time.Minute))
893
894 rsClient := c.AppsV1().ReplicaSets(ns.Name)
895 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
896 newRS, err := rsClient.Get(tCtx, rs.Name, metav1.GetOptions{})
897 if err != nil {
898 return false, err
899 }
900
901 return newRS.Status.Replicas == 3 && newRS.Status.ReadyReplicas == 2 && newRS.Status.AvailableReplicas == 1, nil
902 }); err != nil {
903 t.Fatalf("Failed to verify number of Replicas, ReadyReplicas and AvailableReplicas of rs %s to be as expected: %v", rs.Name, err)
904 }
905 }
906
907 func TestRSScaleSubresource(t *testing.T) {
908 _, closeFn, rm, informers, c := rmSetup(t)
909 defer closeFn()
910 ns := framework.CreateNamespaceOrDie(c, "test-rs-scale-subresource", t)
911 defer framework.DeleteNamespaceOrDie(c, ns, t)
912 stopControllers := runControllerAndInformers(t, rm, informers, 0)
913 defer stopControllers()
914
915 rs := newRS("rs", ns.Name, 1)
916 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
917 rs = rss[0]
918 waitRSStable(t, c, rs)
919
920
921 testScalingUsingScaleSubresource(t, c, rs, 3)
922
923 testScalingUsingScaleSubresource(t, c, rs, 0)
924 }
925
926 func TestExtraPodsAdoptionAndDeletion(t *testing.T) {
927 _, closeFn, rm, informers, c := rmSetup(t)
928 defer closeFn()
929 ns := framework.CreateNamespaceOrDie(c, "test-extra-pods-adoption-and-deletion", t)
930 defer framework.DeleteNamespaceOrDie(c, ns, t)
931
932 rs := newRS("rs", ns.Name, 2)
933
934 podList := []*v1.Pod{}
935 for i := 0; i < 3; i++ {
936 pod := newMatchingPod(fmt.Sprintf("pod-%d", i+1), ns.Name)
937 pod.Labels = labelMap()
938 podList = append(podList, pod)
939 }
940 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, podList)
941 rs = rss[0]
942 stopControllers := runControllerAndInformers(t, rm, informers, 3)
943 defer stopControllers()
944 waitRSStable(t, c, rs)
945
946
947
948 podClient := c.CoreV1().Pods(ns.Name)
949 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
950
951 pods := getPods(t, podClient, labelMap())
952 return int32(len(pods.Items)) == *rs.Spec.Replicas, nil
953 }); err != nil {
954 t.Fatalf("Failed to verify number of all pods within current namespace matches .spec.replicas of rs %s: %v", rs.Name, err)
955 }
956 }
957
958 func TestFullyLabeledReplicas(t *testing.T) {
959 tCtx, closeFn, rm, informers, c := rmSetup(t)
960 defer closeFn()
961 ns := framework.CreateNamespaceOrDie(c, "test-fully-labeled-replicas", t)
962 defer framework.DeleteNamespaceOrDie(c, ns, t)
963 stopControllers := runControllerAndInformers(t, rm, informers, 0)
964 defer stopControllers()
965
966 extraLabelMap := map[string]string{"foo": "bar", "extraKey": "extraValue"}
967 rs := newRS("rs", ns.Name, 2)
968 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
969 rs = rss[0]
970 waitRSStable(t, c, rs)
971
972
973 rsClient := c.AppsV1().ReplicaSets(ns.Name)
974 updateRS(t, rsClient, rs.Name, func(rs *apps.ReplicaSet) {
975 rs.Spec.Template.Labels = extraLabelMap
976 })
977
978
979 podClient := c.CoreV1().Pods(ns.Name)
980 pods := getPods(t, podClient, labelMap())
981 if len(pods.Items) != 2 {
982 t.Fatalf("len(pods) = %d, want 2", len(pods.Items))
983 }
984 fullyLabeledPod := &pods.Items[0]
985 updatePod(t, podClient, fullyLabeledPod.Name, func(pod *v1.Pod) {
986 pod.Labels = extraLabelMap
987 })
988
989
990 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
991 newRS, err := rsClient.Get(tCtx, rs.Name, metav1.GetOptions{})
992 if err != nil {
993 return false, err
994 }
995 return (newRS.Status.Replicas == 2 && newRS.Status.FullyLabeledReplicas == 1), nil
996 }); err != nil {
997 t.Fatalf("Failed to verify only one pod is fully labeled: %v", err)
998 }
999 }
1000
1001 func TestReplicaSetsAppsV1DefaultGCPolicy(t *testing.T) {
1002 tCtx, closeFn, rm, informers, c := rmSetup(t)
1003 defer closeFn()
1004 ns := framework.CreateNamespaceOrDie(c, "test-default-gc-v1", t)
1005 defer framework.DeleteNamespaceOrDie(c, ns, t)
1006 stopControllers := runControllerAndInformers(t, rm, informers, 0)
1007 defer stopControllers()
1008
1009 rs := newRS("rs", ns.Name, 2)
1010 fakeFinalizer := "kube.io/dummy-finalizer"
1011 rs.Finalizers = []string{fakeFinalizer}
1012 rss, _ := createRSsPods(t, c, []*apps.ReplicaSet{rs}, []*v1.Pod{})
1013 rs = rss[0]
1014 waitRSStable(t, c, rs)
1015
1016
1017 podClient := c.CoreV1().Pods(ns.Name)
1018 pods := getPods(t, podClient, labelMap())
1019 if len(pods.Items) != 2 {
1020 t.Fatalf("len(pods) = %d, want 2", len(pods.Items))
1021 }
1022
1023 rsClient := c.AppsV1().ReplicaSets(ns.Name)
1024 err := rsClient.Delete(tCtx, rs.Name, metav1.DeleteOptions{})
1025 if err != nil {
1026 t.Fatalf("Failed to delete rs: %v", err)
1027 }
1028
1029
1030 if err := wait.PollImmediate(interval, timeout, func() (bool, error) {
1031 newRS, err := rsClient.Get(tCtx, rs.Name, metav1.GetOptions{})
1032 if err != nil {
1033 return false, err
1034 }
1035 if newRS.DeletionTimestamp == nil {
1036 return false, nil
1037 }
1038 if got, want := newRS.Finalizers, []string{fakeFinalizer}; !reflect.DeepEqual(got, want) {
1039 return false, fmt.Errorf("got finalizers: %+v; want: %+v", got, want)
1040 }
1041 return true, nil
1042 }); err != nil {
1043 t.Fatalf("Failed to verify the finalizer: %v", err)
1044 }
1045
1046 updateRS(t, c.AppsV1().ReplicaSets(ns.Name), rs.Name, func(rs *apps.ReplicaSet) {
1047 var finalizers []string
1048
1049 for _, finalizer := range rs.Finalizers {
1050 if finalizer != fakeFinalizer {
1051 finalizers = append(finalizers, finalizer)
1052 }
1053 }
1054 rs.Finalizers = finalizers
1055 })
1056
1057 _ = rsClient.Delete(tCtx, rs.Name, metav1.DeleteOptions{})
1058 }
1059
View as plain text