diff --git a/bindata/network/ovn-kubernetes/dpu-rbac.yaml b/bindata/network/ovn-kubernetes/dpu-rbac.yaml new file mode 100644 index 0000000000..d028530b8c --- /dev/null +++ b/bindata/network/ovn-kubernetes/dpu-rbac.yaml @@ -0,0 +1,16 @@ +--- +# Grant lease permissions to the DPU service account so the DPU can renew +# the health check lease in the openshift-ovn-kubernetes namespace. +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: openshift-ovn-kubernetes-node-dpu-service-limited + namespace: openshift-ovn-kubernetes +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: openshift-ovn-kubernetes-node-limited +subjects: +- kind: ServiceAccount + name: ovn-kubernetes-node-dpu-service + namespace: openshift-ovn-kubernetes diff --git a/pkg/network/ovn_kubernetes.go b/pkg/network/ovn_kubernetes.go index 0ba767b963..82b3fec10f 100644 --- a/pkg/network/ovn_kubernetes.go +++ b/pkg/network/ovn_kubernetes.go @@ -473,6 +473,14 @@ func renderOVNKubernetes(conf *operv1.NetworkSpec, bootstrapResult *bootstrap.Bo objs = append(objs, manifests...) } + if len(bootstrapResult.OVN.OVNKubernetesConfig.DpuHostModeNodes) > 0 || len(bootstrapResult.OVN.OVNKubernetesConfig.DpuModeNodes) > 0 { + manifests, err = render.RenderTemplate(filepath.Join(manifestDir, "network/ovn-kubernetes/dpu-rbac.yaml"), &data) + if err != nil { + return nil, progressing, errors.Wrap(err, "failed to render DPU RBAC manifests") + } + objs = append(objs, manifests...) + } + if len(bootstrapResult.OVN.OVNKubernetesConfig.DpuModeNodes) > 0 { // "OVN_NODE_MODE" not set when render.RenderDir() called above, // so render just the error-cni.yaml with "OVN_NODE_MODE" set. diff --git a/pkg/network/ovn_kubernetes_dpu_host_test.go b/pkg/network/ovn_kubernetes_dpu_host_test.go index 3b8aef7bf8..ba44011061 100644 --- a/pkg/network/ovn_kubernetes_dpu_host_test.go +++ b/pkg/network/ovn_kubernetes_dpu_host_test.go @@ -1,6 +1,7 @@ package network import ( + "strings" "testing" "github.com/ghodss/yaml" @@ -355,3 +356,37 @@ func TestOVNKubernetesNodeSelectorOperator(t *testing.T) { } } } + +func TestOVNKubernetesDPURBAC(t *testing.T) { + g := NewGomegaWithT(t) + rbacTemplatePath := "../../bindata/network/ovn-kubernetes/dpu-rbac.yaml" + + data := render.MakeRenderData() + + objs, err := render.RenderTemplate(rbacTemplatePath, &data) + g.Expect(err).NotTo(HaveOccurred()) + + var foundRoleBinding bool + for _, obj := range objs { + if obj.GetKind() != "RoleBinding" || !strings.HasPrefix(obj.GetName(), "openshift-ovn-kubernetes-node-dpu-service") { + continue + } + foundRoleBinding = true + g.Expect(obj.GetName()).To(Equal("openshift-ovn-kubernetes-node-dpu-service-limited")) + + subjects, found, err := uns.NestedSlice(obj.Object, "subjects") + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(found).To(BeTrue()) + g.Expect(subjects).To(HaveLen(1)) + + subj := subjects[0].(map[string]interface{}) + kind, _, _ := uns.NestedString(subj, "kind") + name, _, _ := uns.NestedString(subj, "name") + g.Expect(kind).To(Equal("ServiceAccount")) + g.Expect(name).To(Equal("ovn-kubernetes-node-dpu-service")) + + roleRefName, _, _ := uns.NestedString(obj.Object, "roleRef", "name") + g.Expect(roleRefName).To(Equal("openshift-ovn-kubernetes-node-limited")) + } + g.Expect(foundRoleBinding).To(BeTrue(), "DPU service RoleBinding should be present") +}