From 9580fed78f6a135b14a3fa6a0206e816e31f46cf Mon Sep 17 00:00:00 2001 From: Chin2691 Date: Wed, 10 Jun 2026 12:36:03 +0530 Subject: [PATCH] fix(kubevirt): validate additionalNetworks name format via CEL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The additionalNetworks[].name field in KubeVirt NodePools requires Multus NAD references in / format, but no validation enforces this. Invalid names are silently accepted — NodePool reports ValidPlatformConfig=True — while VMs fail to start with errors buried 4 layers deep in the hosted control plane namespace (VM conditions set by virt-controller). Add admission-time CEL validation on the KubevirtNetwork API type: - Format: XValidation regex enforcing exactly one slash with non-empty, non-whitespace namespace and name segments - Uniqueness: listType=map with listMapKey=name for schema-level duplicate rejection - Length: MaxLength reduced from 255 to 55 to ensure the generated interface name (iface{idx+1}_{name}, max prefix iface20_ at MaxItems=20) stays within the 63-character Linux interface name limit Fixes: https://redhat.atlassian.net/browse/OCPBUGS-87991 --- api/hypershift/v1beta1/kubevirt.go | 5 +- .../AAA_ungated.yaml | 9 +- .../GCPPlatform.yaml | 9 +- .../OSStreams.yaml | 9 +- .../OpenStack.yaml | 9 +- .../stable.nodepools.kubevirt.testsuite.yaml | 269 ++++++++++++++++++ .../nodepools-CustomNoUpgrade.crd.yaml | 9 +- .../nodepools-Default.crd.yaml | 9 +- .../nodepools-TechPreviewNoUpgrade.crd.yaml | 9 +- .../api/hypershift/v1beta1/kubevirt.go | 5 +- 10 files changed, 333 insertions(+), 9 deletions(-) create mode 100644 cmd/install/assets/crds/hypershift-operator/tests/nodepools.hypershift.openshift.io/stable.nodepools.kubevirt.testsuite.yaml diff --git a/api/hypershift/v1beta1/kubevirt.go b/api/hypershift/v1beta1/kubevirt.go index cc83e14d45bc..a88c17734c5c 100644 --- a/api/hypershift/v1beta1/kubevirt.go +++ b/api/hypershift/v1beta1/kubevirt.go @@ -169,6 +169,8 @@ type KubevirtNodePoolPlatform struct { // additionalNetworks specify the extra networks attached to the nodes // // +optional + // +listType=map + // +listMapKey=name // +kubebuilder:validation:MaxItems=20 AdditionalNetworks []KubevirtNetwork `json:"additionalNetworks,omitempty"` @@ -199,7 +201,8 @@ type KubevirtNetwork struct { // name specify the network attached to the nodes // it is a value with the format "[namespace]/[name]" to reference the // multus network attachment definition - // +kubebuilder:validation:MaxLength=255 + // +kubebuilder:validation:MaxLength=55 + // +kubebuilder:validation:XValidation:rule="self.matches('^[^/\\\\s]+/[^/\\\\s]+$')",message="name must be in the format / to reference a multus network attachment definition" // +required Name string `json:"name"` } diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yaml index 9463ef0840c2..9cd5c9086ceb 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yaml @@ -1082,13 +1082,20 @@ spec: name specify the network attached to the nodes it is a value with the format "[namespace]/[name]" to reference the multus network attachment definition - maxLength: 255 + maxLength: 55 type: string + x-kubernetes-validations: + - message: name must be in the format / + to reference a multus network attachment definition + rule: self.matches('^[^/\\s]+/[^/\\s]+$') required: - name type: object maxItems: 20 type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map attachDefaultNetwork: default: true description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/GCPPlatform.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/GCPPlatform.yaml index ea37b91c13af..7ee65504ee07 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/GCPPlatform.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/GCPPlatform.yaml @@ -1349,13 +1349,20 @@ spec: name specify the network attached to the nodes it is a value with the format "[namespace]/[name]" to reference the multus network attachment definition - maxLength: 255 + maxLength: 55 type: string + x-kubernetes-validations: + - message: name must be in the format / + to reference a multus network attachment definition + rule: self.matches('^[^/\\s]+/[^/\\s]+$') required: - name type: object maxItems: 20 type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map attachDefaultNetwork: default: true description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OSStreams.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OSStreams.yaml index 686feae62fab..8313a6105066 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OSStreams.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OSStreams.yaml @@ -1115,13 +1115,20 @@ spec: name specify the network attached to the nodes it is a value with the format "[namespace]/[name]" to reference the multus network attachment definition - maxLength: 255 + maxLength: 55 type: string + x-kubernetes-validations: + - message: name must be in the format / + to reference a multus network attachment definition + rule: self.matches('^[^/\\s]+/[^/\\s]+$') required: - name type: object maxItems: 20 type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map attachDefaultNetwork: default: true description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yaml index baed37846b3e..8a4c089012f9 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yaml @@ -1082,13 +1082,20 @@ spec: name specify the network attached to the nodes it is a value with the format "[namespace]/[name]" to reference the multus network attachment definition - maxLength: 255 + maxLength: 55 type: string + x-kubernetes-validations: + - message: name must be in the format / + to reference a multus network attachment definition + rule: self.matches('^[^/\\s]+/[^/\\s]+$') required: - name type: object maxItems: 20 type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map attachDefaultNetwork: default: true description: |- diff --git a/cmd/install/assets/crds/hypershift-operator/tests/nodepools.hypershift.openshift.io/stable.nodepools.kubevirt.testsuite.yaml b/cmd/install/assets/crds/hypershift-operator/tests/nodepools.hypershift.openshift.io/stable.nodepools.kubevirt.testsuite.yaml new file mode 100644 index 000000000000..ac1b0b9d94d3 --- /dev/null +++ b/cmd/install/assets/crds/hypershift-operator/tests/nodepools.hypershift.openshift.io/stable.nodepools.kubevirt.testsuite.yaml @@ -0,0 +1,269 @@ +apiVersion: apiextensions.k8s.io/v1 +name: "NodePool KubeVirt additionalNetworks validation" +crdName: nodepools.hypershift.openshift.io +version: v1beta1 +tests: + onCreate: + # --- additionalNetworks name format validation --- + - name: when additionalNetworks name is valid namespace/name format it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "my-ns/my-nad" + type: KubeVirt + + - name: when additionalNetworks has multiple valid networks it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "ns-a/nad-1" + - name: "ns-b/nad-2" + type: KubeVirt + + - name: when additionalNetworks name has no slash it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "just-a-name" + type: KubeVirt + expectedError: "name must be in the format / to reference a multus network attachment definition" + + - name: when additionalNetworks name has multiple slashes it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "ns/sub/name" + type: KubeVirt + expectedError: "name must be in the format / to reference a multus network attachment definition" + + - name: when additionalNetworks name has empty namespace it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "/my-nad" + type: KubeVirt + expectedError: "name must be in the format / to reference a multus network attachment definition" + + - name: when additionalNetworks name has empty name segment it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "my-ns/" + type: KubeVirt + expectedError: "name must be in the format / to reference a multus network attachment definition" + + - name: when additionalNetworks name has whitespace in namespace it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: " /name" + type: KubeVirt + expectedError: "name must be in the format / to reference a multus network attachment definition" + + - name: when additionalNetworks name has whitespace in name segment it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "my-ns/my nad" + type: KubeVirt + expectedError: "name must be in the format / to reference a multus network attachment definition" + + - name: when additionalNetworks has duplicate names it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "ns/nad1" + - name: "ns/nad1" + type: KubeVirt + expectedError: "Duplicate value" + + - name: when additionalNetworks name is at max length 55 it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "my-namespace-name-that-is-long/my-nad-name-also-long-ab" + type: KubeVirt + + - name: when additionalNetworks name exceeds max length 55 it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: NodePool + spec: + arch: amd64 + clusterName: some-cluster + management: + autoRepair: false + upgradeType: Replace + release: + image: quay.io/openshift-release-dev/ocp-release:4.17.0-rc.0-x86_64 + replicas: 0 + platform: + kubevirt: + rootVolume: + type: Persistent + persistent: + size: 32Gi + additionalNetworks: + - name: "my-namespace-name-that-is-long/my-nad-name-also-long-abc" + type: KubeVirt + expectedError: "Too long" diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yaml index 5b7938038b03..cd3e8ac28250 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yaml @@ -1385,13 +1385,20 @@ spec: name specify the network attached to the nodes it is a value with the format "[namespace]/[name]" to reference the multus network attachment definition - maxLength: 255 + maxLength: 55 type: string + x-kubernetes-validations: + - message: name must be in the format / + to reference a multus network attachment definition + rule: self.matches('^[^/\\s]+/[^/\\s]+$') required: - name type: object maxItems: 20 type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map attachDefaultNetwork: default: true description: |- diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml index d317df1b41ae..57f944b56f4d 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml @@ -1085,13 +1085,20 @@ spec: name specify the network attached to the nodes it is a value with the format "[namespace]/[name]" to reference the multus network attachment definition - maxLength: 255 + maxLength: 55 type: string + x-kubernetes-validations: + - message: name must be in the format / + to reference a multus network attachment definition + rule: self.matches('^[^/\\s]+/[^/\\s]+$') required: - name type: object maxItems: 20 type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map attachDefaultNetwork: default: true description: |- diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yaml index 4d15644f9fb5..efc8239fbfd8 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yaml @@ -1385,13 +1385,20 @@ spec: name specify the network attached to the nodes it is a value with the format "[namespace]/[name]" to reference the multus network attachment definition - maxLength: 255 + maxLength: 55 type: string + x-kubernetes-validations: + - message: name must be in the format / + to reference a multus network attachment definition + rule: self.matches('^[^/\\s]+/[^/\\s]+$') required: - name type: object maxItems: 20 type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map attachDefaultNetwork: default: true description: |- diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/kubevirt.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/kubevirt.go index cc83e14d45bc..a88c17734c5c 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/kubevirt.go +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/kubevirt.go @@ -169,6 +169,8 @@ type KubevirtNodePoolPlatform struct { // additionalNetworks specify the extra networks attached to the nodes // // +optional + // +listType=map + // +listMapKey=name // +kubebuilder:validation:MaxItems=20 AdditionalNetworks []KubevirtNetwork `json:"additionalNetworks,omitempty"` @@ -199,7 +201,8 @@ type KubevirtNetwork struct { // name specify the network attached to the nodes // it is a value with the format "[namespace]/[name]" to reference the // multus network attachment definition - // +kubebuilder:validation:MaxLength=255 + // +kubebuilder:validation:MaxLength=55 + // +kubebuilder:validation:XValidation:rule="self.matches('^[^/\\\\s]+/[^/\\\\s]+$')",message="name must be in the format / to reference a multus network attachment definition" // +required Name string `json:"name"` }