From 72b91dbd56b0a5f458fee0e85137d9757837e290 Mon Sep 17 00:00:00 2001 From: pontiyaraja <1989030+pontiyaraja@users.noreply.github.com> Date: Thu, 17 Jan 2019 14:51:37 +0530 Subject: [PATCH] graceful pod termination with preStop container lifecycle hook --- test/e2e/node/BUILD | 1 + test/e2e/node/pre_stop.go | 73 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/test/e2e/node/BUILD b/test/e2e/node/BUILD index c841fea21d..6053a44869 100644 --- a/test/e2e/node/BUILD +++ b/test/e2e/node/BUILD @@ -24,6 +24,7 @@ go_library( "//pkg/kubelet/apis/stats/v1alpha1:go_default_library", "//pkg/kubelet/events:go_default_library", "//pkg/kubelet/runtimeclass/testing:go_default_library", + "//pkg/master/ports:go_default_library", "//pkg/util/slice:go_default_library", "//staging/src/k8s.io/api/batch/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", diff --git a/test/e2e/node/pre_stop.go b/test/e2e/node/pre_stop.go index 1affa9d919..398cb9b0bb 100644 --- a/test/e2e/node/pre_stop.go +++ b/test/e2e/node/pre_stop.go @@ -24,12 +24,15 @@ import ( "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/wait" clientset "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/test/e2e/framework" imageutils "k8s.io/kubernetes/test/utils/image" . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" ) // partially cloned from webserver.go @@ -160,6 +163,10 @@ func testPreStop(c clientset.Interface, ns string) { var _ = SIGDescribe("PreStop", func() { f := framework.NewDefaultFramework("prestop") + var podClient *framework.PodClient + BeforeEach(func() { + podClient = f.PodClient() + }) /* Release : v1.9 @@ -169,4 +176,70 @@ var _ = SIGDescribe("PreStop", func() { framework.ConformanceIt("should call prestop when killing a pod ", func() { testPreStop(f.ClientSet, f.Namespace.Name) }) + + It("graceful pod terminated should wait until preStop hook completes the process", func() { + gracefulTerminationPeriodSeconds := int64(30) + By("creating the pod") + name := "pod-prestop-hook-" + string(uuid.NewUUID()) + pod := getPodWithpreStopLifeCycle(name) + + By("submitting the pod to kubernetes") + podClient.Create(pod) + + By("waiting for pod running") + framework.ExpectNoError(f.WaitForPodRunning(pod.Name)) + + var err error + pod, err = podClient.Get(pod.Name, metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred(), "failed to GET scheduled pod") + + By("deleting the pod gracefully") + err = podClient.Delete(pod.Name, metav1.NewDeleteOptions(gracefulTerminationPeriodSeconds)) + Expect(err).NotTo(HaveOccurred(), "failed to delete pod") + + //wait up to graceful termination period seconds + time.Sleep(30 * time.Second) + + By("verifying the pod running state after graceful termination") + result := &v1.PodList{} + err = wait.Poll(time.Second*5, time.Second*60, func() (bool, error) { + client, err := framework.NodeProxyRequest(f.ClientSet, pod.Spec.NodeName, "pods", ports.KubeletPort) + Expect(err).NotTo(HaveOccurred(), "failed to get the pods of the node") + err = client.Into(result) + Expect(err).NotTo(HaveOccurred(), "failed to parse the pods of the node") + + for _, kubeletPod := range result.Items { + if pod.Name != kubeletPod.Name { + continue + } else if kubeletPod.Status.Phase == v1.PodRunning { + framework.Logf("pod is running") + return true, err + } + } + return false, err + }) + }) }) + +func getPodWithpreStopLifeCycle(name string) *v1.Pod { + return &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "nginx", + Image: imageutils.GetE2EImage(imageutils.Nginx), + Lifecycle: &v1.Lifecycle{ + PreStop: &v1.Handler{ + Exec: &v1.ExecAction{ + Command: []string{"sh", "-c", "while true; do echo preStop; sleep 1; done"}, + }, + }, + }, + }, + }, + }, + } +}