From 18f9a084635f9c0625c3b78a23a40c85c86b819d Mon Sep 17 00:00:00 2001 From: Matthias Bertschy Date: Tue, 13 Feb 2024 09:18:39 +0100 Subject: [PATCH] add coverage tests for probes behavior Signed-off-by: Matthias Bertschy --- test/e2e_node/container_lifecycle_test.go | 159 ++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/test/e2e_node/container_lifecycle_test.go b/test/e2e_node/container_lifecycle_test.go index 660735efd07..496b475ccbe 100644 --- a/test/e2e_node/container_lifecycle_test.go +++ b/test/e2e_node/container_lifecycle_test.go @@ -32,11 +32,15 @@ import ( e2epod "k8s.io/kubernetes/test/e2e/framework/pod" "k8s.io/kubernetes/test/e2e/nodefeature" imageutils "k8s.io/kubernetes/test/utils/image" + "k8s.io/utils/ptr" ) const ( + LivenessPrefix = "Liveness" PostStartPrefix = "PostStart" PreStopPrefix = "PreStop" + ReadinessPrefix = "Readiness" + StartupPrefix = "Startup" ) var containerRestartPolicyAlways = v1.ContainerRestartPolicyAlways @@ -746,6 +750,161 @@ var _ = SIGDescribe(framework.WithNodeConformance(), "Containers Lifecycle", fun framework.ExpectNoError(results.Starts(prefixedName(PreStopPrefix, regular1))) framework.ExpectNoError(results.Exits(regular1)) }) + + ginkgo.When("a pod is terminating because its liveness probe fails", func() { + regular1 := "regular-1" + + testPod := func() *v1.Pod { + return &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + }, + Spec: v1.PodSpec{ + RestartPolicy: v1.RestartPolicyNever, + TerminationGracePeriodSeconds: ptr.To(int64(100)), + Containers: []v1.Container{ + { + Name: regular1, + Image: imageutils.GetE2EImage(imageutils.BusyBox), + Command: ExecCommand(regular1, execCommand{ + Delay: 100, + TerminationSeconds: 15, + ExitCode: 0, + }), + LivenessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + Exec: &v1.ExecAction{ + Command: ExecCommand(prefixedName(LivenessPrefix, regular1), execCommand{ + ExitCode: 1, + ContainerName: regular1, + }), + }, + }, + InitialDelaySeconds: 10, + PeriodSeconds: 1, + FailureThreshold: 1, + }, + }, + }, + }, + } + } + + f.It("should execute readiness probe while in preStop, but not liveness", f.WithNodeConformance(), func() { + client := e2epod.NewPodClient(f) + podSpec := testPod() + + ginkgo.By("creating a pod with a readiness probe and a preStop hook") + podSpec.Spec.Containers[0].Lifecycle = &v1.Lifecycle{ + PreStop: &v1.LifecycleHandler{ + Exec: &v1.ExecAction{ + Command: ExecCommand(prefixedName(PreStopPrefix, regular1), execCommand{ + Delay: 1, + ExitCode: 0, + ContainerName: regular1, + }), + }, + }, + } + podSpec.Spec.Containers[0].ReadinessProbe = &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + Exec: &v1.ExecAction{ + Command: ExecCommand(prefixedName(ReadinessPrefix, regular1), execCommand{ + ExitCode: 0, + ContainerName: regular1, + }), + }, + }, + InitialDelaySeconds: 1, + PeriodSeconds: 1, + } + + preparePod(podSpec) + + podSpec = client.Create(context.TODO(), podSpec) + + ginkgo.By("Waiting for the pod to complete") + err := e2epod.WaitForPodNoLongerRunningInNamespace(context.TODO(), f.ClientSet, podSpec.Name, podSpec.Namespace) + framework.ExpectNoError(err) + + ginkgo.By("Parsing results") + podSpec, err = client.Get(context.TODO(), podSpec.Name, metav1.GetOptions{}) + framework.ExpectNoError(err) + results := parseOutput(context.TODO(), f, podSpec) + + ginkgo.By("Analyzing results") + // readiness probes are called during pod termination + framework.ExpectNoError(results.RunTogether(prefixedName(PreStopPrefix, regular1), prefixedName(ReadinessPrefix, regular1))) + // liveness probes are not called during pod termination + err = results.RunTogether(prefixedName(PreStopPrefix, regular1), prefixedName(LivenessPrefix, regular1)) + gomega.Expect(err).To(gomega.HaveOccurred()) + }) + + f.It("should continue running liveness probes for restartable init containers and restart them while in preStop", f.WithNodeConformance(), func() { + client := e2epod.NewPodClient(f) + podSpec := testPod() + restartableInit1 := "restartable-init-1" + + ginkgo.By("creating a pod with a restartable init container and a preStop hook") + podSpec.Spec.InitContainers = []v1.Container{{ + RestartPolicy: &containerRestartPolicyAlways, + Name: restartableInit1, + Image: imageutils.GetE2EImage(imageutils.BusyBox), + Command: ExecCommand(restartableInit1, execCommand{ + Delay: 100, + TerminationSeconds: 1, + ExitCode: 0, + }), + LivenessProbe: &v1.Probe{ + ProbeHandler: v1.ProbeHandler{ + Exec: &v1.ExecAction{ + Command: ExecCommand(prefixedName(LivenessPrefix, restartableInit1), execCommand{ + ExitCode: 1, + ContainerName: restartableInit1, + }), + }, + }, + InitialDelaySeconds: 1, + PeriodSeconds: 1, + FailureThreshold: 1, + }, + }} + podSpec.Spec.Containers[0].Lifecycle = &v1.Lifecycle{ + PreStop: &v1.LifecycleHandler{ + Exec: &v1.ExecAction{ + Command: ExecCommand(prefixedName(PreStopPrefix, regular1), execCommand{ + Delay: 40, + ExitCode: 0, + ContainerName: regular1, + }), + }, + }, + } + + preparePod(podSpec) + + podSpec = client.Create(context.TODO(), podSpec) + + ginkgo.By("Waiting for the pod to complete") + err := e2epod.WaitForPodNoLongerRunningInNamespace(context.TODO(), f.ClientSet, podSpec.Name, podSpec.Namespace) + framework.ExpectNoError(err) + + ginkgo.By("Parsing results") + podSpec, err = client.Get(context.TODO(), podSpec.Name, metav1.GetOptions{}) + framework.ExpectNoError(err) + results := parseOutput(context.TODO(), f, podSpec) + + ginkgo.By("Analyzing results") + // FIXME ExpectNoError: this will be implemented in KEP 4438 + // liveness probes are called for restartable init containers during pod termination + err = results.RunTogether(prefixedName(PreStopPrefix, regular1), prefixedName(LivenessPrefix, restartableInit1)) + gomega.Expect(err).To(gomega.HaveOccurred()) + // FIXME ExpectNoError: this will be implemented in KEP 4438 + // restartable init containers are restarted during pod termination + err = results.RunTogether(prefixedName(PreStopPrefix, regular1), restartableInit1) + gomega.Expect(err).To(gomega.HaveOccurred()) + }) + }) }) var _ = SIGDescribe(framework.WithSerial(), "Containers Lifecycle", func() {