mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 23:37:01 +00:00
Add more Node E2E tests to cover pod termination for Sidecar Containers
* A pod with restartable init container that exits with a non-zero code is marked as a pod succeeded phase * A pod with restartable init containers that exits with a non-zero code by prestop hook is marked as a pod succeeded phase * A pod with regular container that exceeds its termination grace period seconds is marked as a pod failed phase * A pod with restartable init containers that exceeds its termination grace period seconds is marked as a pod succeeded phase * A pod with a regular container that exceeded its termination grace period seconds by PreStop hook is marked as a pod failed phase * A pod with restartable init containers that exceeds its termination grace period seconds by PreStop hook is marked as a pod succeeded phase Signed-off-by: Tsubasa Nagasawa <toversus2357@gmail.com>
This commit is contained in:
parent
bd00f83578
commit
82b690ddf6
@ -3651,6 +3651,654 @@ var _ = SIGDescribe(nodefeature.SidecarContainers, "Containers Lifecycle", func(
|
||||
framework.ExpectNoError(err, "the pod should be deleted before its terminationGracePeriodSeconds if the restartalbe init containers get termination signal correctly")
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.When("The restartable init containers exit with non-zero exit code", func() {
|
||||
ginkgo.It("should mark pod as succeeded if any of the restartable init containers have terminated with non-zero exit code", func(ctx context.Context) {
|
||||
restartableInit1 := "restartable-init-1"
|
||||
restartableInit2 := "restartable-init-2"
|
||||
restartableInit3 := "restartable-init-3"
|
||||
regular1 := "regular-1"
|
||||
|
||||
podTerminationGracePeriodSeconds := int64(30)
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "restartable-init-terminated-with-non-zero-exit-code",
|
||||
Finalizers: []string{testFinalizer},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
TerminationGracePeriodSeconds: ptr.To(podTerminationGracePeriodSeconds),
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: restartableInit1,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: restartableInit2,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit2, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 1,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: restartableInit3,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit3, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: regular1,
|
||||
Image: busyboxImage,
|
||||
Command: ExecCommand(regular1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
preparePod(pod)
|
||||
|
||||
ginkgo.By("Creating the pod with finalizer")
|
||||
client := e2epod.NewPodClient(f)
|
||||
pod = client.Create(ctx, pod)
|
||||
defer client.RemoveFinalizer(ctx, pod.Name, testFinalizer)
|
||||
|
||||
ginkgo.By("Waiting for the pod to be initialized and run")
|
||||
err := e2epod.WaitForPodRunningInNamespace(ctx, f.ClientSet, pod)
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By("Deleting the pod")
|
||||
err = client.Delete(ctx, pod.Name, metav1.DeleteOptions{GracePeriodSeconds: &podTerminationGracePeriodSeconds})
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Waiting for the pod (%s/%s) to be transitioned into the Succeeded phase", pod.Namespace, pod.Name))
|
||||
err = e2epod.WaitForPodSuccessInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name)
|
||||
framework.ExpectNoError(err, "Failed to await for the pod to be terminated: %q", pod.Name)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Fetch the end state of the pod (%s/%s)", pod.Namespace, pod.Name))
|
||||
pod, err = client.Get(ctx, pod.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "Failed to fetch the end state of the pod: %q", pod.Name)
|
||||
|
||||
// regular container is gracefully terminated
|
||||
expectPodTerminationContainerStatuses(pod.Status.ContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
regular1: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
|
||||
// restartable-init-2 that terminated with non-zero exit code is marked as error
|
||||
expectPodTerminationContainerStatuses(pod.Status.InitContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
restartableInit1: {exitCode: int32(0), reason: "Completed"},
|
||||
restartableInit2: {exitCode: int32(1), reason: "Error"},
|
||||
restartableInit3: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.When("The restartable init containers exit with non-zero exit code by prestop hook", func() {
|
||||
ginkgo.It("should mark pod as succeeded if any of the restartable init containers have terminated with non-zero exit code by prestop hook", func(ctx context.Context) {
|
||||
restartableInit1 := "restartable-init-1"
|
||||
restartableInit2 := "restartable-init-2"
|
||||
restartableInit3 := "restartable-init-3"
|
||||
regular1 := "regular-1"
|
||||
|
||||
podTerminationGracePeriodSeconds := int64(30)
|
||||
|
||||
makePrestop := func(containerName string, exitCode int) *v1.Lifecycle {
|
||||
return &v1.Lifecycle{
|
||||
PreStop: &v1.LifecycleHandler{
|
||||
Exec: &v1.ExecAction{
|
||||
Command: ExecCommand(containerName, execCommand{
|
||||
Delay: 1,
|
||||
ExitCode: exitCode,
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "restartable-init-terminated-with-non-zero-exit-code",
|
||||
Finalizers: []string{testFinalizer},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
TerminationGracePeriodSeconds: ptr.To(podTerminationGracePeriodSeconds),
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: restartableInit1,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
Lifecycle: makePrestop(restartableInit1, 0),
|
||||
},
|
||||
{
|
||||
Name: restartableInit2,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit2, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
Lifecycle: makePrestop(restartableInit2, 1),
|
||||
},
|
||||
{
|
||||
Name: restartableInit3,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit3, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
Lifecycle: makePrestop(restartableInit3, 0),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: regular1,
|
||||
Image: busyboxImage,
|
||||
Command: ExecCommand(regular1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
preparePod(pod)
|
||||
|
||||
ginkgo.By("Creating the pod with finalizer")
|
||||
client := e2epod.NewPodClient(f)
|
||||
pod = client.Create(ctx, pod)
|
||||
defer client.RemoveFinalizer(ctx, pod.Name, testFinalizer)
|
||||
|
||||
ginkgo.By("Waiting for the pod to be initialized and run")
|
||||
err := e2epod.WaitForPodRunningInNamespace(ctx, f.ClientSet, pod)
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By("Deleting the pod")
|
||||
err = client.Delete(ctx, pod.Name, metav1.DeleteOptions{GracePeriodSeconds: &podTerminationGracePeriodSeconds})
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Waiting for the pod (%s/%s) to be transitioned into the Succeeded phase", pod.Namespace, pod.Name))
|
||||
err = e2epod.WaitForPodSuccessInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name)
|
||||
framework.ExpectNoError(err, "Failed to await for the pod to be terminated: %q", pod.Name)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Fetch the end state of the pod (%s/%s)", pod.Namespace, pod.Name))
|
||||
pod, err = client.Get(ctx, pod.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "Failed to fetch the end state of the pod: %q", pod.Name)
|
||||
|
||||
// regular container is gracefully terminated
|
||||
expectPodTerminationContainerStatuses(pod.Status.ContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
regular1: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
|
||||
// restartable init containers are marked as completed if their prestop hooks are failed
|
||||
expectPodTerminationContainerStatuses(pod.Status.InitContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
restartableInit1: {exitCode: int32(0), reason: "Completed"},
|
||||
restartableInit2: {exitCode: int32(0), reason: "Completed"},
|
||||
restartableInit3: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.When("The regular container has exceeded its termination grace period seconds", func() {
|
||||
ginkgo.It("should mark pod as failed if regular container has exceeded its termination grace period seconds", func(ctx context.Context) {
|
||||
restartableInit1 := "restartable-init-1"
|
||||
restartableInit2 := "restartable-init-2"
|
||||
restartableInit3 := "restartable-init-3"
|
||||
regular1 := "regular-1"
|
||||
|
||||
podTerminationGracePeriodSeconds := int64(5)
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "regular-exceeded-termination-grace-period",
|
||||
Finalizers: []string{testFinalizer},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
TerminationGracePeriodSeconds: ptr.To(podTerminationGracePeriodSeconds),
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: restartableInit1,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 20,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: restartableInit2,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit2, execCommand{
|
||||
Delay: 600,
|
||||
// SIGKILL won't be sent because it only gets triggered 2 seconds after SIGTERM.
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: restartableInit3,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit3, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 20,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: regular1,
|
||||
Image: busyboxImage,
|
||||
Command: ExecCommand(regular1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 20,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
preparePod(pod)
|
||||
|
||||
ginkgo.By("Creating the pod with finalizer")
|
||||
client := e2epod.NewPodClient(f)
|
||||
pod = client.Create(ctx, pod)
|
||||
defer client.RemoveFinalizer(ctx, pod.Name, testFinalizer)
|
||||
|
||||
ginkgo.By("Waiting for the pod to be initialized and run")
|
||||
err := e2epod.WaitForPodRunningInNamespace(ctx, f.ClientSet, pod)
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By("Deleting the pod")
|
||||
err = client.Delete(ctx, pod.Name, metav1.DeleteOptions{GracePeriodSeconds: &podTerminationGracePeriodSeconds})
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Waiting for the pod (%s/%s) to be transitioned into the Failed phase", pod.Namespace, pod.Name))
|
||||
err = e2epod.WaitForPodTerminatedInNamespace(ctx, f.ClientSet, pod.Name, "", f.Namespace.Name)
|
||||
framework.ExpectNoError(err, "Failed to await for the pod to be terminated: %q", pod.Name)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Fetch the end state of the pod (%s/%s)", pod.Namespace, pod.Name))
|
||||
pod, err = client.Get(ctx, pod.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "Failed to fetch the end state of the pod: %q", pod.Name)
|
||||
|
||||
// regular container that exceeds its termination grace period seconds is sigkilled with exit code 137
|
||||
expectPodTerminationContainerStatuses(pod.Status.ContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
regular1: {exitCode: int32(137), reason: "Error"},
|
||||
})
|
||||
|
||||
// restartable-init-2 is gracefully terminated within 2 seconds after receiving SIGTERM.
|
||||
// The other containers that exceed 2 seconds after receiving SIGTERM are sigkilled with exit code 137.
|
||||
expectPodTerminationContainerStatuses(pod.Status.InitContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
restartableInit1: {exitCode: int32(137), reason: "Error"},
|
||||
restartableInit2: {exitCode: int32(0), reason: "Completed"},
|
||||
restartableInit3: {exitCode: int32(137), reason: "Error"},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.When("The restartable init containers have exceeded its termination grace period seconds", func() {
|
||||
ginkgo.It("should mark pod as succeeded if any of the restartable init containers have exceeded its termination grace period seconds", func(ctx context.Context) {
|
||||
restartableInit1 := "restartable-init-1"
|
||||
restartableInit2 := "restartable-init-2"
|
||||
restartableInit3 := "restartable-init-3"
|
||||
regular1 := "regular-1"
|
||||
|
||||
podTerminationGracePeriodSeconds := int64(5)
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "restartable-init-exceeded-termination-grace-period",
|
||||
Finalizers: []string{testFinalizer},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
TerminationGracePeriodSeconds: ptr.To(podTerminationGracePeriodSeconds),
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: restartableInit1,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: restartableInit2,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit2, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 20,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: restartableInit3,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit3, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: regular1,
|
||||
Image: busyboxImage,
|
||||
Command: ExecCommand(regular1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
preparePod(pod)
|
||||
|
||||
ginkgo.By("Creating the pod with finalizer")
|
||||
client := e2epod.NewPodClient(f)
|
||||
pod = client.Create(ctx, pod)
|
||||
defer client.RemoveFinalizer(ctx, pod.Name, testFinalizer)
|
||||
|
||||
ginkgo.By("Waiting for the pod to be initialized and run")
|
||||
err := e2epod.WaitForPodRunningInNamespace(ctx, f.ClientSet, pod)
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By("Deleting the pod")
|
||||
err = client.Delete(ctx, pod.Name, metav1.DeleteOptions{GracePeriodSeconds: &podTerminationGracePeriodSeconds})
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Waiting for the pod (%s/%s) to be transitioned into the Succeeded phase", pod.Namespace, pod.Name))
|
||||
err = e2epod.WaitForPodSuccessInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name)
|
||||
framework.ExpectNoError(err, "Failed to await for the pod to be terminated: %q", pod.Name)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Fetch the end state of the pod (%s/%s)", pod.Namespace, pod.Name))
|
||||
pod, err = client.Get(ctx, pod.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "Failed to fetch the end state of the pod: %q", pod.Name)
|
||||
|
||||
// regular container is gracefully terminated
|
||||
expectPodTerminationContainerStatuses(pod.Status.ContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
regular1: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
|
||||
// restartable-init-2 that exceeds its termination grace period seconds is sigkilled with exit code 137.
|
||||
// The other containers are gracefully terminated within 2 seconds after receiving SIGTERM
|
||||
expectPodTerminationContainerStatuses(pod.Status.InitContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
restartableInit1: {exitCode: int32(0), reason: "Completed"},
|
||||
restartableInit2: {exitCode: int32(137), reason: "Error"},
|
||||
restartableInit3: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.When("The regular containers have exceeded its termination grace period seconds by prestop hook", func() {
|
||||
ginkgo.It("should mark pod as failed if any of the prestop hook in regular container has exceeded its termination grace period seconds", func(ctx context.Context) {
|
||||
restartableInit1 := "restartable-init-1"
|
||||
restartableInit2 := "restartable-init-2"
|
||||
restartableInit3 := "restartable-init-3"
|
||||
regular1 := "regular-1"
|
||||
|
||||
podTerminationGracePeriodSeconds := int64(5)
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "regular-prestop-exceeded-termination-grace-period",
|
||||
Finalizers: []string{testFinalizer},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
TerminationGracePeriodSeconds: ptr.To(podTerminationGracePeriodSeconds),
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: restartableInit1,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: restartableInit2,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit2, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 20,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: restartableInit3,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit3, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: regular1,
|
||||
Image: busyboxImage,
|
||||
Command: ExecCommand(regular1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 20,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
Lifecycle: &v1.Lifecycle{
|
||||
PreStop: &v1.LifecycleHandler{
|
||||
Exec: &v1.ExecAction{
|
||||
Command: ExecCommand(regular1, execCommand{
|
||||
Delay: 20,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
preparePod(pod)
|
||||
|
||||
ginkgo.By("Creating the pod with finalizer")
|
||||
client := e2epod.NewPodClient(f)
|
||||
pod = client.Create(ctx, pod)
|
||||
defer client.RemoveFinalizer(ctx, pod.Name, testFinalizer)
|
||||
|
||||
ginkgo.By("Waiting for the pod to be initialized and run")
|
||||
err := e2epod.WaitForPodRunningInNamespace(ctx, f.ClientSet, pod)
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By("Deleting the pod")
|
||||
err = client.Delete(ctx, pod.Name, metav1.DeleteOptions{GracePeriodSeconds: &podTerminationGracePeriodSeconds})
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Waiting for the pod (%s/%s) to be transitioned into the Failed phase", pod.Namespace, pod.Name))
|
||||
err = e2epod.WaitForPodTerminatedInNamespace(ctx, f.ClientSet, pod.Name, "", f.Namespace.Name)
|
||||
framework.ExpectNoError(err, "Failed to await for the pod to be terminated: %q", pod.Name)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Fetch the end state of the pod (%s/%s)", pod.Namespace, pod.Name))
|
||||
pod, err = client.Get(ctx, pod.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "Failed to fetch the end state of the pod: %q", pod.Name)
|
||||
|
||||
// regular container that exceeds its termination grace period seconds is sigkilled with exit code 137
|
||||
expectPodTerminationContainerStatuses(pod.Status.ContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
regular1: {exitCode: int32(137), reason: "Error"},
|
||||
})
|
||||
|
||||
// restartable-init-2 that exceed 2 seconds after receiving SIGTERM is sigkilled with exit code 137.
|
||||
// The other containers are gracefully terminated within 2 seconds after receiving SIGTERM
|
||||
expectPodTerminationContainerStatuses(pod.Status.InitContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
restartableInit1: {exitCode: int32(0), reason: "Completed"},
|
||||
restartableInit2: {exitCode: int32(137), reason: "Error"},
|
||||
restartableInit3: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.When("The restartable init containers have exceeded its termination grace period seconds by prestop hook", func() {
|
||||
ginkgo.It("should mark pod as succeeded if any of the prestop hook in restartable init containers have exceeded its termination grace period seconds", func(ctx context.Context) {
|
||||
restartableInit1 := "restartable-init-1"
|
||||
restartableInit2 := "restartable-init-2"
|
||||
restartableInit3 := "restartable-init-3"
|
||||
regular1 := "regular-1"
|
||||
|
||||
podTerminationGracePeriodSeconds := int64(5)
|
||||
|
||||
makePrestop := func(containerName string, delay int) *v1.Lifecycle {
|
||||
return &v1.Lifecycle{
|
||||
PreStop: &v1.LifecycleHandler{
|
||||
Exec: &v1.ExecAction{
|
||||
Command: ExecCommand(containerName, execCommand{
|
||||
Delay: delay,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "restartable-init-prestop-exceeded-termination-grace-period",
|
||||
Finalizers: []string{testFinalizer},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
RestartPolicy: v1.RestartPolicyNever,
|
||||
TerminationGracePeriodSeconds: ptr.To(podTerminationGracePeriodSeconds),
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: restartableInit1,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
Lifecycle: makePrestop(restartableInit1, 1),
|
||||
},
|
||||
{
|
||||
Name: restartableInit2,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit2, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 20,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
Lifecycle: makePrestop(restartableInit1, 30),
|
||||
},
|
||||
{
|
||||
Name: restartableInit3,
|
||||
Image: busyboxImage,
|
||||
RestartPolicy: &containerRestartPolicyAlways,
|
||||
Command: ExecCommand(restartableInit3, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
Lifecycle: makePrestop(restartableInit1, 1),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: regular1,
|
||||
Image: busyboxImage,
|
||||
Command: ExecCommand(regular1, execCommand{
|
||||
Delay: 600,
|
||||
TerminationSeconds: 1,
|
||||
ExitCode: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
preparePod(pod)
|
||||
|
||||
ginkgo.By("Creating the pod with finalizer")
|
||||
client := e2epod.NewPodClient(f)
|
||||
pod = client.Create(ctx, pod)
|
||||
defer client.RemoveFinalizer(ctx, pod.Name, testFinalizer)
|
||||
|
||||
ginkgo.By("Waiting for the pod to be initialized and run")
|
||||
err := e2epod.WaitForPodRunningInNamespace(ctx, f.ClientSet, pod)
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By("Deleting the pod")
|
||||
err = client.Delete(ctx, pod.Name, metav1.DeleteOptions{GracePeriodSeconds: &podTerminationGracePeriodSeconds})
|
||||
framework.ExpectNoError(err)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Waiting for the pod (%s/%s) to be transitioned into the Succeeded phase", pod.Namespace, pod.Name))
|
||||
err = e2epod.WaitForPodSuccessInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name)
|
||||
framework.ExpectNoError(err, "Failed to await for the pod to be terminated: %q", pod.Name)
|
||||
|
||||
ginkgo.By(fmt.Sprintf("Fetch the end state of the pod (%s/%s)", pod.Namespace, pod.Name))
|
||||
pod, err = client.Get(ctx, pod.Name, metav1.GetOptions{})
|
||||
framework.ExpectNoError(err, "Failed to fetch the end state of the pod: %q", pod.Name)
|
||||
|
||||
// regular container is gracefully terminated
|
||||
expectPodTerminationContainerStatuses(pod.Status.ContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
regular1: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
|
||||
// restartable-init-2 that exceed its termination grace period seconds by prestop hook is sigkilled
|
||||
// with exit code 137.
|
||||
// The other containers are gracefully terminated within their termination grace period seconds
|
||||
expectPodTerminationContainerStatuses(pod.Status.InitContainerStatuses, map[string]podTerminationContainerStatus{
|
||||
restartableInit1: {exitCode: int32(0), reason: "Completed"},
|
||||
restartableInit2: {exitCode: int32(137), reason: "Error"},
|
||||
restartableInit3: {exitCode: int32(0), reason: "Completed"},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user