@@ -39,6 +39,7 @@ import (
3939 "k8s.io/apimachinery/pkg/api/errors"
4040 "k8s.io/apimachinery/pkg/types"
4141 "k8s.io/apimachinery/pkg/util/validation"
42+ k8sclient "k8s.io/client-go/kubernetes"
4243 "k8s.io/klog/v2"
4344 klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog"
4445 "sigs.k8s.io/yaml"
@@ -130,41 +131,83 @@ type nfdWorker struct {
130131 kubernetesNamespace string
131132 grpcClient pb.LabelerClient
132133 healthServer * grpc.Server
134+ k8sClient k8sclient.Interface
133135 nfdClient * nfdclient.Clientset
134136 stop chan struct {} // channel for signaling stop
135137 featureSources []source.FeatureSource
136138 labelSources []source.LabelSource
139+ ownerReference []metav1.OwnerReference
137140}
138141
139142// This ticker can represent infinite and normal intervals.
140143type infiniteTicker struct {
141144 * time.Ticker
142145}
143146
147+ // NfdWorkerOption sets properties of the NfdWorker instance.
148+ type NfdWorkerOption interface {
149+ apply (* nfdWorker )
150+ }
151+
152+ // WithArgs is used for passing settings from command line arguments.
153+ func WithArgs (args * Args ) NfdWorkerOption {
154+ return & nfdMWorkerOpt {f : func (n * nfdWorker ) { n .args = * args }}
155+ }
156+
157+ // WithKuberneteClient forces to use the given kubernetes client, without
158+ // initializing one from kubeconfig.
159+ func WithKubernetesClient (cli k8sclient.Interface ) NfdWorkerOption {
160+ return & nfdMWorkerOpt {f : func (n * nfdWorker ) { n .k8sClient = cli }}
161+ }
162+
163+ type nfdMWorkerOpt struct {
164+ f func (* nfdWorker )
165+ }
166+
167+ func (f * nfdMWorkerOpt ) apply (n * nfdWorker ) {
168+ f .f (n )
169+ }
170+
144171// NewNfdWorker creates new NfdWorker instance.
145- func NewNfdWorker (args * Args ) (NfdWorker , error ) {
172+ func NewNfdWorker (opts ... NfdWorkerOption ) (NfdWorker , error ) {
146173 nfd := & nfdWorker {
147- args : * args ,
148174 config : & NFDConfig {},
149175 kubernetesNamespace : utils .GetKubernetesNamespace (),
150176 stop : make (chan struct {}),
151177 }
152178
179+ for _ , o := range opts {
180+ o .apply (nfd )
181+ }
182+
153183 // Check TLS related args
154- if args .CertFile != "" || args .KeyFile != "" || args .CaFile != "" {
155- if args .CertFile == "" {
184+ if nfd . args .CertFile != "" || nfd . args .KeyFile != "" || nfd . args .CaFile != "" {
185+ if nfd . args .CertFile == "" {
156186 return nfd , fmt .Errorf ("-cert-file needs to be specified alongside -key-file and -ca-file" )
157187 }
158- if args .KeyFile == "" {
188+ if nfd . args .KeyFile == "" {
159189 return nfd , fmt .Errorf ("-key-file needs to be specified alongside -cert-file and -ca-file" )
160190 }
161- if args .CaFile == "" {
191+ if nfd . args .CaFile == "" {
162192 return nfd , fmt .Errorf ("-ca-file needs to be specified alongside -cert-file and -key-file" )
163193 }
164194 }
165195
166- if args .ConfigFile != "" {
167- nfd .configFilePath = filepath .Clean (args .ConfigFile )
196+ if nfd .args .ConfigFile != "" {
197+ nfd .configFilePath = filepath .Clean (nfd .args .ConfigFile )
198+ }
199+
200+ // k8sClient might've been set via opts by tests
201+ if nfd .k8sClient == nil {
202+ kubeconfig , err := utils .GetKubeconfig (nfd .args .Kubeconfig )
203+ if err != nil {
204+ return nfd , err
205+ }
206+ cli , err := k8sclient .NewForConfig (kubeconfig )
207+ if err != nil {
208+ return nfd , err
209+ }
210+ nfd .k8sClient = cli
168211 }
169212
170213 return nfd , nil
@@ -271,6 +314,37 @@ func (w *nfdWorker) Run() error {
271314 labelTrigger .Reset (w .config .Core .SleepInterval .Duration )
272315 defer labelTrigger .Stop ()
273316
317+ // Create owner ref
318+ ownerReference := []metav1.OwnerReference {}
319+ // Get pod owner reference
320+ podName := os .Getenv ("POD_NAME" )
321+
322+ // Add pod owner reference if it exists
323+ if podName != "" {
324+ if selfPod , err := w .k8sClient .CoreV1 ().Pods (w .kubernetesNamespace ).Get (context .TODO (), podName , metav1.GetOptions {}); err != nil {
325+ klog .ErrorS (err , "failed to get self pod, cannot inherit ownerReference for NodeFeature" )
326+ return err
327+ } else {
328+ ownerReference = append (ownerReference , selfPod .OwnerReferences ... )
329+ }
330+
331+ podUID := os .Getenv ("POD_UID" )
332+ if podUID != "" {
333+ ownerReference = append (ownerReference , metav1.OwnerReference {
334+ APIVersion : "v1" ,
335+ Kind : "Pod" ,
336+ Name : podName ,
337+ UID : types .UID (podUID ),
338+ })
339+ } else {
340+ klog .InfoS ("Cannot append POD ownerReference to NodeFeature, POD_UID not specified" )
341+ }
342+ } else {
343+ klog .InfoS ("Cannot set NodeFeature owner references, POD_NAME not specified" )
344+ }
345+
346+ w .ownerReference = ownerReference
347+
274348 // Register to metrics server
275349 if w .args .MetricsPort > 0 {
276350 m := utils .CreateMetricsServer (w .args .MetricsPort ,
@@ -713,25 +787,6 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
713787
714788 features := source .GetAllFeatures ()
715789
716- // Create owner ref
717- ownerRefs := []metav1.OwnerReference {}
718- podName := os .Getenv ("POD_NAME" )
719- podUID := os .Getenv ("POD_UID" )
720- if podName != "" && podUID != "" {
721- isTrue := true
722- ownerRefs = []metav1.OwnerReference {
723- {
724- APIVersion : "v1" ,
725- Kind : "Pod" ,
726- Name : podName ,
727- UID : types .UID (podUID ),
728- Controller : & isTrue ,
729- },
730- }
731- } else {
732- klog .InfoS ("Cannot set NodeFeature owner reference, POD_NAME and/or POD_UID not specified" )
733- }
734-
735790 // TODO: we could implement some simple caching of the object, only get it
736791 // every 10 minutes or so because nobody else should really be modifying it
737792 if nfr , err := cli .NfdV1alpha1 ().NodeFeatures (namespace ).Get (context .TODO (), nodename , metav1.GetOptions {}); errors .IsNotFound (err ) {
@@ -740,7 +795,7 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
740795 Name : nodename ,
741796 Annotations : map [string ]string {nfdv1alpha1 .WorkerVersionAnnotation : version .Get ()},
742797 Labels : map [string ]string {nfdv1alpha1 .NodeFeatureObjNodeNameLabel : nodename },
743- OwnerReferences : ownerRefs ,
798+ OwnerReferences : m . ownerReference ,
744799 },
745800 Spec : nfdv1alpha1.NodeFeatureSpec {
746801 Features : * features ,
@@ -761,7 +816,7 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
761816 nfrUpdated := nfr .DeepCopy ()
762817 nfrUpdated .Annotations = map [string ]string {nfdv1alpha1 .WorkerVersionAnnotation : version .Get ()}
763818 nfrUpdated .Labels = map [string ]string {nfdv1alpha1 .NodeFeatureObjNodeNameLabel : nodename }
764- nfrUpdated .OwnerReferences = ownerRefs
819+ nfrUpdated .OwnerReferences = m . ownerReference
765820 nfrUpdated .Spec = nfdv1alpha1.NodeFeatureSpec {
766821 Features : * features ,
767822 Labels : labels ,
0 commit comments