diff --git a/test/extended/node/README.md b/test/extended/node/README.md index 4d0f1f7abd0c..3c0904fa41e7 100644 --- a/test/extended/node/README.md +++ b/test/extended/node/README.md @@ -19,6 +19,7 @@ This directory contains OpenShift end-to-end tests for node-related features. - **image_volume.go** - Tests mounting container images as volumes in pods, including subPath and error handling - **node_swap.go** - Tests default kubelet swap settings (failSwapOn and swapBehavior) and rejection of user overrides - **zstd_chunked.go** - Tests building and running images with zstd:chunked compression format +- **node_e2e/node.go** - Probe-level terminationGracePeriodSeconds (OCP-44493) - Tests configurable termination grace period for liveness and startup probes [Lifecycle:informing] ## Directory Structure diff --git a/test/extended/node/node_e2e/node.go b/test/extended/node/node_e2e/node.go index 5f43c93e20af..483b5963f112 100644 --- a/test/extended/node/node_e2e/node.go +++ b/test/extended/node/node_e2e/node.go @@ -4,15 +4,19 @@ import ( "context" "fmt" "path/filepath" + "strconv" "strings" "time" g "github.com/onsi/ginkgo/v2" o "github.com/onsi/gomega" + ote "github.com/openshift-eng/openshift-tests-extension/pkg/ginkgo" configv1 "github.com/openshift/api/config/v1" "github.com/openshift/origin/test/extended/imagepolicy" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" utilrand "k8s.io/apimachinery/pkg/util/rand" "k8s.io/apimachinery/pkg/util/wait" e2e "k8s.io/kubernetes/test/e2e/framework" @@ -164,6 +168,284 @@ var _ = g.Describe("[sig-node] [Jira:Node/Kubelet] Kubelet, CRI-O, CPU manager", e2e.Logf("/dev/fuse mount output: %s", output) o.Expect(output).To(o.ContainSubstring("fuse"), "dev fuse is not mounted inside pod") }) + + //author: minmli@redhat.com + //migrated from openshift-tests-private + //automates: https://issues.redhat.com/browse/OCPBUGS-44493 + g.It("[OTP] add configurable terminationGracePeriodSeconds to liveness and startup probes [OCP-44493]", ote.Informing(), func() { + ctx := context.Background() + var err error + + oc.SetupProject() + namespace := oc.Namespace() + + // Helper function to parse duration string like "1m30s" or "45s" to seconds + parseDurationToSeconds := func(durationStr string) (int, error) { + var totalSeconds int + if strings.Contains(durationStr, "m") { + parts := strings.Split(durationStr, "m") + minutes, err := strconv.Atoi(parts[0]) + if err != nil { + return 0, err + } + totalSeconds = minutes * 60 + if len(parts) > 1 && strings.Contains(parts[1], "s") { + secStr := strings.TrimSuffix(parts[1], "s") + if secStr != "" { + seconds, err := strconv.Atoi(secStr) + if err != nil { + return 0, err + } + totalSeconds += seconds + } + } + } else if strings.Contains(durationStr, "s") { + secStr := strings.TrimSuffix(durationStr, "s") + seconds, err := strconv.Atoi(secStr) + if err != nil { + return 0, err + } + totalSeconds = seconds + } + return totalSeconds, nil + } + + // Helper to verify probe termination period + verifyProbeTermination := func(podName, containerName string, expectedTerminationSec int) error { + return wait.PollUntilContextTimeout(ctx, 10*time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { + podDesc, err := oc.AsAdmin().WithoutNamespace().Run("describe").Args("pod", podName, "-n", namespace).Output() + if err != nil { + e2e.Logf("Error describing pod: %v", err) + return false, nil + } + + // Look for probe failure (killing) and container restart events + // Event format: "Normal Killing