Skip to content

Commit fd2893e

Browse files
authored
Merge pull request #1592 from AhmedThresh/feat-configure-cr-restrictions
feat/nfd-master: configure CR restrictions
2 parents 83ba1ff + 28b40c9 commit fd2893e

File tree

13 files changed

+728
-41
lines changed

13 files changed

+728
-41
lines changed

deployment/base/rbac/master-clusterrole.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ kind: ClusterRole
33
metadata:
44
name: nfd-master
55
rules:
6+
- apiGroups:
7+
- ""
8+
resources:
9+
- namespaces
10+
verbs:
11+
- watch
12+
- list
613
- apiGroups:
714
- ""
815
resources:

deployment/components/master-config/nfd-master.conf.example

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@
66
# enableTaints: false
77
# labelWhiteList: "foo"
88
# resyncPeriod: "2h"
9+
# restrictions:
10+
# disableLabels: true
11+
# disableTaints: true
12+
# disableExtendedResources: true
13+
# disableAnnotations: true
14+
# allowOverwrite: false
15+
# denyNodeFeatureLabels: true
16+
# nodeFeatureNamespaceSelector:
17+
# matchLabels:
18+
# kubernetes.io/metadata.name: "node-feature-discovery"
19+
# matchExpressions:
20+
# - key: "kubernetes.io/metadata.name"
21+
# operator: "In"
22+
# values:
23+
# - "node-feature-discovery"
924
# klog:
1025
# addDirHeader: false
1126
# alsologtostderr: false

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ metadata:
66
labels:
77
{{- include "node-feature-discovery.labels" . | nindent 4 }}
88
rules:
9+
- apiGroups:
10+
- ""
11+
resources:
12+
- namespaces
13+
verbs:
14+
- watch
15+
- list
916
- apiGroups:
1017
- ""
1118
resources:

deployment/helm/node-feature-discovery/values.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,21 @@ master:
3030
# enableTaints: false
3131
# labelWhiteList: "foo"
3232
# resyncPeriod: "2h"
33+
# restrictions:
34+
# disableLabels: true
35+
# disableTaints: true
36+
# disableExtendedResources: true
37+
# disableAnnotations: true
38+
# allowOverwrite: false
39+
# denyNodeFeatureLabels: true
40+
# nodeFeatureNamespaceSelector:
41+
# matchLabels:
42+
# kubernetes.io/metadata.name: "node-feature-discovery"
43+
# matchExpressions:
44+
# - key: "kubernetes.io/metadata.name"
45+
# operator: "In"
46+
# values:
47+
# - "node-feature-discovery"
3348
# klog:
3449
# addDirHeader: false
3550
# alsologtostderr: false

docs/reference/master-configuration-reference.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,104 @@ Comma-separated list of `pattern=N` settings for file-filtered logging.
338338
Default: *empty*
339339

340340
Run-time configurable: yes
341+
342+
## restrictions (EXPERIMENTAL)
343+
344+
The following options specify the restrictions that can be applied by the
345+
nfd-master on the deployed Custom Resources in the cluster.
346+
347+
### restrictions.nodeFeatureNamespaceSelector
348+
349+
The `nodeFeatureNamespaceSelector` option specifies the NodeFeatures namespaces
350+
to watch, which can be selected by using `metav1.LabelSelector` as a type for
351+
this option. An empty value selects all namespaces to be watched.
352+
353+
Default: *empty*
354+
355+
Example:
356+
357+
```yaml
358+
restrictions:
359+
nodeFeatureNamespaceSelector:
360+
matchLabels:
361+
kubernetes.io/metadata.name: "node-feature-discovery"
362+
matchExpressions:
363+
- key: "kubernetes.io/metadata.name"
364+
operator: "In"
365+
values:
366+
- "node-feature-discovery"
367+
```
368+
369+
### restrictions.disableLabels
370+
371+
The `disableLabels` option controls whether to allow creation of node labels
372+
from NodeFeature and NodeFeatureRule CRs or not.
373+
374+
Default: false
375+
376+
Example:
377+
378+
```yaml
379+
restrictions:
380+
disableLabels: true
381+
```
382+
383+
### restrictions.disableExtendedResources
384+
385+
The `disableExtendedResources` option controls whether to allow creation of
386+
node extended resources from NodeFeatureRule CR or not.
387+
388+
Default: false
389+
390+
Example:
391+
392+
```yaml
393+
restrictions:
394+
disableExtendedResources: true
395+
```
396+
397+
### restrictions.disableAnnotations
398+
399+
he `disableAnnotations` option controls whether to allow creation of node annotations
400+
from NodeFeatureRule CR or not.
401+
402+
Default: false
403+
404+
Example:
405+
406+
```yaml
407+
restrictions:
408+
disableAnnotations: true
409+
```
410+
411+
### restrictions.allowOverwrite
412+
413+
The `allowOverwrite` option controls whether NFD is allowed to overwrite and
414+
take over management of existing node labels, annotations, and extended resources.
415+
Labels, annotations and extended resources created by NFD itself are not affected
416+
(overwrite cannot be disabled). NFD tracks the labels, annotations and extended
417+
resources that it manages with specific
418+
[node annotations](../get-started/introduction.md#node-annotations).
419+
420+
Default: true
421+
422+
Example:
423+
424+
```yaml
425+
restrictions:
426+
allowOverwrite: false
427+
```
428+
429+
### restrictions.denyNodeFeatureLabels
430+
431+
The `denyNodeFeatureLabels` option specifies whether to deny labels from 3rd party
432+
NodeFeature objects or not. NodeFeature objects created by nfd-worker are not affected.
433+
434+
Default: false
435+
436+
Example:
437+
438+
```yaml
439+
restrictions:
440+
denyNodeFeatureLabels: true
441+
```

pkg/nfd-master/namespace-lister.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package nfdmaster
17+
18+
import (
19+
"time"
20+
21+
corev1 "k8s.io/api/core/v1"
22+
"k8s.io/apimachinery/pkg/labels"
23+
"k8s.io/client-go/informers"
24+
k8sclient "k8s.io/client-go/kubernetes"
25+
v1lister "k8s.io/client-go/listers/core/v1"
26+
)
27+
28+
// NamespaceLister lists kubernetes namespaces.
29+
type NamespaceLister struct {
30+
namespaceLister v1lister.NamespaceLister
31+
labelsSelector labels.Selector
32+
stopChan chan struct{}
33+
}
34+
35+
func newNamespaceLister(k8sClient k8sclient.Interface, labelsSelector labels.Selector) *NamespaceLister {
36+
factory := informers.NewSharedInformerFactory(k8sClient, time.Hour)
37+
namespaceLister := factory.Core().V1().Namespaces().Lister()
38+
39+
stopChan := make(chan struct{})
40+
factory.Start(stopChan) // runs in background
41+
factory.WaitForCacheSync(stopChan)
42+
43+
return &NamespaceLister{
44+
namespaceLister: namespaceLister,
45+
labelsSelector: labelsSelector,
46+
stopChan: stopChan,
47+
}
48+
}
49+
50+
// list returns all kubernetes namespaces.
51+
func (lister *NamespaceLister) list() ([]*corev1.Namespace, error) {
52+
return lister.namespaceLister.List(lister.labelsSelector)
53+
}
54+
55+
// stop closes the channel used by the lister
56+
func (lister *NamespaceLister) stop() {
57+
close(lister.stopChan)
58+
}

pkg/nfd-master/nfd-api-controller.go

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2424
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
25+
k8sclient "k8s.io/client-go/kubernetes"
2526
restclient "k8s.io/client-go/rest"
2627
"k8s.io/client-go/tools/cache"
2728
"k8s.io/klog/v2"
@@ -46,12 +47,16 @@ type nfdController struct {
4647
updateOneNodeChan chan string
4748
updateAllNodeFeatureGroupsChan chan struct{}
4849
updateNodeFeatureGroupChan chan string
50+
51+
namespaceLister *NamespaceLister
4952
}
5053

5154
type nfdApiControllerOptions struct {
52-
DisableNodeFeature bool
53-
DisableNodeFeatureGroup bool
54-
ResyncPeriod time.Duration
55+
DisableNodeFeature bool
56+
DisableNodeFeatureGroup bool
57+
ResyncPeriod time.Duration
58+
K8sClient k8sclient.Interface
59+
NodeFeatureNamespaceSelector *metav1.LabelSelector
5560
}
5661

5762
func init() {
@@ -67,8 +72,16 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC
6772
updateNodeFeatureGroupChan: make(chan string),
6873
}
6974

70-
nfdClient := nfdclientset.NewForConfigOrDie(config)
75+
if nfdApiControllerOptions.NodeFeatureNamespaceSelector != nil {
76+
labelMap, err := metav1.LabelSelectorAsSelector(nfdApiControllerOptions.NodeFeatureNamespaceSelector)
77+
if err != nil {
78+
klog.ErrorS(err, "failed to convert label selector to map", "selector", nfdApiControllerOptions.NodeFeatureNamespaceSelector)
79+
return nil, err
80+
}
81+
c.namespaceLister = newNamespaceLister(nfdApiControllerOptions.K8sClient, labelMap)
82+
}
7183

84+
nfdClient := nfdclientset.NewForConfigOrDie(config)
7285
klog.V(2).InfoS("initializing new NFD API controller", "options", utils.DelayedDumper(nfdApiControllerOptions))
7386

7487
informerFactory := nfdinformers.NewSharedInformerFactory(nfdClient, nfdApiControllerOptions.ResyncPeriod)
@@ -89,7 +102,11 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC
89102
AddFunc: func(obj interface{}) {
90103
nfr := obj.(*nfdv1alpha1.NodeFeature)
91104
klog.V(2).InfoS("NodeFeature added", "nodefeature", klog.KObj(nfr))
92-
c.updateOneNode("NodeFeature", nfr)
105+
if c.isNamespaceSelected(nfr.Namespace) {
106+
c.updateOneNode("NodeFeature", nfr)
107+
} else {
108+
klog.V(2).InfoS("NodeFeature namespace is not selected, skipping", "nodefeature", klog.KObj(nfr))
109+
}
93110
if !nfdApiControllerOptions.DisableNodeFeatureGroup {
94111
c.updateAllNodeFeatureGroups()
95112
}
@@ -187,6 +204,7 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC
187204

188205
func (c *nfdController) stop() {
189206
close(c.stopChan)
207+
c.namespaceLister.stop()
190208
}
191209

192210
func getNodeNameForObj(obj metav1.Object) (string, error) {
@@ -212,6 +230,28 @@ func (c *nfdController) updateOneNode(typ string, obj metav1.Object) {
212230
}
213231
}
214232

233+
func (c *nfdController) isNamespaceSelected(namespace string) bool {
234+
// this means that the user didn't specify any namespace selector
235+
// which means that we allow all namespaces
236+
if c.namespaceLister == nil {
237+
return true
238+
}
239+
240+
namespaces, err := c.namespaceLister.list()
241+
if err != nil {
242+
klog.ErrorS(err, "failed to query namespaces by the namespace lister")
243+
return false
244+
}
245+
246+
for _, ns := range namespaces {
247+
if ns.Name == namespace {
248+
return true
249+
}
250+
}
251+
252+
return false
253+
}
254+
215255
func (c *nfdController) updateAllNodes() {
216256
select {
217257
case c.updateAllNodesChan <- struct{}{}:

0 commit comments

Comments
 (0)