diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go index 282a6e717..4b434f94b 100644 --- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go +++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go @@ -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 { diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeatureworkerconfig.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeatureworkerconfig.go new file mode 100644 index 000000000..d21037439 --- /dev/null +++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeatureworkerconfig.go @@ -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 +} diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go index 02d3e3518..a397081a7 100644 --- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go +++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go @@ -23,3 +23,5 @@ type NodeFeatureExpansion interface{} type NodeFeatureGroupExpansion interface{} type NodeFeatureRuleExpansion interface{} + +type NodeFeatureWorkerConfigExpansion interface{} diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go index 37a6f340a..1e7d7c7de 100644 --- a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go +++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go @@ -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). diff --git a/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeatureworkerconfig.go b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeatureworkerconfig.go new file mode 100644 index 000000000..477f70084 --- /dev/null +++ b/api/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeatureworkerconfig.go @@ -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{} }), + } +} diff --git a/api/generated/informers/externalversions/generic.go b/api/generated/informers/externalversions/generic.go index 86577fff5..295cc4dd3 100644 --- a/api/generated/informers/externalversions/generic.go +++ b/api/generated/informers/externalversions/generic.go @@ -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 } diff --git a/api/generated/informers/externalversions/nfd/v1alpha1/interface.go b/api/generated/informers/externalversions/nfd/v1alpha1/interface.go index ea861a472..95a61415f 100644 --- a/api/generated/informers/externalversions/nfd/v1alpha1/interface.go +++ b/api/generated/informers/externalversions/nfd/v1alpha1/interface.go @@ -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} +} diff --git a/api/generated/informers/externalversions/nfd/v1alpha1/nodefeatureworkerconfig.go b/api/generated/informers/externalversions/nfd/v1alpha1/nodefeatureworkerconfig.go new file mode 100644 index 000000000..35d70f6ce --- /dev/null +++ b/api/generated/informers/externalversions/nfd/v1alpha1/nodefeatureworkerconfig.go @@ -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()) +} diff --git a/api/generated/listers/nfd/v1alpha1/expansion_generated.go b/api/generated/listers/nfd/v1alpha1/expansion_generated.go index 5890048ee..bd7b9c274 100644 --- a/api/generated/listers/nfd/v1alpha1/expansion_generated.go +++ b/api/generated/listers/nfd/v1alpha1/expansion_generated.go @@ -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{} diff --git a/api/generated/listers/nfd/v1alpha1/nodefeatureworkerconfig.go b/api/generated/listers/nfd/v1alpha1/nodefeatureworkerconfig.go new file mode 100644 index 000000000..7fa83d45c --- /dev/null +++ b/api/generated/listers/nfd/v1alpha1/nodefeatureworkerconfig.go @@ -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] +} diff --git a/api/nfd/v1alpha1/register.go b/api/nfd/v1alpha1/register.go index 9ccfbba25..33c42912a 100644 --- a/api/nfd/v1alpha1/register.go +++ b/api/nfd/v1alpha1/register.go @@ -43,6 +43,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { &NodeFeature{}, &NodeFeatureRule{}, &NodeFeatureGroup{}, + &NodeFeatureWorkerConfig{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/api/nfd/v1alpha1/types.go b/api/nfd/v1alpha1/types.go index c89efd818..9a75a99fa 100644 --- a/api/nfd/v1alpha1/types.go +++ b/api/nfd/v1alpha1/types.go @@ -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 diff --git a/api/nfd/v1alpha1/zz_generated.deepcopy.go b/api/nfd/v1alpha1/zz_generated.deepcopy.go index 491d9866c..842bdcae8 100644 --- a/api/nfd/v1alpha1/zz_generated.deepcopy.go +++ b/api/nfd/v1alpha1/zz_generated.deepcopy.go @@ -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 +} diff --git a/deployment/base/nfd-crds/nfd-api-crds.yaml b/deployment/base/nfd-crds/nfd-api-crds.yaml index 56142c6ce..54899cd2f 100644 --- a/deployment/base/nfd-crds/nfd-api-crds.yaml +++ b/deployment/base/nfd-crds/nfd-api-crds.yaml @@ -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 diff --git a/deployment/helm/node-feature-discovery/crds/nfd-api-crds.yaml b/deployment/helm/node-feature-discovery/crds/nfd-api-crds.yaml index 56142c6ce..54899cd2f 100644 --- a/deployment/helm/node-feature-discovery/crds/nfd-api-crds.yaml +++ b/deployment/helm/node-feature-discovery/crds/nfd-api-crds.yaml @@ -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 diff --git a/pkg/nfd-worker/nfd-api-controller.go b/pkg/nfd-worker/nfd-api-controller.go new file mode 100644 index 000000000..393da669d --- /dev/null +++ b/pkg/nfd-worker/nfd-api-controller.go @@ -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: + } +} diff --git a/pkg/nfd-worker/nfd-worker.go b/pkg/nfd-worker/nfd-worker.go index 7b5ce4d16..e00d583aa 100644 --- a/pkg/nfd-worker/nfd-worker.go +++ b/pkg/nfd-worker/nfd-worker.go @@ -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 { diff --git a/test/e2e/data/workerconfig-1.yaml b/test/e2e/data/workerconfig-1.yaml new file mode 100644 index 000000000..82e88ca0a --- /dev/null +++ b/test/e2e/data/workerconfig-1.yaml @@ -0,0 +1,7 @@ +apiVersion: nfd.k8s-sigs.io/v1alpha1 +kind: NodeFeatureWorkerConfig +metadata: + name: e2e-worker-config-1 +spec: + core: + noPublish: false diff --git a/test/e2e/data/workerconfig-2.yaml b/test/e2e/data/workerconfig-2.yaml new file mode 100644 index 000000000..3e4b3227b --- /dev/null +++ b/test/e2e/data/workerconfig-2.yaml @@ -0,0 +1,7 @@ +apiVersion: nfd.k8s-sigs.io/v1alpha1 +kind: NodeFeatureWorkerConfig +metadata: + name: e2e-worker-config-1 +spec: + core: + noPublish: true diff --git a/test/e2e/node_feature_discovery_test.go b/test/e2e/node_feature_discovery_test.go index 5e6777ac9..182068b97 100644 --- a/test/e2e/node_feature_discovery_test.go +++ b/test/e2e/node_feature_discovery_test.go @@ -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 // diff --git a/test/e2e/utils/crd.go b/test/e2e/utils/crd.go index 3cefe7eef..f761b97a6 100644 --- a/test/e2e/utils/crd.go +++ b/test/e2e/utils/crd.go @@ -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) diff --git a/test/e2e/utils/rbac.go b/test/e2e/utils/rbac.go index 561cbf353..e2b0eeaec 100644 --- a/test/e2e/utils/rbac.go +++ b/test/e2e/utils/rbac.go @@ -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{})