diff --git a/bindata/network/ovn-kubernetes/common/008-script-lib.yaml b/bindata/network/ovn-kubernetes/common/008-script-lib.yaml index b244e6b3f8..a995f5d244 100644 --- a/bindata/network/ovn-kubernetes/common/008-script-lib.yaml +++ b/bindata/network/ovn-kubernetes/common/008-script-lib.yaml @@ -478,6 +478,18 @@ data: echo "$(date --iso-8601=seconds) [{$1}] ${2}" } + # set-encap-ip-flag() sets --encap-ip from the OVN_ENCAP_IP environment + # variable when present. + set-encap-ip-flag() + { + ovn_encap_ip_flag= + + if [[ -n "${OVN_ENCAP_IP}" ]]; then + log "encapip" "Using OVN_ENCAP_IP=${OVN_ENCAP_IP}" + ovn_encap_ip_flag="--encap-ip=${OVN_ENCAP_IP}" + fi + } + # cni-bin-copy() detects the host OS and copies the correct shim binary to # the CNI binary directory. # @@ -688,6 +700,8 @@ data: enable_interconnect_flag="--enable-interconnect" fi + set-encap-ip-flag + exec /usr/bin/ovnkube \ ${init_ovnkube_controller} \ --init-node "${K8S_NODE}" \ @@ -698,6 +712,7 @@ data: ${gateway_mode_flags} \ ${node_mgmt_port_netdev_flags} \ ${ovnkube_node_mode} \ + ${ovn_encap_ip_flag} \ --metrics-bind-address "127.0.0.1:${metrics_port}" \ --ovn-metrics-bind-address "127.0.0.1:${ovn_metrics_port}" \ --metrics-enable-pprof \ diff --git a/pkg/network/ovn_kubernetes_test.go b/pkg/network/ovn_kubernetes_test.go index 6c06d16f16..b93c0b65ae 100644 --- a/pkg/network/ovn_kubernetes_test.go +++ b/pkg/network/ovn_kubernetes_test.go @@ -4402,6 +4402,113 @@ func TestRenderOVNKubernetes_OpenFlowProbeOverride(t *testing.T) { }) } +// TestRenderOVNKubernetes_EncapIPEnvOverrideWiring verifies the rendered OVN +// script library sources per-node overrides and wires OVN_ENCAP_IP into the +// ovnkube-node command line. +func TestRenderOVNKubernetes_EncapIPEnvOverrideWiring(t *testing.T) { + g := NewGomegaWithT(t) + + crd := OVNKubernetesConfig.DeepCopy() + config := &crd.Spec + fillDefaults(config, nil) + + bootstrapResult := fakeBootstrapResult() + bootstrapResult.OVN = bootstrap.OVNBootstrapResult{ + ControlPlaneReplicaCount: 3, + OVNKubernetesConfig: &bootstrap.OVNConfigBoostrapResult{ + DpuHostModeLabel: OVN_NODE_SELECTOR_DEFAULT_DPU_HOST, + DpuModeLabel: OVN_NODE_SELECTOR_DEFAULT_DPU, + SmartNicModeLabel: OVN_NODE_SELECTOR_DEFAULT_SMART_NIC, + MgmtPortResourceName: "", + DpuNodeLeaseRenewInterval: DPU_NODE_LEASE_RENEW_INTERVAL_DEFAULT, + DpuNodeLeaseDuration: DPU_NODE_LEASE_DURATION_DEFAULT, + HyperShiftConfig: &bootstrap.OVNHyperShiftBootstrapResult{ + Enabled: false, + }, + }, + } + featureGatesCNO := getDefaultFeatureGates() + fakeClient := cnofake.NewFakeClient() + + objs, _, err := renderOVNKubernetes(config, bootstrapResult, manifestDirOvn, fakeClient, featureGatesCNO) + g.Expect(err).NotTo(HaveOccurred()) + + ovnkubeScriptLib := extractOVNScriptLib(g, objs) + g.Expect(ovnkubeScriptLib).To(ContainSubstring(`if [[ -n "${K8S_NODE}" && -f "/env/${K8S_NODE}" ]]; then`)) + g.Expect(ovnkubeScriptLib).To(ContainSubstring(`source "/env/${K8S_NODE}"`)) + g.Expect(ovnkubeScriptLib).To(ContainSubstring(`if [[ -n "${OVN_ENCAP_IP}" ]]; then`)) + g.Expect(ovnkubeScriptLib).To(ContainSubstring(`ovn_encap_ip_flag="--encap-ip=${OVN_ENCAP_IP}"`)) + g.Expect(ovnkubeScriptLib).To(ContainSubstring(`${ovn_encap_ip_flag}`)) +} + +// TestRenderOVNKubernetes_NodeDaemonSetEnvOverridesVolume verifies the +// ovnkube-node DaemonSet keeps the optional env-overrides ConfigMap mounted so +// node-specific OVN encapsulation overrides can be sourced at startup. +func TestRenderOVNKubernetes_NodeDaemonSetEnvOverridesVolume(t *testing.T) { + g := NewGomegaWithT(t) + + crd := OVNKubernetesConfig.DeepCopy() + config := &crd.Spec + fillDefaults(config, nil) + + bootstrapResult := fakeBootstrapResult() + bootstrapResult.OVN = bootstrap.OVNBootstrapResult{ + ControlPlaneReplicaCount: 3, + OVNKubernetesConfig: &bootstrap.OVNConfigBoostrapResult{ + DpuHostModeLabel: OVN_NODE_SELECTOR_DEFAULT_DPU_HOST, + DpuModeLabel: OVN_NODE_SELECTOR_DEFAULT_DPU, + SmartNicModeLabel: OVN_NODE_SELECTOR_DEFAULT_SMART_NIC, + MgmtPortResourceName: "", + DpuNodeLeaseRenewInterval: DPU_NODE_LEASE_RENEW_INTERVAL_DEFAULT, + DpuNodeLeaseDuration: DPU_NODE_LEASE_DURATION_DEFAULT, + HyperShiftConfig: &bootstrap.OVNHyperShiftBootstrapResult{ + Enabled: false, + }, + }, + } + featureGatesCNO := getDefaultFeatureGates() + fakeClient := cnofake.NewFakeClient() + + objs, _, err := renderOVNKubernetes(config, bootstrapResult, manifestDirOvn, fakeClient, featureGatesCNO) + g.Expect(err).NotTo(HaveOccurred()) + + nodeDS := findInObjs("apps", "DaemonSet", "ovnkube-node", "openshift-ovn-kubernetes", objs) + g.Expect(nodeDS).NotTo(BeNil()) + + ds := appsv1.DaemonSet{} + g.Expect(convert(nodeDS, &ds)).To(Succeed()) + + var envOverridesVolume *v1.Volume + for i := range ds.Spec.Template.Spec.Volumes { + volume := &ds.Spec.Template.Spec.Volumes[i] + if volume.Name == "env-overrides" { + envOverridesVolume = volume + break + } + } + + g.Expect(envOverridesVolume).NotTo(BeNil()) + g.Expect(envOverridesVolume.ConfigMap).NotTo(BeNil()) + g.Expect(envOverridesVolume.ConfigMap.Name).To(Equal("env-overrides")) + g.Expect(envOverridesVolume.ConfigMap.Optional).NotTo(BeNil()) + g.Expect(*envOverridesVolume.ConfigMap.Optional).To(BeTrue()) + + nodeContainer, ok := findContainer(ds.Spec.Template.Spec.Containers, "ovnkube-node") + if !ok { + nodeContainer, ok = findContainer(ds.Spec.Template.Spec.Containers, "ovnkube-controller") + } + g.Expect(ok).To(BeTrue(), "expecting container named ovnkube-node or ovnkube-controller in the DaemonSet") + + hasEnvOverridesMount := false + for _, mount := range nodeContainer.VolumeMounts { + if mount.Name == "env-overrides" && mount.MountPath == "/env" { + hasEnvOverridesMount = true + break + } + } + g.Expect(hasEnvOverridesMount).To(BeTrue()) +} + func TestRenderOVNKubernetes_AllowICMPNetworkPolicyOverride(t *testing.T) { g := NewGomegaWithT(t)