-
Notifications
You must be signed in to change notification settings - Fork 4.8k
OCPNODE-4567: Adding e2e test case for runc deprecation #31257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
asahay19
wants to merge
1
commit into
openshift:main
Choose a base branch
from
asahay19:4567
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+251
−0
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| package node | ||
|
|
||
| import ( | ||
| "context" | ||
| "time" | ||
|
|
||
| g "github.com/onsi/ginkgo/v2" | ||
| o "github.com/onsi/gomega" | ||
| corev1 "k8s.io/api/core/v1" | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "k8s.io/kubernetes/test/e2e/framework" | ||
| e2epod "k8s.io/kubernetes/test/e2e/framework/pod" | ||
|
|
||
| configv1 "github.com/openshift/api/config/v1" | ||
| mcclient "github.com/openshift/client-go/machineconfiguration/clientset/versioned" | ||
| exutil "github.com/openshift/origin/test/extended/util" | ||
| "github.com/openshift/origin/test/extended/util/image" | ||
| ) | ||
|
|
||
| // runc Deprecation Test Suite | ||
|
|
||
| var _ = g.Describe("[Jira:Node][sig-node] runc deprecation cases", func() { | ||
| defer g.GinkgoRecover() | ||
|
|
||
| var oc = exutil.NewCLI("runc-deprecation") | ||
|
|
||
| g.BeforeEach(func(ctx context.Context) { | ||
| isMicroShift, err := exutil.IsMicroShiftCluster(oc.AdminKubeClient()) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to check if cluster is MicroShift") | ||
| if isMicroShift { | ||
| g.Skip("Skipping runc deprecation tests on MicroShift") | ||
| } | ||
|
|
||
| controlPlaneTopology, err := exutil.GetControlPlaneTopology(oc) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to get control plane topology") | ||
| if *controlPlaneTopology == configv1.ExternalTopologyMode { | ||
| g.Skip("Skipping runc deprecation tests on Hypershift — MachineConfig API unavailable") | ||
| } | ||
| }) | ||
|
|
||
| // A cluster on RHCOS 9 should use crun as the default container runtime | ||
| // with no custom ContainerRuntimeConfig present. | ||
| g.It("RHCOS 9 cluster install should use crun as the default container runtime", func(ctx context.Context) { | ||
|
|
||
| g.By("Checking ClusterVersion is Available and not Progressing") | ||
| cv, err := oc.AdminConfigClient().ConfigV1().ClusterVersions().Get(ctx, "version", metav1.GetOptions{}) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to get ClusterVersion") | ||
| var cvAvailable, cvProgressing bool | ||
| for _, cond := range cv.Status.Conditions { | ||
| switch cond.Type { | ||
| case configv1.OperatorAvailable: | ||
| cvAvailable = cond.Status == configv1.ConditionTrue | ||
| case configv1.OperatorProgressing: | ||
| cvProgressing = cond.Status == configv1.ConditionTrue | ||
| } | ||
| } | ||
| o.Expect(cvAvailable).To(o.BeTrue(), "ClusterVersion should be Available") | ||
| o.Expect(cvProgressing).To(o.BeFalse(), "ClusterVersion should not be Progressing") | ||
| framework.Logf("ClusterVersion %s: Available=%v Progressing=%v", | ||
| cv.Status.Desired.Version, cvAvailable, cvProgressing) | ||
|
|
||
| g.By("Getting a worker node for inspection") | ||
| workerNodes, err := getNodesByLabel(ctx, oc, "node-role.kubernetes.io/worker") | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to list worker nodes") | ||
| o.Expect(workerNodes).NotTo(o.BeEmpty(), "expected at least one worker node") | ||
| targetNode := workerNodes[0].Name | ||
| framework.Logf("Using worker node: %s", targetNode) | ||
|
|
||
| g.By("Checking RHCOS 9 is reported in /etc/os-release on the worker node") | ||
| osRelease, err := ExecOnNodeWithChroot(oc, targetNode, "cat", "/etc/os-release") | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to read /etc/os-release on node %s", targetNode) | ||
| o.Expect(osRelease).To(o.ContainSubstring("VARIANT_ID=coreos"), | ||
| "expected RHCOS (VARIANT_ID=coreos) on node %s", targetNode) | ||
| o.Expect(osRelease).To(o.ContainSubstring(`VERSION_ID="9.`), | ||
| "expected RHCOS 9 (VERSION_ID=\"9.x\") on node %s", targetNode) | ||
| framework.Logf("Confirmed: node %s is running RHCOS 9", targetNode) | ||
|
|
||
| g.By("Checking no ContainerRuntimeConfig resources exist") | ||
| mcClient, err := mcclient.NewForConfig(oc.KubeFramework().ClientConfig()) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to create MachineConfig client") | ||
| ctrcfgList, err := mcClient.MachineconfigurationV1().ContainerRuntimeConfigs().List(ctx, metav1.ListOptions{}) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to list ContainerRuntimeConfigs") | ||
| o.Expect(ctrcfgList.Items).To(o.BeEmpty(), | ||
| "expected no ContainerRuntimeConfigs on a fresh cluster, found %d item(s)", len(ctrcfgList.Items)) | ||
| framework.Logf("Confirmed: no custom ContainerRuntimeConfig exists") | ||
|
|
||
| g.By("Checking CRI-O default_runtime is crun on the worker node") | ||
| crioConfig, err := ExecOnNodeWithChroot(oc, targetNode, "crio", "status", "config") | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to get CRI-O status config on node %s", targetNode) | ||
| o.Expect(crioConfig).To(o.ContainSubstring(`default_runtime = "crun"`), | ||
| "expected CRI-O default_runtime to be crun on node %s", targetNode) | ||
| framework.Logf("Confirmed: CRI-O default_runtime is crun on node %s", targetNode) | ||
|
|
||
| g.By("Checking machine-config ClusterOperator is Available and not Degraded") | ||
| co, err := oc.AdminConfigClient().ConfigV1().ClusterOperators().Get(ctx, "machine-config", metav1.GetOptions{}) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to get machine-config ClusterOperator") | ||
| var mcAvailable, mcProgressing, mcDegraded bool | ||
| for _, cond := range co.Status.Conditions { | ||
| switch cond.Type { | ||
| case configv1.OperatorAvailable: | ||
| mcAvailable = cond.Status == configv1.ConditionTrue | ||
| case configv1.OperatorProgressing: | ||
| mcProgressing = cond.Status == configv1.ConditionTrue | ||
| case configv1.OperatorDegraded: | ||
| mcDegraded = cond.Status == configv1.ConditionTrue | ||
| } | ||
| } | ||
| o.Expect(mcAvailable).To(o.BeTrue(), "machine-config ClusterOperator should be Available") | ||
| o.Expect(mcProgressing).To(o.BeFalse(), "machine-config ClusterOperator should not be Progressing") | ||
| o.Expect(mcDegraded).To(o.BeFalse(), "machine-config ClusterOperator should not be Degraded") | ||
| framework.Logf("Confirmed: machine-config ClusterOperator is healthy (Available=true Progressing=false Degraded=false)") | ||
|
|
||
| g.By("Creating a test pod with ubi9-minimal image") | ||
| namespace := oc.Namespace() | ||
| pod := &corev1.Pod{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: "test-fresh-crun", | ||
| Namespace: namespace, | ||
| }, | ||
| Spec: corev1.PodSpec{ | ||
| NodeSelector: map[string]string{ | ||
| "kubernetes.io/hostname": targetNode, | ||
| }, | ||
| RestartPolicy: corev1.RestartPolicyNever, | ||
| Containers: []corev1.Container{ | ||
| { | ||
| Name: "ubi-minimal", | ||
| Image: image.ShellImage(), | ||
| Command: []string{"echo", "crun-fresh-install-test-passed"}, | ||
| }, | ||
| }, | ||
| }, | ||
| } | ||
| _, err = oc.KubeClient().CoreV1().Pods(namespace).Create(ctx, pod, metav1.CreateOptions{}) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to create test pod") | ||
|
|
||
| g.By("Waiting for the test pod to reach Succeeded phase") | ||
| err = e2epod.WaitForPodSuccessInNamespaceTimeout(ctx, oc.KubeClient(), pod.Name, namespace, 2*time.Minute) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "test pod did not complete successfully with crun runtime") | ||
|
|
||
| resultPod, err := oc.KubeClient().CoreV1().Pods(namespace).Get(ctx, pod.Name, metav1.GetOptions{}) | ||
| o.Expect(err).NotTo(o.HaveOccurred(), "failed to get test pod after completion") | ||
| o.Expect(resultPod.Status.Phase).To(o.Equal(corev1.PodSucceeded), | ||
| "test pod should have Succeeded, got phase: %s", resultPod.Status.Phase) | ||
| framework.Logf("Test PASSED: RHCOS 9 cluster uses crun as default runtime and workloads run successfully") | ||
| }) | ||
| }) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| # Test Plan: runc Deprecation Cases | ||
|
|
||
| ## Metadata | ||
|
|
||
| | Field | Value | | ||
| |---------------------|-------| | ||
| | **Test file** | `test/extended/node/runcdeprecationcases.go` | | ||
| | **Package** | `node` | | ||
| | **Test suite** | `[Jira:Node][sig-node] runc deprecation cases` | | ||
| | **Feature** | [OCPSTRAT-3154](https://redhat.atlassian.net/browse/OCPSTRAT-3154) — runc deprecation warning in OCP 5.0 for clusters upgrading from 4.22 | | ||
| | **Epic** | [OCPNODE-4013](https://redhat.atlassian.net/browse/OCPNODE-4013) — Block upgrade from RHCOS 9 to RHCOS 10 when runc is in use | | ||
| | **User Story** | [OCPNODE-4567](https://redhat.atlassian.net/browse/OCPNODE-4567) | | ||
| | **Assignee** | Aditi Sahay (asahay@redhat.com) | | ||
| | **Component** | `sig-node`, MCO, CRI-O | | ||
| | **Test type** | E2E / functional | | ||
| | **Ginkgo label** | `[Jira:Node][sig-node]` | | ||
| | **Disruptive** | No | | ||
| | **Requires reboot** | No | | ||
|
|
||
| --- | ||
|
|
||
| ## UseCase3: Fresh Install on RHCOS 9 with crun | ||
|
|
||
| ### Description | ||
|
|
||
| A freshly installed OpenShift cluster on RHCOS 9 uses **crun** as the default container runtime. | ||
| This is the standard out-of-the-box configuration — no custom `ContainerRuntimeConfig` should be | ||
| present, and `crun` must be the CRI-O default on all worker nodes. | ||
|
|
||
| ### Scope | ||
|
|
||
| | Item | Value | | ||
| |----------------------------|-------| | ||
| | **OpenShift versions** | 5.0, 5.1, 5.2 (fresh install) | | ||
| | **OS** | RHCOS 9 (`VARIANT_ID=coreos`, `VERSION_ID=9.x`) | | ||
| | **Default runtime** | `crun` | | ||
| | **ContainerRuntimeConfig** | None (no custom CRC expected) | | ||
| | **Skip conditions** | MicroShift, Hypershift (external control plane) | | ||
|
|
||
| ### Test Function | ||
|
|
||
| ```go | ||
| g.It("RHCOS 9 cluster install should use crun as the default container runtime") | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## What This Test Validates | ||
|
|
||
| This test verifies that a fresh RHCOS 9 cluster has `crun` configured as the default container | ||
| runtime with no custom overrides, and that the cluster is fully healthy. It performs the following | ||
| validations in sequence: | ||
|
|
||
| 1. **Cluster health** — Confirms the `ClusterVersion` is `Available=True` and `Progressing=False`, | ||
| indicating the cluster is stable before any further checks. | ||
|
|
||
| 2. **RHCOS 9 OS identity** — Selects a worker node and reads `/etc/os-release` via `oc debug` to | ||
| confirm `VARIANT_ID=coreos` (confirms RHCOS, not plain RHEL) and `VERSION_ID=9.x` (confirms | ||
| RHCOS 9 major version). | ||
|
|
||
| 3. **No custom ContainerRuntimeConfig** — Lists all `ContainerRuntimeConfig` objects cluster-wide | ||
| and asserts the list is empty. This confirms no administrator-applied runtime override is present, | ||
| which is the expected state on a fresh install. | ||
|
|
||
| 4. **CRI-O default runtime is crun** — Reads the effective CRI-O configuration on the worker node | ||
| (`crio status config`) and asserts `default_runtime = "crun"`. This is the authoritative | ||
| on-node check that crun is active, independent of the API-level CRC check above. | ||
|
|
||
| 5. **machine-config ClusterOperator health** — Verifies the `machine-config` ClusterOperator | ||
| conditions: `Available=True`, `Progressing=False`, `Degraded=False`. A degraded MCO could | ||
| indicate the runc guard (from MCO PR [#5891](https://github.com/openshift/machine-config-operator/pull/5891)) | ||
| has incorrectly fired on a valid crun cluster. | ||
|
|
||
| 6. **Functional workload execution** — Creates a test pod pinned to the inspected worker node using | ||
| the framework shell image and waits for it to reach `Succeeded` phase. This confirms the crun | ||
| runtime can successfully pull and execute containers end-to-end. | ||
|
|
||
| This test is **read-only and non-disruptive** — it does not create or modify any | ||
| `MachineConfig`, `ContainerRuntimeConfig`, or node configuration. | ||
|
|
||
| --- | ||
|
|
||
| ## Pass/Fail Criteria | ||
|
|
||
| | Check | Pass condition | | ||
| |----------------------------------------|----------------| | ||
| | ClusterVersion Available | `AVAILABLE=True`, `PROGRESSING=False` | | ||
| | RHCOS version on worker node | `VARIANT_ID=coreos` and `VERSION_ID="9.x"` | | ||
| | No ContainerRuntimeConfig | List is empty (no custom CRC present) | | ||
| | CRI-O default runtime | `default_runtime = "crun"` in `crio status config` | | ||
| | machine-config ClusterOperator healthy | `Available=True`, `Progressing=False`, `Degraded=False` | | ||
| | Test workload runs successfully | Pod reaches `Succeeded` phase on the inspected node | | ||
|
|
||
| --- | ||
|
|
||
| ## Related Links | ||
|
|
||
| - **This PR**: [openshift/origin#31257](https://github.com/openshift/origin/pull/31257) — contains `test/extended/node/runcdeprecationcases.go` and `test/extended/node/runcdeprecationcases.md` | ||
| - Strategy: [OCPSTRAT-3154](https://redhat.atlassian.net/browse/OCPSTRAT-3154) | ||
| - Epic: [OCPNODE-4013](https://redhat.atlassian.net/browse/OCPNODE-4013) | ||
| - User Story: [OCPNODE-4567](https://redhat.atlassian.net/browse/OCPNODE-4567) | ||
| - Design doc: `OCPNODE-4013-design-and-use-cases.md` (§5g / UC-7) | ||
| - MCO guard PR: [openshift/machine-config-operator#5891](https://github.com/openshift/machine-config-operator/pull/5891) | ||
| - Related test: `test/extended/node/node_swap.go` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.