Skip to content

Commit 8817055

Browse files
committed
Migrate OCP-38271 from openshift-tests-private
Add test to verify init containers do not restart when removed from node. - Add pod-initContainer.yaml template - Add helper functions in node_utils.go - Add OCP-38271 test in node_e2e/node.go Author: minmli@redhat.com (original) Migrated-by: bgudi@redhat.com Move OCP-38271 test to separate Describe block Refactor OCP-38271 to use standard origin patterns instead of compat_otp Fix race condition and Add retry logic and explicit failure for MicroShift cluster check
1 parent c77ff4a commit 8817055

1 file changed

Lines changed: 190 additions & 4 deletions

File tree

test/extended/node/node_e2e/node.go

Lines changed: 190 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
package node
22

33
import (
4+
"context"
5+
"fmt"
6+
"regexp"
47
"strings"
58
"time"
69

710
g "github.com/onsi/ginkgo/v2"
811
o "github.com/onsi/gomega"
9-
nodeutils "github.com/openshift/origin/test/extended/node"
10-
exutil "github.com/openshift/origin/test/extended/util"
12+
corev1 "k8s.io/api/core/v1"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1114
"k8s.io/apimachinery/pkg/util/wait"
1215
e2e "k8s.io/kubernetes/test/e2e/framework"
16+
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
17+
18+
nodeutils "github.com/openshift/origin/test/extended/node"
19+
exutil "github.com/openshift/origin/test/extended/util"
1320
)
1421

1522
var _ = g.Describe("[sig-node] [Jira:Node/Kubelet] Kubelet, CRI-O, CPU manager", func() {
@@ -19,8 +26,24 @@ var _ = g.Describe("[sig-node] [Jira:Node/Kubelet] Kubelet, CRI-O, CPU manager",
1926

2027
// Skip all tests on MicroShift clusters as MachineConfig resources are not available
2128
g.BeforeEach(func() {
22-
isMicroShift, err := exutil.IsMicroShiftCluster(oc.AdminKubeClient())
23-
o.Expect(err).NotTo(o.HaveOccurred())
29+
var isMicroShift bool
30+
var err error
31+
32+
// Retry check for robustness - OpenShift should eventually respond
33+
pollErr := wait.Poll(2*time.Second, 30*time.Second, func() (bool, error) {
34+
isMicroShift, err = exutil.IsMicroShiftCluster(oc.AdminKubeClient())
35+
if err != nil {
36+
e2e.Logf("Failed to check if cluster is MicroShift: %v, retrying...", err)
37+
return false, nil
38+
}
39+
return true, nil
40+
})
41+
42+
if pollErr != nil {
43+
e2e.Logf("Setup failed: unable to determine if cluster is MicroShift after retries: %v", err)
44+
g.Fail("Setup failed: unable to determine cluster type - this is an infrastructure/connectivity issue, not a test failure")
45+
}
46+
2447
if isMicroShift {
2548
g.Skip("Skipping test on MicroShift cluster - MachineConfig resources are not available")
2649
}
@@ -104,3 +127,166 @@ var _ = g.Describe("[sig-node] [Jira:Node/Kubelet] Kubelet, CRI-O, CPU manager",
104127
o.Expect(output).To(o.ContainSubstring("spec.cgroupMode: Unsupported value: \"v1\": supported values: \"v2\", \"\""))
105128
})
106129
})
130+
131+
var _ = g.Describe("[sig-node] [Jira:Node/Kubelet] NODE initContainer policy,volume,readines,quota", func() {
132+
defer g.GinkgoRecover()
133+
134+
var (
135+
oc = exutil.NewCLI("node-initcontainer")
136+
)
137+
138+
// Skip all tests on MicroShift clusters as MachineConfig resources are not available
139+
g.BeforeEach(func() {
140+
var isMicroShift bool
141+
var err error
142+
143+
// Retry check for robustness - OpenShift should eventually respond
144+
pollErr := wait.Poll(2*time.Second, 30*time.Second, func() (bool, error) {
145+
isMicroShift, err = exutil.IsMicroShiftCluster(oc.AdminKubeClient())
146+
if err != nil {
147+
e2e.Logf("Failed to check if cluster is MicroShift: %v, retrying...", err)
148+
return false, nil
149+
}
150+
return true, nil
151+
})
152+
153+
if pollErr != nil {
154+
e2e.Logf("Setup failed: unable to determine if cluster is MicroShift after retries: %v", err)
155+
g.Fail("Setup failed: unable to determine cluster type - this is an infrastructure/connectivity issue, not a test failure")
156+
}
157+
158+
if isMicroShift {
159+
g.Skip("Skipping test on MicroShift cluster - MachineConfig resources are not available")
160+
}
161+
})
162+
163+
//author: bgudi@redhat.com
164+
g.It("[OTP] Init containers should not restart when the exited init container is removed from node [OCP-38271]", func() {
165+
g.By("Test for case OCP-38271")
166+
oc.SetupProject()
167+
168+
podName := "initcon-pod"
169+
namespace := oc.Namespace()
170+
ctx := context.Background()
171+
172+
g.By("Create a pod with init container")
173+
pod := &corev1.Pod{
174+
ObjectMeta: metav1.ObjectMeta{
175+
Name: podName,
176+
Namespace: namespace,
177+
},
178+
Spec: corev1.PodSpec{
179+
InitContainers: []corev1.Container{
180+
{
181+
Name: "inittest",
182+
Image: "quay.io/openshifttest/busybox@sha256:c5439d7db88ab5423999530349d327b04279ad3161d7596d2126dfb5b02bfd1f",
183+
Command: []string{"bin/sh", "-ec", "echo running >> /mnt/data/test"},
184+
VolumeMounts: []corev1.VolumeMount{
185+
{
186+
Name: "data",
187+
MountPath: "/mnt/data",
188+
},
189+
},
190+
},
191+
},
192+
Containers: []corev1.Container{
193+
{
194+
Name: "hello-test",
195+
Image: "quay.io/openshifttest/busybox@sha256:c5439d7db88ab5423999530349d327b04279ad3161d7596d2126dfb5b02bfd1f",
196+
Command: []string{"bin/sh", "-c", "sleep 3600"},
197+
VolumeMounts: []corev1.VolumeMount{
198+
{
199+
Name: "data",
200+
MountPath: "/mnt/data",
201+
},
202+
},
203+
},
204+
},
205+
Volumes: []corev1.Volume{
206+
{
207+
Name: "data",
208+
VolumeSource: corev1.VolumeSource{
209+
EmptyDir: &corev1.EmptyDirVolumeSource{},
210+
},
211+
},
212+
},
213+
RestartPolicy: corev1.RestartPolicyNever,
214+
},
215+
}
216+
217+
_, err := oc.KubeClient().CoreV1().Pods(namespace).Create(ctx, pod, metav1.CreateOptions{})
218+
o.Expect(err).NotTo(o.HaveOccurred())
219+
defer func() {
220+
oc.KubeClient().CoreV1().Pods(namespace).Delete(ctx, podName, metav1.DeleteOptions{})
221+
}()
222+
223+
g.By("Check pod status")
224+
err = e2epod.WaitForPodRunningInNamespace(ctx, oc.KubeClient(), pod)
225+
o.Expect(err).NotTo(o.HaveOccurred(), "pod is not running")
226+
227+
g.By("Check init container exit normally")
228+
err = wait.Poll(5*time.Second, 1*time.Minute, func() (bool, error) {
229+
pod, err := oc.KubeClient().CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{})
230+
if err != nil {
231+
return false, err
232+
}
233+
for _, status := range pod.Status.InitContainerStatuses {
234+
if status.Name == "inittest" {
235+
if status.State.Terminated != nil && status.State.Terminated.ExitCode == 0 {
236+
e2e.Logf("Init container exited with code 0")
237+
return true, nil
238+
}
239+
}
240+
}
241+
return false, nil
242+
})
243+
o.Expect(err).NotTo(o.HaveOccurred(), "container not exit normally")
244+
245+
g.By("Get node where pod is running")
246+
pod, err = oc.KubeClient().CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{})
247+
o.Expect(err).NotTo(o.HaveOccurred())
248+
nodeName := pod.Spec.NodeName
249+
o.Expect(nodeName).NotTo(o.BeEmpty(), "pod node name is empty")
250+
251+
g.By("Get init container ID from pod status")
252+
var containerID string
253+
for _, status := range pod.Status.InitContainerStatuses {
254+
if status.Name == "inittest" {
255+
containerID = status.ContainerID
256+
break
257+
}
258+
}
259+
o.Expect(containerID).NotTo(o.BeEmpty(), "init container ID is empty")
260+
261+
// Extract the actual container ID (remove prefix like "cri-o://")
262+
containerIDPattern := regexp.MustCompile(`^[^/]+://(.+)$`)
263+
matches := containerIDPattern.FindStringSubmatch(containerID)
264+
o.Expect(matches).To(o.HaveLen(2), "failed to parse container ID")
265+
actualContainerID := matches[1]
266+
267+
g.By("Delete init container from node")
268+
deleteCmd := fmt.Sprintf("crictl rm %s", actualContainerID)
269+
output, err := nodeutils.ExecOnNodeWithChroot(oc, nodeName, "/bin/bash", "-c", deleteCmd)
270+
o.Expect(err).NotTo(o.HaveOccurred(), "fail to delete container")
271+
e2e.Logf("Container deletion output: %s", output)
272+
273+
g.By("Check init container not restart again")
274+
err = wait.Poll(5*time.Second, 1*time.Minute, func() (bool, error) {
275+
pod, err := oc.KubeClient().CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{})
276+
if err != nil {
277+
return false, err
278+
}
279+
for _, status := range pod.Status.InitContainerStatuses {
280+
if status.Name == "inittest" {
281+
if status.RestartCount > 0 {
282+
e2e.Logf("Init container restarted, restart count: %d", status.RestartCount)
283+
return true, fmt.Errorf("init container restarted")
284+
}
285+
}
286+
}
287+
e2e.Logf("Init container has not restarted")
288+
return false, nil
289+
})
290+
o.Expect(err).To(o.Equal(wait.ErrWaitTimeout), "expected timeout while waiting confirms init container did not restart")
291+
})
292+
})

0 commit comments

Comments
 (0)