Skip to content

Commit d859a3c

Browse files
committed
Adding e2e test case for runc deprecation
1 parent 17afd52 commit d859a3c

2 files changed

Lines changed: 326 additions & 0 deletions

File tree

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package node
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
g "github.com/onsi/ginkgo/v2"
8+
o "github.com/onsi/gomega"
9+
corev1 "k8s.io/api/core/v1"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/kubernetes/test/e2e/framework"
12+
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
13+
14+
configv1 "github.com/openshift/api/config/v1"
15+
mcclient "github.com/openshift/client-go/machineconfiguration/clientset/versioned"
16+
exutil "github.com/openshift/origin/test/extended/util"
17+
"github.com/openshift/origin/test/extended/util/image"
18+
)
19+
20+
// runc Deprecation Test Suite
21+
22+
var _ = g.Describe("[Jira:Node][sig-node] runc deprecation cases", func() {
23+
defer g.GinkgoRecover()
24+
25+
var oc = exutil.NewCLI("runc-deprecation")
26+
27+
g.BeforeEach(func(ctx context.Context) {
28+
isMicroShift, err := exutil.IsMicroShiftCluster(oc.AdminKubeClient())
29+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to check if cluster is MicroShift")
30+
if isMicroShift {
31+
g.Skip("Skipping runc deprecation tests on MicroShift")
32+
}
33+
34+
controlPlaneTopology, err := exutil.GetControlPlaneTopology(oc)
35+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to get control plane topology")
36+
if *controlPlaneTopology == configv1.ExternalTopologyMode {
37+
g.Skip("Skipping runc deprecation tests on Hypershift — MachineConfig API unavailable")
38+
}
39+
})
40+
41+
// A cluster on RHCOS 9 should use crun as the default container runtime
42+
// with no custom ContainerRuntimeConfig present.
43+
g.It("RHCOS 9 cluster install should use crun as the default container runtime", func(ctx context.Context) {
44+
45+
g.By("Checking ClusterVersion is Available and not Progressing")
46+
cv, err := oc.AdminConfigClient().ConfigV1().ClusterVersions().Get(ctx, "version", metav1.GetOptions{})
47+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to get ClusterVersion")
48+
var cvAvailable, cvProgressing bool
49+
for _, cond := range cv.Status.Conditions {
50+
switch cond.Type {
51+
case configv1.OperatorAvailable:
52+
cvAvailable = cond.Status == configv1.ConditionTrue
53+
case configv1.OperatorProgressing:
54+
cvProgressing = cond.Status == configv1.ConditionTrue
55+
}
56+
}
57+
o.Expect(cvAvailable).To(o.BeTrue(), "ClusterVersion should be Available")
58+
o.Expect(cvProgressing).To(o.BeFalse(), "ClusterVersion should not be Progressing")
59+
framework.Logf("ClusterVersion %s: Available=%v Progressing=%v",
60+
cv.Status.Desired.Version, cvAvailable, cvProgressing)
61+
62+
g.By("Getting a worker node for inspection")
63+
workerNodes, err := getNodesByLabel(ctx, oc, "node-role.kubernetes.io/worker")
64+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to list worker nodes")
65+
o.Expect(workerNodes).NotTo(o.BeEmpty(), "expected at least one worker node")
66+
targetNode := workerNodes[0].Name
67+
framework.Logf("Using worker node: %s", targetNode)
68+
69+
g.By("Checking RHCOS 9 is reported in /etc/os-release on the worker node")
70+
osRelease, err := ExecOnNodeWithChroot(oc, targetNode, "cat", "/etc/os-release")
71+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to read /etc/os-release on node %s", targetNode)
72+
o.Expect(osRelease).To(o.ContainSubstring("VARIANT_ID=coreos"),
73+
"expected RHCOS (VARIANT_ID=coreos) on node %s", targetNode)
74+
o.Expect(osRelease).To(o.ContainSubstring(`VERSION_ID="9.`),
75+
"expected RHCOS 9 (VERSION_ID=\"9.x\") on node %s", targetNode)
76+
framework.Logf("Confirmed: node %s is running RHCOS 9", targetNode)
77+
78+
g.By("Checking no ContainerRuntimeConfig resources exist")
79+
mcClient, err := mcclient.NewForConfig(oc.KubeFramework().ClientConfig())
80+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to create MachineConfig client")
81+
ctrcfgList, err := mcClient.MachineconfigurationV1().ContainerRuntimeConfigs().List(ctx, metav1.ListOptions{})
82+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to list ContainerRuntimeConfigs")
83+
o.Expect(ctrcfgList.Items).To(o.BeEmpty(),
84+
"expected no ContainerRuntimeConfigs on a fresh cluster, found %d item(s)", len(ctrcfgList.Items))
85+
framework.Logf("Confirmed: no custom ContainerRuntimeConfig exists")
86+
87+
g.By("Checking CRI-O default_runtime is crun on the worker node")
88+
crioConfig, err := ExecOnNodeWithChroot(oc, targetNode, "crio", "status", "config")
89+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to get CRI-O status config on node %s", targetNode)
90+
o.Expect(crioConfig).To(o.ContainSubstring(`default_runtime = "crun"`),
91+
"expected CRI-O default_runtime to be crun on node %s", targetNode)
92+
framework.Logf("Confirmed: CRI-O default_runtime is crun on node %s", targetNode)
93+
94+
g.By("Checking machine-config ClusterOperator is Available and not Degraded")
95+
co, err := oc.AdminConfigClient().ConfigV1().ClusterOperators().Get(ctx, "machine-config", metav1.GetOptions{})
96+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to get machine-config ClusterOperator")
97+
var mcAvailable, mcProgressing, mcDegraded bool
98+
for _, cond := range co.Status.Conditions {
99+
switch cond.Type {
100+
case configv1.OperatorAvailable:
101+
mcAvailable = cond.Status == configv1.ConditionTrue
102+
case configv1.OperatorProgressing:
103+
mcProgressing = cond.Status == configv1.ConditionTrue
104+
case configv1.OperatorDegraded:
105+
mcDegraded = cond.Status == configv1.ConditionTrue
106+
}
107+
}
108+
o.Expect(mcAvailable).To(o.BeTrue(), "machine-config ClusterOperator should be Available")
109+
o.Expect(mcProgressing).To(o.BeFalse(), "machine-config ClusterOperator should not be Progressing")
110+
o.Expect(mcDegraded).To(o.BeFalse(), "machine-config ClusterOperator should not be Degraded")
111+
framework.Logf("Confirmed: machine-config ClusterOperator is healthy (Available=true Progressing=false Degraded=false)")
112+
113+
g.By("Creating a test pod with ubi9-minimal image")
114+
namespace := oc.Namespace()
115+
pod := &corev1.Pod{
116+
ObjectMeta: metav1.ObjectMeta{
117+
Name: "test-fresh-crun",
118+
Namespace: namespace,
119+
},
120+
Spec: corev1.PodSpec{
121+
NodeSelector: map[string]string{
122+
"kubernetes.io/hostname": targetNode,
123+
},
124+
RestartPolicy: corev1.RestartPolicyNever,
125+
Containers: []corev1.Container{
126+
{
127+
Name: "ubi-minimal",
128+
Image: image.LocationFor("registry.access.redhat.com/ubi9/ubi-minimal"),
129+
Command: []string{"echo", "crun-fresh-install-test-passed"},
130+
},
131+
},
132+
},
133+
}
134+
_, err = oc.KubeClient().CoreV1().Pods(namespace).Create(ctx, pod, metav1.CreateOptions{})
135+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to create test pod")
136+
137+
g.By("Waiting for the test pod to reach Succeeded phase")
138+
err = e2epod.WaitForPodSuccessInNamespaceTimeout(ctx, oc.KubeClient(), pod.Name, namespace, 2*time.Minute)
139+
o.Expect(err).NotTo(o.HaveOccurred(), "test pod did not complete successfully with crun runtime")
140+
141+
resultPod, err := oc.KubeClient().CoreV1().Pods(namespace).Get(ctx, pod.Name, metav1.GetOptions{})
142+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to get test pod after completion")
143+
o.Expect(resultPod.Status.Phase).To(o.Equal(corev1.PodSucceeded),
144+
"test pod should have Succeeded, got phase: %s", resultPod.Status.Phase)
145+
framework.Logf("Test PASSED: RHCOS 9 cluster uses crun as default runtime and workloads run successfully")
146+
})
147+
})
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# Test Plan: runc Deprecation Cases
2+
3+
## Metadata
4+
5+
| Field | Value |
6+
|---------------------|-------|
7+
| **Test file** | `test/extended/node/runcdeprecationcases.go` |
8+
| **Package** | `node` |
9+
| **Test suite** | `[Jira:Node][sig-node] runc deprecation cases` |
10+
| **Strategy** | [OCPSTRAT-3154](https://redhat.atlassian.net/browse/OCPSTRAT-3154) — runc deprecation warning in OCP 5.0 for clusters upgrading from 4.22 |
11+
| **Epic** | [OCPNODE-4013](https://redhat.atlassian.net/browse/OCPNODE-4013) — Block upgrade from RHCOS 9 to RHCOS 10 when runc is in use |
12+
| **User Story** | [OCPNODE-4567](https://redhat.atlassian.net/browse/OCPNODE-4567) |
13+
| **Assignee** | Aditi Sahay (asahay@redhat.com) |
14+
| **Component** | `sig-node`, MCO, CRI-O |
15+
| **Test type** | E2E / functional |
16+
| **Ginkgo label** | `[Jira:Node][sig-node]` |
17+
| **Disruptive** | No |
18+
| **Requires reboot** | No |
19+
20+
---
21+
22+
## UseCase3: Fresh Install on RHCOS 9 with crun
23+
24+
### Description
25+
26+
A freshly installed OpenShift 5.0–5.2 cluster on RHCOS 9 uses **crun** as the default container runtime.
27+
This is the standard configuration for new installations — no custom `ContainerRuntimeConfig`
28+
should be present, and `crun` must be the CRI-O default on all worker nodes.
29+
30+
### Scope
31+
32+
| Item | Value |
33+
|----------------------------|-------|
34+
| **OpenShift versions** | 5.0, 5.1, 5.2 (fresh install) |
35+
| **OS** | RHCOS 9 (`VARIANT_ID=coreos`, `VERSION_ID=9.x`) |
36+
| **Default runtime** | `crun` |
37+
| **ContainerRuntimeConfig** | None (no custom CRC expected) |
38+
| **Skip conditions** | MicroShift, Hypershift (external control plane) |
39+
40+
### Test Function
41+
42+
```go
43+
g.It("RHCOS 9 cluster install should use crun as the default container runtime")
44+
```
45+
46+
---
47+
48+
## Manual Test Execution Steps
49+
50+
### Prerequisites
51+
52+
- A live OpenShift 5.0–5.2 cluster (fresh install, no custom runtime configuration)
53+
- `oc` binary matching the cluster version
54+
- `KUBECONFIG` set to a valid kubeconfig for that cluster
55+
- `cluster-admin` privileges
56+
57+
---
58+
59+
<table>
60+
<thead>
61+
<tr><th>STEPS</th><th>EXPECTED OUTPUT</th></tr>
62+
</thead>
63+
<tbody>
64+
<tr>
65+
<td>
66+
<b>1. Check clusterversion</b><br><br>
67+
<code>oc get clusterversion</code>
68+
</td>
69+
<td>
70+
<pre>NAME VERSION AVAILABLE PROGRESSING SINCE STATUS
71+
version 5.0.0-0.nightly-2026-05-11-043758 True False 55m Cluster version is 5.0.0-0.nightly-2026-05-11-043758</pre>
72+
✅ <code>AVAILABLE=True</code>, <code>PROGRESSING=False</code>
73+
</td>
74+
</tr>
75+
<tr>
76+
<td>
77+
<b>2. Check the RHCOS Version</b><br><br>
78+
<code>oc debug node/&lt;worker-node-name&gt;</code><br><br>
79+
Inside the debug pod:<br>
80+
<code>chroot /host</code><br>
81+
<code>cat /etc/os-release</code>
82+
</td>
83+
<td>
84+
<pre>NAME="Red Hat Enterprise Linux CoreOS"
85+
VERSION="9.8.20260508-0 (Plow)"
86+
ID="rhel"
87+
ID_LIKE="fedora"
88+
VERSION_ID="9.8"
89+
PLATFORM_ID="platform:el9"
90+
PRETTY_NAME="Red Hat Enterprise Linux CoreOS 9.8.20260508-0 (Plow)"
91+
ANSI_COLOR="0;31"
92+
VARIANT=CoreOS
93+
VARIANT_ID=coreos
94+
OPENSHIFT_VERSION="5.0"</pre>
95+
✅ <code>VARIANT_ID=coreos</code> (confirms RHCOS, not plain RHEL)<br>
96+
✅ <code>VERSION_ID="9.x"</code> (confirms RHCOS 9)
97+
</td>
98+
</tr>
99+
<tr>
100+
<td>
101+
<b>3. Verify no custom ContainerRuntimeConfig exists</b><br><br>
102+
<code>oc get containerruntimeconfig</code>
103+
</td>
104+
<td>
105+
<pre>No resources found</pre>
106+
✅ Zero <code>ContainerRuntimeConfig</code> objects on a fresh cluster
107+
</td>
108+
</tr>
109+
<tr>
110+
<td>
111+
<b>4. Check the default runtime (should be crun)</b><br><br>
112+
Inside the debug pod (continuing or re-enter):<br>
113+
<code>chroot /host</code><br>
114+
<code>crio status config | grep "default_runtime"</code>
115+
</td>
116+
<td>
117+
<pre>INFO[...] Updating config from single file: /etc/crio/crio.conf
118+
INFO[...] Updating config from drop-in file: /etc/crio/crio.conf
119+
INFO[...] Updating config from path: /etc/crio/crio.conf.d
120+
INFO[...] Updating config from drop-in file: /etc/crio/crio.conf.d/00-default
121+
default_runtime = "crun"</pre>
122+
✅ <code>default_runtime = "crun"</code>
123+
</td>
124+
</tr>
125+
<tr>
126+
<td>
127+
<b>5. Verify machine-config ClusterOperator status</b><br><br>
128+
<code>oc get co machine-config</code>
129+
</td>
130+
<td>
131+
<pre>NAME VERSION AVAILABLE PROGRESSING DEGRADED SINCE MESSAGE
132+
machine-config 5.0.0-0.nightly-2026-05-11-043758 True False False 84m</pre>
133+
✅ <code>AVAILABLE=True</code>, <code>PROGRESSING=False</code>, <code>DEGRADED=False</code>
134+
</td>
135+
</tr>
136+
<tr>
137+
<td>
138+
<b>6. Create a test workload</b><br><br>
139+
<code>oc create deployment test-fresh-crun --image=registry.access.redhat.com/ubi9/ubi-minimal</code><br><br>
140+
Then check the pod:<br>
141+
<code>oc get pods -l app=test-fresh-crun</code>
142+
</td>
143+
<td>
144+
<pre>deployment.apps/test-fresh-crun created</pre>
145+
<pre>NAME READY STATUS RESTARTS AGE
146+
test-fresh-crun-5767cbc848-pxtw8 0/1 Completed 4 (61s ago) 109s</pre>
147+
✅ Fresh cluster installs successfully with crun on RHCOS 9
148+
</td>
149+
</tr>
150+
</tbody>
151+
</table>
152+
153+
---
154+
155+
## Pass/Fail Criteria
156+
157+
| Check | Pass condition |
158+
|----------------------------------------|----------------|
159+
| ClusterVersion Available | `AVAILABLE=True`, `PROGRESSING=False` |
160+
| RHCOS version on worker node | `VARIANT_ID=coreos` and `VERSION_ID="9.x"` |
161+
| No ContainerRuntimeConfig | `oc get containerruntimeconfig` returns no resources |
162+
| CRI-O default runtime | `default_runtime = "crun"` in `crio status config` |
163+
| machine-config ClusterOperator healthy | `Available=True`, `Progressing=False`, `Degraded=False` |
164+
| Test workload runs successfully | Pod reaches `Succeeded` / `Completed` phase |
165+
166+
---
167+
168+
## Automated Test Mapping
169+
170+
| Manual step | Automated assertion in `runcdeprecationcases.go` |
171+
|-------------|--------------------------------------------------|
172+
| `oc get clusterversion` | `ClusterVersions().Get("version")` — asserts `Available=True`, `Progressing=False` |
173+
| `cat /etc/os-release` on worker node | `ExecOnNodeWithChroot` — asserts `VARIANT_ID=coreos` and `VERSION_ID="9.` |
174+
| `oc get containerruntimeconfig` | `ContainerRuntimeConfigs().List()` — asserts list is empty |
175+
| `crio status config \| grep default_runtime` | `ExecOnNodeWithChroot("crio","status","config")` — asserts `default_runtime = "crun"` |
176+
| `oc get co machine-config` | `ClusterOperators().Get("machine-config")` — asserts `Available`, `!Progressing`, `!Degraded` |
177+
| `oc create deployment test-fresh-crun` | Creates `corev1.Pod` with `ubi9/ubi-minimal` — waits for `PodSucceeded` |
178+
179+
---

0 commit comments

Comments
 (0)