Skip to content

Commit 521206d

Browse files
authored
Merge pull request #1775 from ArangoGutierrez/cp_1752_r0.15
[Release-0.15] Use worker DS OwnerReference for NF's
2 parents 46d5026 + 8a1d33b commit 521206d

File tree

7 files changed

+128
-46
lines changed

7 files changed

+128
-46
lines changed

cmd/nfd-worker/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func main() {
7373
utils.ConfigureGrpcKlog()
7474

7575
// Get new NfdWorker instance
76-
instance, err := worker.NewNfdWorker(args)
76+
instance, err := worker.NewNfdWorker(worker.WithArgs(args))
7777
if err != nil {
7878
klog.ErrorS(err, "failed to initialize NfdWorker instance")
7979
os.Exit(1)

deployment/base/rbac/worker-role.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,9 @@ rules:
1111
- create
1212
- get
1313
- update
14+
- apiGroups:
15+
- ""
16+
resources:
17+
- pods
18+
verbs:
19+
- get

deployment/helm/node-feature-discovery/templates/role.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,10 @@ rules:
1515
- create
1616
- get
1717
- update
18+
- apiGroups:
19+
- ""
20+
resources:
21+
- pods
22+
verbs:
23+
- get
1824
{{- end }}
19-

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/pkg/apis/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: 89 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
135139
type 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,

pkg/nfd-worker/nfd-worker_test.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"time"
2525

2626
. "github.com/smartystreets/goconvey/convey"
27+
fakeclient "k8s.io/client-go/kubernetes/fake"
2728

2829
master "sigs.k8s.io/node-feature-discovery/pkg/nfd-master"
2930
worker "sigs.k8s.io/node-feature-discovery/pkg/nfd-worker"
@@ -78,9 +79,12 @@ func teardownTest(ctx testContext) {
7879
func TestNewNfdWorker(t *testing.T) {
7980
Convey("When initializing new NfdWorker instance", t, func() {
8081
Convey("When one of -cert-file, -key-file or -ca-file is missing", func() {
81-
_, err := worker.NewNfdWorker(&worker.Args{CertFile: "crt", KeyFile: "key"})
82-
_, err2 := worker.NewNfdWorker(&worker.Args{KeyFile: "key", CaFile: "ca"})
83-
_, err3 := worker.NewNfdWorker(&worker.Args{CertFile: "crt", CaFile: "ca"})
82+
_, err := worker.NewNfdWorker(worker.WithArgs(&worker.Args{CertFile: "crt", KeyFile: "key"}),
83+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
84+
_, err2 := worker.NewNfdWorker(worker.WithArgs(&worker.Args{KeyFile: "key", CaFile: "ca"}),
85+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
86+
_, err3 := worker.NewNfdWorker(worker.WithArgs(&worker.Args{CertFile: "crt", CaFile: "ca"}),
87+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
8488
Convey("An error should be returned", func() {
8589
So(err, ShouldNotBeNil)
8690
So(err2, ShouldNotBeNil)
@@ -100,7 +104,8 @@ func TestRun(t *testing.T) {
100104
Oneshot: true,
101105
Overrides: worker.ConfigOverrideArgs{LabelSources: &utils.StringSliceVal{"fake"}},
102106
}
103-
fooasdf, _ := worker.NewNfdWorker(args)
107+
fooasdf, _ := worker.NewNfdWorker(worker.WithArgs(args),
108+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
104109
err := fooasdf.Run()
105110
Convey("No error should be returned", func() {
106111
So(err, ShouldBeNil)
@@ -129,7 +134,8 @@ func TestRunTls(t *testing.T) {
129134
Oneshot: true,
130135
Overrides: worker.ConfigOverrideArgs{LabelSources: &utils.StringSliceVal{"fake"}},
131136
}
132-
w, _ := worker.NewNfdWorker(&workerArgs)
137+
w, _ := worker.NewNfdWorker(worker.WithArgs(&workerArgs),
138+
worker.WithKubernetesClient(fakeclient.NewSimpleClientset()))
133139
err := w.Run()
134140
Convey("No error should be returned", func() {
135141
So(err, ShouldBeNil)

test/e2e/utils/rbac.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ func createRoleWorker(ctx context.Context, cs clientset.Interface, ns string) (*
204204
Resources: []string{"nodefeatures"},
205205
Verbs: []string{"create", "get", "update"},
206206
},
207+
{
208+
APIGroups: []string{""},
209+
Resources: []string{"pods"},
210+
Verbs: []string{"get"},
211+
},
207212
},
208213
}
209214
return cs.RbacV1().Roles(ns).Update(ctx, cr, metav1.UpdateOptions{})

0 commit comments

Comments
 (0)