@@ -20,6 +20,7 @@ import (
2020 "encoding/json"
2121 "fmt"
2222 "net/http"
23+ "net/url"
2324 "os"
2425 "path/filepath"
2526 "regexp"
@@ -38,8 +39,10 @@ import (
3839 "k8s.io/apimachinery/pkg/util/validation"
3940 k8sclient "k8s.io/client-go/kubernetes"
4041 "k8s.io/klog/v2"
42+ kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
4143 "k8s.io/utils/ptr"
4244 klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog"
45+ "sigs.k8s.io/node-feature-discovery/pkg/utils/kubeconf"
4346 "sigs.k8s.io/yaml"
4447
4548 apiequality "k8s.io/apimachinery/pkg/api/equality"
@@ -57,6 +60,7 @@ import (
5760 _ "sigs.k8s.io/node-feature-discovery/source/kernel"
5861 _ "sigs.k8s.io/node-feature-discovery/source/local"
5962 _ "sigs.k8s.io/node-feature-discovery/source/memory"
63+ memory "sigs.k8s.io/node-feature-discovery/source/memory"
6064 _ "sigs.k8s.io/node-feature-discovery/source/network"
6165 _ "sigs.k8s.io/node-feature-discovery/source/pci"
6266 _ "sigs.k8s.io/node-feature-discovery/source/storage"
@@ -94,13 +98,16 @@ type Labels map[string]string
9498
9599// Args are the command line arguments of NfdWorker.
96100type Args struct {
97- ConfigFile string
98- Klog map [string ]* utils.KlogFlagVal
99- Kubeconfig string
100- Oneshot bool
101- Options string
102- Port int
103- NoOwnerRefs bool
101+ ConfigFile string
102+ Klog map [string ]* utils.KlogFlagVal
103+ Kubeconfig string
104+ Oneshot bool
105+ Options string
106+ Port int
107+ NoOwnerRefs bool
108+ KubeletConfigPath string
109+ KubeletConfigURI string
110+ APIAuthTokenFile string
104111
105112 Overrides ConfigOverrideArgs
106113}
@@ -124,6 +131,7 @@ type nfdWorker struct {
124131 featureSources []source.FeatureSource
125132 labelSources []source.LabelSource
126133 ownerReference []metav1.OwnerReference
134+ kubeletConfigFunc func () (* kubeletconfigv1beta1.KubeletConfiguration , error )
127135}
128136
129137// This ticker can represent infinite and normal intervals.
@@ -169,12 +177,25 @@ func NewNfdWorker(opts ...NfdWorkerOption) (NfdWorker, error) {
169177 stop : make (chan struct {}),
170178 }
171179
180+ if nfd .args .ConfigFile != "" {
181+ nfd .configFilePath = filepath .Clean (nfd .args .ConfigFile )
182+ }
183+
172184 for _ , o := range opts {
173185 o .apply (nfd )
174186 }
175187
176- if nfd .args .ConfigFile != "" {
177- nfd .configFilePath = filepath .Clean (nfd .args .ConfigFile )
188+ kubeletConfigFunc , err := getKubeletConfigFunc (nfd .args .KubeletConfigURI , nfd .args .APIAuthTokenFile )
189+ if err != nil {
190+ return nil , err
191+ }
192+
193+ nfd = & nfdWorker {
194+ kubeletConfigFunc : kubeletConfigFunc ,
195+ }
196+
197+ for _ , o := range opts {
198+ o .apply (nfd )
178199 }
179200
180201 // k8sClient might've been set via opts by tests
@@ -239,6 +260,8 @@ func (w *nfdWorker) runFeatureDiscovery() error {
239260 }
240261 // Get the set of feature labels.
241262 labels := createFeatureLabels (w .labelSources , w .config .Core .LabelWhiteList .Regexp )
263+ // Append a label with app=nfd
264+ labels ["app" ] = "nfd"
242265
243266 // Update the node with the feature labels.
244267 if ! w .config .Core .NoPublish {
@@ -255,9 +278,10 @@ func (w *nfdWorker) setOwnerReference() error {
255278 if ! w .config .Core .NoOwnerRefs {
256279 // Get pod owner reference
257280 podName := os .Getenv ("POD_NAME" )
281+ podNamespace := os .Getenv ("POD_NAMESPACE" )
258282 // Add pod owner reference if it exists
259283 if podName != "" {
260- if selfPod , err := w .k8sClient .CoreV1 ().Pods (w . kubernetesNamespace ).Get (context .TODO (), podName , metav1.GetOptions {}); err != nil {
284+ if selfPod , err := w .k8sClient .CoreV1 ().Pods (podNamespace ).Get (context .TODO (), podName , metav1.GetOptions {}); err != nil {
261285 klog .ErrorS (err , "failed to get self pod, cannot inherit ownerReference for NodeFeature" )
262286 return err
263287 } else {
@@ -312,6 +336,12 @@ func (w *nfdWorker) Run() error {
312336 httpMux .Handle ("/metrics" , promhttp .HandlerFor (promRegistry , promhttp.HandlerOpts {}))
313337 registerVersion (version .Get ())
314338
339+ klConfig , err := w .kubeletConfigFunc ()
340+ if err != nil {
341+ return err
342+ }
343+ memory .SetSwapMode (klConfig .MemorySwap .SwapBehavior )
344+
315345 err = w .runFeatureDiscovery ()
316346 if err != nil {
317347 return err
@@ -624,7 +654,7 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
624654 return err
625655 }
626656 nodename := utils .NodeName ()
627- namespace := m . kubernetesNamespace
657+ namespace := os . Getenv ( "POD_NAMESPACE" )
628658
629659 features := source .GetAllFeatures ()
630660
@@ -720,3 +750,38 @@ func (c *sourcesConfig) UnmarshalJSON(data []byte) error {
720750
721751 return nil
722752}
753+
754+ func getKubeletConfigFunc (uri , apiAuthTokenFile string ) (func () (* kubeletconfigv1beta1.KubeletConfiguration , error ), error ) {
755+ u , err := url .ParseRequestURI (uri )
756+ if err != nil {
757+ return nil , fmt .Errorf ("failed to parse -kubelet-config-uri: %w" , err )
758+ }
759+
760+ // init kubelet API client
761+ var klConfig * kubeletconfigv1beta1.KubeletConfiguration
762+ switch u .Scheme {
763+ case "file" :
764+ return func () (* kubeletconfigv1beta1.KubeletConfiguration , error ) {
765+ klConfig , err = kubeconf .GetKubeletConfigFromLocalFile (u .Path )
766+ if err != nil {
767+ return nil , fmt .Errorf ("failed to read kubelet config: %w" , err )
768+ }
769+ return klConfig , err
770+ }, nil
771+ case "https" :
772+ restConfig , err := kubeconf .InsecureConfig (u .String (), apiAuthTokenFile )
773+ if err != nil {
774+ return nil , fmt .Errorf ("failed to initialize rest config for kubelet config uri: %w" , err )
775+ }
776+
777+ return func () (* kubeletconfigv1beta1.KubeletConfiguration , error ) {
778+ klConfig , err = kubeconf .GetKubeletConfiguration (restConfig )
779+ if err != nil {
780+ return nil , fmt .Errorf ("failed to get kubelet config from configz endpoint: %w" , err )
781+ }
782+ return klConfig , nil
783+ }, nil
784+ }
785+
786+ return nil , fmt .Errorf ("unsupported URI scheme: %v" , u .Scheme )
787+ }
0 commit comments