1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2024-12-14 11:57:51 +00:00

Add CRD for nfd-worker config

Signed-off-by: Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>
This commit is contained in:
Oleg Zhurakivskyy 2024-09-02 19:30:44 +03:00
parent 620e16e334
commit 760caaccce
22 changed files with 1038 additions and 0 deletions

View file

@ -40,6 +40,10 @@ func (c *FakeNfdV1alpha1) NodeFeatureRules() v1alpha1.NodeFeatureRuleInterface {
return &FakeNodeFeatureRules{c}
}
func (c *FakeNfdV1alpha1) NodeFeatureWorkerConfigs(namespace string) v1alpha1.NodeFeatureWorkerConfigInterface {
return &FakeNodeFeatureWorkerConfigs{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeNfdV1alpha1) RESTClient() rest.Interface {

View file

@ -0,0 +1,134 @@
/*
Copyright 2024 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
v1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
)
// FakeNodeFeatureWorkerConfigs implements NodeFeatureWorkerConfigInterface
type FakeNodeFeatureWorkerConfigs struct {
Fake *FakeNfdV1alpha1
ns string
}
var nodefeatureworkerconfigsResource = v1alpha1.SchemeGroupVersion.WithResource("nodefeatureworkerconfigs")
var nodefeatureworkerconfigsKind = v1alpha1.SchemeGroupVersion.WithKind("NodeFeatureWorkerConfig")
// Get takes name of the nodeFeatureWorkerConfig, and returns the corresponding nodeFeatureWorkerConfig object, and an error if there is any.
func (c *FakeNodeFeatureWorkerConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeFeatureWorkerConfig, err error) {
emptyResult := &v1alpha1.NodeFeatureWorkerConfig{}
obj, err := c.Fake.
Invokes(testing.NewGetActionWithOptions(nodefeatureworkerconfigsResource, c.ns, name, options), emptyResult)
if obj == nil {
return emptyResult, err
}
return obj.(*v1alpha1.NodeFeatureWorkerConfig), err
}
// List takes label and field selectors, and returns the list of NodeFeatureWorkerConfigs that match those selectors.
func (c *FakeNodeFeatureWorkerConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeFeatureWorkerConfigList, err error) {
emptyResult := &v1alpha1.NodeFeatureWorkerConfigList{}
obj, err := c.Fake.
Invokes(testing.NewListActionWithOptions(nodefeatureworkerconfigsResource, nodefeatureworkerconfigsKind, c.ns, opts), emptyResult)
if obj == nil {
return emptyResult, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.NodeFeatureWorkerConfigList{ListMeta: obj.(*v1alpha1.NodeFeatureWorkerConfigList).ListMeta}
for _, item := range obj.(*v1alpha1.NodeFeatureWorkerConfigList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested nodeFeatureWorkerConfigs.
func (c *FakeNodeFeatureWorkerConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchActionWithOptions(nodefeatureworkerconfigsResource, c.ns, opts))
}
// Create takes the representation of a nodeFeatureWorkerConfig and creates it. Returns the server's representation of the nodeFeatureWorkerConfig, and an error, if there is any.
func (c *FakeNodeFeatureWorkerConfigs) Create(ctx context.Context, nodeFeatureWorkerConfig *v1alpha1.NodeFeatureWorkerConfig, opts v1.CreateOptions) (result *v1alpha1.NodeFeatureWorkerConfig, err error) {
emptyResult := &v1alpha1.NodeFeatureWorkerConfig{}
obj, err := c.Fake.
Invokes(testing.NewCreateActionWithOptions(nodefeatureworkerconfigsResource, c.ns, nodeFeatureWorkerConfig, opts), emptyResult)
if obj == nil {
return emptyResult, err
}
return obj.(*v1alpha1.NodeFeatureWorkerConfig), err
}
// Update takes the representation of a nodeFeatureWorkerConfig and updates it. Returns the server's representation of the nodeFeatureWorkerConfig, and an error, if there is any.
func (c *FakeNodeFeatureWorkerConfigs) Update(ctx context.Context, nodeFeatureWorkerConfig *v1alpha1.NodeFeatureWorkerConfig, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureWorkerConfig, err error) {
emptyResult := &v1alpha1.NodeFeatureWorkerConfig{}
obj, err := c.Fake.
Invokes(testing.NewUpdateActionWithOptions(nodefeatureworkerconfigsResource, c.ns, nodeFeatureWorkerConfig, opts), emptyResult)
if obj == nil {
return emptyResult, err
}
return obj.(*v1alpha1.NodeFeatureWorkerConfig), err
}
// Delete takes name of the nodeFeatureWorkerConfig and deletes it. Returns an error if one occurs.
func (c *FakeNodeFeatureWorkerConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteActionWithOptions(nodefeatureworkerconfigsResource, c.ns, name, opts), &v1alpha1.NodeFeatureWorkerConfig{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeNodeFeatureWorkerConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionActionWithOptions(nodefeatureworkerconfigsResource, c.ns, opts, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha1.NodeFeatureWorkerConfigList{})
return err
}
// Patch applies the patch and returns the patched nodeFeatureWorkerConfig.
func (c *FakeNodeFeatureWorkerConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureWorkerConfig, err error) {
emptyResult := &v1alpha1.NodeFeatureWorkerConfig{}
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceActionWithOptions(nodefeatureworkerconfigsResource, c.ns, name, pt, data, opts, subresources...), emptyResult)
if obj == nil {
return emptyResult, err
}
return obj.(*v1alpha1.NodeFeatureWorkerConfig), err
}

View file

@ -23,3 +23,5 @@ type NodeFeatureExpansion interface{}
type NodeFeatureGroupExpansion interface{}
type NodeFeatureRuleExpansion interface{}
type NodeFeatureWorkerConfigExpansion interface{}

View file

@ -31,6 +31,7 @@ type NfdV1alpha1Interface interface {
NodeFeaturesGetter
NodeFeatureGroupsGetter
NodeFeatureRulesGetter
NodeFeatureWorkerConfigsGetter
}
// NfdV1alpha1Client is used to interact with features provided by the nfd.k8s-sigs.io group.
@ -50,6 +51,10 @@ func (c *NfdV1alpha1Client) NodeFeatureRules() NodeFeatureRuleInterface {
return newNodeFeatureRules(c)
}
func (c *NfdV1alpha1Client) NodeFeatureWorkerConfigs(namespace string) NodeFeatureWorkerConfigInterface {
return newNodeFeatureWorkerConfigs(c, namespace)
}
// NewForConfig creates a new NfdV1alpha1Client for the given config.
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
// where httpClient was generated with rest.HTTPClientFor(c).

View file

@ -0,0 +1,67 @@
/*
Copyright 2024 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
gentype "k8s.io/client-go/gentype"
scheme "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/scheme"
v1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
)
// NodeFeatureWorkerConfigsGetter has a method to return a NodeFeatureWorkerConfigInterface.
// A group's client should implement this interface.
type NodeFeatureWorkerConfigsGetter interface {
NodeFeatureWorkerConfigs(namespace string) NodeFeatureWorkerConfigInterface
}
// NodeFeatureWorkerConfigInterface has methods to work with NodeFeatureWorkerConfig resources.
type NodeFeatureWorkerConfigInterface interface {
Create(ctx context.Context, nodeFeatureWorkerConfig *v1alpha1.NodeFeatureWorkerConfig, opts v1.CreateOptions) (*v1alpha1.NodeFeatureWorkerConfig, error)
Update(ctx context.Context, nodeFeatureWorkerConfig *v1alpha1.NodeFeatureWorkerConfig, opts v1.UpdateOptions) (*v1alpha1.NodeFeatureWorkerConfig, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.NodeFeatureWorkerConfig, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.NodeFeatureWorkerConfigList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureWorkerConfig, err error)
NodeFeatureWorkerConfigExpansion
}
// nodeFeatureWorkerConfigs implements NodeFeatureWorkerConfigInterface
type nodeFeatureWorkerConfigs struct {
*gentype.ClientWithList[*v1alpha1.NodeFeatureWorkerConfig, *v1alpha1.NodeFeatureWorkerConfigList]
}
// newNodeFeatureWorkerConfigs returns a NodeFeatureWorkerConfigs
func newNodeFeatureWorkerConfigs(c *NfdV1alpha1Client, namespace string) *nodeFeatureWorkerConfigs {
return &nodeFeatureWorkerConfigs{
gentype.NewClientWithList[*v1alpha1.NodeFeatureWorkerConfig, *v1alpha1.NodeFeatureWorkerConfigList](
"nodefeatureworkerconfigs",
c.RESTClient(),
scheme.ParameterCodec,
namespace,
func() *v1alpha1.NodeFeatureWorkerConfig { return &v1alpha1.NodeFeatureWorkerConfig{} },
func() *v1alpha1.NodeFeatureWorkerConfigList { return &v1alpha1.NodeFeatureWorkerConfigList{} }),
}
}

View file

@ -59,6 +59,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
return &genericInformer{resource: resource.GroupResource(), informer: f.Nfd().V1alpha1().NodeFeatureGroups().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("nodefeaturerules"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Nfd().V1alpha1().NodeFeatureRules().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("nodefeatureworkerconfigs"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Nfd().V1alpha1().NodeFeatureWorkerConfigs().Informer()}, nil
}

View file

@ -30,6 +30,8 @@ type Interface interface {
NodeFeatureGroups() NodeFeatureGroupInformer
// NodeFeatureRules returns a NodeFeatureRuleInformer.
NodeFeatureRules() NodeFeatureRuleInformer
// NodeFeatureWorkerConfigs returns a NodeFeatureWorkerConfigInformer.
NodeFeatureWorkerConfigs() NodeFeatureWorkerConfigInformer
}
type version struct {
@ -57,3 +59,8 @@ func (v *version) NodeFeatureGroups() NodeFeatureGroupInformer {
func (v *version) NodeFeatureRules() NodeFeatureRuleInformer {
return &nodeFeatureRuleInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
}
// NodeFeatureWorkerConfigs returns a NodeFeatureWorkerConfigInformer.
func (v *version) NodeFeatureWorkerConfigs() NodeFeatureWorkerConfigInformer {
return &nodeFeatureWorkerConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View file

@ -0,0 +1,90 @@
/*
Copyright 2024 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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
time "time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
versioned "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned"
internalinterfaces "sigs.k8s.io/node-feature-discovery/api/generated/informers/externalversions/internalinterfaces"
v1alpha1 "sigs.k8s.io/node-feature-discovery/api/generated/listers/nfd/v1alpha1"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
)
// NodeFeatureWorkerConfigInformer provides access to a shared informer and lister for
// NodeFeatureWorkerConfigs.
type NodeFeatureWorkerConfigInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1alpha1.NodeFeatureWorkerConfigLister
}
type nodeFeatureWorkerConfigInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewNodeFeatureWorkerConfigInformer constructs a new informer for NodeFeatureWorkerConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewNodeFeatureWorkerConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredNodeFeatureWorkerConfigInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredNodeFeatureWorkerConfigInformer constructs a new informer for NodeFeatureWorkerConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredNodeFeatureWorkerConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.NfdV1alpha1().NodeFeatureWorkerConfigs(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.NfdV1alpha1().NodeFeatureWorkerConfigs(namespace).Watch(context.TODO(), options)
},
},
&nfdv1alpha1.NodeFeatureWorkerConfig{},
resyncPeriod,
indexers,
)
}
func (f *nodeFeatureWorkerConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredNodeFeatureWorkerConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *nodeFeatureWorkerConfigInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&nfdv1alpha1.NodeFeatureWorkerConfig{}, f.defaultInformer)
}
func (f *nodeFeatureWorkerConfigInformer) Lister() v1alpha1.NodeFeatureWorkerConfigLister {
return v1alpha1.NewNodeFeatureWorkerConfigLister(f.Informer().GetIndexer())
}

View file

@ -37,3 +37,11 @@ type NodeFeatureGroupNamespaceListerExpansion interface{}
// NodeFeatureRuleListerExpansion allows custom methods to be added to
// NodeFeatureRuleLister.
type NodeFeatureRuleListerExpansion interface{}
// NodeFeatureWorkerConfigListerExpansion allows custom methods to be added to
// NodeFeatureWorkerConfigLister.
type NodeFeatureWorkerConfigListerExpansion interface{}
// NodeFeatureWorkerConfigNamespaceListerExpansion allows custom methods to be added to
// NodeFeatureWorkerConfigNamespaceLister.
type NodeFeatureWorkerConfigNamespaceListerExpansion interface{}

View file

@ -0,0 +1,70 @@
/*
Copyright 2024 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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/listers"
"k8s.io/client-go/tools/cache"
v1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
)
// NodeFeatureWorkerConfigLister helps list NodeFeatureWorkerConfigs.
// All objects returned here must be treated as read-only.
type NodeFeatureWorkerConfigLister interface {
// List lists all NodeFeatureWorkerConfigs in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.NodeFeatureWorkerConfig, err error)
// NodeFeatureWorkerConfigs returns an object that can list and get NodeFeatureWorkerConfigs.
NodeFeatureWorkerConfigs(namespace string) NodeFeatureWorkerConfigNamespaceLister
NodeFeatureWorkerConfigListerExpansion
}
// nodeFeatureWorkerConfigLister implements the NodeFeatureWorkerConfigLister interface.
type nodeFeatureWorkerConfigLister struct {
listers.ResourceIndexer[*v1alpha1.NodeFeatureWorkerConfig]
}
// NewNodeFeatureWorkerConfigLister returns a new NodeFeatureWorkerConfigLister.
func NewNodeFeatureWorkerConfigLister(indexer cache.Indexer) NodeFeatureWorkerConfigLister {
return &nodeFeatureWorkerConfigLister{listers.New[*v1alpha1.NodeFeatureWorkerConfig](indexer, v1alpha1.Resource("nodefeatureworkerconfig"))}
}
// NodeFeatureWorkerConfigs returns an object that can list and get NodeFeatureWorkerConfigs.
func (s *nodeFeatureWorkerConfigLister) NodeFeatureWorkerConfigs(namespace string) NodeFeatureWorkerConfigNamespaceLister {
return nodeFeatureWorkerConfigNamespaceLister{listers.NewNamespaced[*v1alpha1.NodeFeatureWorkerConfig](s.ResourceIndexer, namespace)}
}
// NodeFeatureWorkerConfigNamespaceLister helps list and get NodeFeatureWorkerConfigs.
// All objects returned here must be treated as read-only.
type NodeFeatureWorkerConfigNamespaceLister interface {
// List lists all NodeFeatureWorkerConfigs in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.NodeFeatureWorkerConfig, err error)
// Get retrieves the NodeFeatureWorkerConfig from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*v1alpha1.NodeFeatureWorkerConfig, error)
NodeFeatureWorkerConfigNamespaceListerExpansion
}
// nodeFeatureWorkerConfigNamespaceLister implements the NodeFeatureWorkerConfigNamespaceLister
// interface.
type nodeFeatureWorkerConfigNamespaceLister struct {
listers.ResourceIndexer[*v1alpha1.NodeFeatureWorkerConfig]
}

View file

@ -43,6 +43,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&NodeFeature{},
&NodeFeatureRule{},
&NodeFeatureGroup{},
&NodeFeatureWorkerConfig{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View file

@ -139,6 +139,55 @@ type NodeFeatureRuleSpec struct {
Rules []Rule `json:"rules"`
}
// NodeFeatureWorkerConfig resource holds the configuration for NFD worker
// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Namespaced
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type NodeFeatureWorkerConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Specification of the WorkerConfig, containing configuration data
Spec NodeFeatureWorkerConfigSpec `json:"spec"`
}
// NodeFeatureWorkerConfigSpec holds configuration data
type NodeFeatureWorkerConfigSpec struct {
// +optional
Core WorkerCoreConfigCore `json:"core"`
// +optional
Sources map[string]map[string]string `json:"sources"`
}
type WorkerCoreConfigCore struct {
// +optional
Klog map[string]string `json:"klog"`
// +optional
LabelWhiteList string `json:"labelWhitelist"`
// +optional
NoPublish bool `json:"noPublish"`
// +optional
FeatureSources []string `json:"featureSources"`
// +optional
Sources *[]string `json:"sources"`
// +optional
LabelSources []string `json:"labelSources"`
// +optional
SleepInterval int `json:"sleepInterval"`
}
// NodeFeatureWorkerConfigList contains a list of WorkerConfig objects.
// +kubebuilder:object:root=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type NodeFeatureWorkerConfigList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata"`
// List of NodeFeatureWorkerConfigs
Items []NodeFeatureWorkerConfig `json:"items"`
}
// NodeFeatureGroup resource holds Node pools by featureGroup
// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Namespaced,shortName=nfg

View file

@ -645,6 +645,100 @@ func (in *NodeFeatureSpec) DeepCopy() *NodeFeatureSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeFeatureWorkerConfig) DeepCopyInto(out *NodeFeatureWorkerConfig) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureWorkerConfig.
func (in *NodeFeatureWorkerConfig) DeepCopy() *NodeFeatureWorkerConfig {
if in == nil {
return nil
}
out := new(NodeFeatureWorkerConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NodeFeatureWorkerConfig) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeFeatureWorkerConfigList) DeepCopyInto(out *NodeFeatureWorkerConfigList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]NodeFeatureWorkerConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureWorkerConfigList.
func (in *NodeFeatureWorkerConfigList) DeepCopy() *NodeFeatureWorkerConfigList {
if in == nil {
return nil
}
out := new(NodeFeatureWorkerConfigList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *NodeFeatureWorkerConfigList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NodeFeatureWorkerConfigSpec) DeepCopyInto(out *NodeFeatureWorkerConfigSpec) {
*out = *in
in.Core.DeepCopyInto(&out.Core)
if in.Sources != nil {
in, out := &in.Sources, &out.Sources
*out = make(map[string]map[string]string, len(*in))
for key, val := range *in {
var outVal map[string]string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
(*out)[key] = outVal
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureWorkerConfigSpec.
func (in *NodeFeatureWorkerConfigSpec) DeepCopy() *NodeFeatureWorkerConfigSpec {
if in == nil {
return nil
}
out := new(NodeFeatureWorkerConfigSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Rule) DeepCopyInto(out *Rule) {
*out = *in
@ -709,3 +803,45 @@ func (in *Rule) DeepCopy() *Rule {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkerCoreConfigCore) DeepCopyInto(out *WorkerCoreConfigCore) {
*out = *in
if in.Klog != nil {
in, out := &in.Klog, &out.Klog
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.FeatureSources != nil {
in, out := &in.FeatureSources, &out.FeatureSources
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Sources != nil {
in, out := &in.Sources, &out.Sources
*out = new([]string)
if **in != nil {
in, out := *in, *out
*out = make([]string, len(*in))
copy(*out, *in)
}
}
if in.LabelSources != nil {
in, out := &in.LabelSources, &out.LabelSources
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkerCoreConfigCore.
func (in *WorkerCoreConfigCore) DeepCopy() *WorkerCoreConfigCore {
if in == nil {
return nil
}
out := new(WorkerCoreConfigCore)
in.DeepCopyInto(out)
return out
}

View file

@ -708,3 +708,83 @@ spec:
type: object
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.16.3
name: nodefeatureworkerconfigs.nfd.k8s-sigs.io
spec:
group: nfd.k8s-sigs.io
names:
kind: NodeFeatureWorkerConfig
listKind: NodeFeatureWorkerConfigList
plural: nodefeatureworkerconfigs
singular: nodefeatureworkerconfig
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: NodeFeatureWorkerConfig resource holds the configuration for
NFD worker
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: Specification of the WorkerConfig, containing configuration
data
properties:
core:
properties:
featureSources:
items:
type: string
type: array
klog:
additionalProperties:
type: string
type: object
labelSources:
items:
type: string
type: array
labelWhitelist:
type: string
noPublish:
type: boolean
sleepInterval:
type: integer
sources:
items:
type: string
type: array
type: object
sources:
additionalProperties:
additionalProperties:
type: string
type: object
type: object
type: object
required:
- spec
type: object
served: true
storage: true

View file

@ -708,3 +708,83 @@ spec:
type: object
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.16.3
name: nodefeatureworkerconfigs.nfd.k8s-sigs.io
spec:
group: nfd.k8s-sigs.io
names:
kind: NodeFeatureWorkerConfig
listKind: NodeFeatureWorkerConfigList
plural: nodefeatureworkerconfigs
singular: nodefeatureworkerconfig
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: NodeFeatureWorkerConfig resource holds the configuration for
NFD worker
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: Specification of the WorkerConfig, containing configuration
data
properties:
core:
properties:
featureSources:
items:
type: string
type: array
klog:
additionalProperties:
type: string
type: object
labelSources:
items:
type: string
type: array
labelWhitelist:
type: string
noPublish:
type: boolean
sleepInterval:
type: integer
sources:
items:
type: string
type: array
type: object
sources:
additionalProperties:
additionalProperties:
type: string
type: object
type: object
type: object
required:
- spec
type: object
served: true
storage: true

View file

@ -0,0 +1,120 @@
/*
Copyright 2024 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 nfdworker
import (
"fmt"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
nfdclientset "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned"
nfdscheme "sigs.k8s.io/node-feature-discovery/api/generated/clientset/versioned/scheme"
nfdinformers "sigs.k8s.io/node-feature-discovery/api/generated/informers/externalversions"
nfdinformersv1alpha1 "sigs.k8s.io/node-feature-discovery/api/generated/informers/externalversions/nfd/v1alpha1"
nfdlisters "sigs.k8s.io/node-feature-discovery/api/generated/listers/nfd/v1alpha1"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
"sigs.k8s.io/node-feature-discovery/pkg/utils"
)
type nfdController struct {
configLister nfdlisters.NodeFeatureWorkerConfigLister
stopChan chan struct{}
updateConfigChan chan nfdv1alpha1.NodeFeatureWorkerConfig
}
type nfdApiControllerOptions struct {
ResyncPeriod time.Duration
}
func init() {
utilruntime.Must(nfdv1alpha1.AddToScheme(nfdscheme.Scheme))
}
func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiControllerOptions, ns string) (*nfdController, error) {
c := &nfdController{
stopChan: make(chan struct{}),
updateConfigChan: make(chan nfdv1alpha1.NodeFeatureWorkerConfig),
}
nfdClient := nfdclientset.NewForConfigOrDie(config)
klog.V(2).InfoS("initializing new NFD API controller", "options", utils.DelayedDumper(nfdApiControllerOptions))
informerFactory := nfdinformers.NewSharedInformerFactory(nfdClient, nfdApiControllerOptions.ResyncPeriod)
// Add informer for NodeFeature objects
tweakListOpts := func(opts *metav1.ListOptions) {
// Tweak list opts on initial sync to avoid timeouts on the apiserver.
// NodeFeature objects are huge and the Kubernetes apiserver
// (v1.30) experiences http handler timeouts when the resource
// version is set to some non-empty value (TODO: find out why).
if opts.ResourceVersion == "0" {
opts.ResourceVersion = ""
}
}
configInformer := nfdinformersv1alpha1.New(informerFactory, ns, tweakListOpts).NodeFeatureWorkerConfigs()
if _, err := configInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
cfg := obj.(*nfdv1alpha1.NodeFeatureWorkerConfig)
klog.V(2).InfoS("NodeFeatureWorkerConfig added", "workerconfig", klog.KObj(cfg))
c.updateConfiguration(cfg)
},
UpdateFunc: func(oldObj, newObj interface{}) {
cfg := newObj.(*nfdv1alpha1.NodeFeatureWorkerConfig)
klog.V(2).InfoS("NodeFeatureWorkerConfig updated", "workerconfig", klog.KObj(cfg))
c.updateConfiguration(cfg)
},
DeleteFunc: func(obj interface{}) {
cfg := obj.(*nfdv1alpha1.NodeFeatureWorkerConfig)
klog.V(2).InfoS("NodeFeatureWorkerConfig deleted", "workerconfig", klog.KObj(cfg))
c.updateConfiguration(cfg)
},
}); err != nil {
return nil, err
}
c.configLister = configInformer.Lister()
// Start informers
informerFactory.Start(c.stopChan)
now := time.Now()
ret := informerFactory.WaitForCacheSync(c.stopChan)
for res, ok := range ret {
if !ok {
return nil, fmt.Errorf("informer cache failed to sync resource %s", res)
}
}
klog.InfoS("informer caches synced", "duration", time.Since(now))
return c, nil
}
func (c *nfdController) stop() {
close(c.stopChan)
}
func (c *nfdController) updateConfiguration(cfg *nfdv1alpha1.NodeFeatureWorkerConfig) {
select {
case c.updateConfigChan <- *cfg:
case <-c.stopChan:
}
}

View file

@ -111,6 +111,8 @@ type ConfigOverrideArgs struct {
}
type nfdWorker struct {
*nfdController
args Args
configFilePath string
config *NFDConfig
@ -270,6 +272,10 @@ func (w *nfdWorker) runFeatureDiscovery() error {
func (w *nfdWorker) Run() error {
klog.InfoS("Node Feature Discovery Worker", "version", version.Get(), "nodeName", utils.NodeName(), "namespace", w.kubernetesNamespace)
if err := w.startNfdApiController(); err != nil {
return err
}
// Read configuration file
err := w.configure(w.configFilePath, w.args.Options)
if err != nil {
@ -352,6 +358,10 @@ func (w *nfdWorker) Run() error {
return err
}
case cfg := <-w.nfdController.updateConfigChan:
klog.InfoS("updating configuration", "cfg", cfg)
w.configureFromAPI(&cfg)
case <-w.stop:
klog.InfoS("shutting down nfd-worker")
if w.healthServer != nil {
@ -535,6 +545,44 @@ func (w *nfdWorker) configure(filepath string, overrides string) error {
return nil
}
func (w *nfdWorker) configureFromAPI(c *nfdv1alpha1.NodeFeatureWorkerConfig) error {
klog.InfoS("configuring from API", "configuration", *c)
if len(c.Spec.Core.LabelWhiteList) > 0 {
w.config.Core.LabelWhiteList = utils.RegexpVal{Regexp: *regexp.MustCompile(c.Spec.Core.LabelWhiteList)}
}
if len(c.Spec.Core.FeatureSources) > 0 {
w.config.Core.FeatureSources = c.Spec.Core.FeatureSources
}
if len(c.Spec.Core.LabelSources) > 0 {
w.config.Core.LabelSources = c.Spec.Core.LabelSources
}
if c.Spec.Core.NoPublish != w.config.Core.NoPublish {
w.config.Core.NoPublish = c.Spec.Core.NoPublish
}
if c.Spec.Core.SleepInterval != 0 {
w.config.Core.SleepInterval = utils.DurationVal{Duration: time.Duration(c.Spec.Core.SleepInterval) * time.Second}
}
if err := w.configureCore(w.config.Core); err != nil {
return err
}
confSources := source.GetAllConfigurableSources()
// (Re-)configure sources
for _, s := range confSources {
s.SetConfig(w.config.Sources[s.Name()])
}
klog.InfoS("configuration successfully updated", "configuration", w.config)
return nil
}
// createFeatureLabels returns the set of feature labels from the enabled
// sources and the whitelist argument.
func createFeatureLabels(sources []source.LabelSource, labelWhiteList regexp.Regexp) (labels Labels) {
@ -683,6 +731,21 @@ func (m *nfdWorker) updateNodeFeatureObject(labels Labels) error {
return nil
}
func (m *nfdWorker) startNfdApiController() error {
kubeconfig, err := utils.GetKubeconfig(m.args.Kubeconfig)
if err != nil {
return err
}
klog.InfoS("starting the nfd api controller")
m.nfdController, err = newNfdController(kubeconfig, nfdApiControllerOptions{
ResyncPeriod: time.Duration(1) * time.Hour,
}, m.kubernetesNamespace)
if err != nil {
return fmt.Errorf("failed to initialize CRD controller: %w", err)
}
return nil
}
// getNfdClient returns the clientset for using the nfd CRD api
func (m *nfdWorker) getNfdClient() (nfdclient.Interface, error) {
if m.nfdClient != nil {

View file

@ -0,0 +1,7 @@
apiVersion: nfd.k8s-sigs.io/v1alpha1
kind: NodeFeatureWorkerConfig
metadata:
name: e2e-worker-config-1
spec:
core:
noPublish: false

View file

@ -0,0 +1,7 @@
apiVersion: nfd.k8s-sigs.io/v1alpha1
kind: NodeFeatureWorkerConfig
metadata:
name: e2e-worker-config-1
spec:
core:
noPublish: true

View file

@ -312,6 +312,47 @@ var _ = NFDDescribe(Label("nfd-master"), func() {
})
})
// Test NodeFeatureWorkerConfig
Context("and NodeFeatureWorkerConfig objects deployed", Label("workerconfig"), func() {
It("custom WorkerConfgig should be updated", func(ctx context.Context) {
By("Creating nfd-worker daemonset")
podSpecOpts := []testpod.SpecOption{
testpod.SpecWithContainerImage(dockerImage()),
}
workerDS := testds.NFDWorker(podSpecOpts...)
workerDS, err := f.ClientSet.AppsV1().DaemonSets(f.Namespace.Name).Create(ctx, workerDS, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
By("Waiting for worker daemonset pods to be ready")
Expect(testpod.WaitForReady(ctx, f.ClientSet, f.Namespace.Name, workerDS.Spec.Template.Labels["name"], 2)).NotTo(HaveOccurred())
nodes, err := getNonControlPlaneNodes(ctx, f.ClientSet)
Expect(err).NotTo(HaveOccurred())
nodes = nodes
By("Creating NodeFeatureWorkerConfig #1")
Expect(testutils.CreateNodeFeatureWorkerConfigFromFile(ctx, nfdClient, f.Namespace.Name, "workerconfig-1.yaml")).NotTo(HaveOccurred())
By("Updating NodeFeatureWorkerConfig #1")
Expect(testutils.UpdateNodeFeatureWorkerConfigFromFile(ctx, nfdClient, f.Namespace.Name, "workerconfig-2.yaml")).NotTo(HaveOccurred())
expectedConfig := nfdv1alpha1.NodeFeatureWorkerConfig{
Spec: nfdv1alpha1.NodeFeatureWorkerConfigSpec{
Core: nfdv1alpha1.WorkerCoreConfigCore{
NoPublish: true,
},
},
}
Eventually(func() bool {
By("Verifying NodeFeatureWorkerConfig #1")
config, err := nfdClient.NfdV1alpha1().NodeFeatureWorkerConfigs(f.Namespace.Name).Get(ctx, "e2e-worker-config-1", metav1.GetOptions{})
if err != nil {
return false
}
return config.Spec.Core.NoPublish == expectedConfig.Spec.Core.NoPublish
}, 1*time.Minute, 5*time.Second).Should(BeTrue())
})
})
//
// More comprehensive test when --e2e-node-config is enabled
//

View file

@ -159,6 +159,42 @@ func UpdateNodeFeatureRulesFromFile(ctx context.Context, cli nfdclientset.Interf
return nil
}
// CreateNodeFeatureGroupsFromFile creates a NodeFeatureGroup object from a given file located under test data directory.
func CreateNodeFeatureWorkerConfigFromFile(ctx context.Context, cli nfdclientset.Interface, namespace, filename string) error {
objs, err := workerConfigFromFile(filepath.Join(packagePath, "..", "data", filename))
if err != nil {
return err
}
for _, obj := range objs {
if _, err = cli.NfdV1alpha1().NodeFeatureWorkerConfigs(namespace).Create(ctx, obj, metav1.CreateOptions{}); err != nil {
return err
}
}
return nil
}
// UpdateNodeFeatureWorkerConfigFromFile updates existing NodeFeatureWorkerConfig object from a given file located under test data directory.
func UpdateNodeFeatureWorkerConfigFromFile(ctx context.Context, cli nfdclientset.Interface, namespace, filename string) error {
objs, err := workerConfigFromFile(filepath.Join(packagePath, "..", "data", filename))
if err != nil {
return err
}
for _, obj := range objs {
var cfg *nfdv1alpha1.NodeFeatureWorkerConfig
if cfg, err = cli.NfdV1alpha1().NodeFeatureWorkerConfigs(namespace).Get(ctx, obj.Name, metav1.GetOptions{}); err != nil {
return fmt.Errorf("failed to get NodeFeatureWorkerConfig %w", err)
}
obj.SetResourceVersion(cfg.GetResourceVersion())
if _, err = cli.NfdV1alpha1().NodeFeatureWorkerConfigs(namespace).Update(ctx, obj, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("failed to update NodeFeatureWorkerConfig %w", err)
}
}
return nil
}
// CreateNodeFeature creates a dummy NodeFeature object for a node
func CreateNodeFeature(ctx context.Context, cli nfdclientset.Interface, namespace, name, nodeName string) error {
nr := &nfdv1alpha1.NodeFeature{
@ -272,6 +308,25 @@ func nodeFeatureGroupsFromFile(path string) ([]*nfdv1alpha1.NodeFeatureGroup, er
return crs, nil
}
func workerConfigFromFile(path string) ([]*nfdv1alpha1.NodeFeatureWorkerConfig, error) {
objs, err := apiObjsFromFile(path, nfdscheme.Codecs.UniversalDeserializer())
if err != nil {
return nil, err
}
crs := make([]*nfdv1alpha1.NodeFeatureWorkerConfig, len(objs))
for i, obj := range objs {
var ok bool
crs[i], ok = obj.(*nfdv1alpha1.NodeFeatureWorkerConfig)
if !ok {
return nil, fmt.Errorf("unexpected type %t when reading %q", obj, path)
}
}
return crs, nil
}
func init() {
_, thisFile, _, _ := runtime.Caller(0)
packagePath = filepath.Dir(thisFile)

View file

@ -201,6 +201,11 @@ func createClusterRoleMaster(ctx context.Context, cs clientset.Interface) (*rbac
Resources: []string{"nodefeaturegroups/status"},
Verbs: []string{"patch", "update"},
},
{
APIGroups: []string{"nfd.k8s-sigs.io"},
Resources: []string{"workerconfigs"},
Verbs: []string{"get", "watch", "update"},
},
},
}
if *openShift {
@ -234,6 +239,11 @@ func createRoleWorker(ctx context.Context, cs clientset.Interface, ns string) (*
Resources: []string{"pods"},
Verbs: []string{"get"},
},
{
APIGroups: []string{"nfd.k8s-sigs.io"},
Resources: []string{"workerconfigs"},
Verbs: []string{"get", "list", "watch", "update"},
},
},
}
return cs.RbacV1().Roles(ns).Update(ctx, cr, metav1.UpdateOptions{})