1
16
17 package kuberuntime
18
19 import (
20 "context"
21 "os"
22 "path/filepath"
23 "regexp"
24 goruntime "runtime"
25 "strings"
26 "testing"
27 "time"
28
29 "github.com/google/go-cmp/cmp"
30 "github.com/stretchr/testify/assert"
31 "github.com/stretchr/testify/require"
32 "k8s.io/apimachinery/pkg/api/resource"
33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34 "k8s.io/apimachinery/pkg/types"
35 "k8s.io/apimachinery/pkg/util/intstr"
36 utilfeature "k8s.io/apiserver/pkg/util/feature"
37 featuregatetesting "k8s.io/component-base/featuregate/testing"
38
39 v1 "k8s.io/api/core/v1"
40 runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
41
42 "k8s.io/kubernetes/pkg/features"
43 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
44 containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
45 "k8s.io/kubernetes/pkg/kubelet/lifecycle"
46 )
47
48
49 func TestRemoveContainer(t *testing.T) {
50 ctx := context.Background()
51 fakeRuntime, _, m, err := createTestRuntimeManager()
52 require.NoError(t, err)
53 pod := &v1.Pod{
54 ObjectMeta: metav1.ObjectMeta{
55 UID: "12345678",
56 Name: "bar",
57 Namespace: "new",
58 },
59 Spec: v1.PodSpec{
60 Containers: []v1.Container{
61 {
62 Name: "foo",
63 Image: "busybox",
64 ImagePullPolicy: v1.PullIfNotPresent,
65 },
66 },
67 },
68 }
69
70
71 _, fakeContainers := makeAndSetFakePod(t, m, fakeRuntime, pod)
72 assert.Equal(t, len(fakeContainers), 1)
73
74 containerID := fakeContainers[0].Id
75 fakeOS := m.osInterface.(*containertest.FakeOS)
76 fakeOS.GlobFn = func(pattern, path string) bool {
77 pattern = strings.Replace(pattern, "*", ".*", -1)
78 pattern = strings.Replace(pattern, "\\", "\\\\", -1)
79 return regexp.MustCompile(pattern).MatchString(path)
80 }
81 podLogsDirectory := "/var/log/pods"
82 expectedContainerLogPath := filepath.Join(podLogsDirectory, "new_bar_12345678", "foo", "0.log")
83 expectedContainerLogPathRotated := filepath.Join(podLogsDirectory, "new_bar_12345678", "foo", "0.log.20060102-150405")
84 expectedContainerLogSymlink := legacyLogSymlink(containerID, "foo", "bar", "new")
85
86 fakeOS.Create(expectedContainerLogPath)
87 fakeOS.Create(expectedContainerLogPathRotated)
88
89 err = m.removeContainer(ctx, containerID)
90 assert.NoError(t, err)
91
92
93
94 assert.ElementsMatch(t,
95 []string{expectedContainerLogSymlink, expectedContainerLogPath, expectedContainerLogPathRotated},
96 fakeOS.Removes)
97
98 assert.Contains(t, fakeRuntime.Called, "RemoveContainer")
99 containers, err := fakeRuntime.ListContainers(ctx, &runtimeapi.ContainerFilter{Id: containerID})
100 assert.NoError(t, err)
101 assert.Empty(t, containers)
102 }
103
104
105 func TestKillContainer(t *testing.T) {
106 _, _, m, _ := createTestRuntimeManager()
107
108 tests := []struct {
109 caseName string
110 pod *v1.Pod
111 containerID kubecontainer.ContainerID
112 containerName string
113 reason string
114 gracePeriodOverride int64
115 succeed bool
116 }{
117 {
118 caseName: "Failed to find container in pods, expect to return error",
119 pod: &v1.Pod{
120 ObjectMeta: metav1.ObjectMeta{UID: "pod1_id", Name: "pod1", Namespace: "default"},
121 Spec: v1.PodSpec{Containers: []v1.Container{{Name: "empty_container"}}},
122 },
123 containerID: kubecontainer.ContainerID{Type: "docker", ID: "not_exist_container_id"},
124 containerName: "not_exist_container",
125 reason: "unknown reason",
126 gracePeriodOverride: 0,
127 succeed: false,
128 },
129 }
130
131 for _, test := range tests {
132 ctx := context.Background()
133 err := m.killContainer(ctx, test.pod, test.containerID, test.containerName, test.reason, "", &test.gracePeriodOverride, nil)
134 if test.succeed != (err == nil) {
135 t.Errorf("%s: expected %v, got %v (%v)", test.caseName, test.succeed, (err == nil), err)
136 }
137 }
138 }
139
140
141
142
143 func TestToKubeContainerStatus(t *testing.T) {
144 cid := &kubecontainer.ContainerID{Type: "testRuntime", ID: "dummyid"}
145 meta := &runtimeapi.ContainerMetadata{Name: "cname", Attempt: 3}
146 imageSpec := &runtimeapi.ImageSpec{Image: "fimage"}
147 var (
148 createdAt int64 = 327
149 startedAt int64 = 999
150 finishedAt int64 = 1278
151 )
152
153 for desc, test := range map[string]struct {
154 input *runtimeapi.ContainerStatus
155 expected *kubecontainer.Status
156 }{
157 "created container": {
158 input: &runtimeapi.ContainerStatus{
159 Id: cid.ID,
160 Metadata: meta,
161 Image: imageSpec,
162 State: runtimeapi.ContainerState_CONTAINER_CREATED,
163 CreatedAt: createdAt,
164 },
165 expected: &kubecontainer.Status{
166 ID: *cid,
167 Image: imageSpec.Image,
168 State: kubecontainer.ContainerStateCreated,
169 CreatedAt: time.Unix(0, createdAt),
170 },
171 },
172 "running container": {
173 input: &runtimeapi.ContainerStatus{
174 Id: cid.ID,
175 Metadata: meta,
176 Image: imageSpec,
177 State: runtimeapi.ContainerState_CONTAINER_RUNNING,
178 CreatedAt: createdAt,
179 StartedAt: startedAt,
180 },
181 expected: &kubecontainer.Status{
182 ID: *cid,
183 Image: imageSpec.Image,
184 State: kubecontainer.ContainerStateRunning,
185 CreatedAt: time.Unix(0, createdAt),
186 StartedAt: time.Unix(0, startedAt),
187 },
188 },
189 "exited container": {
190 input: &runtimeapi.ContainerStatus{
191 Id: cid.ID,
192 Metadata: meta,
193 Image: imageSpec,
194 State: runtimeapi.ContainerState_CONTAINER_EXITED,
195 CreatedAt: createdAt,
196 StartedAt: startedAt,
197 FinishedAt: finishedAt,
198 ExitCode: int32(121),
199 Reason: "GotKilled",
200 Message: "The container was killed",
201 },
202 expected: &kubecontainer.Status{
203 ID: *cid,
204 Image: imageSpec.Image,
205 State: kubecontainer.ContainerStateExited,
206 CreatedAt: time.Unix(0, createdAt),
207 StartedAt: time.Unix(0, startedAt),
208 FinishedAt: time.Unix(0, finishedAt),
209 ExitCode: 121,
210 Reason: "GotKilled",
211 Message: "The container was killed",
212 },
213 },
214 "unknown container": {
215 input: &runtimeapi.ContainerStatus{
216 Id: cid.ID,
217 Metadata: meta,
218 Image: imageSpec,
219 State: runtimeapi.ContainerState_CONTAINER_UNKNOWN,
220 CreatedAt: createdAt,
221 StartedAt: startedAt,
222 },
223 expected: &kubecontainer.Status{
224 ID: *cid,
225 Image: imageSpec.Image,
226 State: kubecontainer.ContainerStateUnknown,
227 CreatedAt: time.Unix(0, createdAt),
228 StartedAt: time.Unix(0, startedAt),
229 },
230 },
231 } {
232 actual := toKubeContainerStatus(test.input, cid.Type)
233 assert.Equal(t, test.expected, actual, desc)
234 }
235 }
236
237
238
239 func TestToKubeContainerStatusWithResources(t *testing.T) {
240 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScaling, true)()
241 cid := &kubecontainer.ContainerID{Type: "testRuntime", ID: "dummyid"}
242 meta := &runtimeapi.ContainerMetadata{Name: "cname", Attempt: 3}
243 imageSpec := &runtimeapi.ImageSpec{Image: "fimage"}
244 var (
245 createdAt int64 = 327
246 startedAt int64 = 999
247 )
248
249 for desc, test := range map[string]struct {
250 input *runtimeapi.ContainerStatus
251 expected *kubecontainer.Status
252 }{
253 "container reporting cpu and memory": {
254 input: &runtimeapi.ContainerStatus{
255 Id: cid.ID,
256 Metadata: meta,
257 Image: imageSpec,
258 State: runtimeapi.ContainerState_CONTAINER_RUNNING,
259 CreatedAt: createdAt,
260 StartedAt: startedAt,
261 Resources: func() *runtimeapi.ContainerResources {
262 if goruntime.GOOS == "windows" {
263 return &runtimeapi.ContainerResources{
264 Windows: &runtimeapi.WindowsContainerResources{
265 CpuMaximum: 2500,
266 CpuCount: 1,
267 MemoryLimitInBytes: 524288000,
268 },
269 }
270 }
271 return &runtimeapi.ContainerResources{
272 Linux: &runtimeapi.LinuxContainerResources{
273 CpuQuota: 25000,
274 CpuPeriod: 100000,
275 MemoryLimitInBytes: 524288000,
276 OomScoreAdj: -998,
277 },
278 }
279 }(),
280 },
281 expected: &kubecontainer.Status{
282 ID: *cid,
283 Image: imageSpec.Image,
284 State: kubecontainer.ContainerStateRunning,
285 CreatedAt: time.Unix(0, createdAt),
286 StartedAt: time.Unix(0, startedAt),
287 Resources: &kubecontainer.ContainerResources{
288 CPULimit: resource.NewMilliQuantity(250, resource.DecimalSI),
289 MemoryLimit: resource.NewQuantity(524288000, resource.BinarySI),
290 },
291 },
292 },
293 "container reporting cpu only": {
294 input: &runtimeapi.ContainerStatus{
295 Id: cid.ID,
296 Metadata: meta,
297 Image: imageSpec,
298 State: runtimeapi.ContainerState_CONTAINER_RUNNING,
299 CreatedAt: createdAt,
300 StartedAt: startedAt,
301 Resources: func() *runtimeapi.ContainerResources {
302 if goruntime.GOOS == "windows" {
303 return &runtimeapi.ContainerResources{
304 Windows: &runtimeapi.WindowsContainerResources{
305 CpuMaximum: 2500,
306 CpuCount: 2,
307 },
308 }
309 }
310 return &runtimeapi.ContainerResources{
311 Linux: &runtimeapi.LinuxContainerResources{
312 CpuQuota: 50000,
313 CpuPeriod: 100000,
314 },
315 }
316 }(),
317 },
318 expected: &kubecontainer.Status{
319 ID: *cid,
320 Image: imageSpec.Image,
321 State: kubecontainer.ContainerStateRunning,
322 CreatedAt: time.Unix(0, createdAt),
323 StartedAt: time.Unix(0, startedAt),
324 Resources: &kubecontainer.ContainerResources{
325 CPULimit: resource.NewMilliQuantity(500, resource.DecimalSI),
326 },
327 },
328 },
329 "container reporting memory only": {
330 input: &runtimeapi.ContainerStatus{
331 Id: cid.ID,
332 Metadata: meta,
333 Image: imageSpec,
334 State: runtimeapi.ContainerState_CONTAINER_RUNNING,
335 CreatedAt: createdAt,
336 StartedAt: startedAt,
337 Resources: &runtimeapi.ContainerResources{
338 Linux: &runtimeapi.LinuxContainerResources{
339 MemoryLimitInBytes: 524288000,
340 OomScoreAdj: -998,
341 },
342 Windows: &runtimeapi.WindowsContainerResources{
343 MemoryLimitInBytes: 524288000,
344 },
345 },
346 },
347 expected: &kubecontainer.Status{
348 ID: *cid,
349 Image: imageSpec.Image,
350 State: kubecontainer.ContainerStateRunning,
351 CreatedAt: time.Unix(0, createdAt),
352 StartedAt: time.Unix(0, startedAt),
353 Resources: &kubecontainer.ContainerResources{
354 MemoryLimit: resource.NewQuantity(524288000, resource.BinarySI),
355 },
356 },
357 },
358 } {
359 t.Run(desc, func(t *testing.T) {
360 actual := toKubeContainerStatus(test.input, cid.Type)
361 assert.Equal(t, test.expected, actual, desc)
362 })
363 }
364 }
365
366 func testLifeCycleHook(t *testing.T, testPod *v1.Pod, testContainer *v1.Container) {
367
368
369 fakeRuntime, _, m, _ := createTestRuntimeManager()
370
371 gracePeriod := int64(30)
372 cID := kubecontainer.ContainerID{
373 Type: "docker",
374 ID: "foo",
375 }
376
377 cmdPostStart := &v1.Lifecycle{
378 PostStart: &v1.LifecycleHandler{
379 Exec: &v1.ExecAction{
380 Command: []string{"PostStartCMD"},
381 },
382 },
383 }
384
385 httpLifeCycle := &v1.Lifecycle{
386 PreStop: &v1.LifecycleHandler{
387 HTTPGet: &v1.HTTPGetAction{
388 Host: "testHost.com",
389 Path: "/GracefulExit",
390 },
391 },
392 }
393
394 cmdLifeCycle := &v1.Lifecycle{
395 PreStop: &v1.LifecycleHandler{
396 Exec: &v1.ExecAction{
397 Command: []string{"PreStopCMD"},
398 },
399 },
400 }
401
402 fakeRunner := &containertest.FakeContainerCommandRunner{}
403 fakeHTTP := &fakeHTTP{}
404 fakePodStatusProvider := podStatusProviderFunc(func(uid types.UID, name, namespace string) (*kubecontainer.PodStatus, error) {
405 return &kubecontainer.PodStatus{
406 ID: uid,
407 Name: name,
408 Namespace: namespace,
409 IPs: []string{
410 "127.0.0.1",
411 },
412 }, nil
413 })
414
415 lcHanlder := lifecycle.NewHandlerRunner(
416 fakeHTTP,
417 fakeRunner,
418 fakePodStatusProvider,
419 nil)
420
421 m.runner = lcHanlder
422
423
424 t.Run("PreStop-CMDExec", func(t *testing.T) {
425 ctx := context.Background()
426 testContainer.Lifecycle = cmdLifeCycle
427 _ = m.killContainer(ctx, testPod, cID, "foo", "testKill", "", &gracePeriod, nil)
428 if fakeRunner.Cmd[0] != cmdLifeCycle.PreStop.Exec.Command[0] {
429 t.Errorf("CMD Prestop hook was not invoked")
430 }
431 })
432
433
434 t.Run("PreStop-HTTPGet", func(t *testing.T) {
435 t.Run("consistent", func(t *testing.T) {
436 ctx := context.Background()
437 defer func() { fakeHTTP.req = nil }()
438 httpLifeCycle.PreStop.HTTPGet.Port = intstr.FromInt32(80)
439 testContainer.Lifecycle = httpLifeCycle
440 _ = m.killContainer(ctx, testPod, cID, "foo", "testKill", "", &gracePeriod, nil)
441 if fakeHTTP.req == nil || !strings.Contains(fakeHTTP.req.URL.String(), httpLifeCycle.PreStop.HTTPGet.Host) {
442 t.Errorf("HTTP Prestop hook was not invoked")
443 }
444 })
445 })
446
447
448 t.Run("PreStop-NoTimeToRun", func(t *testing.T) {
449 ctx := context.Background()
450 gracePeriodLocal := int64(0)
451
452 testPod.DeletionGracePeriodSeconds = &gracePeriodLocal
453 testPod.Spec.TerminationGracePeriodSeconds = &gracePeriodLocal
454
455 _ = m.killContainer(ctx, testPod, cID, "foo", "testKill", "", &gracePeriodLocal, nil)
456 if fakeHTTP.req != nil {
457 t.Errorf("HTTP Prestop hook Should not execute when gracePeriod is 0")
458 }
459 })
460
461
462 t.Run("PostStart-CmdExe", func(t *testing.T) {
463 ctx := context.Background()
464
465 fakeSandBox, _ := makeAndSetFakePod(t, m, fakeRuntime, testPod)
466 fakeSandBoxConfig, _ := m.generatePodSandboxConfig(testPod, 0)
467 testContainer.Lifecycle = cmdPostStart
468 fakePodStatus := &kubecontainer.PodStatus{
469 ContainerStatuses: []*kubecontainer.Status{
470 {
471 ID: kubecontainer.ContainerID{
472 Type: "docker",
473 ID: testContainer.Name,
474 },
475 Name: testContainer.Name,
476 State: kubecontainer.ContainerStateCreated,
477 CreatedAt: time.Unix(0, time.Now().Unix()),
478 },
479 },
480 }
481
482
483 _, err := m.startContainer(ctx, fakeSandBox.Id, fakeSandBoxConfig, containerStartSpec(testContainer), testPod, fakePodStatus, nil, "", []string{})
484 if err != nil {
485 t.Errorf("startContainer error =%v", err)
486 }
487 if fakeRunner.Cmd[0] != cmdPostStart.PostStart.Exec.Command[0] {
488 t.Errorf("CMD PostStart hook was not invoked")
489 }
490 })
491 }
492
493 func TestLifeCycleHook(t *testing.T) {
494 testPod := &v1.Pod{
495 ObjectMeta: metav1.ObjectMeta{
496 Name: "bar",
497 Namespace: "default",
498 },
499 Spec: v1.PodSpec{
500 Containers: []v1.Container{
501 {
502 Name: "foo",
503 Image: "busybox",
504 ImagePullPolicy: v1.PullIfNotPresent,
505 Command: []string{"testCommand"},
506 WorkingDir: "testWorkingDir",
507 },
508 },
509 },
510 }
511
512 testLifeCycleHook(t, testPod, &testPod.Spec.Containers[0])
513 }
514
515 func TestLifeCycleHookForRestartableInitContainer(t *testing.T) {
516 testPod := &v1.Pod{
517 ObjectMeta: metav1.ObjectMeta{
518 Name: "bar",
519 Namespace: "default",
520 },
521 Spec: v1.PodSpec{
522 InitContainers: []v1.Container{
523 {
524 Name: "foo",
525 Image: "busybox",
526 ImagePullPolicy: v1.PullIfNotPresent,
527 Command: []string{"testCommand"},
528 WorkingDir: "testWorkingDir",
529 RestartPolicy: &containerRestartPolicyAlways,
530 },
531 },
532 },
533 }
534
535 testLifeCycleHook(t, testPod, &testPod.Spec.InitContainers[0])
536 }
537
538 func TestStartSpec(t *testing.T) {
539 podStatus := &kubecontainer.PodStatus{
540 ContainerStatuses: []*kubecontainer.Status{
541 {
542 ID: kubecontainer.ContainerID{
543 Type: "docker",
544 ID: "docker-something-something",
545 },
546 Name: "target",
547 },
548 },
549 }
550
551 for _, tc := range []struct {
552 name string
553 spec *startSpec
554 want *kubecontainer.ContainerID
555 }{
556 {
557 "Regular Container",
558 containerStartSpec(&v1.Container{
559 Name: "test",
560 }),
561 nil,
562 },
563 {
564 "Ephemeral Container w/o Target",
565 ephemeralContainerStartSpec(&v1.EphemeralContainer{
566 EphemeralContainerCommon: v1.EphemeralContainerCommon{
567 Name: "test",
568 },
569 }),
570 nil,
571 },
572 {
573 "Ephemeral Container w/ Target",
574 ephemeralContainerStartSpec(&v1.EphemeralContainer{
575 EphemeralContainerCommon: v1.EphemeralContainerCommon{
576 Name: "test",
577 },
578 TargetContainerName: "target",
579 }),
580 &kubecontainer.ContainerID{
581 Type: "docker",
582 ID: "docker-something-something",
583 },
584 },
585 } {
586 t.Run(tc.name, func(t *testing.T) {
587 if got, err := tc.spec.getTargetID(podStatus); err != nil {
588 t.Fatalf("%v: getTargetID got unexpected error: %v", t.Name(), err)
589 } else if diff := cmp.Diff(tc.want, got); diff != "" {
590 t.Errorf("%v: getTargetID got unexpected result. diff:\n%v", t.Name(), diff)
591 }
592 })
593 }
594 }
595
596 func TestRestartCountByLogDir(t *testing.T) {
597 for _, tc := range []struct {
598 filenames []string
599 restartCount int
600 }{
601 {
602 filenames: []string{"0.log.rotated-log"},
603 restartCount: 1,
604 },
605 {
606 filenames: []string{"0.log"},
607 restartCount: 1,
608 },
609 {
610 filenames: []string{"0.log", "1.log", "2.log"},
611 restartCount: 3,
612 },
613 {
614 filenames: []string{"0.log.rotated", "1.log", "2.log"},
615 restartCount: 3,
616 },
617 {
618 filenames: []string{"5.log.rotated", "6.log.rotated"},
619 restartCount: 7,
620 },
621 {
622 filenames: []string{"5.log.rotated", "6.log", "7.log"},
623 restartCount: 8,
624 },
625
626 {
627 filenames: []string{},
628 restartCount: 0,
629 },
630 {
631 filenames: []string{"a.log.rotated", "b.log.rotated", "12log.rotated"},
632 restartCount: 0,
633 },
634
635 {
636 filenames: []string{"145.log.log.rotated"},
637 restartCount: 146,
638 },
639
640 {
641 filenames: []string{"92233720368547758089223372036854775808.log.rotated"},
642 restartCount: 0,
643 },
644
645 {
646 filenames: []string{"9223372036854775808.log.rotated", "23.log", "23a.log", "1aaa.log.rotated", "2.log", "3.log.rotated"},
647 restartCount: 24,
648 },
649
650 {
651 filenames: []string{"rotated.23.log"},
652 restartCount: 0,
653 },
654 {
655 filenames: []string{"mylog42.log"},
656 restartCount: 0,
657 },
658 {
659 filenames: []string{"-42.log"},
660 restartCount: 0,
661 },
662
663 {
664 filenames: []string{"6.log", "6.log.rotated", "6.log.rotated.rotated"},
665 restartCount: 7,
666 },
667 } {
668 tempDirPath, err := os.MkdirTemp("", "test-restart-count-")
669 assert.NoError(t, err, "create tempdir error")
670 defer os.RemoveAll(tempDirPath)
671 for _, filename := range tc.filenames {
672 err = os.WriteFile(filepath.Join(tempDirPath, filename), []byte("a log line"), 0600)
673 assert.NoError(t, err, "could not write log file")
674 }
675 count, err := calcRestartCountByLogDir(tempDirPath)
676 if assert.NoError(t, err) {
677 assert.Equal(t, count, tc.restartCount, "count %v should equal restartCount %v", count, tc.restartCount)
678 }
679 }
680 }
681
682 func TestKillContainerGracePeriod(t *testing.T) {
683
684 shortGracePeriod := int64(10)
685 mediumGracePeriod := int64(30)
686 longGracePeriod := int64(60)
687
688 tests := []struct {
689 name string
690 pod *v1.Pod
691 reason containerKillReason
692 expectedGracePeriod int64
693 }{
694 {
695 name: "default termination grace period",
696 pod: &v1.Pod{
697 Spec: v1.PodSpec{Containers: []v1.Container{{Name: "foo"}}},
698 },
699 reason: reasonUnknown,
700 expectedGracePeriod: int64(2),
701 },
702 {
703 name: "use pod termination grace period",
704 pod: &v1.Pod{
705 Spec: v1.PodSpec{
706 Containers: []v1.Container{{Name: "foo"}},
707 TerminationGracePeriodSeconds: &longGracePeriod,
708 },
709 },
710 reason: reasonUnknown,
711 expectedGracePeriod: longGracePeriod,
712 },
713 {
714 name: "liveness probe overrides pod termination grace period",
715 pod: &v1.Pod{
716 Spec: v1.PodSpec{
717 Containers: []v1.Container{{
718 Name: "foo", LivenessProbe: &v1.Probe{TerminationGracePeriodSeconds: &shortGracePeriod},
719 }},
720 TerminationGracePeriodSeconds: &longGracePeriod,
721 },
722 },
723 reason: reasonLivenessProbe,
724 expectedGracePeriod: shortGracePeriod,
725 },
726 {
727 name: "startup probe overrides pod termination grace period",
728 pod: &v1.Pod{
729 Spec: v1.PodSpec{
730 Containers: []v1.Container{{
731 Name: "foo", StartupProbe: &v1.Probe{TerminationGracePeriodSeconds: &shortGracePeriod},
732 }},
733 TerminationGracePeriodSeconds: &longGracePeriod,
734 },
735 },
736 reason: reasonStartupProbe,
737 expectedGracePeriod: shortGracePeriod,
738 },
739 {
740 name: "startup probe overrides pod termination grace period, probe period > pod period",
741 pod: &v1.Pod{
742 Spec: v1.PodSpec{
743 Containers: []v1.Container{{
744 Name: "foo", StartupProbe: &v1.Probe{TerminationGracePeriodSeconds: &longGracePeriod},
745 }},
746 TerminationGracePeriodSeconds: &shortGracePeriod,
747 },
748 },
749 reason: reasonStartupProbe,
750 expectedGracePeriod: longGracePeriod,
751 },
752 {
753 name: "liveness probe overrides pod termination grace period, probe period > pod period",
754 pod: &v1.Pod{
755 Spec: v1.PodSpec{
756 Containers: []v1.Container{{
757 Name: "foo", LivenessProbe: &v1.Probe{TerminationGracePeriodSeconds: &longGracePeriod},
758 }},
759 TerminationGracePeriodSeconds: &shortGracePeriod,
760 },
761 },
762 reason: reasonLivenessProbe,
763 expectedGracePeriod: longGracePeriod,
764 },
765 {
766 name: "non-liveness probe failure, use pod termination grace period",
767 pod: &v1.Pod{
768 Spec: v1.PodSpec{
769 Containers: []v1.Container{{
770 Name: "foo", LivenessProbe: &v1.Probe{TerminationGracePeriodSeconds: &shortGracePeriod},
771 }},
772 TerminationGracePeriodSeconds: &longGracePeriod,
773 },
774 },
775 reason: reasonUnknown,
776 expectedGracePeriod: longGracePeriod,
777 },
778 {
779 name: "non-startup probe failure, use pod termination grace period",
780 pod: &v1.Pod{
781 Spec: v1.PodSpec{
782 Containers: []v1.Container{{
783 Name: "foo", StartupProbe: &v1.Probe{TerminationGracePeriodSeconds: &shortGracePeriod},
784 }},
785 TerminationGracePeriodSeconds: &longGracePeriod,
786 },
787 },
788 reason: reasonUnknown,
789 expectedGracePeriod: longGracePeriod,
790 },
791 {
792 name: "all three grace periods set, use pod termination grace period",
793 pod: &v1.Pod{
794 Spec: v1.PodSpec{
795 Containers: []v1.Container{{
796 Name: "foo",
797 StartupProbe: &v1.Probe{TerminationGracePeriodSeconds: &shortGracePeriod},
798 LivenessProbe: &v1.Probe{TerminationGracePeriodSeconds: &mediumGracePeriod},
799 }},
800 TerminationGracePeriodSeconds: &longGracePeriod,
801 },
802 },
803 reason: reasonUnknown,
804 expectedGracePeriod: longGracePeriod,
805 },
806 {
807 name: "all three grace periods set, use startup termination grace period",
808 pod: &v1.Pod{
809 Spec: v1.PodSpec{
810 Containers: []v1.Container{{
811 Name: "foo",
812 StartupProbe: &v1.Probe{TerminationGracePeriodSeconds: &shortGracePeriod},
813 LivenessProbe: &v1.Probe{TerminationGracePeriodSeconds: &mediumGracePeriod},
814 }},
815 TerminationGracePeriodSeconds: &longGracePeriod,
816 },
817 },
818 reason: reasonStartupProbe,
819 expectedGracePeriod: shortGracePeriod,
820 },
821 {
822 name: "all three grace periods set, use liveness termination grace period",
823 pod: &v1.Pod{
824 Spec: v1.PodSpec{
825 Containers: []v1.Container{{
826 Name: "foo",
827 StartupProbe: &v1.Probe{TerminationGracePeriodSeconds: &shortGracePeriod},
828 LivenessProbe: &v1.Probe{TerminationGracePeriodSeconds: &mediumGracePeriod},
829 }},
830 TerminationGracePeriodSeconds: &longGracePeriod,
831 },
832 },
833 reason: reasonLivenessProbe,
834 expectedGracePeriod: mediumGracePeriod,
835 },
836 }
837
838 for _, test := range tests {
839 t.Run(test.name, func(t *testing.T) {
840 actualGracePeriod := setTerminationGracePeriod(test.pod, &test.pod.Spec.Containers[0], "", kubecontainer.ContainerID{}, test.reason)
841 require.Equal(t, test.expectedGracePeriod, actualGracePeriod)
842 })
843 }
844 }
845
846
847 func TestUpdateContainerResources(t *testing.T) {
848 fakeRuntime, _, m, errCreate := createTestRuntimeManager()
849 require.NoError(t, errCreate)
850 pod := &v1.Pod{
851 ObjectMeta: metav1.ObjectMeta{
852 UID: "12345678",
853 Name: "bar",
854 Namespace: "new",
855 },
856 Spec: v1.PodSpec{
857 Containers: []v1.Container{
858 {
859 Name: "foo",
860 Image: "busybox",
861 ImagePullPolicy: v1.PullIfNotPresent,
862 },
863 },
864 },
865 }
866
867
868 _, fakeContainers := makeAndSetFakePod(t, m, fakeRuntime, pod)
869 assert.Equal(t, len(fakeContainers), 1)
870
871 ctx := context.Background()
872 cStatus, err := m.getPodContainerStatuses(ctx, pod.UID, pod.Name, pod.Namespace)
873 assert.NoError(t, err)
874 containerID := cStatus[0].ID
875
876 err = m.updateContainerResources(pod, &pod.Spec.Containers[0], containerID)
877 assert.NoError(t, err)
878
879
880 assert.Contains(t, fakeRuntime.Called, "UpdateContainerResources")
881 }
882
View as plain text