Skip to content

Commit 36f2a99

Browse files
Merge pull request #2363 from haircommander/carry-128642-openshift
OCPBUGS-57666: Adjust durations for PodLifecycleSleepAction e2e tests
2 parents 9c2642e + 47f547e commit 36f2a99

File tree

2 files changed

+112
-36
lines changed

2 files changed

+112
-36
lines changed

openshift-hack/e2e/annotate/generated/zz_generated.annotations.go

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/e2e/common/node/lifecycle_hook.go

Lines changed: 106 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
3333
imageutils "k8s.io/kubernetes/test/utils/image"
3434
admissionapi "k8s.io/pod-security-admission/api"
35+
"k8s.io/utils/ptr"
3536

3637
"github.com/onsi/ginkgo/v2"
3738
"github.com/onsi/gomega"
@@ -551,7 +552,7 @@ func validDuration(duration time.Duration, low, high int64) bool {
551552
return duration >= time.Second*time.Duration(low) && duration <= time.Second*time.Duration(high)
552553
}
553554

554-
var _ = SIGDescribe(feature.PodLifecycleSleepAction, func() {
555+
var _ = SIGDescribe("Lifecycle Sleep Hook", func() {
555556
f := framework.NewDefaultFramework("pod-lifecycle-sleep-action")
556557
f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
557558
var podClient *e2epod.PodClient
@@ -560,73 +561,148 @@ var _ = SIGDescribe(feature.PodLifecycleSleepAction, func() {
560561
ginkgo.BeforeEach(func(ctx context.Context) {
561562
podClient = e2epod.NewPodClient(f)
562563
})
564+
565+
var finalizer = "test/finalizer"
566+
/*
567+
Release : v1.34
568+
Testname: Pod Lifecycle, prestop sleep hook
569+
Description: When a pre-stop handler is specified in the container lifecycle using a 'Sleep' action, then the handler MUST be invoked before the container is terminated. A test pod will be created to verify if its termination time aligns with the sleep time specified when it is terminated.
570+
*/
563571
ginkgo.It("valid prestop hook using sleep action", func(ctx context.Context) {
572+
const sleepSeconds = 50
573+
const gracePeriod = 100
564574
lifecycle := &v1.Lifecycle{
565575
PreStop: &v1.LifecycleHandler{
566-
Sleep: &v1.SleepAction{Seconds: 5},
576+
Sleep: &v1.SleepAction{Seconds: sleepSeconds},
567577
},
568578
}
569-
podWithHook := getPodWithHook("pod-with-prestop-sleep-hook", imageutils.GetPauseImageName(), lifecycle)
579+
name := "pod-with-prestop-sleep-hook"
580+
podWithHook := getPodWithHook(name, imageutils.GetPauseImageName(), lifecycle)
581+
podWithHook.Finalizers = append(podWithHook.Finalizers, finalizer)
582+
podWithHook.Spec.TerminationGracePeriodSeconds = ptr.To[int64](gracePeriod)
570583
ginkgo.By("create the pod with lifecycle hook using sleep action")
571-
podClient.CreateSync(ctx, podWithHook)
584+
p := podClient.CreateSync(ctx, podWithHook)
585+
defer podClient.RemoveFinalizer(ctx, name, finalizer)
572586
ginkgo.By("delete the pod with lifecycle hook using sleep action")
573-
start := time.Now()
574-
podClient.DeleteSync(ctx, podWithHook.Name, metav1.DeleteOptions{}, f.Timeouts.PodDelete)
575-
cost := time.Since(start)
576-
// cost should be
577-
// longer than 5 seconds (pod should sleep for 5 seconds)
578-
// shorter than gracePeriodSeconds (default 30 seconds here)
579-
if !validDuration(cost, 5, 30) {
580-
framework.Failf("unexpected delay duration before killing the pod, cost = %v", cost)
587+
_ = podClient.Delete(ctx, podWithHook.Name, metav1.DeleteOptions{})
588+
p, err := podClient.Get(ctx, p.Name, metav1.GetOptions{})
589+
if err != nil {
590+
framework.Failf("failed getting pod after deletion")
591+
}
592+
// deletionTimestamp equals to delete_time + tgps
593+
// TODO: reduce sleep_seconds and tgps after issues.k8s.io/132205 is solved
594+
// we get deletionTimestamp before container become terminated here because of issues.k8s.io/132205
595+
deletionTS := p.DeletionTimestamp.Time
596+
if err := e2epod.WaitForContainerTerminated(ctx, f.ClientSet, p.Namespace, p.Name, name, sleepSeconds*2*time.Second); err != nil {
597+
framework.Failf("failed waiting for container terminated")
598+
}
599+
600+
p, err = podClient.Get(ctx, p.Name, metav1.GetOptions{})
601+
if err != nil {
602+
framework.Failf("failed getting pod after deletion")
603+
}
604+
// finishAt equals to delete_time + sleep_duration
605+
finishAt := p.Status.ContainerStatuses[0].State.Terminated.FinishedAt
606+
607+
// sleep_duration = (delete_time + sleep_duration) - (delete_time + tgps) + tgps
608+
sleepDuration := finishAt.Sub(deletionTS) + time.Second*gracePeriod
609+
610+
// sleep_duration should be
611+
// longer than 50 seconds (pod should sleep for 50 seconds)
612+
// shorter than gracePeriodSeconds (100 seconds here)
613+
if !validDuration(sleepDuration, sleepSeconds, gracePeriod) {
614+
framework.Failf("unexpected delay duration before killing the pod, finishAt = %v, deletionAt= %v", finishAt, deletionTS)
581615
}
582616
})
583617

618+
/*
619+
Release : v1.34
620+
Testname: Pod Lifecycle, prestop sleep hook with low gracePeriodSeconds
621+
Description: When a pre-stop handler is specified in the container lifecycle using a 'Sleep' action, then the handler MUST be invoked before the container is terminated. A test pod will be created, and its `gracePeriodSeconds` will be modified to a value less than the sleep time before termination. The termination time will then be checked to ensure it aligns with the `gracePeriodSeconds` value.
622+
*/
584623
ginkgo.It("reduce GracePeriodSeconds during runtime", func(ctx context.Context) {
624+
const sleepSeconds = 50
585625
lifecycle := &v1.Lifecycle{
586626
PreStop: &v1.LifecycleHandler{
587-
Sleep: &v1.SleepAction{Seconds: 15},
627+
Sleep: &v1.SleepAction{Seconds: sleepSeconds},
588628
},
589629
}
590-
podWithHook := getPodWithHook("pod-with-prestop-sleep-hook", imageutils.GetPauseImageName(), lifecycle)
630+
name := "pod-with-prestop-sleep-hook"
631+
podWithHook := getPodWithHook(name, imageutils.GetPauseImageName(), lifecycle)
632+
podWithHook.Finalizers = append(podWithHook.Finalizers, finalizer)
633+
podWithHook.Spec.TerminationGracePeriodSeconds = ptr.To[int64](100)
591634
ginkgo.By("create the pod with lifecycle hook using sleep action")
592-
podClient.CreateSync(ctx, podWithHook)
635+
p := podClient.CreateSync(ctx, podWithHook)
636+
defer podClient.RemoveFinalizer(ctx, name, finalizer)
593637
ginkgo.By("delete the pod with lifecycle hook using sleep action")
594-
start := time.Now()
595-
podClient.DeleteSync(ctx, podWithHook.Name, *metav1.NewDeleteOptions(2), f.Timeouts.PodDelete)
596-
cost := time.Since(start)
597-
// cost should be
598-
// longer than 2 seconds (we change gracePeriodSeconds to 2 seconds here, and it's less than sleep action)
638+
639+
const gracePeriod = 30
640+
_ = podClient.Delete(ctx, podWithHook.Name, *metav1.NewDeleteOptions(gracePeriod))
641+
p, err := podClient.Get(ctx, p.Name, metav1.GetOptions{})
642+
if err != nil {
643+
framework.Failf("failed getting pod after deletion")
644+
}
645+
// deletionTimestamp equals to delete_time + tgps
646+
// TODO: reduce sleep_seconds and tgps after issues.k8s.io/132205 is solved
647+
// we get deletionTimestamp before container become terminated here because of issues.k8s.io/132205
648+
deletionTS := p.DeletionTimestamp.Time
649+
if err := e2epod.WaitForContainerTerminated(ctx, f.ClientSet, p.Namespace, p.Name, name, sleepSeconds*2*time.Second); err != nil {
650+
framework.Failf("failed waiting for container terminated")
651+
}
652+
p, err = podClient.Get(ctx, p.Name, metav1.GetOptions{})
653+
if err != nil {
654+
framework.Failf("failed getting pod after deletion")
655+
}
656+
// finishAt equals to delete_time + sleep_duration
657+
finishAt := p.Status.ContainerStatuses[0].State.Terminated.FinishedAt
658+
659+
// sleep_duration = (delete_time + sleep_duration) - (delete_time + tgps) + tgps
660+
sleepDuration := finishAt.Sub(deletionTS) + time.Second*gracePeriod
661+
// sleep_duration should be
662+
// longer than 30 seconds (we change gracePeriodSeconds to 30 seconds here, and it's less than sleep action)
599663
// shorter than sleep action (to make sure it doesn't take effect)
600-
if !validDuration(cost, 2, 15) {
601-
framework.Failf("unexpected delay duration before killing the pod, cost = %v", cost)
664+
if !validDuration(sleepDuration, gracePeriod, sleepSeconds) {
665+
framework.Failf("unexpected delay duration before killing the pod, finishAt = %v, deletionAt= %v", finishAt, deletionTS)
602666
}
603667
})
604668

669+
/*
670+
Release : v1.34
671+
Testname: Pod Lifecycle, prestop sleep hook with erroneous startup command
672+
Description: When a pre-stop handler is specified in the container lifecycle using a 'Sleep' action, then the handler MUST be invoked before the container is terminated. A test pod with an erroneous startup command will be created, and upon termination, it will be checked whether it ignored the sleep time.
673+
*/
605674
ginkgo.It("ignore terminated container", func(ctx context.Context) {
675+
const sleepSeconds = 10
676+
const gracePeriod = 30
606677
lifecycle := &v1.Lifecycle{
607678
PreStop: &v1.LifecycleHandler{
608-
Sleep: &v1.SleepAction{Seconds: 20},
679+
Sleep: &v1.SleepAction{Seconds: sleepSeconds},
609680
},
610681
}
611682
name := "pod-with-prestop-sleep-hook"
612683
podWithHook := getPodWithHook(name, imageutils.GetE2EImage(imageutils.BusyBox), lifecycle)
684+
podWithHook.Spec.TerminationGracePeriodSeconds = ptr.To[int64](gracePeriod)
613685
podWithHook.Spec.Containers[0].Command = []string{"/bin/sh"}
614686
podWithHook.Spec.Containers[0].Args = []string{"-c", "exit 0"}
615687
podWithHook.Spec.RestartPolicy = v1.RestartPolicyNever
616688
ginkgo.By("create the pod with lifecycle hook using sleep action")
617689
p := podClient.Create(ctx, podWithHook)
618-
framework.ExpectNoError(e2epod.WaitForContainerTerminated(ctx, f.ClientSet, f.Namespace.Name, p.Name, name, 3*time.Minute))
619-
ginkgo.By("delete the pod with lifecycle hook using sleep action")
620-
start := time.Now()
621-
podClient.DeleteSync(ctx, podWithHook.Name, metav1.DeleteOptions{}, f.Timeouts.PodDelete)
622-
cost := time.Since(start)
690+
defer podClient.DeleteSync(ctx, podWithHook.Name, metav1.DeleteOptions{}, f.Timeouts.PodDelete)
691+
framework.ExpectNoError(e2epod.WaitForContainerTerminated(ctx, f.ClientSet, f.Namespace.Name, p.Name, name, gracePeriod*time.Second))
692+
693+
p, err := podClient.Get(ctx, p.Name, metav1.GetOptions{})
694+
if err != nil {
695+
framework.Failf("failed getting pod after deletion")
696+
}
697+
finishAt := p.Status.ContainerStatuses[0].State.Terminated.FinishedAt
698+
startedAt := p.Status.ContainerStatuses[0].State.Terminated.StartedAt
699+
cost := finishAt.Sub(startedAt.Time)
623700
// cost should be
624701
// shorter than sleep action (container is terminated and sleep action should be ignored)
625-
if !validDuration(cost, 0, 15) {
702+
if !validDuration(cost, 0, sleepSeconds) {
626703
framework.Failf("unexpected delay duration before killing the pod, cost = %v", cost)
627704
}
628705
})
629-
630706
})
631707
})
632708

0 commit comments

Comments
 (0)