@@ -36,6 +36,7 @@ import (
3636 "k8s.io/apimachinery/pkg/api/errors"
3737 "k8s.io/apimachinery/pkg/types"
3838 "k8s.io/apimachinery/pkg/util/validation"
39+ k8sclient "k8s.io/client-go/kubernetes"
3940 "k8s.io/klog/v2"
4041 klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog"
4142 "sigs.k8s.io/yaml"
@@ -125,41 +126,84 @@ type nfdWorker struct {
125126 config * NFDConfig
126127 kubernetesNamespace string
127128 grpcClient pb.LabelerClient
128- nfdClient * nfdclient.Clientset
129- stop chan struct {} // channel for signaling stop
130- featureSources []source.FeatureSource
131- labelSources []source.LabelSource
129+
130+ k8sClient k8sclient.Interface
131+ nfdClient * nfdclient.Clientset
132+ stop chan struct {} // channel for signaling stop
133+ featureSources []source.FeatureSource
134+ labelSources []source.LabelSource
135+ ownerReference []metav1.OwnerReference
132136}
133137
134138// This ticker can represent infinite and normal intervals.
135139type infiniteTicker struct {
136140 * time.Ticker
137141}
138142
143+ // NfdWorkerOption sets properties of the NfdWorker instance.
144+ type NfdWorkerOption interface {
145+ apply (* nfdWorker )
146+ }
147+
148+ // WithArgs is used for passing settings from command line arguments.
149+ func WithArgs (args * Args ) NfdWorkerOption {
150+ return & nfdMWorkerOpt {f : func (n * nfdWorker ) { n .args = * args }}
151+ }
152+
153+ // WithKuberneteClient forces to use the given kubernetes client, without
154+ // initializing one from kubeconfig.
155+ func WithKubernetesClient (cli k8sclient.Interface ) NfdWorkerOption {
156+ return & nfdMWorkerOpt {f : func (n * nfdWorker ) { n .k8sClient = cli }}
157+ }
158+
159+ type nfdMWorkerOpt struct {
160+ f func (* nfdWorker )
161+ }
162+
163+ func (f * nfdMWorkerOpt ) apply (n * nfdWorker ) {
164+ f .f (n )
165+ }
166+
139167// NewNfdWorker creates new NfdWorker instance.
140- func NewNfdWorker (args * Args ) (NfdWorker , error ) {
168+ func NewNfdWorker (opts ... NfdWorkerOption ) (NfdWorker , error ) {
141169 nfd := & nfdWorker {
142- args : * args ,
143170 config : & NFDConfig {},
144171 kubernetesNamespace : utils .GetKubernetesNamespace (),
145172 stop : make (chan struct {}, 1 ),
146173 }
147174
175+ for _ , o := range opts {
176+ o .apply (nfd )
177+ }
178+
148179 // Check TLS related args
149- if args .CertFile != "" || args .KeyFile != "" || args .CaFile != "" {
150- if args .CertFile == "" {
180+ if nfd . args .CertFile != "" || nfd . args .KeyFile != "" || nfd . args .CaFile != "" {
181+ if nfd . args .CertFile == "" {
151182 return nfd , fmt .Errorf ("-cert-file needs to be specified alongside -key-file and -ca-file" )
152183 }
153- if args .KeyFile == "" {
184+ if nfd . args .KeyFile == "" {
154185 return nfd , fmt .Errorf ("-key-file needs to be specified alongside -cert-file and -ca-file" )
155186 }
156- if args .CaFile == "" {
187+ if nfd . args .CaFile == "" {
157188 return nfd , fmt .Errorf ("-ca-file needs to be specified alongside -cert-file and -key-file" )
158189 }
159190 }
160191
161- if args .ConfigFile != "" {
162- nfd .configFilePath = filepath .Clean (args .ConfigFile )
192+ if nfd .args .ConfigFile != "" {
193+ nfd .configFilePath = filepath .Clean (nfd .args .ConfigFile )
194+ }
195+
196+ // k8sClient might've been set via opts by tests
197+ if nfd .k8sClient == nil {
198+ kubeconfig , err := apihelper .GetKubeconfig (nfd .args .Kubeconfig )
199+ if err != nil {
200+ return nfd , err
201+ }
202+ cli , err := k8sclient .NewForConfig (kubeconfig )
203+ if err != nil {
204+ return nfd , err
205+ }
206+ nfd .k8sClient = cli
163207 }
164208
165209 return nfd , nil
@@ -243,6 +287,37 @@ func (w *nfdWorker) Run() error {
243287 labelTrigger .Reset (w .config .Core .SleepInterval .Duration )
244288 defer labelTrigger .Stop ()
245289
290+ // Create owner ref
291+ ownerReference := []metav1.OwnerReference {}
292+ // Get pod owner reference
293+ podName := os .Getenv ("POD_NAME" )
294+
295+ // Add pod owner reference if it exists
296+ if podName != "" {
297+ if selfPod , err := w .k8sClient .CoreV1 ().Pods (w .kubernetesNamespace ).Get (context .TODO (), podName , metav1.GetOptions {}); err != nil {
298+ klog .ErrorS (err , "failed to get self pod, cannot inherit ownerReference for NodeFeature" )
299+ return err
300+ } else {
301+ ownerReference = append (ownerReference , selfPod .OwnerReferences ... )
302+ }
303+
304+ podUID := os .Getenv ("POD_UID" )
305+ if podUID != "" {
306+ ownerReference = append (ownerReference , metav1.OwnerReference {
307+ APIVersion : "v1" ,
308+ Kind : "Pod" ,
309+ Name : podName ,
310+ UID : types .UID (podUID ),
311+ })
312+ } else {
313+ klog .InfoS ("Cannot append POD ownerReference to NodeFeature, POD_UID not specified" )
314+ }
315+ } else {
316+ klog .InfoS ("Cannot set NodeFeature owner references, POD_NAME not specified" )
317+ }
318+
319+ w .ownerReference = ownerReference
320+
246321 // Register to metrics server
247322 if w .args .MetricsPort > 0 {
248323 m := utils .CreateMetricsServer (w .args .MetricsPort ,
@@ -673,25 +748,6 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
673748
674749 features := source .GetAllFeatures ()
675750
676- // Create owner ref
677- ownerRefs := []metav1.OwnerReference {}
678- podName := os .Getenv ("POD_NAME" )
679- podUID := os .Getenv ("POD_UID" )
680- if podName != "" && podUID != "" {
681- isTrue := true
682- ownerRefs = []metav1.OwnerReference {
683- {
684- APIVersion : "v1" ,
685- Kind : "Pod" ,
686- Name : podName ,
687- UID : types .UID (podUID ),
688- Controller : & isTrue ,
689- },
690- }
691- } else {
692- klog .InfoS ("Cannot set NodeFeature owner reference, POD_NAME and/or POD_UID not specified" )
693- }
694-
695751 // TODO: we could implement some simple caching of the object, only get it
696752 // every 10 minutes or so because nobody else should really be modifying it
697753 if nfr , err := cli .NfdV1alpha1 ().NodeFeatures (namespace ).Get (context .TODO (), nodename , metav1.GetOptions {}); errors .IsNotFound (err ) {
@@ -701,7 +757,7 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
701757 Name : nodename ,
702758 Annotations : map [string ]string {nfdv1alpha1 .WorkerVersionAnnotation : version .Get ()},
703759 Labels : map [string ]string {nfdv1alpha1 .NodeFeatureObjNodeNameLabel : nodename },
704- OwnerReferences : ownerRefs ,
760+ OwnerReferences : m . ownerReference ,
705761 },
706762 Spec : nfdv1alpha1.NodeFeatureSpec {
707763 Features : * features ,
@@ -721,7 +777,7 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
721777 nfrUpdated := nfr .DeepCopy ()
722778 nfrUpdated .Annotations = map [string ]string {nfdv1alpha1 .WorkerVersionAnnotation : version .Get ()}
723779 nfrUpdated .Labels = map [string ]string {nfdv1alpha1 .NodeFeatureObjNodeNameLabel : nodename }
724- nfrUpdated .OwnerReferences = ownerRefs
780+ nfrUpdated .OwnerReferences = m . ownerReference
725781 nfrUpdated .Spec = nfdv1alpha1.NodeFeatureSpec {
726782 Features : * features ,
727783 Labels : labels ,
0 commit comments