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:
commit
116b24697b
11 changed files with 178 additions and 47 deletions
|
@ -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,
|
||||
|
|
|
@ -20,3 +20,11 @@ rules:
|
|||
- create
|
||||
- get
|
||||
- update
|
||||
- apiGroups:
|
||||
- nfd.k8s-sigs.io
|
||||
resources:
|
||||
- nodefeaturerules
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -24,6 +24,7 @@ nodeFeatureRule:
|
|||
master:
|
||||
instance:
|
||||
extraLabelNs: []
|
||||
featureRulesController: true
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
77
pkg/nfd-master/nodefeaturerule-controller.go
Normal file
77
pkg/nfd-master/nodefeaturerule-controller.go
Normal 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:
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue