1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-28 02:37:11 +00:00

Merge pull request #656 from marquiz/devel/crd-controller

nfd-master: implement controller for NodeFeatureRule CRs
This commit is contained in:
Kubernetes Prow Robot 2021-11-22 08:33:09 -08:00 committed by GitHub
commit 116b24697b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 178 additions and 47 deletions

View file

@ -96,6 +96,8 @@ func initFlags(flagset *flag.FlagSet) *master.Args {
"NB: the label namespace is omitted i.e. the filter is only applied to the name part after '/'.")
flagset.BoolVar(&args.NoPublish, "no-publish", false,
"Do not publish feature labels")
flagset.BoolVar(&args.FeatureRulesController, "featurerules-controller", true,
"Enable controller for NodeFeatureRule objects. Generates node labels based on the rules in these CRs.")
flagset.IntVar(&args.Port, "port", 8080,
"Port on which to listen for connections.")
flagset.BoolVar(&args.Prune, "prune", false,

View file

@ -20,3 +20,11 @@ rules:
- create
- get
- update
- apiGroups:
- nfd.k8s-sigs.io
resources:
- nodefeaturerules
verbs:
- get
- list
- watch

View file

@ -18,6 +18,14 @@ rules:
- patch
- update
- list
- apiGroups:
- nfd.k8s-sigs.io
resources:
- nodefeaturerules
verbs:
- get
- list
- watch
{{- if .Values.topologyUpdater.enable }}
- apiGroups:
- topology.node.k8s.io

View file

@ -62,6 +62,7 @@ spec:
{{- if .Values.master.extraLabelNs | empty | not }}
- "--extra-label-ns={{- join "," .Values.master.extraLabelNs }}"
{{- end }}
- "-featurerules-controller={{ .Values.master.featureRulesController }}"
## Enable TLS authentication
## The example below assumes having the root certificate named ca.crt stored in
## a ConfigMap named nfd-ca-cert, and, the TLS authentication credentials stored

View file

@ -24,6 +24,7 @@ nodeFeatureRule:
master:
instance:
extraLabelNs: []
featureRulesController: true
replicaCount: 1

View file

@ -139,10 +139,9 @@ nfd-master -verify-node-name -ca-file=/opt/nfd/ca.crt \
### -no-publish
The `-no-publish` flag disables all communication with the Kubernetes API
server, making a "dry-run" flag for nfd-master. No Labels, Annotations or
ExtendedResources (or any other properties of any Kubernetes API objects) are
modified.
The `-no-publish` flag disables updates to the Node objects in the Kubernetes
API server, making a "dry-run" flag for nfd-master. No Labels, Annotations or
ExtendedResources of nodes are updated.
Default: *false*
@ -152,6 +151,20 @@ Example:
nfd-master -no-publish
```
### -featurerules-controller
The `-featurerules-controller` flag controlers the processing of
NodeFeatureRule objects, effectively enabling/disabling labels from these
custom labeling rules.
Default: *true*
Example:
```bash
nfd-master -featurerules-controller=false
```
### -label-whitelist
The `-label-whitelist` specifies a regular expression for filtering feature

View file

@ -299,6 +299,7 @@ We have introduced the following Chart parameters.
| `master.*` | dict | | NFD master deployment configuration |
| `master.instance` | string | | Instance name. Used to separate annotation namespaces for multiple parallel deployments |
| `master.extraLabelNs` | array | [] | List of allowed extra label namespaces |
| `master.featureRulesController` | bool | True | Specifies whether the controller for processing of NodeFeatureRule objects is enable. |
| `master.replicaCount` | integer | 1 | Number of desired pods. This is a pointer to distinguish between explicit zero and not specified |
| `master.podSecurityContext` | dict | {} | SecurityContext holds pod-level security attributes and common container settings |
| `master.service.type` | string | ClusterIP | NFD master service type |

View file

@ -31,24 +31,11 @@ import (
// Implements APIHelpers
type K8sHelpers struct {
Kubeconfig string
Kubeconfig *restclient.Config
}
func (h K8sHelpers) GetClient() (*k8sclient.Clientset, error) {
// Set up an in-cluster K8S client.
var config *restclient.Config
var err error
if h.Kubeconfig == "" {
config, err = restclient.InClusterConfig()
} else {
config, err = clientcmd.BuildConfigFromFlags("", h.Kubeconfig)
}
if err != nil {
return nil, err
}
clientset, err := k8sclient.NewForConfig(config)
clientset, err := k8sclient.NewForConfig(h.Kubeconfig)
if err != nil {
return nil, err
}
@ -56,20 +43,7 @@ func (h K8sHelpers) GetClient() (*k8sclient.Clientset, error) {
}
func (h K8sHelpers) GetTopologyClient() (*topologyclientset.Clientset, error) {
// Set up an in-cluster K8S client.
var config *restclient.Config
var err error
if h.Kubeconfig == "" {
config, err = restclient.InClusterConfig()
} else {
config, err = clientcmd.BuildConfigFromFlags("", h.Kubeconfig)
}
if err != nil {
return nil, err
}
topologyClient, err := topologyclientset.NewForConfig(config)
topologyClient, err := topologyclientset.NewForConfig(h.Kubeconfig)
if err != nil {
return nil, err
}
@ -132,3 +106,10 @@ func (h K8sHelpers) GetPod(cli *k8sclient.Clientset, namespace string, podName s
return pod, nil
}
func GetKubeconfig(path string) (*restclient.Config, error) {
if path == "" {
return restclient.InClusterConfig()
}
return clientcmd.BuildConfigFromFlags("", path)
}

View file

@ -91,7 +91,15 @@ func (w *nfdTopologyUpdater) Run() error {
return fmt.Errorf("failed to get PodResource Client: %w", err)
}
kubeApihelper := apihelper.K8sHelpers{Kubeconfig: w.args.KubeConfigFile}
var kubeApihelper apihelper.K8sHelpers
if !w.args.NoPublish {
kubeconfig, err := apihelper.GetKubeconfig(w.args.KubeConfigFile)
if err != nil {
return err
}
kubeApihelper = apihelper.K8sHelpers{Kubeconfig: kubeconfig}
}
var resScan resourcemonitor.ResourcesScanner
resScan, err = resourcemonitor.NewPodResourcesScanner(w.resourcemonitorArgs.Namespace, podResClient, kubeApihelper)

View file

@ -39,6 +39,7 @@ import (
api "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
restclient "k8s.io/client-go/rest"
"k8s.io/klog/v2"
"sigs.k8s.io/node-feature-discovery/pkg/apihelper"
@ -82,18 +83,19 @@ type Annotations map[string]string
// Args holds command line arguments
type Args struct {
CaFile string
CertFile string
ExtraLabelNs utils.StringSetVal
Instance string
KeyFile string
Kubeconfig string
LabelWhiteList utils.RegexpVal
NoPublish bool
Port int
Prune bool
VerifyNodeName bool
ResourceLabels utils.StringSetVal
CaFile string
CertFile string
ExtraLabelNs utils.StringSetVal
Instance string
KeyFile string
Kubeconfig string
LabelWhiteList utils.RegexpVal
FeatureRulesController bool
NoPublish bool
Port int
Prune bool
VerifyNodeName bool
ResourceLabels utils.StringSetVal
}
type NfdMaster interface {
@ -103,6 +105,8 @@ type NfdMaster interface {
}
type nfdMaster struct {
*nfdController
args Args
nodeName string
annotationNs string
@ -110,6 +114,7 @@ type nfdMaster struct {
stop chan struct{}
ready chan bool
apihelper apihelper.APIHelpers
kubeconfig *restclient.Config
}
// Create new NfdMaster server instance.
@ -145,7 +150,13 @@ func NewNfdMaster(args *Args) (NfdMaster, error) {
}
// Initialize Kubernetes API helpers
nfd.apihelper = apihelper.K8sHelpers{Kubeconfig: args.Kubeconfig}
if !args.NoPublish {
kubeconfig, err := nfd.getKubeconfig()
if err != nil {
return nfd, err
}
nfd.apihelper = apihelper.K8sHelpers{Kubeconfig: kubeconfig}
}
return nfd, nil
}
@ -163,6 +174,14 @@ func (m *nfdMaster) Run() error {
return m.prune()
}
if m.args.FeatureRulesController {
kubeconfig, err := m.getKubeconfig()
if err != nil {
return err
}
m.nfdController = newNfdController(kubeconfig)
}
if !m.args.NoPublish {
err := m.updateMasterNode()
if err != nil {
@ -233,6 +252,10 @@ func (m *nfdMaster) Run() error {
func (m *nfdMaster) Stop() {
m.server.Stop()
if m.nfdController != nil {
m.nfdController.stop()
}
select {
case m.stop <- struct{}{}:
default:
@ -519,6 +542,14 @@ func (m *nfdMaster) annotationName(name string) string {
return path.Join(m.annotationNs, name)
}
func (m *nfdMaster) getKubeconfig() (*restclient.Config, error) {
var err error
if m.kubeconfig == nil {
m.kubeconfig, err = apihelper.GetKubeconfig(m.args.Kubeconfig)
}
return m.kubeconfig, err
}
// Remove any labels having the given prefix
func removeLabelsWithPrefix(n *api.Node, search string) []apihelper.JsonPatch {
var p []apihelper.JsonPatch

View file

@ -0,0 +1,77 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nfdmaster
import (
"time"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
nfdclientset "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned"
nfdscheme "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned/scheme"
nfdinformers "sigs.k8s.io/node-feature-discovery/pkg/generated/informers/externalversions"
nfdlisters "sigs.k8s.io/node-feature-discovery/pkg/generated/listers/nfd/v1alpha1"
)
type nfdController struct {
lister nfdlisters.NodeFeatureRuleLister
stopChan chan struct{}
}
func newNfdController(config *restclient.Config) *nfdController {
c := &nfdController{
stopChan: make(chan struct{}, 1),
}
nfdClient := nfdclientset.NewForConfigOrDie(config)
informerFactory := nfdinformers.NewSharedInformerFactory(nfdClient, 5*time.Minute)
informer := informerFactory.Nfd().V1alpha1().NodeFeatureRules()
informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(object interface{}) {
key, _ := cache.MetaNamespaceKeyFunc(object)
klog.V(2).Infof("LabelRule %v added", key)
},
UpdateFunc: func(oldObject, newObject interface{}) {
key, _ := cache.MetaNamespaceKeyFunc(newObject)
klog.V(2).Infof("LabelRule %v updated", key)
},
DeleteFunc: func(object interface{}) {
key, _ := cache.MetaNamespaceKeyFunc(object)
klog.V(2).Infof("LabelRule %v deleted", key)
},
})
informerFactory.Start(c.stopChan)
utilruntime.Must(nfdv1alpha1.AddToScheme(nfdscheme.Scheme))
c.lister = informer.Lister()
return c
}
func (c *nfdController) stop() {
select {
case c.stopChan <- struct{}{}:
default:
}
}