Skip to content

Commit 57f1b79

Browse files
authored
Merge pull request #1813 from marquiz/devel/gc-metalister
nfd-gc: only fetch object metadata
2 parents b2f2888 + 54befff commit 57f1b79

File tree

2 files changed

+82
-78
lines changed

2 files changed

+82
-78
lines changed

pkg/nfd-gc/nfd-gc.go

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,28 @@ import (
2121
"fmt"
2222
"time"
2323

24-
topologyclientset "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/generated/clientset/versioned"
24+
topologyv1alpha2 "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2"
2525
corev1 "k8s.io/api/core/v1"
2626
"k8s.io/apimachinery/pkg/api/errors"
2727
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2828
"k8s.io/apimachinery/pkg/labels"
2929
"k8s.io/apimachinery/pkg/util/sets"
30-
"k8s.io/client-go/informers"
31-
"k8s.io/client-go/kubernetes"
30+
metadataclient "k8s.io/client-go/metadata"
31+
"k8s.io/client-go/metadata/metadatainformer"
3232
"k8s.io/client-go/tools/cache"
3333
"k8s.io/klog/v2"
3434

35-
nfdclientset "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned"
3635
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
3736
"sigs.k8s.io/node-feature-discovery/pkg/utils"
3837
"sigs.k8s.io/node-feature-discovery/pkg/version"
3938
)
4039

40+
var (
41+
gvrNF = nfdv1alpha1.SchemeGroupVersion.WithResource("nodefeatures")
42+
gvrNRT = topologyv1alpha2.SchemeGroupVersion.WithResource("noderesourcetopologies")
43+
gvrNode = corev1.SchemeGroupVersion.WithResource("nodes")
44+
)
45+
4146
// Args are the command line arguments
4247
type Args struct {
4348
GCPeriod time.Duration
@@ -51,11 +56,10 @@ type NfdGarbageCollector interface {
5156
}
5257

5358
type nfdGarbageCollector struct {
54-
args *Args
55-
stopChan chan struct{}
56-
nfdClient nfdclientset.Interface
57-
topoClient topologyclientset.Interface
58-
factory informers.SharedInformerFactory
59+
args *Args
60+
stopChan chan struct{}
61+
client metadataclient.Interface
62+
factory metadatainformer.SharedInformerFactory
5963
}
6064

6165
func New(args *Args) (NfdGarbageCollector, error) {
@@ -64,20 +68,19 @@ func New(args *Args) (NfdGarbageCollector, error) {
6468
return nil, err
6569
}
6670

67-
clientset := kubernetes.NewForConfigOrDie(kubeconfig)
71+
cli := metadataclient.NewForConfigOrDie(kubeconfig)
6872

6973
return &nfdGarbageCollector{
70-
args: args,
71-
stopChan: make(chan struct{}),
72-
topoClient: topologyclientset.NewForConfigOrDie(kubeconfig),
73-
nfdClient: nfdclientset.NewForConfigOrDie(kubeconfig),
74-
factory: informers.NewSharedInformerFactory(clientset, 5*time.Minute),
74+
args: args,
75+
stopChan: make(chan struct{}),
76+
client: cli,
77+
factory: metadatainformer.NewSharedInformerFactory(cli, 0),
7578
}, nil
7679
}
7780

7881
func (n *nfdGarbageCollector) deleteNodeFeature(namespace, name string) {
7982
kind := "NodeFeature"
80-
if err := n.nfdClient.NfdV1alpha1().NodeFeatures(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil {
83+
if err := n.client.Resource(gvrNF).Namespace(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil {
8184
if errors.IsNotFound(err) {
8285
klog.V(2).InfoS("NodeFeature not found, omitting deletion", "nodefeature", klog.KRef(namespace, name))
8386
return
@@ -93,7 +96,7 @@ func (n *nfdGarbageCollector) deleteNodeFeature(namespace, name string) {
9396

9497
func (n *nfdGarbageCollector) deleteNRT(nodeName string) {
9598
kind := "NodeResourceTopology"
96-
if err := n.topoClient.TopologyV1alpha2().NodeResourceTopologies().Delete(context.TODO(), nodeName, metav1.DeleteOptions{}); err != nil {
99+
if err := n.client.Resource(gvrNRT).Delete(context.TODO(), nodeName, metav1.DeleteOptions{}); err != nil {
97100
if errors.IsNotFound(err) {
98101
klog.V(2).InfoS("NodeResourceTopology not found, omitting deletion", "nodeName", nodeName)
99102
return
@@ -115,17 +118,18 @@ func (n *nfdGarbageCollector) deleteNodeHandler(object interface{}) {
115118
obj = deletedFinalStateUnknown.Obj
116119
}
117120

118-
node, ok := obj.(*corev1.Node)
121+
meta, ok := obj.(*metav1.PartialObjectMetadata)
119122
if !ok {
120-
klog.InfoS("cannot convert object to v1.Node", "object", object)
123+
klog.InfoS("cannot convert object to metav1.ObjectMeta", "object", object)
121124
return
122125
}
126+
nodeName := meta.ObjectMeta.GetName()
123127

124-
n.deleteNRT(node.GetName())
128+
n.deleteNRT(nodeName)
125129

126130
// Delete all NodeFeature objects (from all namespaces) targeting the deleted node
127-
nfListOptions := metav1.ListOptions{LabelSelector: nfdv1alpha1.NodeFeatureObjNodeNameLabel + "=" + node.GetName()}
128-
if nfs, err := n.nfdClient.NfdV1alpha1().NodeFeatures("").List(context.TODO(), nfListOptions); err != nil {
131+
nfListOptions := metav1.ListOptions{LabelSelector: nfdv1alpha1.NodeFeatureObjNodeNameLabel + "=" + nodeName}
132+
if nfs, err := n.client.Resource(gvrNF).List(context.TODO(), nfListOptions); err != nil {
129133
klog.ErrorS(err, "failed to list NodeFeature objects")
130134
} else {
131135
for _, nf := range nfs.Items {
@@ -137,24 +141,25 @@ func (n *nfdGarbageCollector) deleteNodeHandler(object interface{}) {
137141
// garbageCollect removes all stale API objects
138142
func (n *nfdGarbageCollector) garbageCollect() {
139143
klog.InfoS("performing garbage collection")
140-
nodes, err := n.factory.Core().V1().Nodes().Lister().List(labels.Everything())
144+
objs, err := n.factory.ForResource(gvrNode).Lister().List(labels.Everything())
141145
if err != nil {
142146
klog.ErrorS(err, "failed to list Node objects")
143147
return
144148
}
145149
nodeNames := sets.NewString()
146-
for _, node := range nodes {
147-
nodeNames.Insert(node.Name)
150+
for _, obj := range objs {
151+
meta := obj.(*metav1.PartialObjectMetadata).ObjectMeta
152+
nodeNames.Insert(meta.Name)
148153
}
149154

150155
// Handle NodeFeature objects
151-
nfs, err := n.nfdClient.NfdV1alpha1().NodeFeatures("").List(context.TODO(), metav1.ListOptions{})
156+
objMetas, err := n.client.Resource(gvrNF).List(context.TODO(), metav1.ListOptions{})
152157
if errors.IsNotFound(err) {
153158
klog.V(2).InfoS("NodeFeature CRD does not exist")
154159
} else if err != nil {
155160
klog.ErrorS(err, "failed to list NodeFeature objects")
156161
} else {
157-
for _, nf := range nfs.Items {
162+
for _, nf := range objMetas.Items {
158163
nodeName, ok := nf.GetLabels()[nfdv1alpha1.NodeFeatureObjNodeNameLabel]
159164
if !ok {
160165
klog.InfoS("node name label missing from NodeFeature object", "nodefeature", klog.KObj(&nf))
@@ -166,13 +171,13 @@ func (n *nfdGarbageCollector) garbageCollect() {
166171
}
167172

168173
// Handle NodeResourceTopology objects
169-
nrts, err := n.topoClient.TopologyV1alpha2().NodeResourceTopologies().List(context.TODO(), metav1.ListOptions{})
174+
objMetas, err = n.client.Resource(gvrNRT).List(context.TODO(), metav1.ListOptions{})
170175
if errors.IsNotFound(err) {
171176
klog.V(2).InfoS("NodeResourceTopology CRD does not exist")
172177
} else if err != nil {
173178
klog.ErrorS(err, "failed to list NodeResourceTopology objects")
174179
} else {
175-
for _, nrt := range nrts.Items {
180+
for _, nrt := range objMetas.Items {
176181
if !nodeNames.Has(nrt.Name) {
177182
n.deleteNRT(nrt.Name)
178183
}
@@ -199,7 +204,7 @@ func (n *nfdGarbageCollector) periodicGC(gcPeriod time.Duration) {
199204
}
200205

201206
func (n *nfdGarbageCollector) startNodeInformer() error {
202-
nodeInformer := n.factory.Core().V1().Nodes().Informer()
207+
nodeInformer := n.factory.ForResource(gvrNode).Informer()
203208

204209
if _, err := nodeInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
205210
DeleteFunc: n.deleteNodeHandler,

pkg/nfd-gc/nfd-gc_test.go

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,16 @@ import (
2121
"testing"
2222
"time"
2323

24-
"github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2"
25-
topologyclientset "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/generated/clientset/versioned"
26-
faketopologyv1alpha2 "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/generated/clientset/versioned/fake"
24+
topologyv1alpha2 "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/apis/topology/v1alpha2"
25+
2726
corev1 "k8s.io/api/core/v1"
2827
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2928
"k8s.io/apimachinery/pkg/runtime"
3029
"k8s.io/apimachinery/pkg/util/sets"
31-
"k8s.io/client-go/informers"
32-
k8sclientset "k8s.io/client-go/kubernetes"
33-
fakek8sclientset "k8s.io/client-go/kubernetes/fake"
34-
fakenfdclientset "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/fake"
30+
metadataclient "k8s.io/client-go/metadata"
31+
"k8s.io/client-go/metadata/fake"
32+
fakemetadataclient "k8s.io/client-go/metadata/fake"
33+
"k8s.io/client-go/metadata/metadatainformer"
3534

3635
. "github.com/smartystreets/goconvey/convey"
3736
)
@@ -43,7 +42,7 @@ func TestNRTGC(t *testing.T) {
4342
errChan := make(chan error)
4443
go func() { errChan <- gc.Run() }()
4544

46-
So(waitForNRT(gc.topoClient), ShouldBeTrue)
45+
So(waitForNRT(gc.client), ShouldBeTrue)
4746

4847
gc.Stop()
4948
So(<-errChan, ShouldBeNil)
@@ -54,7 +53,7 @@ func TestNRTGC(t *testing.T) {
5453
errChan := make(chan error)
5554
go func() { errChan <- gc.Run() }()
5655

57-
So(waitForNRT(gc.topoClient, "node1"), ShouldBeTrue)
56+
So(waitForNRT(gc.client, "node1"), ShouldBeTrue)
5857

5958
gc.Stop()
6059
So(<-errChan, ShouldBeNil)
@@ -65,85 +64,85 @@ func TestNRTGC(t *testing.T) {
6564
errChan := make(chan error)
6665
go func() { errChan <- gc.Run() }()
6766

68-
err := gc.k8sClient.CoreV1().Nodes().Delete(context.TODO(), "node1", metav1.DeleteOptions{})
67+
gvr := corev1.SchemeGroupVersion.WithResource("nodes")
68+
err := gc.client.Resource(gvr).Delete(context.TODO(), "node1", metav1.DeleteOptions{})
6969
So(err, ShouldBeNil)
7070

71-
So(waitForNRT(gc.topoClient, "node2"), ShouldBeTrue)
71+
So(waitForNRT(gc.client, "node2"), ShouldBeTrue)
7272
})
7373
Convey("periodic GC should remove obsolete NRT", t, func() {
7474
gc := newMockGC([]string{"node1", "node2"}, []string{"node1", "node2"})
7575
// Override period to run fast
7676
gc.args.GCPeriod = 100 * time.Millisecond
7777

78-
nrt := v1alpha2.NodeResourceTopology{
79-
ObjectMeta: metav1.ObjectMeta{
80-
Name: "not-existing",
81-
},
82-
}
78+
nrt := createPartialObjectMetadata("topology.node.k8s.io/v1alpha2", "NodeResourceTopology", "", "not-existing")
8379

8480
errChan := make(chan error)
8581
go func() { errChan <- gc.Run() }()
8682

87-
_, err := gc.topoClient.TopologyV1alpha2().NodeResourceTopologies().Create(context.TODO(), &nrt, metav1.CreateOptions{})
83+
gvr := topologyv1alpha2.SchemeGroupVersion.WithResource("noderesourcetopologies")
84+
_, err := gc.client.Resource(gvr).(fake.MetadataClient).CreateFake(nrt, metav1.CreateOptions{})
8885
So(err, ShouldBeNil)
8986

90-
So(waitForNRT(gc.topoClient, "node1", "node2"), ShouldBeTrue)
87+
So(waitForNRT(gc.client, "node1", "node2"), ShouldBeTrue)
9188
})
9289
}
9390

9491
func newMockGC(nodes, nrts []string) *mockGC {
95-
k8sClient := fakek8sclientset.NewSimpleClientset(createFakeNodes(nodes...)...)
92+
// Create fake objects
93+
objs := []runtime.Object{}
94+
for _, name := range nodes {
95+
objs = append(objs, createPartialObjectMetadata("v1", "Node", "", name))
96+
}
97+
for _, name := range nrts {
98+
objs = append(objs, createPartialObjectMetadata("topology.node.k8s.io/v1alpha2", "NodeResourceTopology", "", name))
99+
}
100+
101+
scheme := fake.NewTestScheme()
102+
_ = metav1.AddMetaToScheme(scheme)
103+
cli := fakemetadataclient.NewSimpleMetadataClient(scheme, objs...)
96104
return &mockGC{
97105
nfdGarbageCollector: nfdGarbageCollector{
98-
factory: informers.NewSharedInformerFactory(k8sClient, 5*time.Minute),
99-
nfdClient: fakenfdclientset.NewSimpleClientset(),
100-
topoClient: faketopologyv1alpha2.NewSimpleClientset(createFakeNRTs(nrts...)...),
101-
stopChan: make(chan struct{}),
106+
factory: metadatainformer.NewSharedInformerFactory(cli, 0),
107+
client: cli,
108+
stopChan: make(chan struct{}),
102109
args: &Args{
103110
GCPeriod: 10 * time.Minute,
104111
},
105112
},
106-
k8sClient: k8sClient,
113+
client: cli,
107114
}
108115
}
109116

110-
func createFakeNodes(names ...string) []runtime.Object {
111-
nodes := make([]runtime.Object, len(names))
112-
for i, n := range names {
113-
nodes[i] = &corev1.Node{
114-
ObjectMeta: metav1.ObjectMeta{
115-
Name: n,
116-
}}
117-
}
118-
return nodes
119-
}
120-
121-
func createFakeNRTs(names ...string) []runtime.Object {
122-
nrts := make([]runtime.Object, len(names))
123-
for i, n := range names {
124-
nrts[i] = &v1alpha2.NodeResourceTopology{
125-
ObjectMeta: metav1.ObjectMeta{
126-
Name: n,
127-
}}
117+
func createPartialObjectMetadata(apiVersion, kind, namespace, name string) *metav1.PartialObjectMetadata {
118+
return &metav1.PartialObjectMetadata{
119+
TypeMeta: metav1.TypeMeta{
120+
APIVersion: apiVersion,
121+
Kind: kind,
122+
},
123+
ObjectMeta: metav1.ObjectMeta{
124+
Namespace: namespace,
125+
Name: name,
126+
},
128127
}
129-
return nrts
130128
}
131129

132130
type mockGC struct {
133131
nfdGarbageCollector
134132

135-
k8sClient k8sclientset.Interface
133+
client metadataclient.Interface
136134
}
137135

138-
func waitForNRT(cli topologyclientset.Interface, names ...string) bool {
136+
func waitForNRT(cli metadataclient.Interface, names ...string) bool {
139137
nameSet := sets.NewString(names...)
138+
gvr := topologyv1alpha2.SchemeGroupVersion.WithResource("noderesourcetopologies")
140139
for i := 0; i < 2; i++ {
141-
nrts, err := cli.TopologyV1alpha2().NodeResourceTopologies().List(context.TODO(), metav1.ListOptions{})
140+
rsp, err := cli.Resource(gvr).List(context.TODO(), metav1.ListOptions{})
142141
So(err, ShouldBeNil)
143142

144143
nrtNames := sets.NewString()
145-
for _, nrt := range nrts.Items {
146-
nrtNames.Insert(nrt.Name)
144+
for _, meta := range rsp.Items {
145+
nrtNames.Insert(meta.Name)
147146
}
148147

149148
if nrtNames.Equal(nameSet) {

0 commit comments

Comments
 (0)