Skip to content

Commit 8f5830f

Browse files
authored
Merge pull request #1658 from marquiz/devel/master-opts
nfd-master: implement opts for modifying NfdMaster instance
2 parents 199d665 + fcb8d3c commit 8f5830f

File tree

6 files changed

+88
-51
lines changed

6 files changed

+88
-51
lines changed

cmd/nfd-master/main.go

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

110110
// Get new NfdMaster instance
111111
args.GrpcHealthPort = GrpcHealthPort
112-
instance, err := master.NewNfdMaster(args)
112+
instance, err := master.NewNfdMaster(master.WithArgs(args))
113113
if err != nil {
114114
klog.ErrorS(err, "failed to initialize NfdMaster instance")
115115
os.Exit(1)

pkg/nfd-master/nfd-master-internal_test.go

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import (
3636
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3737
"k8s.io/apimachinery/pkg/runtime"
3838
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
39-
k8sclient "k8s.io/client-go/kubernetes"
4039
fakeclient "k8s.io/client-go/kubernetes/fake"
4140
fakecorev1client "k8s.io/client-go/kubernetes/typed/core/v1/fake"
4241
clienttesting "k8s.io/client-go/testing"
@@ -104,12 +103,24 @@ func newFakeNfdAPIController(client *fakenfdclient.Clientset) *nfdController {
104103
return c
105104
}
106105

107-
func newFakeMaster(cli k8sclient.Interface) *nfdMaster {
108-
return &nfdMaster{
109-
nodeName: testNodeName,
110-
config: &NFDConfig{},
111-
k8sClient: cli,
106+
func withNodeName(nodeName string) NfdMasterOption {
107+
return &nfdMasterOpt{f: func(n *nfdMaster) { n.nodeName = nodeName }}
108+
}
109+
110+
func withConfig(config *NFDConfig) NfdMasterOption {
111+
return &nfdMasterOpt{f: func(n *nfdMaster) { n.config = config }}
112+
}
113+
114+
func newFakeMaster(opts ...NfdMasterOption) *nfdMaster {
115+
defaultOpts := []NfdMasterOption{
116+
withNodeName(testNodeName),
117+
withConfig(&NFDConfig{}),
118+
}
119+
m, err := NewNfdMaster(append(defaultOpts, opts...)...)
120+
if err != nil {
121+
panic(err)
112122
}
123+
return m.(*nfdMaster)
113124
}
114125

115126
func TestUpdateNodeObject(t *testing.T) {
@@ -153,7 +164,7 @@ func TestUpdateNodeObject(t *testing.T) {
153164

154165
// Create fake api client and initialize NfdMaster instance
155166
fakeCli := fakeclient.NewSimpleClientset(testNode)
156-
fakeMaster := newFakeMaster(fakeCli)
167+
fakeMaster := newFakeMaster(WithKubernetesClient(fakeCli))
157168

158169
Convey("When I successfully update the node with feature labels", func() {
159170
err := fakeMaster.updateNodeObject(testNode, featureLabels, featureAnnotations, featureExtResources, nil)
@@ -205,7 +216,7 @@ func TestUpdateMasterNode(t *testing.T) {
205216

206217
Convey("When update operation succeeds", func() {
207218
fakeCli := fakeclient.NewSimpleClientset(testNode)
208-
fakeMaster := newFakeMaster(fakeCli)
219+
fakeMaster := newFakeMaster(WithKubernetesClient(fakeCli))
209220
err := fakeMaster.updateMasterNode()
210221
Convey("No error should be returned", func() {
211222
So(err, ShouldBeNil)
@@ -220,7 +231,7 @@ func TestUpdateMasterNode(t *testing.T) {
220231

221232
Convey("When getting API node object fails", func() {
222233
fakeCli := fakeclient.NewSimpleClientset(testNode)
223-
fakeMaster := newFakeMaster(fakeCli)
234+
fakeMaster := newFakeMaster(WithKubernetesClient(fakeCli))
224235
fakeMaster.nodeName = "does-not-exist"
225236

226237
err := fakeMaster.updateMasterNode()
@@ -235,7 +246,7 @@ func TestUpdateMasterNode(t *testing.T) {
235246
fakeCli.CoreV1().(*fakecorev1client.FakeCoreV1).PrependReactor("patch", "nodes", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
236247
return true, &v1.Node{}, fakeErr
237248
})
238-
fakeMaster := newFakeMaster(fakeCli)
249+
fakeMaster := newFakeMaster(WithKubernetesClient(fakeCli))
239250

240251
err := fakeMaster.updateMasterNode()
241252
Convey("An error should be returned", func() {
@@ -247,7 +258,7 @@ func TestUpdateMasterNode(t *testing.T) {
247258

248259
func TestAddingExtResources(t *testing.T) {
249260
Convey("When adding extended resources", t, func() {
250-
fakeMaster := newFakeMaster(nil)
261+
fakeMaster := newFakeMaster()
251262
Convey("When there are no matching labels", func() {
252263
testNode := newTestNode()
253264
resourceLabels := ExtendedResources{}
@@ -290,7 +301,7 @@ func TestAddingExtResources(t *testing.T) {
290301

291302
func TestRemovingExtResources(t *testing.T) {
292303
Convey("When removing extended resources", t, func() {
293-
fakeMaster := newFakeMaster(nil)
304+
fakeMaster := newFakeMaster()
294305
Convey("When none are removed", func() {
295306
testNode := newTestNode()
296307
resourceLabels := ExtendedResources{nfdv1alpha1.FeatureLabelNs + "/feature-1": "1", nfdv1alpha1.FeatureLabelNs + "/feature-2": "2"}
@@ -339,7 +350,7 @@ func TestSetLabels(t *testing.T) {
339350

340351
Convey("When node update succeeds", func() {
341352
fakeCli := fakeclient.NewSimpleClientset(testNode)
342-
fakeMaster := newFakeMaster(fakeCli)
353+
fakeMaster := newFakeMaster(WithKubernetesClient(fakeCli))
343354

344355
_, err := fakeMaster.SetLabels(ctx, req)
345356
Convey("No error should be returned", func() {
@@ -354,11 +365,13 @@ func TestSetLabels(t *testing.T) {
354365

355366
Convey("When -resource-labels is specified", func() {
356367
fakeCli := fakeclient.NewSimpleClientset(testNode)
357-
fakeMaster := newFakeMaster(fakeCli)
358-
fakeMaster.config.ResourceLabels = map[string]struct{}{
359-
"feature.node.kubernetes.io/feature-3": {},
360-
"feature-1": {},
361-
}
368+
fakeMaster := newFakeMaster(
369+
WithKubernetesClient(fakeCli),
370+
withConfig(&NFDConfig{
371+
ResourceLabels: map[string]struct{}{
372+
"feature.node.kubernetes.io/feature-3": {},
373+
"feature-1": {}},
374+
}))
362375

363376
_, err := fakeMaster.SetLabels(ctx, req)
364377
Convey("Error is nil", func() {
@@ -374,7 +387,7 @@ func TestSetLabels(t *testing.T) {
374387

375388
Convey("When node update fails", func() {
376389
fakeCli := fakeclient.NewSimpleClientset(testNode)
377-
fakeMaster := newFakeMaster(fakeCli)
390+
fakeMaster := newFakeMaster(WithKubernetesClient(fakeCli))
378391

379392
fakeErr := errors.New("Fake error when patching node")
380393
fakeCli.CoreV1().(*fakecorev1client.FakeCoreV1).PrependReactor("patch", "nodes", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
@@ -388,7 +401,7 @@ func TestSetLabels(t *testing.T) {
388401

389402
Convey("With '-no-publish'", func() {
390403
fakeCli := fakeclient.NewSimpleClientset(testNode)
391-
fakeMaster := newFakeMaster(fakeCli)
404+
fakeMaster := newFakeMaster(WithKubernetesClient(fakeCli))
392405

393406
fakeMaster.config.NoPublish = true
394407
_, err := fakeMaster.SetLabels(ctx, req)
@@ -400,7 +413,7 @@ func TestSetLabels(t *testing.T) {
400413
}
401414

402415
func TestFilterLabels(t *testing.T) {
403-
fakeMaster := newFakeMaster(nil)
416+
fakeMaster := newFakeMaster()
404417
fakeMaster.config.ExtraLabelNs = map[string]struct{}{"example.io": {}}
405418
fakeMaster.deniedNs = deniedNs{
406419
normal: map[string]struct{}{"": struct{}{}, "kubernetes.io": struct{}{}, "denied.ns": struct{}{}},
@@ -571,9 +584,7 @@ func TestRemoveLabelsWithPrefix(t *testing.T) {
571584

572585
func TestConfigParse(t *testing.T) {
573586
Convey("When parsing configuration", t, func() {
574-
m, err := NewNfdMaster(&Args{})
575-
So(err, ShouldBeNil)
576-
master := m.(*nfdMaster)
587+
master := newFakeMaster()
577588
overrides := `{"noPublish": true, "enableTaints": true, "extraLabelNs": ["added.ns.io","added.kubernetes.io"], "denyLabelNs": ["denied.ns.io","denied.kubernetes.io"], "resourceLabels": ["vendor-1.com/feature-1","vendor-2.io/feature-2"], "labelWhiteList": "foo"}`
578589

579590
Convey("and no core cmdline flags have been specified", func() {
@@ -684,18 +695,16 @@ extraLabelNs: ["added.ns.io"]
684695
os.Exit(1)
685696
}
686697
_ = features.NFDMutableFeatureGate.OverrideDefault(features.NodeFeatureAPI, false)
687-
m, err := NewNfdMaster(&Args{
698+
master := newFakeMaster(WithArgs(&Args{
688699
ConfigFile: configFile,
689700
Overrides: ConfigOverrideArgs{
690701
NoPublish: &noPublish,
691702
},
692-
})
693-
So(err, ShouldBeNil)
694-
master := m.(*nfdMaster)
703+
}))
695704

696705
Convey("config file updates should take effect", func() {
697-
go func() { _ = m.Run() }()
698-
defer m.Stop()
706+
go func() { _ = master.Run() }()
707+
defer master.Stop()
699708
// Check initial config
700709
time.Sleep(10 * time.Second)
701710
So(func() interface{} { return master.config.ExtraLabelNs },
@@ -759,7 +768,7 @@ func newTestNodeList() *corev1.NodeList {
759768

760769
func BenchmarkNfdAPIUpdateAllNodes(b *testing.B) {
761770
fakeCli := fakeclient.NewSimpleClientset(newTestNodeList())
762-
fakeMaster := newFakeMaster(fakeCli)
771+
fakeMaster := newFakeMaster(WithKubernetesClient(fakeCli))
763772
fakeMaster.nfdController = newFakeNfdAPIController(fakenfdclient.NewSimpleClientset())
764773

765774
nodeUpdaterPool := newNodeUpdaterPool(fakeMaster)

pkg/nfd-master/nfd-master.go

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,44 +157,72 @@ type nfdMaster struct {
157157
}
158158

159159
// NewNfdMaster creates a new NfdMaster server instance.
160-
func NewNfdMaster(args *Args) (NfdMaster, error) {
161-
nfd := &nfdMaster{args: *args,
160+
func NewNfdMaster(opts ...NfdMasterOption) (NfdMaster, error) {
161+
nfd := &nfdMaster{
162162
nodeName: utils.NodeName(),
163163
namespace: utils.GetKubernetesNamespace(),
164164
ready: make(chan struct{}),
165165
stop: make(chan struct{}),
166166
}
167167

168-
if args.Instance != "" {
169-
if ok, _ := regexp.MatchString(`^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$`, args.Instance); !ok {
168+
for _, o := range opts {
169+
o.apply(nfd)
170+
}
171+
172+
if nfd.args.Instance != "" {
173+
if ok, _ := regexp.MatchString(`^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$`, nfd.args.Instance); !ok {
170174
return nfd, fmt.Errorf("invalid -instance %q: instance name "+
171175
"must start and end with an alphanumeric character and may only contain "+
172-
"alphanumerics, `-`, `_` or `.`", args.Instance)
176+
"alphanumerics, `-`, `_` or `.`", nfd.args.Instance)
173177
}
174178
}
175179

176180
// Check TLS related args
177-
if args.CertFile != "" || args.KeyFile != "" || args.CaFile != "" {
178-
if args.CertFile == "" {
181+
if nfd.args.CertFile != "" || nfd.args.KeyFile != "" || nfd.args.CaFile != "" {
182+
if nfd.args.CertFile == "" {
179183
return nfd, fmt.Errorf("-cert-file needs to be specified alongside -key-file and -ca-file")
180184
}
181-
if args.KeyFile == "" {
185+
if nfd.args.KeyFile == "" {
182186
return nfd, fmt.Errorf("-key-file needs to be specified alongside -cert-file and -ca-file")
183187
}
184-
if args.CaFile == "" {
188+
if nfd.args.CaFile == "" {
185189
return nfd, fmt.Errorf("-ca-file needs to be specified alongside -cert-file and -key-file")
186190
}
187191
}
188192

189-
if args.ConfigFile != "" {
190-
nfd.configFilePath = filepath.Clean(args.ConfigFile)
193+
if nfd.args.ConfigFile != "" {
194+
nfd.configFilePath = filepath.Clean(nfd.args.ConfigFile)
191195
}
192196

193197
nfd.nodeUpdaterPool = newNodeUpdaterPool(nfd)
194198

195199
return nfd, nil
196200
}
197201

202+
// NfdMasterOption sets properties of the NfdMaster instance.
203+
type NfdMasterOption interface {
204+
apply(*nfdMaster)
205+
}
206+
207+
// WithArgs is used for passing settings from command line arguments.
208+
func WithArgs(args *Args) NfdMasterOption {
209+
return &nfdMasterOpt{f: func(n *nfdMaster) { n.args = *args }}
210+
}
211+
212+
// WithKuberneteClient forces to use the given kubernetes client, without
213+
// initializing one from kubeconfig.
214+
func WithKubernetesClient(cli k8sclient.Interface) NfdMasterOption {
215+
return &nfdMasterOpt{f: func(n *nfdMaster) { n.k8sClient = cli }}
216+
}
217+
218+
type nfdMasterOpt struct {
219+
f func(*nfdMaster)
220+
}
221+
222+
func (f *nfdMasterOpt) apply(n *nfdMaster) {
223+
f.f(n)
224+
}
225+
198226
func newDefaultConfig() *NFDConfig {
199227
return &NFDConfig{
200228
DenyLabelNs: utils.StringSetVal{},

pkg/nfd-master/nfd-master_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ import (
2626
func TestNewNfdMaster(t *testing.T) {
2727
Convey("When initializing new NfdMaster instance", t, func() {
2828
Convey("When one of -cert-file, -key-file or -ca-file is missing", func() {
29-
_, err := m.NewNfdMaster(&m.Args{CertFile: "crt", KeyFile: "key"})
30-
_, err2 := m.NewNfdMaster(&m.Args{KeyFile: "key", CaFile: "ca"})
31-
_, err3 := m.NewNfdMaster(&m.Args{CertFile: "crt", CaFile: "ca"})
29+
_, err := m.NewNfdMaster(m.WithArgs(&m.Args{CertFile: "crt", KeyFile: "key"}))
30+
_, err2 := m.NewNfdMaster(m.WithArgs(&m.Args{KeyFile: "key", CaFile: "ca"}))
31+
_, err3 := m.NewNfdMaster(m.WithArgs(&m.Args{CertFile: "crt", CaFile: "ca"}))
3232
Convey("An error should be returned", func() {
3333
So(err, ShouldNotBeNil)
3434
So(err2, ShouldNotBeNil)
3535
So(err3, ShouldNotBeNil)
3636
})
3737
})
3838
Convey("When -config is supplied", func() {
39-
_, err := m.NewNfdMaster(&m.Args{CertFile: "crt", KeyFile: "key", CaFile: "ca", ConfigFile: "master-config.yaml"})
39+
_, err := m.NewNfdMaster(m.WithArgs(&m.Args{CertFile: "crt", KeyFile: "key", CaFile: "ca", ConfigFile: "master-config.yaml"}))
4040
Convey("An error should not be returned", func() {
4141
So(err, ShouldBeNil)
4242
})

pkg/nfd-master/node-updater-pool_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func newFakeNodeUpdaterPool(nfdMaster *nfdMaster) *nodeUpdaterPool {
3434
}
3535

3636
func TestNodeUpdaterStart(t *testing.T) {
37-
fakeMaster := newFakeMaster(nil)
37+
fakeMaster := newFakeMaster()
3838
nodeUpdaterPool := newFakeNodeUpdaterPool(fakeMaster)
3939

4040
Convey("When starting the node updater pool", t, func() {
@@ -53,7 +53,7 @@ func TestNodeUpdaterStart(t *testing.T) {
5353
}
5454

5555
func TestNodeUpdaterStop(t *testing.T) {
56-
fakeMaster := newFakeMaster(nil)
56+
fakeMaster := newFakeMaster()
5757
nodeUpdaterPool := newFakeNodeUpdaterPool(fakeMaster)
5858

5959
nodeUpdaterPool.start(10)
@@ -70,7 +70,7 @@ func TestNodeUpdaterStop(t *testing.T) {
7070
}
7171

7272
func TestRunNodeUpdater(t *testing.T) {
73-
fakeMaster := newFakeMaster(fakek8sclient.NewSimpleClientset())
73+
fakeMaster := newFakeMaster(WithKubernetesClient(fakek8sclient.NewSimpleClientset()))
7474
fakeMaster.nfdController = newFakeNfdAPIController(fakenfdclient.NewSimpleClientset())
7575
nodeUpdaterPool := newFakeNodeUpdaterPool(fakeMaster)
7676

pkg/nfd-worker/nfd-worker_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func setupTest(args *master.Args) testContext {
5252
os.Exit(1)
5353
}
5454
_ = features.NFDMutableFeatureGate.OverrideDefault(features.NodeFeatureAPI, false)
55-
m, err := master.NewNfdMaster(args)
55+
m, err := master.NewNfdMaster(master.WithArgs(args))
5656
if err != nil {
5757
fmt.Printf("Test setup failed: %v\n", err)
5858
os.Exit(1)

0 commit comments

Comments
 (0)