1
16
17 package pods
18
19 import (
20 "context"
21 "fmt"
22 "strings"
23 "testing"
24
25 v1 "k8s.io/api/core/v1"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/types"
28 clientset "k8s.io/client-go/kubernetes"
29 typedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
30 kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
31 "k8s.io/kubernetes/test/integration"
32 "k8s.io/kubernetes/test/integration/framework"
33 )
34
35 func TestPodUpdateActiveDeadlineSeconds(t *testing.T) {
36
37 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
38 defer server.TearDownFn()
39
40 client := clientset.NewForConfigOrDie(server.ClientConfig)
41
42 ns := framework.CreateNamespaceOrDie(client, "pod-activedeadline-update", t)
43 defer framework.DeleteNamespaceOrDie(client, ns, t)
44
45 var (
46 iZero = int64(0)
47 i30 = int64(30)
48 i60 = int64(60)
49 iNeg = int64(-1)
50 )
51
52 prototypePod := func() *v1.Pod {
53 return &v1.Pod{
54 ObjectMeta: metav1.ObjectMeta{
55 Name: "xxx",
56 },
57 Spec: v1.PodSpec{
58 Containers: []v1.Container{
59 {
60 Name: "fake-name",
61 Image: "fakeimage",
62 },
63 },
64 },
65 }
66 }
67
68 cases := []struct {
69 name string
70 original *int64
71 update *int64
72 valid bool
73 }{
74 {
75 name: "no change, nil",
76 original: nil,
77 update: nil,
78 valid: true,
79 },
80 {
81 name: "no change, set",
82 original: &i30,
83 update: &i30,
84 valid: true,
85 },
86 {
87 name: "change to positive from nil",
88 original: nil,
89 update: &i60,
90 valid: true,
91 },
92 {
93 name: "change to smaller positive",
94 original: &i60,
95 update: &i30,
96 valid: true,
97 },
98 {
99 name: "change to larger positive",
100 original: &i30,
101 update: &i60,
102 valid: false,
103 },
104 {
105 name: "change to negative from positive",
106 original: &i30,
107 update: &iNeg,
108 valid: false,
109 },
110 {
111 name: "change to negative from nil",
112 original: nil,
113 update: &iNeg,
114 valid: false,
115 },
116
117 {
118 name: "change to zero from positive",
119 original: &i30,
120 update: &iZero,
121 valid: false,
122 },
123 {
124 name: "change to nil from positive",
125 original: &i30,
126 update: nil,
127 valid: false,
128 },
129 }
130
131 for i, tc := range cases {
132 pod := prototypePod()
133 pod.Spec.ActiveDeadlineSeconds = tc.original
134 pod.ObjectMeta.Name = fmt.Sprintf("activedeadlineseconds-test-%v", i)
135
136 if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil {
137 t.Errorf("Failed to create pod: %v", err)
138 }
139
140 pod.Spec.ActiveDeadlineSeconds = tc.update
141
142 _, err := client.CoreV1().Pods(ns.Name).Update(context.TODO(), pod, metav1.UpdateOptions{})
143 if tc.valid && err != nil {
144 t.Errorf("%v: failed to update pod: %v", tc.name, err)
145 } else if !tc.valid && err == nil {
146 t.Errorf("%v: unexpected allowed update to pod", tc.name)
147 }
148
149 integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
150 }
151 }
152
153 func TestPodReadOnlyFilesystem(t *testing.T) {
154
155 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
156 defer server.TearDownFn()
157
158 client := clientset.NewForConfigOrDie(server.ClientConfig)
159
160 isReadOnly := true
161 ns := framework.CreateNamespaceOrDie(client, "pod-readonly-root", t)
162 defer framework.DeleteNamespaceOrDie(client, ns, t)
163
164 pod := &v1.Pod{
165 ObjectMeta: metav1.ObjectMeta{
166 Name: "xxx",
167 },
168 Spec: v1.PodSpec{
169 Containers: []v1.Container{
170 {
171 Name: "fake-name",
172 Image: "fakeimage",
173 SecurityContext: &v1.SecurityContext{
174 ReadOnlyRootFilesystem: &isReadOnly,
175 },
176 },
177 },
178 },
179 }
180
181 if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil {
182 t.Errorf("Failed to create pod: %v", err)
183 }
184
185 integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
186 }
187
188 func TestPodCreateEphemeralContainers(t *testing.T) {
189
190 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
191 defer server.TearDownFn()
192
193 client := clientset.NewForConfigOrDie(server.ClientConfig)
194
195 ns := framework.CreateNamespaceOrDie(client, "pod-create-ephemeral-containers", t)
196 defer framework.DeleteNamespaceOrDie(client, ns, t)
197
198 pod := &v1.Pod{
199 ObjectMeta: metav1.ObjectMeta{
200 Name: "xxx",
201 },
202 Spec: v1.PodSpec{
203 Containers: []v1.Container{
204 {
205 Name: "fake-name",
206 Image: "fakeimage",
207 ImagePullPolicy: "Always",
208 TerminationMessagePolicy: "File",
209 },
210 },
211 EphemeralContainers: []v1.EphemeralContainer{
212 {
213 EphemeralContainerCommon: v1.EphemeralContainerCommon{
214 Name: "debugger",
215 Image: "debugimage",
216 ImagePullPolicy: "Always",
217 TerminationMessagePolicy: "File",
218 },
219 },
220 },
221 },
222 }
223
224 if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err == nil {
225 t.Errorf("Unexpected allowed creation of pod with ephemeral containers")
226 integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
227 } else if !strings.HasSuffix(err.Error(), "spec.ephemeralContainers: Forbidden: cannot be set on create") {
228 t.Errorf("Unexpected error when creating pod with ephemeral containers: %v", err)
229 }
230 }
231
232
233
234 func setUpEphemeralContainers(podsClient typedv1.PodInterface, pod *v1.Pod, containers []v1.EphemeralContainer) (*v1.Pod, error) {
235 result, err := podsClient.Create(context.TODO(), pod, metav1.CreateOptions{})
236 if err != nil {
237 return nil, fmt.Errorf("failed to create pod: %v", err)
238 }
239
240 if len(containers) == 0 {
241 return result, nil
242 }
243
244 pod.Spec.EphemeralContainers = containers
245 if _, err := podsClient.Update(context.TODO(), pod, metav1.UpdateOptions{}); err == nil {
246 return nil, fmt.Errorf("unexpected allowed direct update of ephemeral containers during set up: %v", err)
247 }
248
249 result, err = podsClient.UpdateEphemeralContainers(context.TODO(), pod.Name, pod, metav1.UpdateOptions{})
250 if err != nil {
251 return nil, fmt.Errorf("failed to update ephemeral containers for test case set up: %v", err)
252 }
253
254 return result, nil
255 }
256
257 func TestPodPatchEphemeralContainers(t *testing.T) {
258
259 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
260 defer server.TearDownFn()
261
262 client := clientset.NewForConfigOrDie(server.ClientConfig)
263
264 ns := framework.CreateNamespaceOrDie(client, "pod-patch-ephemeral-containers", t)
265 defer framework.DeleteNamespaceOrDie(client, ns, t)
266
267 testPod := func(name string) *v1.Pod {
268 return &v1.Pod{
269 ObjectMeta: metav1.ObjectMeta{
270 Name: name,
271 },
272 Spec: v1.PodSpec{
273 Containers: []v1.Container{
274 {
275 Name: "fake-name",
276 Image: "fakeimage",
277 ImagePullPolicy: "Always",
278 TerminationMessagePolicy: "File",
279 },
280 },
281 },
282 }
283 }
284
285 cases := []struct {
286 name string
287 original []v1.EphemeralContainer
288 patchType types.PatchType
289 patchBody []byte
290 valid bool
291 }{
292 {
293 name: "create single container (strategic)",
294 original: nil,
295 patchType: types.StrategicMergePatchType,
296 patchBody: []byte(`{
297 "spec": {
298 "ephemeralContainers": [{
299 "name": "debugger1",
300 "image": "debugimage",
301 "imagePullPolicy": "Always",
302 "terminationMessagePolicy": "File"
303 }]
304 }
305 }`),
306 valid: true,
307 },
308 {
309 name: "create single container (merge)",
310 original: nil,
311 patchType: types.MergePatchType,
312 patchBody: []byte(`{
313 "spec": {
314 "ephemeralContainers":[{
315 "name": "debugger1",
316 "image": "debugimage",
317 "imagePullPolicy": "Always",
318 "terminationMessagePolicy": "File"
319 }]
320 }
321 }`),
322 valid: true,
323 },
324 {
325 name: "create single container (JSON)",
326 original: nil,
327 patchType: types.JSONPatchType,
328
329
330 patchBody: []byte(`[{
331 "op":"add",
332 "path":"/spec/ephemeralContainers",
333 "value":[{
334 "name":"debugger1",
335 "image":"debugimage",
336 "imagePullPolicy": "Always",
337 "terminationMessagePolicy": "File"
338 }]
339 }]`),
340 valid: true,
341 },
342 {
343 name: "add single container (strategic)",
344 original: []v1.EphemeralContainer{
345 {
346 EphemeralContainerCommon: v1.EphemeralContainerCommon{
347 Name: "debugger1",
348 Image: "debugimage",
349 ImagePullPolicy: "Always",
350 TerminationMessagePolicy: "File",
351 },
352 },
353 },
354 patchType: types.StrategicMergePatchType,
355 patchBody: []byte(`{
356 "spec": {
357 "ephemeralContainers":[{
358 "name": "debugger2",
359 "image": "debugimage",
360 "imagePullPolicy": "Always",
361 "terminationMessagePolicy": "File"
362 }]
363 }
364 }`),
365 valid: true,
366 },
367 {
368 name: "add single container (merge)",
369 original: []v1.EphemeralContainer{
370 {
371 EphemeralContainerCommon: v1.EphemeralContainerCommon{
372 Name: "debugger1",
373 Image: "debugimage",
374 ImagePullPolicy: "Always",
375 TerminationMessagePolicy: "File",
376 },
377 },
378 },
379 patchType: types.MergePatchType,
380 patchBody: []byte(`{
381 "spec": {
382 "ephemeralContainers":[{
383 "name": "debugger1",
384 "image": "debugimage",
385 "imagePullPolicy": "Always",
386 "terminationMessagePolicy": "File"
387 },{
388 "name": "debugger2",
389 "image": "debugimage",
390 "imagePullPolicy": "Always",
391 "terminationMessagePolicy": "File"
392 }]
393 }
394 }`),
395 valid: true,
396 },
397 {
398 name: "add single container (JSON)",
399 original: []v1.EphemeralContainer{
400 {
401 EphemeralContainerCommon: v1.EphemeralContainerCommon{
402 Name: "debugger1",
403 Image: "debugimage",
404 ImagePullPolicy: "Always",
405 TerminationMessagePolicy: "File",
406 },
407 },
408 },
409 patchType: types.JSONPatchType,
410 patchBody: []byte(`[{
411 "op":"add",
412 "path":"/spec/ephemeralContainers/-",
413 "value":{
414 "name":"debugger2",
415 "image":"debugimage",
416 "imagePullPolicy": "Always",
417 "terminationMessagePolicy": "File"
418 }
419 }]`),
420 valid: true,
421 },
422 {
423 name: "remove all containers (merge)",
424 original: []v1.EphemeralContainer{
425 {
426 EphemeralContainerCommon: v1.EphemeralContainerCommon{
427 Name: "debugger1",
428 Image: "debugimage",
429 ImagePullPolicy: "Always",
430 TerminationMessagePolicy: "File",
431 },
432 },
433 },
434 patchType: types.MergePatchType,
435 patchBody: []byte(`{"spec": {"ephemeralContainers":[]}}`),
436 valid: false,
437 },
438 {
439 name: "remove the single container (JSON)",
440 original: []v1.EphemeralContainer{
441 {
442 EphemeralContainerCommon: v1.EphemeralContainerCommon{
443 Name: "debugger1",
444 Image: "debugimage",
445 ImagePullPolicy: "Always",
446 TerminationMessagePolicy: "File",
447 },
448 },
449 },
450 patchType: types.JSONPatchType,
451 patchBody: []byte(`[{"op":"remove","path":"/spec/ephemeralContainers/0"}]`),
452 valid: false,
453 },
454 {
455 name: "remove all containers (JSON)",
456 original: []v1.EphemeralContainer{
457 {
458 EphemeralContainerCommon: v1.EphemeralContainerCommon{
459 Name: "debugger1",
460 Image: "debugimage",
461 ImagePullPolicy: "Always",
462 TerminationMessagePolicy: "File",
463 },
464 },
465 },
466 patchType: types.JSONPatchType,
467 patchBody: []byte(`[{"op":"remove","path":"/spec/ephemeralContainers"}]`),
468 valid: false,
469 },
470 }
471
472 for i, tc := range cases {
473 pod := testPod(fmt.Sprintf("ephemeral-container-test-%v", i))
474 if _, err := setUpEphemeralContainers(client.CoreV1().Pods(ns.Name), pod, tc.original); err != nil {
475 t.Errorf("%v: %v", tc.name, err)
476 }
477
478 if _, err := client.CoreV1().Pods(ns.Name).Patch(context.TODO(), pod.Name, tc.patchType, tc.patchBody, metav1.PatchOptions{}, "ephemeralcontainers"); tc.valid && err != nil {
479 t.Errorf("%v: failed to update ephemeral containers: %v", tc.name, err)
480 } else if !tc.valid && err == nil {
481 t.Errorf("%v: unexpected allowed update to ephemeral containers", tc.name)
482 }
483
484 integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
485 }
486 }
487
488 func TestPodUpdateEphemeralContainers(t *testing.T) {
489
490 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
491 defer server.TearDownFn()
492
493 client := clientset.NewForConfigOrDie(server.ClientConfig)
494
495 ns := framework.CreateNamespaceOrDie(client, "pod-update-ephemeral-containers", t)
496 defer framework.DeleteNamespaceOrDie(client, ns, t)
497
498 testPod := func(name string) *v1.Pod {
499 return &v1.Pod{
500 ObjectMeta: metav1.ObjectMeta{
501 Name: name,
502 },
503 Spec: v1.PodSpec{
504 Containers: []v1.Container{
505 {
506 Name: "fake-name",
507 Image: "fakeimage",
508 },
509 },
510 },
511 }
512 }
513
514 cases := []struct {
515 name string
516 original []v1.EphemeralContainer
517 update []v1.EphemeralContainer
518 valid bool
519 }{
520 {
521 name: "no change, nil",
522 original: nil,
523 update: nil,
524 valid: true,
525 },
526 {
527 name: "no change, set",
528 original: []v1.EphemeralContainer{
529 {
530 EphemeralContainerCommon: v1.EphemeralContainerCommon{
531 Name: "debugger",
532 Image: "debugimage",
533 ImagePullPolicy: "Always",
534 TerminationMessagePolicy: "File",
535 },
536 },
537 },
538 update: []v1.EphemeralContainer{
539 {
540 EphemeralContainerCommon: v1.EphemeralContainerCommon{
541 Name: "debugger",
542 Image: "debugimage",
543 ImagePullPolicy: "Always",
544 TerminationMessagePolicy: "File",
545 },
546 },
547 },
548 valid: true,
549 },
550 {
551 name: "add single container",
552 original: nil,
553 update: []v1.EphemeralContainer{
554 {
555 EphemeralContainerCommon: v1.EphemeralContainerCommon{
556 Name: "debugger",
557 Image: "debugimage",
558 ImagePullPolicy: "Always",
559 TerminationMessagePolicy: "File",
560 },
561 },
562 },
563 valid: true,
564 },
565 {
566 name: "remove all containers, nil",
567 original: []v1.EphemeralContainer{
568 {
569 EphemeralContainerCommon: v1.EphemeralContainerCommon{
570 Name: "debugger",
571 Image: "debugimage",
572 ImagePullPolicy: "Always",
573 TerminationMessagePolicy: "File",
574 },
575 },
576 },
577 update: nil,
578 valid: false,
579 },
580 {
581 name: "remove all containers, empty",
582 original: []v1.EphemeralContainer{
583 {
584 EphemeralContainerCommon: v1.EphemeralContainerCommon{
585 Name: "debugger",
586 Image: "debugimage",
587 ImagePullPolicy: "Always",
588 TerminationMessagePolicy: "File",
589 },
590 },
591 },
592 update: []v1.EphemeralContainer{},
593 valid: false,
594 },
595 {
596 name: "increase number of containers",
597 original: []v1.EphemeralContainer{
598 {
599 EphemeralContainerCommon: v1.EphemeralContainerCommon{
600 Name: "debugger1",
601 Image: "debugimage",
602 ImagePullPolicy: "Always",
603 TerminationMessagePolicy: "File",
604 },
605 },
606 },
607 update: []v1.EphemeralContainer{
608 {
609 EphemeralContainerCommon: v1.EphemeralContainerCommon{
610 Name: "debugger1",
611 Image: "debugimage",
612 ImagePullPolicy: "Always",
613 TerminationMessagePolicy: "File",
614 },
615 },
616 {
617 EphemeralContainerCommon: v1.EphemeralContainerCommon{
618 Name: "debugger2",
619 Image: "debugimage",
620 ImagePullPolicy: "Always",
621 TerminationMessagePolicy: "File",
622 },
623 },
624 },
625 valid: true,
626 },
627 {
628 name: "decrease number of containers",
629 original: []v1.EphemeralContainer{
630 {
631 EphemeralContainerCommon: v1.EphemeralContainerCommon{
632 Name: "debugger1",
633 Image: "debugimage",
634 ImagePullPolicy: "Always",
635 TerminationMessagePolicy: "File",
636 },
637 },
638 {
639 EphemeralContainerCommon: v1.EphemeralContainerCommon{
640 Name: "debugger2",
641 Image: "debugimage",
642 ImagePullPolicy: "Always",
643 TerminationMessagePolicy: "File",
644 },
645 },
646 },
647 update: []v1.EphemeralContainer{
648 {
649 EphemeralContainerCommon: v1.EphemeralContainerCommon{
650 Name: "debugger1",
651 Image: "debugimage",
652 ImagePullPolicy: "Always",
653 TerminationMessagePolicy: "File",
654 },
655 },
656 },
657 valid: false,
658 },
659 }
660
661 for i, tc := range cases {
662 pod, err := setUpEphemeralContainers(client.CoreV1().Pods(ns.Name), testPod(fmt.Sprintf("ephemeral-container-test-%v", i)), tc.original)
663 if err != nil {
664 t.Errorf("%v: %v", tc.name, err)
665 }
666
667 pod.Spec.EphemeralContainers = tc.update
668 if _, err := client.CoreV1().Pods(ns.Name).UpdateEphemeralContainers(context.TODO(), pod.Name, pod, metav1.UpdateOptions{}); tc.valid && err != nil {
669 t.Errorf("%v: failed to update ephemeral containers: %v", tc.name, err)
670 } else if !tc.valid && err == nil {
671 t.Errorf("%v: unexpected allowed update to ephemeral containers", tc.name)
672 }
673
674 integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
675 }
676 }
677
678 func TestMutablePodSchedulingDirectives(t *testing.T) {
679
680 server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
681 defer server.TearDownFn()
682
683 client := clientset.NewForConfigOrDie(server.ClientConfig)
684
685 ns := framework.CreateNamespaceOrDie(client, "mutable-pod-scheduling-directives", t)
686 defer framework.DeleteNamespaceOrDie(client, ns, t)
687
688 cases := []struct {
689 name string
690 create *v1.Pod
691 update *v1.Pod
692 err string
693 }{
694 {
695 name: "adding node selector is allowed for gated pods",
696 create: &v1.Pod{
697 ObjectMeta: metav1.ObjectMeta{
698 Name: "test-pod",
699 },
700 Spec: v1.PodSpec{
701 Containers: []v1.Container{
702 {
703 Name: "fake-name",
704 Image: "fakeimage",
705 },
706 },
707 SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
708 },
709 },
710 update: &v1.Pod{
711 ObjectMeta: metav1.ObjectMeta{
712 Name: "test-pod",
713 },
714 Spec: v1.PodSpec{
715 Containers: []v1.Container{
716 {
717 Name: "fake-name",
718 Image: "fakeimage",
719 },
720 },
721 NodeSelector: map[string]string{
722 "foo": "bar",
723 },
724 SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
725 },
726 },
727 },
728 {
729 name: "addition to nodeAffinity is allowed for gated pods",
730 create: &v1.Pod{
731 ObjectMeta: metav1.ObjectMeta{
732 Name: "test-pod",
733 },
734 Spec: v1.PodSpec{
735 Containers: []v1.Container{
736 {
737 Name: "fake-name",
738 Image: "fakeimage",
739 },
740 },
741 Affinity: &v1.Affinity{
742 NodeAffinity: &v1.NodeAffinity{
743 RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
744 NodeSelectorTerms: []v1.NodeSelectorTerm{
745 {
746 MatchExpressions: []v1.NodeSelectorRequirement{
747 {
748 Key: "expr",
749 Operator: v1.NodeSelectorOpIn,
750 Values: []string{"foo"},
751 },
752 },
753 },
754 },
755 },
756 },
757 },
758 SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
759 },
760 },
761 update: &v1.Pod{
762 ObjectMeta: metav1.ObjectMeta{
763 Name: "test-pod",
764 },
765 Spec: v1.PodSpec{
766 Containers: []v1.Container{
767 {
768 Name: "fake-name",
769 Image: "fakeimage",
770 },
771 },
772 Affinity: &v1.Affinity{
773 NodeAffinity: &v1.NodeAffinity{
774 RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
775
776 NodeSelectorTerms: []v1.NodeSelectorTerm{
777 {
778 MatchExpressions: []v1.NodeSelectorRequirement{
779 {
780 Key: "expr",
781 Operator: v1.NodeSelectorOpIn,
782 Values: []string{"foo"},
783 },
784 {
785 Key: "expr2",
786 Operator: v1.NodeSelectorOpIn,
787 Values: []string{"foo2"},
788 },
789 },
790 MatchFields: []v1.NodeSelectorRequirement{
791 {
792 Key: "metadata.name",
793 Operator: v1.NodeSelectorOpIn,
794 Values: []string{"foo"},
795 },
796 },
797 },
798 },
799 },
800 },
801 },
802 SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
803 },
804 },
805 },
806 {
807 name: "addition to nodeAffinity is allowed for gated pods with nil affinity",
808 create: &v1.Pod{
809 ObjectMeta: metav1.ObjectMeta{
810 Name: "test-pod",
811 },
812 Spec: v1.PodSpec{
813 Containers: []v1.Container{
814 {
815 Name: "fake-name",
816 Image: "fakeimage",
817 },
818 },
819 SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
820 },
821 },
822 update: &v1.Pod{
823 ObjectMeta: metav1.ObjectMeta{
824 Name: "test-pod",
825 },
826 Spec: v1.PodSpec{
827 Containers: []v1.Container{
828 {
829 Name: "fake-name",
830 Image: "fakeimage",
831 },
832 },
833 Affinity: &v1.Affinity{
834 NodeAffinity: &v1.NodeAffinity{
835 RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
836
837 NodeSelectorTerms: []v1.NodeSelectorTerm{
838 {
839 MatchExpressions: []v1.NodeSelectorRequirement{
840 {
841 Key: "expr",
842 Operator: v1.NodeSelectorOpIn,
843 Values: []string{"foo"},
844 },
845 },
846 MatchFields: []v1.NodeSelectorRequirement{
847 {
848 Key: "metadata.name",
849 Operator: v1.NodeSelectorOpIn,
850 Values: []string{"foo"},
851 },
852 },
853 },
854 },
855 },
856 },
857 },
858 SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
859 },
860 },
861 },
862 }
863 for _, tc := range cases {
864 if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), tc.create, metav1.CreateOptions{}); err != nil {
865 t.Errorf("Failed to create pod: %v", err)
866 }
867
868 _, err := client.CoreV1().Pods(ns.Name).Update(context.TODO(), tc.update, metav1.UpdateOptions{})
869 if (tc.err == "" && err != nil) || (tc.err != "" && err != nil && !strings.Contains(err.Error(), tc.err)) {
870 t.Errorf("Unexpected error: got %q, want %q", err.Error(), err)
871 }
872 integration.DeletePodOrErrorf(t, client, ns.Name, tc.update.Name)
873 }
874 }
875
View as plain text