diff --git a/deployment/base/rbac-topologyupdater/topologyupdater-clusterrole.yaml b/deployment/base/rbac-topologyupdater/topologyupdater-clusterrole.yaml index 493f396c12..94d4e5e2cf 100644 --- a/deployment/base/rbac-topologyupdater/topologyupdater-clusterrole.yaml +++ b/deployment/base/rbac-topologyupdater/topologyupdater-clusterrole.yaml @@ -10,6 +10,12 @@ rules: verbs: - get - list +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get - apiGroups: - "" resources: diff --git a/deployment/helm/node-feature-discovery/templates/clusterrole.yaml b/deployment/helm/node-feature-discovery/templates/clusterrole.yaml index e652e1df8c..5ffb21c4d4 100644 --- a/deployment/helm/node-feature-discovery/templates/clusterrole.yaml +++ b/deployment/helm/node-feature-discovery/templates/clusterrole.yaml @@ -58,6 +58,12 @@ rules: verbs: - get - list +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get - apiGroups: - "" resources: diff --git a/pkg/nfd-topology-updater/nfd-topology-updater.go b/pkg/nfd-topology-updater/nfd-topology-updater.go index 0f8095fb8a..131547b873 100644 --- a/pkg/nfd-topology-updater/nfd-topology-updater.go +++ b/pkg/nfd-topology-updater/nfd-topology-updater.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" k8sclient "k8s.io/client-go/kubernetes" "k8s.io/klog/v2" kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1" @@ -80,6 +81,9 @@ type nfdTopologyUpdater struct { eventSource <-chan kubeletnotifier.Info configFilePath string config *NFDConfig + kubernetesNamespace string + ownerRefs []metav1.OwnerReference + k8sClient k8sclient.Interface kubeletConfigFunc func() (*kubeletconfigv1beta1.KubeletConfiguration, error) } @@ -105,6 +109,8 @@ func NewTopologyUpdater(args Args, resourcemonitorArgs resourcemonitor.Args) (Nf nodeName: utils.NodeName(), eventSource: eventSource, config: &NFDConfig{}, + kubernetesNamespace: utils.GetKubernetesNamespace(), + ownerRefs: []metav1.OwnerReference{}, kubeletConfigFunc: kubeletConfigFunc, } if args.ConfigFile != "" { @@ -146,6 +152,7 @@ func (w *nfdTopologyUpdater) Run() error { if err != nil { return err } + w.k8sClient = k8sClient if err := w.configure(); err != nil { return fmt.Errorf("faild to configure Node Feature Discovery Topology Updater: %w", err) @@ -222,11 +229,29 @@ func (w *nfdTopologyUpdater) Stop() { } func (w *nfdTopologyUpdater) updateNodeResourceTopology(zoneInfo v1alpha2.ZoneList, scanResponse resourcemonitor.ScanResponse, readKubeletConfig bool) error { + + if len(w.ownerRefs) == 0 { + ns, err := w.k8sClient.CoreV1().Namespaces().Get(context.TODO(), w.kubernetesNamespace, metav1.GetOptions{}) + if err != nil { + klog.ErrorS(err, "Cannot get NodeResourceTopology owner reference") + } else { + w.ownerRefs = []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Namespace", + Name: ns.Name, + UID: types.UID(ns.UID), + }, + } + } + } + nrt, err := w.topoClient.TopologyV1alpha2().NodeResourceTopologies().Get(context.TODO(), w.nodeName, metav1.GetOptions{}) if errors.IsNotFound(err) { nrtNew := v1alpha2.NodeResourceTopology{ ObjectMeta: metav1.ObjectMeta{ - Name: w.nodeName, + Name: w.nodeName, + OwnerReferences: w.ownerRefs, }, Zones: zoneInfo, Attributes: v1alpha2.AttributeList{}, @@ -248,6 +273,7 @@ func (w *nfdTopologyUpdater) updateNodeResourceTopology(zoneInfo v1alpha2.ZoneLi nrtMutated := nrt.DeepCopy() nrtMutated.Zones = zoneInfo + nrtMutated.OwnerReferences = w.ownerRefs attributes := scanResponse.Attributes diff --git a/test/e2e/topology_updater_test.go b/test/e2e/topology_updater_test.go index 8b463ed283..801ebb3fd2 100644 --- a/test/e2e/topology_updater_test.go +++ b/test/e2e/topology_updater_test.go @@ -261,6 +261,28 @@ var _ = NFDDescribe(Label("nfd-topology-updater"), func() { return true }, time.Minute, 5*time.Second).Should(BeTrue(), "didn't get updated node topology info") }) + + It("should check that that topology object is garbage colleted", func(ctx context.Context) { + + By("Deleting the nfd-topology namespace") + err := f.ClientSet.CoreV1().Namespaces().Delete(ctx, f.Namespace.Name, metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("checking that topology was garbage collected") + Eventually(func() bool { + t, err := topologyClient.TopologyV1alpha2().NodeResourceTopologies().Get(ctx, topologyUpdaterNode.Name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + framework.Logf("missing node topology resource for %q", topologyUpdaterNode.Name) + return false + } + framework.Logf("failed to get the node topology resource: %v", err) + return true + } + framework.Logf("topology resource: %v", t) + return true + }).WithPolling(15 * time.Second).WithTimeout(60 * time.Second).Should(BeFalse()) + }) }) When("sleep interval disabled", func() { diff --git a/test/e2e/utils/rbac.go b/test/e2e/utils/rbac.go index 8549256aa3..31d0961492 100644 --- a/test/e2e/utils/rbac.go +++ b/test/e2e/utils/rbac.go @@ -23,6 +23,7 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" clientset "k8s.io/client-go/kubernetes" ) @@ -97,7 +98,15 @@ func ConfigureRBAC(ctx context.Context, cs clientset.Interface, ns string) error // DeconfigureRBAC removes RBAC configuration func DeconfigureRBAC(ctx context.Context, cs clientset.Interface, ns string) error { - err := cs.RbacV1().ClusterRoleBindings().Delete(ctx, "nfd-topology-updater-e2e", metav1.DeleteOptions{}) + _, err := cs.CoreV1().Namespaces().Get(ctx, ns, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + err = cs.RbacV1().ClusterRoleBindings().Delete(ctx, "nfd-topology-updater-e2e", metav1.DeleteOptions{}) if err != nil { return err } @@ -251,6 +260,11 @@ func createClusterRoleTopologyUpdater(ctx context.Context, cs clientset.Interfac Resources: []string{"pods"}, Verbs: []string{"get", "list", "watch"}, }, + { + APIGroups: []string{""}, + Resources: []string{"namespaces"}, + Verbs: []string{"get"}, + }, { APIGroups: []string{"topology.node.k8s.io"}, Resources: []string{"noderesourcetopologies"},