diff --git a/pkg/render/kubecontrollers/kube-controllers.go b/pkg/render/kubecontrollers/kube-controllers.go index 722fa5a5cd..462abd2cde 100644 --- a/pkg/render/kubecontrollers/kube-controllers.go +++ b/pkg/render/kubecontrollers/kube-controllers.go @@ -379,6 +379,12 @@ func kubeControllersRoleCommonRules(cfg *KubeControllersConfiguration) []rbacv1. }, Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, }, + { + // The IPAM GC controller uses informers to list/watch KubeVirt VMs/VMIs for IP garbage collection. + APIGroups: []string{"kubevirt.io"}, + Resources: []string{"virtualmachineinstances", "virtualmachines"}, + Verbs: []string{"get", "list", "watch"}, + }, } if cfg.Installation.KubernetesProvider.IsOpenShift() { diff --git a/pkg/render/kubecontrollers/kube-controllers_test.go b/pkg/render/kubecontrollers/kube-controllers_test.go index 35ca3294ea..f5d380e3d4 100644 --- a/pkg/render/kubecontrollers/kube-controllers_test.go +++ b/pkg/render/kubecontrollers/kube-controllers_test.go @@ -138,6 +138,19 @@ var _ = Describe("kube-controllers rendering tests", func() { })) }) + It("should include kubevirt.io RBAC rules in calico-kube-controllers ClusterRole", func() { + component := kubecontrollers.NewCalicoKubeControllers(&cfg) + Expect(component.ResolveImages(nil)).To(BeNil()) + resources, _ := component.Objects() + + role := rtest.GetResource(resources, "calico-kube-controllers", "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) + Expect(role.Rules).To(ContainElement(rbacv1.PolicyRule{ + APIGroups: []string{"kubevirt.io"}, + Resources: []string{"virtualmachineinstances", "virtualmachines"}, + Verbs: []string{"get", "list", "watch"}, + })) + }) + It("should render all resources for a custom configuration", func() { expectedResources := []struct { name string @@ -252,7 +265,7 @@ var _ = Describe("kube-controllers rendering tests", func() { Expect(len(dp.Spec.Template.Spec.Volumes)).To(Equal(1)) clusterRole := rtest.GetResource(resources, kubecontrollers.KubeControllerRole, "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) - Expect(clusterRole.Rules).To(HaveLen(24), "cluster role should have 24 rules") + Expect(clusterRole.Rules).To(HaveLen(25), "cluster role should have 25 rules") ms := rtest.GetResource(resources, kubecontrollers.KubeControllerMetrics, common.CalicoNamespace, "", "v1", "Service").(*corev1.Service) Expect(ms.Spec.ClusterIP).To(Equal("None"), "metrics service should be headless") @@ -339,7 +352,7 @@ var _ = Describe("kube-controllers rendering tests", func() { Expect(dp.Spec.Template.Spec.Volumes[0].ConfigMap.Name).To(Equal("tigera-ca-bundle")) clusterRole := rtest.GetResource(resources, kubecontrollers.EsKubeControllerRole, "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) - Expect(clusterRole.Rules).To(HaveLen(22), "cluster role should have 22 rules") + Expect(clusterRole.Rules).To(HaveLen(23), "cluster role should have 23 rules") Expect(clusterRole.Rules).To(ContainElement( rbacv1.PolicyRule{ APIGroups: []string{""}, @@ -550,7 +563,7 @@ var _ = Describe("kube-controllers rendering tests", func() { Expect(dp.Spec.Template.Spec.Containers[0].Image).To(Equal("test-reg/tigera/kube-controllers:" + components.ComponentTigeraKubeControllers.Version)) clusterRole := rtest.GetResource(resources, kubecontrollers.EsKubeControllerRole, "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) - Expect(clusterRole.Rules).To(HaveLen(22), "cluster role should have 22 rules") + Expect(clusterRole.Rules).To(HaveLen(23), "cluster role should have 23 rules") Expect(clusterRole.Rules).To(ContainElement( rbacv1.PolicyRule{ APIGroups: []string{""}, diff --git a/pkg/render/node.go b/pkg/render/node.go index 45174fd668..0e46efa923 100644 --- a/pkg/render/node.go +++ b/pkg/render/node.go @@ -633,6 +633,12 @@ func (c *nodeComponent) cniPluginRole() *rbacv1.ClusterRole { }, Verbs: []string{"get", "list", "create", "update", "delete"}, }, + { + // The CNI plugin reads KubeVirt resources for IPAM of KubeVirt workloads. + APIGroups: []string{"kubevirt.io"}, + Resources: []string{"virtualmachineinstances", "virtualmachines"}, + Verbs: []string{"get"}, + }, }, } return role diff --git a/pkg/render/node_test.go b/pkg/render/node_test.go index 4f7dc49ace..8b52ac2e89 100644 --- a/pkg/render/node_test.go +++ b/pkg/render/node_test.go @@ -191,6 +191,14 @@ var _ = Describe("Node rendering tests", func() { i++ } + // calico-cni-plugin clusterRole should have kubevirt.io PolicyRule for IPAM of KubeVirt workloads. + cniRole := rtest.GetResource(resources, "calico-cni-plugin", "", "rbac.authorization.k8s.io", "v1", "ClusterRole").(*rbacv1.ClusterRole) + Expect(cniRole.Rules).To(ContainElement(rbacv1.PolicyRule{ + APIGroups: []string{"kubevirt.io"}, + Resources: []string{"virtualmachineinstances", "virtualmachines"}, + Verbs: []string{"get"}, + })) + // Check CNI configmap. cniCmResource := rtest.GetResource(resources, "cni-config", "calico-system", "", "v1", "ConfigMap") Expect(cniCmResource).ToNot(BeNil())