Skip to content

Commit 67399b9

Browse files
Merge pull request #2740 from tsorya/igal/dpu_mode
MGMT-20706: fix DPU host mode support for OVN templates
2 parents 5df0166 + 9b7d43a commit 67399b9

File tree

3 files changed

+192
-0
lines changed

3 files changed

+192
-0
lines changed

bindata/network/ovn-kubernetes/managed/ovnkube-node.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ spec:
185185
- name: ovn-node-metrics-cert
186186
mountPath: /etc/pki/tls/metrics-cert
187187
readOnly: True
188+
{{ if ne .OVN_NODE_MODE "dpu-host" }}
188189
- name: kube-rbac-proxy-ovn-metrics
189190
image: {{.KubeRBACProxyImage}}
190191
command:
@@ -209,6 +210,8 @@ spec:
209210
- name: ovn-node-metrics-cert
210211
mountPath: /etc/pki/tls/metrics-cert
211212
readOnly: True
213+
{{ end }}
214+
{{ if ne .OVN_NODE_MODE "dpu-host" }}
212215
# ovn-northd: convert network objects in nbdb to flows in sbdb
213216
- name: northd
214217
image: "{{.OvnImage}}"
@@ -369,6 +372,7 @@ spec:
369372
cpu: 10m
370373
memory: 300Mi
371374
terminationMessagePolicy: FallbackToLogsOnError
375+
{{ end }}
372376

373377
# ovnkube-controller: does node-level bookkeeping and configuration
374378
- name: ovnkube-controller

bindata/network/ovn-kubernetes/self-hosted/ovnkube-node.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ spec:
220220
- name: ovn-node-metrics-cert
221221
mountPath: /etc/pki/tls/metrics-cert
222222
readOnly: True
223+
{{ if ne .OVN_NODE_MODE "dpu-host" }}
223224
- name: kube-rbac-proxy-ovn-metrics
224225
image: {{.KubeRBACProxyImage}}
225226
command:
@@ -244,6 +245,8 @@ spec:
244245
- name: ovn-node-metrics-cert
245246
mountPath: /etc/pki/tls/metrics-cert
246247
readOnly: True
248+
{{ end }}
249+
{{ if ne .OVN_NODE_MODE "dpu-host" }}
247250
# ovn-northd: convert network objects in nbdb to flows in sbdb
248251
- name: northd
249252
image: "{{.OvnImage}}"
@@ -430,6 +433,7 @@ spec:
430433
cpu: 10m
431434
memory: 300Mi
432435
terminationMessagePolicy: FallbackToLogsOnError
436+
{{ end }}
433437

434438
# ovnkube-controller: does node-level bookkeeping and configuration
435439
- name: ovnkube-controller
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package network
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ghodss/yaml"
7+
. "github.com/onsi/gomega"
8+
appsv1 "k8s.io/api/apps/v1"
9+
uns "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
10+
11+
"github.com/openshift/cluster-network-operator/pkg/render"
12+
)
13+
14+
// TestOVNKubernetesNodeModeTemplates tests that both managed and self-hosted templates
15+
// correctly handle different OVN_NODE_MODE values for container inclusion/exclusion and YAML validity
16+
func TestOVNKubernetesNodeModeTemplates(t *testing.T) {
17+
18+
templates := []struct {
19+
name string
20+
templatePath string
21+
}{
22+
{
23+
name: "managed",
24+
templatePath: "../../bindata/network/ovn-kubernetes/managed/ovnkube-node.yaml",
25+
},
26+
{
27+
name: "self-hosted",
28+
templatePath: "../../bindata/network/ovn-kubernetes/self-hosted/ovnkube-node.yaml",
29+
},
30+
}
31+
32+
modes := []struct {
33+
name string
34+
ovnNodeMode string
35+
expectedContainers []string
36+
expectedDaemonSet string
37+
}{
38+
{
39+
name: "full mode",
40+
ovnNodeMode: "full",
41+
expectedContainers: []string{
42+
"ovn-controller",
43+
"ovn-acl-logging",
44+
"kube-rbac-proxy-node",
45+
"kube-rbac-proxy-ovn-metrics",
46+
"northd",
47+
"nbdb",
48+
"sbdb",
49+
"ovnkube-controller",
50+
},
51+
expectedDaemonSet: "ovnkube-node",
52+
},
53+
{
54+
name: "smart-nic mode",
55+
ovnNodeMode: "smart-nic",
56+
expectedContainers: []string{
57+
"ovn-controller",
58+
"ovn-acl-logging",
59+
"kube-rbac-proxy-node",
60+
"kube-rbac-proxy-ovn-metrics",
61+
"northd",
62+
"nbdb",
63+
"sbdb",
64+
"ovnkube-controller",
65+
},
66+
expectedDaemonSet: "ovnkube-node-smart-nic",
67+
},
68+
{
69+
name: "dpu-host mode",
70+
ovnNodeMode: "dpu-host",
71+
expectedContainers: []string{
72+
"kube-rbac-proxy-node",
73+
"ovnkube-controller",
74+
},
75+
expectedDaemonSet: "ovnkube-node-dpu-host",
76+
},
77+
}
78+
79+
for _, template := range templates {
80+
for _, mode := range modes {
81+
testName := template.name + "_" + mode.name
82+
t.Run(testName, func(t *testing.T) {
83+
g := NewGomegaWithT(t)
84+
85+
// Create render data
86+
data := createTestRenderData(mode.ovnNodeMode)
87+
88+
// Render the template
89+
objs, err := render.RenderTemplate(template.templatePath, &data)
90+
g.Expect(err).NotTo(HaveOccurred(), "Template rendering should succeed for %s %s", template.name, mode.name)
91+
g.Expect(objs).To(HaveLen(1), "Should render exactly one object")
92+
93+
// Verify it's a DaemonSet with correct name
94+
obj := objs[0]
95+
g.Expect(obj.GetKind()).To(Equal("DaemonSet"))
96+
g.Expect(obj.GetName()).To(Equal(mode.expectedDaemonSet))
97+
g.Expect(obj.GetNamespace()).To(Equal("openshift-ovn-kubernetes"))
98+
99+
// Extract container names
100+
containers, found, err := uns.NestedSlice(obj.Object, "spec", "template", "spec", "containers")
101+
g.Expect(err).NotTo(HaveOccurred())
102+
g.Expect(found).To(BeTrue())
103+
104+
var containerNames []string
105+
for _, container := range containers {
106+
cmap := container.(map[string]interface{})
107+
name, found, err := uns.NestedString(cmap, "name")
108+
g.Expect(err).NotTo(HaveOccurred())
109+
g.Expect(found).To(BeTrue())
110+
containerNames = append(containerNames, name)
111+
}
112+
113+
// Verify container list exactly matches expected containers
114+
expectedContainersInterface := make([]interface{}, len(mode.expectedContainers))
115+
for i, container := range mode.expectedContainers {
116+
expectedContainersInterface[i] = container
117+
}
118+
g.Expect(containerNames).To(ConsistOf(expectedContainersInterface...),
119+
"Container list for %s %s should exactly match expected containers", template.name, mode.name)
120+
121+
// Verify YAML validity - the object should be valid YAML
122+
yamlBytes, err := yaml.Marshal(obj)
123+
g.Expect(err).NotTo(HaveOccurred(), "Object should be valid YAML for %s %s", template.name, mode.name)
124+
g.Expect(yamlBytes).NotTo(BeEmpty(), "YAML should not be empty for %s %s", template.name, mode.name)
125+
126+
// Verify it can be unmarshaled back to a DaemonSet
127+
ds := &appsv1.DaemonSet{}
128+
err = yaml.Unmarshal(yamlBytes, ds)
129+
g.Expect(err).NotTo(HaveOccurred(), "Should be able to unmarshal to DaemonSet for %s %s", template.name, mode.name)
130+
g.Expect(ds.Kind).To(Equal("DaemonSet"))
131+
})
132+
}
133+
}
134+
}
135+
136+
// createTestRenderData creates a standard render data structure with all required template variables
137+
func createTestRenderData(ovnNodeMode string) render.RenderData {
138+
data := render.MakeRenderData()
139+
data.Data["OVN_NODE_MODE"] = ovnNodeMode
140+
141+
// Set required template variables to avoid rendering errors
142+
data.Data["OvnImage"] = "registry.redhat.io/openshift4/ose-ovn-kubernetes:latest"
143+
data.Data["KubeRBACProxyImage"] = "registry.redhat.io/openshift4/ose-kube-rbac-proxy:latest"
144+
data.Data["ReleaseVersion"] = "4.14.0"
145+
data.Data["KUBERNETES_SERVICE_PORT"] = "443"
146+
data.Data["KUBERNETES_SERVICE_HOST"] = "kubernetes.default.svc"
147+
data.Data["OVN_CONTROLLER_INACTIVITY_PROBE"] = "30000"
148+
data.Data["OVN_NORTHD_PROBE_INTERVAL"] = "30000"
149+
data.Data["CNIBinDir"] = "/var/lib/cni/bin"
150+
data.Data["CNIConfDir"] = "/etc/cni/net.d"
151+
data.Data["IsSNO"] = false
152+
data.Data["OVNPlatformAzure"] = false
153+
data.Data["NETWORK_NODE_IDENTITY_ENABLE"] = false
154+
data.Data["OVN_NETWORK_SEGMENTATION_ENABLE"] = false
155+
data.Data["DefaultMasqueradeNetworkCIDRs"] = ""
156+
data.Data["OVNIPsecEnable"] = false
157+
data.Data["DpuHostModeLabel"] = ""
158+
data.Data["SmartNicModeLabel"] = ""
159+
data.Data["DpuModeLabel"] = ""
160+
data.Data["MgmtPortResourceName"] = ""
161+
data.Data["HTTP_PROXY"] = ""
162+
data.Data["HTTPS_PROXY"] = ""
163+
data.Data["NO_PROXY"] = ""
164+
data.Data["NetFlowCollectors"] = ""
165+
data.Data["SFlowCollectors"] = ""
166+
data.Data["IPFIXCollectors"] = ""
167+
data.Data["IPFIXCacheMaxFlows"] = ""
168+
data.Data["IPFIXCacheActiveTimeout"] = ""
169+
data.Data["IPFIXSampling"] = ""
170+
data.Data["K8S_APISERVER"] = "https://test:8443"
171+
data.Data["OVNKubeConfigHash"] = "test-hash"
172+
173+
// Additional variables for self-hosted template
174+
data.Data["IsNetworkTypeLiveMigration"] = false
175+
data.Data["V4MasqueradeSubnet"] = ""
176+
data.Data["V6MasqueradeSubnet"] = ""
177+
data.Data["V4JoinSubnet"] = ""
178+
data.Data["V6JoinSubnet"] = ""
179+
data.Data["V4TransitSwitchSubnet"] = ""
180+
data.Data["V6TransitSwitchSubnet"] = ""
181+
data.Data["NodeIdentityCertDuration"] = "24h"
182+
183+
return data
184+
}

0 commit comments

Comments
 (0)