Skip to content

Commit dd55c9f

Browse files
ArangoGutierrezk8s-infra-cherrypick-robot
authored andcommitted
Add optionable arguments to NewWorker
Signed-off-by: Carlos Eduardo Arango Gutierrez <[email protected]>
1 parent 283caf2 commit dd55c9f

File tree

5 files changed

+99
-59
lines changed

5 files changed

+99
-59
lines changed

cmd/nfd-worker/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func main() {
8383

8484
// Get new NfdWorker instance
8585
args.GrpcHealthPort = GrpcHealthPort
86-
instance, err := worker.NewNfdWorker(args)
86+
instance, err := worker.NewNfdWorker(worker.WithArgs(args))
8787
if err != nil {
8888
klog.ErrorS(err, "failed to initialize NfdWorker instance")
8989
os.Exit(1)

pkg/nfd-worker/nfd-worker-internal_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
. "github.com/smartystreets/goconvey/convey"
2828
"github.com/stretchr/testify/mock"
2929
"github.com/vektra/errors"
30+
fakeclient "k8s.io/client-go/kubernetes/fake"
3031

3132
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
3233
"sigs.k8s.io/node-feature-discovery/pkg/labeler"
@@ -97,7 +98,8 @@ func makeFakeFeatures(names []string) (source.FeatureLabels, Labels) {
9798

9899
func TestConfigParse(t *testing.T) {
99100
Convey("When parsing configuration", t, func() {
100-
w, err := NewNfdWorker(&Args{})
101+
w, err := NewNfdWorker(WithArgs(&Args{}),
102+
WithKubernetesClient(fakeclient.NewSimpleClientset()))
101103
So(err, ShouldBeNil)
102104
worker := w.(*nfdWorker)
103105
overrides := `{"core": {"labelSources": ["fake"],"noPublish": true},"sources": {"cpu": {"cpuid": {"attributeBlacklist": ["foo","bar"]}}}}`
@@ -222,13 +224,13 @@ core:
222224
`)
223225

224226
noPublish := true
225-
w, err := NewNfdWorker(&Args{
227+
w, err := NewNfdWorker(WithArgs(&Args{
226228
ConfigFile: configFile,
227229
Overrides: ConfigOverrideArgs{
228230
FeatureSources: &utils.StringSliceVal{"fake"},
229231
LabelSources: &utils.StringSliceVal{"fake"},
230232
NoPublish: &noPublish},
231-
})
233+
}), WithKubernetesClient(fakeclient.NewSimpleClientset()))
232234
So(err, ShouldBeNil)
233235
worker := w.(*nfdWorker)
234236

@@ -307,7 +309,8 @@ func TestNewNfdWorker(t *testing.T) {
307309

308310
Convey("without any args specified", func() {
309311
args := &Args{}
310-
w, err := NewNfdWorker(args)
312+
w, err := NewNfdWorker(WithArgs(args),
313+
WithKubernetesClient(fakeclient.NewSimpleClientset()))
311314
Convey("no error should be returned", func() {
312315
So(err, ShouldBeNil)
313316
})
@@ -324,7 +327,8 @@ func TestNewNfdWorker(t *testing.T) {
324327
args := &Args{Overrides: ConfigOverrideArgs{
325328
LabelSources: &utils.StringSliceVal{"fake"},
326329
FeatureSources: &utils.StringSliceVal{"cpu"}}}
327-
w, err := NewNfdWorker(args)
330+
w, err := NewNfdWorker(WithArgs(args),
331+
WithKubernetesClient(fakeclient.NewSimpleClientset()))
328332
Convey("no error should be returned", func() {
329333
So(err, ShouldBeNil)
330334
})
@@ -373,7 +377,7 @@ func TestCreateFeatureLabels(t *testing.T) {
373377

374378
func TestAdvertiseFeatureLabels(t *testing.T) {
375379
Convey("When advertising labels", t, func() {
376-
w, err := NewNfdWorker(&Args{})
380+
w, err := NewNfdWorker(WithArgs(&Args{}), WithKubernetesClient(fakeclient.NewSimpleClientset()))
377381
So(err, ShouldBeNil)
378382
worker := w.(*nfdWorker)
379383

pkg/nfd-worker/nfd-worker.go

Lines changed: 73 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import (
3939
"k8s.io/apimachinery/pkg/api/errors"
4040
"k8s.io/apimachinery/pkg/types"
4141
"k8s.io/apimachinery/pkg/util/validation"
42-
"k8s.io/client-go/kubernetes"
42+
k8sclient "k8s.io/client-go/kubernetes"
4343
"k8s.io/klog/v2"
4444
klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog"
4545
"sigs.k8s.io/yaml"
@@ -131,6 +131,7 @@ type nfdWorker struct {
131131
kubernetesNamespace string
132132
grpcClient pb.LabelerClient
133133
healthServer *grpc.Server
134+
k8sClient k8sclient.Interface
134135
nfdClient *nfdclient.Clientset
135136
stop chan struct{} // channel for signaling stop
136137
featureSources []source.FeatureSource
@@ -143,30 +144,70 @@ type infiniteTicker struct {
143144
*time.Ticker
144145
}
145146

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+
146171
// NewNfdWorker creates new NfdWorker instance.
147-
func NewNfdWorker(args *Args) (NfdWorker, error) {
172+
func NewNfdWorker(opts ...NfdWorkerOption) (NfdWorker, error) {
148173
nfd := &nfdWorker{
149-
args: *args,
150174
config: &NFDConfig{},
151175
kubernetesNamespace: utils.GetKubernetesNamespace(),
152176
stop: make(chan struct{}),
153177
}
154178

179+
for _, o := range opts {
180+
o.apply(nfd)
181+
}
182+
155183
// Check TLS related args
156-
if args.CertFile != "" || args.KeyFile != "" || args.CaFile != "" {
157-
if args.CertFile == "" {
184+
if nfd.args.CertFile != "" || nfd.args.KeyFile != "" || nfd.args.CaFile != "" {
185+
if nfd.args.CertFile == "" {
158186
return nfd, fmt.Errorf("-cert-file needs to be specified alongside -key-file and -ca-file")
159187
}
160-
if args.KeyFile == "" {
188+
if nfd.args.KeyFile == "" {
161189
return nfd, fmt.Errorf("-key-file needs to be specified alongside -cert-file and -ca-file")
162190
}
163-
if args.CaFile == "" {
191+
if nfd.args.CaFile == "" {
164192
return nfd, fmt.Errorf("-ca-file needs to be specified alongside -cert-file and -key-file")
165193
}
166194
}
167195

168-
if args.ConfigFile != "" {
169-
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
170211
}
171212

172213
return nfd, nil
@@ -273,32 +314,33 @@ func (w *nfdWorker) Run() error {
273314
labelTrigger.Reset(w.config.Core.SleepInterval.Duration)
274315
defer labelTrigger.Stop()
275316

317+
// Create owner ref
318+
ownerReference := []metav1.OwnerReference{}
276319
// Get pod owner reference
277320
podName := os.Getenv("POD_NAME")
278-
client, err := w.getKubeClient()
279-
if err != nil {
280-
return fmt.Errorf("failed to get kube client: %w", err)
281-
}
282-
283-
selfPod, err := client.CoreV1().Pods(w.kubernetesNamespace).Get(context.TODO(), podName, metav1.GetOptions{})
284-
if err != nil {
285-
return fmt.Errorf("failed to get pod %q: %w", podName, err)
286-
}
287-
288-
// Create owner ref
289-
ownerReference := selfPod.OwnerReferences
290321

291322
// Add pod owner reference if it exists
292-
podUID := os.Getenv("POD_UID")
293-
if podName != "" && podUID != "" {
294-
isTrue := true
295-
ownerReference = append(ownerReference, metav1.OwnerReference{
296-
APIVersion: "v1",
297-
Kind: "Pod",
298-
Name: podName,
299-
UID: types.UID(podUID),
300-
Controller: &isTrue,
301-
})
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")
302344
}
303345

304346
w.ownerReference = ownerReference
@@ -814,22 +856,6 @@ func (m *nfdWorker) getNfdClient() (*nfdclient.Clientset, error) {
814856
return c, nil
815857
}
816858

817-
func (m *nfdWorker) getKubeClient() (*kubernetes.Clientset, error) {
818-
// creates the in-cluster config
819-
kubeconfig, err := utils.GetKubeconfig(m.args.Kubeconfig)
820-
if err != nil {
821-
return nil, err
822-
}
823-
824-
// creates the clientset
825-
clientset, err := kubernetes.NewForConfig(kubeconfig)
826-
if err != nil {
827-
return nil, err
828-
}
829-
830-
return clientset, nil
831-
}
832-
833859
// UnmarshalJSON implements the Unmarshaler interface from "encoding/json"
834860
func (c *sourcesConfig) UnmarshalJSON(data []byte) error {
835861
// First do a raw parse to get the per-source data

pkg/nfd-worker/nfd-worker_test.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,12 @@ func teardownTest(ctx testContext) {
9090
func TestNewNfdWorker(t *testing.T) {
9191
Convey("When initializing new NfdWorker instance", t, func() {
9292
Convey("When one of -cert-file, -key-file or -ca-file is missing", func() {
93-
_, err := worker.NewNfdWorker(&worker.Args{CertFile: "crt", KeyFile: "key"})
94-
_, err2 := worker.NewNfdWorker(&worker.Args{KeyFile: "key", CaFile: "ca"})
95-
_, err3 := worker.NewNfdWorker(&worker.Args{CertFile: "crt", CaFile: "ca"})
93+
_, err := worker.NewNfdWorker(worker.WithArgs(&worker.Args{CertFile: "crt", KeyFile: "key"}),
94+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
95+
_, err2 := worker.NewNfdWorker(worker.WithArgs(&worker.Args{KeyFile: "key", CaFile: "ca"}),
96+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
97+
_, err3 := worker.NewNfdWorker(worker.WithArgs(&worker.Args{CertFile: "crt", CaFile: "ca"}),
98+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
9699
Convey("An error should be returned", func() {
97100
So(err, ShouldNotBeNil)
98101
So(err2, ShouldNotBeNil)
@@ -112,7 +115,8 @@ func TestRun(t *testing.T) {
112115
Oneshot: true,
113116
Overrides: worker.ConfigOverrideArgs{LabelSources: &utils.StringSliceVal{"fake"}},
114117
}
115-
fooasdf, _ := worker.NewNfdWorker(args)
118+
fooasdf, _ := worker.NewNfdWorker(worker.WithArgs(args),
119+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
116120
err := fooasdf.Run()
117121
Convey("No error should be returned", func() {
118122
So(err, ShouldBeNil)
@@ -141,7 +145,8 @@ func TestRunTls(t *testing.T) {
141145
Oneshot: true,
142146
Overrides: worker.ConfigOverrideArgs{LabelSources: &utils.StringSliceVal{"fake"}},
143147
}
144-
w, _ := worker.NewNfdWorker(&workerArgs)
148+
w, _ := worker.NewNfdWorker(worker.WithArgs(&workerArgs),
149+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
145150
err := w.Run()
146151
Convey("No error should be returned", func() {
147152
So(err, ShouldBeNil)

test/e2e/utils/rbac.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ func createRoleWorker(ctx context.Context, cs clientset.Interface, ns string) (*
224224
Resources: []string{"nodefeatures"},
225225
Verbs: []string{"create", "get", "update"},
226226
},
227+
{
228+
APIGroups: []string{""},
229+
Resources: []string{"pods"},
230+
Verbs: []string{"get"},
231+
},
227232
},
228233
}
229234
return cs.RbacV1().Roles(ns).Update(ctx, cr, metav1.UpdateOptions{})

0 commit comments

Comments
 (0)