mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-03-05 08:17:04 +00:00
nfd-gc: support garbage collection of NodeFeatures
Hook into the same logic already exercised for NodeResourceTopology objects: GC watches for node delete events and immediately drops stale objects (NRT and now also NF). In addition there is a periodic resync to catch any missed node deletes, once every hour by default.
This commit is contained in:
parent
01c08d67b6
commit
e3415ec484
2 changed files with 56 additions and 12 deletions
|
@ -33,6 +33,8 @@ import (
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
"sigs.k8s.io/node-feature-discovery/pkg/apihelper"
|
"sigs.k8s.io/node-feature-discovery/pkg/apihelper"
|
||||||
|
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
|
||||||
|
nfdclientset "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Args are the command line arguments
|
// Args are the command line arguments
|
||||||
|
@ -49,6 +51,7 @@ type NfdGarbageCollector interface {
|
||||||
|
|
||||||
type nfdGarbageCollector struct {
|
type nfdGarbageCollector struct {
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
|
nfdClient nfdclientset.Interface
|
||||||
topoClient topologyclientset.Interface
|
topoClient topologyclientset.Interface
|
||||||
gcPeriod time.Duration
|
gcPeriod time.Duration
|
||||||
factory informers.SharedInformerFactory
|
factory informers.SharedInformerFactory
|
||||||
|
@ -77,12 +80,26 @@ func newNfdGarbageCollector(config *restclient.Config, stop chan struct{}, gcPer
|
||||||
|
|
||||||
return &nfdGarbageCollector{
|
return &nfdGarbageCollector{
|
||||||
topoClient: cli,
|
topoClient: cli,
|
||||||
|
nfdClient: nfdclientset.NewForConfigOrDie(config),
|
||||||
stopChan: stop,
|
stopChan: stop,
|
||||||
gcPeriod: gcPeriod,
|
gcPeriod: gcPeriod,
|
||||||
factory: factory,
|
factory: factory,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *nfdGarbageCollector) deleteNodeFeature(namespace, name string) {
|
||||||
|
if err := n.nfdClient.NfdV1alpha1().NodeFeatures(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil {
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
klog.V(2).InfoS("NodeFeature not found, omitting deletion", "nodefeature", klog.KRef(namespace, name))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
klog.ErrorS(err, "failed to delete NodeFeature object", "nodefeature", klog.KRef(namespace, name))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
klog.InfoS("NodeFeature object has been deleted", "nodefeature", klog.KRef(namespace, name))
|
||||||
|
}
|
||||||
|
|
||||||
func (n *nfdGarbageCollector) deleteNRT(nodeName string) {
|
func (n *nfdGarbageCollector) deleteNRT(nodeName string) {
|
||||||
if err := n.topoClient.TopologyV1alpha2().NodeResourceTopologies().Delete(context.TODO(), nodeName, metav1.DeleteOptions{}); err != nil {
|
if err := n.topoClient.TopologyV1alpha2().NodeResourceTopologies().Delete(context.TODO(), nodeName, metav1.DeleteOptions{}); err != nil {
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
|
@ -111,6 +128,16 @@ func (n *nfdGarbageCollector) deleteNodeHandler(object interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
n.deleteNRT(node.GetName())
|
n.deleteNRT(node.GetName())
|
||||||
|
|
||||||
|
// Delete all NodeFeature objects (from all namespaces) targeting the deleted node
|
||||||
|
nfListOptions := metav1.ListOptions{LabelSelector: nfdv1alpha1.NodeFeatureObjNodeNameLabel + "=" + node.GetName()}
|
||||||
|
if nfs, err := n.nfdClient.NfdV1alpha1().NodeFeatures("").List(context.TODO(), nfListOptions); err != nil {
|
||||||
|
klog.ErrorS(err, "failed to list NodeFeature objects")
|
||||||
|
} else {
|
||||||
|
for _, nf := range nfs.Items {
|
||||||
|
n.deleteNodeFeature(nf.Namespace, nf.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// garbageCollect removes all stale API objects
|
// garbageCollect removes all stale API objects
|
||||||
|
@ -126,20 +153,35 @@ func (n *nfdGarbageCollector) garbageCollect() {
|
||||||
nodeNames.Insert(node.Name)
|
nodeNames.Insert(node.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
nrts, err := n.topoClient.TopologyV1alpha2().NodeResourceTopologies().List(context.TODO(), metav1.ListOptions{})
|
// Handle NodeFeature objects
|
||||||
if err != nil {
|
nfs, err := n.nfdClient.NfdV1alpha1().NodeFeatures("").List(context.TODO(), metav1.ListOptions{})
|
||||||
klog.ErrorS(err, "failed to list NodeResourceTopology objects")
|
if errors.IsNotFound(err) {
|
||||||
return
|
klog.V(2).InfoS("NodeFeature CRD does not exist")
|
||||||
|
} else if err != nil {
|
||||||
|
klog.ErrorS(err, "failed to list NodeFeature objects")
|
||||||
|
} else {
|
||||||
|
for _, nf := range nfs.Items {
|
||||||
|
nodeName, ok := nf.GetLabels()[nfdv1alpha1.NodeFeatureObjNodeNameLabel]
|
||||||
|
if !ok {
|
||||||
|
klog.InfoS("node name label missing from NodeFeature object", "nodefeature", klog.KObj(&nf))
|
||||||
|
}
|
||||||
|
if !nodeNames.Has(nodeName) {
|
||||||
|
n.deleteNodeFeature(nf.Namespace, nf.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, nrt := range nrts.Items {
|
// Handle NodeResourceTopology objects
|
||||||
key, err := cache.MetaNamespaceKeyFunc(&nrt)
|
nrts, err := n.topoClient.TopologyV1alpha2().NodeResourceTopologies().List(context.TODO(), metav1.ListOptions{})
|
||||||
if err != nil {
|
if errors.IsNotFound(err) {
|
||||||
klog.ErrorS(err, "failed to create key", "noderesourcetopology", klog.KObj(&nrt))
|
klog.V(2).InfoS("NodeResourceTopology CRD does not exist")
|
||||||
continue
|
} else if err != nil {
|
||||||
}
|
klog.ErrorS(err, "failed to list NodeResourceTopology objects")
|
||||||
if !nodeNames.Has(key) {
|
} else {
|
||||||
n.deleteNRT(key)
|
for _, nrt := range nrts.Items {
|
||||||
|
if !nodeNames.Has(nrt.Name) {
|
||||||
|
n.deleteNRT(nrt.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
k8sclientset "k8s.io/client-go/kubernetes"
|
k8sclientset "k8s.io/client-go/kubernetes"
|
||||||
fakek8sclientset "k8s.io/client-go/kubernetes/fake"
|
fakek8sclientset "k8s.io/client-go/kubernetes/fake"
|
||||||
|
fakenfdclientset "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned/fake"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
@ -95,6 +96,7 @@ func newMockGC(nodes, nrts []string) *mockGC {
|
||||||
return &mockGC{
|
return &mockGC{
|
||||||
nfdGarbageCollector: nfdGarbageCollector{
|
nfdGarbageCollector: nfdGarbageCollector{
|
||||||
factory: informers.NewSharedInformerFactory(k8sClient, 5*time.Minute),
|
factory: informers.NewSharedInformerFactory(k8sClient, 5*time.Minute),
|
||||||
|
nfdClient: fakenfdclientset.NewSimpleClientset(),
|
||||||
topoClient: faketopologyv1alpha2.NewSimpleClientset(createFakeNRTs(nrts...)...),
|
topoClient: faketopologyv1alpha2.NewSimpleClientset(createFakeNRTs(nrts...)...),
|
||||||
stopChan: make(chan struct{}, 1),
|
stopChan: make(chan struct{}, 1),
|
||||||
gcPeriod: 10 * time.Minute,
|
gcPeriod: 10 * time.Minute,
|
||||||
|
|
Loading…
Add table
Reference in a new issue