From 15fc860f8a86b60806cb82635cfd6fe731275f4a Mon Sep 17 00:00:00 2001 From: Carlos Eduardo Arango Gutierrez Date: Fri, 24 Nov 2023 10:54:02 +0100 Subject: [PATCH] Add NodeFeatureGroup API Signed-off-by: Carlos Eduardo Arango Gutierrez --- cmd/nfd-master/main.go | 2 + deployment/base/nfd-crds/nfd-api-crds.yaml | 321 ++ deployment/base/rbac/master-clusterrole.yaml | 11 + .../crds/nfd-api-crds.yaml | 321 ++ .../templates/clusterrole.yaml | 11 + .../templates/master.yaml | 3 + .../helm/node-feature-discovery/values.yaml | 1 + .../reference/master-commandline-reference.md | 14 + docs/usage/custom-resources.md | 48 + examples/nodefeaturerule.yaml | 12 + nf.yml | 2979 +++++++++++++++++ .../{annotations_labels.go => const.go} | 56 +- pkg/apis/nfd/v1alpha1/expression.go | 2 +- .../{types.go => nodefeature_types.go} | 50 - .../nfd/v1alpha1/nodefeaturegroup_types.go | 91 + pkg/apis/nfd/v1alpha1/register.go | 2 + pkg/apis/nfd/v1alpha1/rule.go | 35 + .../nfd/v1alpha1/zz_generated.deepcopy.go | 181 + .../nfd/v1alpha1/fake/fake_nfd_client.go | 8 + .../v1alpha1/fake/fake_nodefeaturegroup.go | 129 + .../fake/fake_nodefeaturegrouprule.go | 121 + .../typed/nfd/v1alpha1/generated_expansion.go | 4 + .../typed/nfd/v1alpha1/nfd_client.go | 10 + .../typed/nfd/v1alpha1/nodefeaturegroup.go | 178 + .../nfd/v1alpha1/nodefeaturegrouprule.go | 168 + .../informers/externalversions/generic.go | 4 + .../nfd/v1alpha1/interface.go | 14 + .../nfd/v1alpha1/nodefeaturegroup.go | 90 + .../nfd/v1alpha1/nodefeaturegrouprule.go | 89 + .../nfd/v1alpha1/expansion_generated.go | 12 + .../listers/nfd/v1alpha1/nodefeaturegroup.go | 99 + .../nfd/v1alpha1/nodefeaturegrouprule.go | 68 + pkg/nfd-gc/nfd-gc.go | 35 + pkg/nfd-master/metrics.go | 23 +- pkg/nfd-master/nfd-api-controller.go | 96 +- pkg/nfd-master/nfd-master-internal_test.go | 8 +- pkg/nfd-master/nfd-master.go | 188 +- pkg/nfd-master/nfg-updater-pool.go | 108 + pkg/nfd-master/nfg-updater-pool_test.go | 102 + ...de-updater-pool.go => nfr-updater-pool.go} | 0 ...-pool_test.go => nfr-updater-pool_test.go} | 0 test/e2e/data/nodefeaturegrouprule-1.yaml | 11 + test/e2e/node_feature_discovery_test.go | 84 + test/e2e/utils/crd.go | 34 + test/e2e/utils/rbac.go | 5 + 45 files changed, 5724 insertions(+), 104 deletions(-) create mode 100644 nf.yml rename pkg/apis/nfd/v1alpha1/{annotations_labels.go => const.go} (58%) rename pkg/apis/nfd/v1alpha1/{types.go => nodefeature_types.go} (79%) create mode 100644 pkg/apis/nfd/v1alpha1/nodefeaturegroup_types.go create mode 100644 pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegroup.go create mode 100644 pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegrouprule.go create mode 100644 pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go create mode 100644 pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegrouprule.go create mode 100644 pkg/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegroup.go create mode 100644 pkg/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegrouprule.go create mode 100644 pkg/generated/listers/nfd/v1alpha1/nodefeaturegroup.go create mode 100644 pkg/generated/listers/nfd/v1alpha1/nodefeaturegrouprule.go create mode 100644 pkg/nfd-master/nfg-updater-pool.go create mode 100644 pkg/nfd-master/nfg-updater-pool_test.go rename pkg/nfd-master/{node-updater-pool.go => nfr-updater-pool.go} (100%) rename pkg/nfd-master/{node-updater-pool_test.go => nfr-updater-pool_test.go} (100%) create mode 100644 test/e2e/data/nodefeaturegrouprule-1.yaml diff --git a/cmd/nfd-master/main.go b/cmd/nfd-master/main.go index 3418d2af14..534bdbd4ba 100644 --- a/cmd/nfd-master/main.go +++ b/cmd/nfd-master/main.go @@ -133,6 +133,8 @@ func initFlags(flagset *flag.FlagSet) (*master.Args, *master.ConfigOverrideArgs) flagset.BoolVar(&args.EnableNodeFeatureApi, "enable-nodefeature-api", true, "Enable the NodeFeature CRD API for receiving node features. This will automatically disable the gRPC communication."+ " DEPRECATED: will be removed in a future release along with the deprecated gRPC API.") + flagset.BoolVar(&args.EnableNodeFeatureGroupApi, "enable-nodefeaturegroup-api", true, + "Enable the NodeFeatureGroup CRD API for receiving cluster feature rules.") flagset.BoolVar(&args.CrdController, "featurerules-controller", true, "Enable NFD CRD API controller. DEPRECATED: use -crd-controller instead") flagset.BoolVar(&args.CrdController, "crd-controller", true, diff --git a/deployment/base/nfd-crds/nfd-api-crds.yaml b/deployment/base/nfd-crds/nfd-api-crds.yaml index 5c94140bfa..1bbdca1bc0 100644 --- a/deployment/base/nfd-crds/nfd-api-crds.yaml +++ b/deployment/base/nfd-crds/nfd-api-crds.yaml @@ -111,6 +111,327 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: nodefeaturegroups.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeatureGroup + listKind: NodeFeatureGroupList + plural: nodefeaturegroups + shortNames: + - nfg + singular: nodefeaturegroup + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeFeatureGroup resource holds Node pools by featureGroup + 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: NodeFeatureGroupSpec describes a NodeFeatureGroup object. + properties: + FeatureGroup: + description: FeatureGroupRules is a list of feature group rules. Feature + group rules are used to group nodes into feature groups. + properties: + name: + description: Name is the name of the feature group + type: string + nodes: + description: Nodes is the list of nodes in the cluster that belong + to this feature group + items: + type: string + type: array + required: + - name + type: object + Features: + additionalProperties: + type: string + description: Features is the set of features that are shared by all + nodes in the feature group + type: object + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: nodefeaturegrouprules.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeatureGroupRule + listKind: NodeFeatureGroupRuleList + plural: nodefeaturegrouprules + shortNames: + - nfgr + singular: nodefeaturegrouprule + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeFeatureGroupRule resource specifies a configuration for feature-based + node grouping. + 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: NodeFeatureGroupRuleSpec describes a NodeFeatureGroupRule. + properties: + featureGroupRules: + items: + description: Rule defines a rule for node customization such as + labeling. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to create if the rule matches. + type: object + extendedResources: + additionalProperties: + type: string + description: ExtendedResources to create if the rule matches. + type: object + labels: + additionalProperties: + type: string + description: Labels to create if the rule matches. + type: object + labelsTemplate: + description: LabelsTemplate specifies a template to expand for + dynamically generating multiple labels. Data (after template + expansion) must be keys with an optional value ([=]) + separated by newlines. + type: string + matchAny: + description: MatchAny specifies a list of matchers one of which + must match. + items: + description: MatchAnyElem specifies one sub-matcher of MatchAny. + properties: + matchFeatures: + description: MatchFeatures specifies a set of matcher + terms all of which must match. + items: + description: FeatureMatcherTerm defines requirements + against one feature set. All requirements (specified + as MatchExpressions) are evaluated against each element + in the feature set. + properties: + feature: + type: string + matchExpressions: + additionalProperties: + description: "MatchExpression specifies an expression + to evaluate against a set of input values. It + contains an operator that is applied when matching + the input and an array of values that the operator + evaluates the input against. \n NB: CreateMatchExpression + or MustCreateMatchExpression() should be used + for creating new instances. \n NB: Validate() + must be called if Op or Value fields are modified + or if a new instance is created from scratch + without using the helper functions." + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: Value is the list of values that + the operand evaluates the input against. + Value should be empty if the operator is + Exists, DoesNotExist, IsTrue or IsFalse. + Value should contain exactly one element + if the operator is Gt or Lt and exactly + two elements if the operator is GtLt. In + other cases Value should contain at least + one element. + items: + type: string + type: array + required: + - op + type: object + description: MatchExpressionSet contains a set of + MatchExpressions, each of which is evaluated against + a set of input values. + type: object + required: + - feature + - matchExpressions + type: object + type: array + required: + - matchFeatures + type: object + type: array + matchFeatures: + description: MatchFeatures specifies a set of matcher terms + all of which must match. + items: + description: FeatureMatcherTerm defines requirements against + one feature set. All requirements (specified as MatchExpressions) + are evaluated against each element in the feature set. + properties: + feature: + type: string + matchExpressions: + additionalProperties: + description: "MatchExpression specifies an expression + to evaluate against a set of input values. It contains + an operator that is applied when matching the input + and an array of values that the operator evaluates + the input against. \n NB: CreateMatchExpression or + MustCreateMatchExpression() should be used for creating + new instances. \n NB: Validate() must be called if + Op or Value fields are modified or if a new instance + is created from scratch without using the helper functions." + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: Value is the list of values that the + operand evaluates the input against. Value should + be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly + one element if the operator is Gt or Lt and exactly + two elements if the operator is GtLt. In other + cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + description: MatchExpressionSet contains a set of MatchExpressions, + each of which is evaluated against a set of input values. + type: object + required: + - feature + - matchExpressions + type: object + type: array + name: + description: Name of the rule. + type: string + taints: + description: Taints to create if the rule matches. + items: + description: The node this Taint is attached to has the "effect" + on any pod that does not tolerate the Taint. + properties: + effect: + description: Required. The effect of the taint on pods + that do not tolerate the taint. Valid effects are NoSchedule, + PreferNoSchedule and NoExecute. + type: string + key: + description: Required. The taint key to be applied to + a node. + type: string + timeAdded: + description: TimeAdded represents the time at which the + taint was added. It is only written for NoExecute taints. + format: date-time + type: string + value: + description: The taint value corresponding to the taint + key. + type: string + required: + - effect + - key + type: object + type: array + vars: + additionalProperties: + type: string + description: Vars is the variables to store if the rule matches. + Variables do not directly inflict any changes in the node + object. However, they can be referenced from other rules enabling + more complex rule hierarchies, without exposing intermediary + output values as labels. + type: object + varsTemplate: + description: VarsTemplate specifies a template to expand for + dynamically generating multiple variables. Data (after template + expansion) must be keys with an optional value ([=]) + separated by newlines. + type: string + required: + - name + type: object + type: array + required: + - featureGroupRules + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.12.1 diff --git a/deployment/base/rbac/master-clusterrole.yaml b/deployment/base/rbac/master-clusterrole.yaml index e61b4dc065..5b3437f5c5 100644 --- a/deployment/base/rbac/master-clusterrole.yaml +++ b/deployment/base/rbac/master-clusterrole.yaml @@ -22,6 +22,17 @@ rules: - get - list - watch +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeaturegroups + - nodefeaturegrouprules + verbs: + - get + - list + - watch + - update + - create - apiGroups: - coordination.k8s.io resources: 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 5c94140bfa..1bbdca1bc0 100644 --- a/deployment/helm/node-feature-discovery/crds/nfd-api-crds.yaml +++ b/deployment/helm/node-feature-discovery/crds/nfd-api-crds.yaml @@ -111,6 +111,327 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: nodefeaturegroups.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeatureGroup + listKind: NodeFeatureGroupList + plural: nodefeaturegroups + shortNames: + - nfg + singular: nodefeaturegroup + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeFeatureGroup resource holds Node pools by featureGroup + 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: NodeFeatureGroupSpec describes a NodeFeatureGroup object. + properties: + FeatureGroup: + description: FeatureGroupRules is a list of feature group rules. Feature + group rules are used to group nodes into feature groups. + properties: + name: + description: Name is the name of the feature group + type: string + nodes: + description: Nodes is the list of nodes in the cluster that belong + to this feature group + items: + type: string + type: array + required: + - name + type: object + Features: + additionalProperties: + type: string + description: Features is the set of features that are shared by all + nodes in the feature group + type: object + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.1 + name: nodefeaturegrouprules.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeatureGroupRule + listKind: NodeFeatureGroupRuleList + plural: nodefeaturegrouprules + shortNames: + - nfgr + singular: nodefeaturegrouprule + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeFeatureGroupRule resource specifies a configuration for feature-based + node grouping. + 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: NodeFeatureGroupRuleSpec describes a NodeFeatureGroupRule. + properties: + featureGroupRules: + items: + description: Rule defines a rule for node customization such as + labeling. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to create if the rule matches. + type: object + extendedResources: + additionalProperties: + type: string + description: ExtendedResources to create if the rule matches. + type: object + labels: + additionalProperties: + type: string + description: Labels to create if the rule matches. + type: object + labelsTemplate: + description: LabelsTemplate specifies a template to expand for + dynamically generating multiple labels. Data (after template + expansion) must be keys with an optional value ([=]) + separated by newlines. + type: string + matchAny: + description: MatchAny specifies a list of matchers one of which + must match. + items: + description: MatchAnyElem specifies one sub-matcher of MatchAny. + properties: + matchFeatures: + description: MatchFeatures specifies a set of matcher + terms all of which must match. + items: + description: FeatureMatcherTerm defines requirements + against one feature set. All requirements (specified + as MatchExpressions) are evaluated against each element + in the feature set. + properties: + feature: + type: string + matchExpressions: + additionalProperties: + description: "MatchExpression specifies an expression + to evaluate against a set of input values. It + contains an operator that is applied when matching + the input and an array of values that the operator + evaluates the input against. \n NB: CreateMatchExpression + or MustCreateMatchExpression() should be used + for creating new instances. \n NB: Validate() + must be called if Op or Value fields are modified + or if a new instance is created from scratch + without using the helper functions." + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: Value is the list of values that + the operand evaluates the input against. + Value should be empty if the operator is + Exists, DoesNotExist, IsTrue or IsFalse. + Value should contain exactly one element + if the operator is Gt or Lt and exactly + two elements if the operator is GtLt. In + other cases Value should contain at least + one element. + items: + type: string + type: array + required: + - op + type: object + description: MatchExpressionSet contains a set of + MatchExpressions, each of which is evaluated against + a set of input values. + type: object + required: + - feature + - matchExpressions + type: object + type: array + required: + - matchFeatures + type: object + type: array + matchFeatures: + description: MatchFeatures specifies a set of matcher terms + all of which must match. + items: + description: FeatureMatcherTerm defines requirements against + one feature set. All requirements (specified as MatchExpressions) + are evaluated against each element in the feature set. + properties: + feature: + type: string + matchExpressions: + additionalProperties: + description: "MatchExpression specifies an expression + to evaluate against a set of input values. It contains + an operator that is applied when matching the input + and an array of values that the operator evaluates + the input against. \n NB: CreateMatchExpression or + MustCreateMatchExpression() should be used for creating + new instances. \n NB: Validate() must be called if + Op or Value fields are modified or if a new instance + is created from scratch without using the helper functions." + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: Value is the list of values that the + operand evaluates the input against. Value should + be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly + one element if the operator is Gt or Lt and exactly + two elements if the operator is GtLt. In other + cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + description: MatchExpressionSet contains a set of MatchExpressions, + each of which is evaluated against a set of input values. + type: object + required: + - feature + - matchExpressions + type: object + type: array + name: + description: Name of the rule. + type: string + taints: + description: Taints to create if the rule matches. + items: + description: The node this Taint is attached to has the "effect" + on any pod that does not tolerate the Taint. + properties: + effect: + description: Required. The effect of the taint on pods + that do not tolerate the taint. Valid effects are NoSchedule, + PreferNoSchedule and NoExecute. + type: string + key: + description: Required. The taint key to be applied to + a node. + type: string + timeAdded: + description: TimeAdded represents the time at which the + taint was added. It is only written for NoExecute taints. + format: date-time + type: string + value: + description: The taint value corresponding to the taint + key. + type: string + required: + - effect + - key + type: object + type: array + vars: + additionalProperties: + type: string + description: Vars is the variables to store if the rule matches. + Variables do not directly inflict any changes in the node + object. However, they can be referenced from other rules enabling + more complex rule hierarchies, without exposing intermediary + output values as labels. + type: object + varsTemplate: + description: VarsTemplate specifies a template to expand for + dynamically generating multiple variables. Data (after template + expansion) must be keys with an optional value ([=]) + separated by newlines. + type: string + required: + - name + type: object + type: array + required: + - featureGroupRules + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.12.1 diff --git a/deployment/helm/node-feature-discovery/templates/clusterrole.yaml b/deployment/helm/node-feature-discovery/templates/clusterrole.yaml index e652e1df8c..2c547aa197 100644 --- a/deployment/helm/node-feature-discovery/templates/clusterrole.yaml +++ b/deployment/helm/node-feature-discovery/templates/clusterrole.yaml @@ -25,6 +25,17 @@ rules: - get - list - watch +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeaturegroups + - nodefeaturegrouprules + verbs: + - get + - list + - watch + - update + - create - apiGroups: - coordination.k8s.io resources: diff --git a/deployment/helm/node-feature-discovery/templates/master.yaml b/deployment/helm/node-feature-discovery/templates/master.yaml index 53a291e0f7..968bc7a54e 100644 --- a/deployment/helm/node-feature-discovery/templates/master.yaml +++ b/deployment/helm/node-feature-discovery/templates/master.yaml @@ -70,6 +70,9 @@ spec: {{- if .Values.master.instance | empty | not }} - "-instance={{ .Values.master.instance }}" {{- end }} + {{- if not .Values.enableNodeFeatureGroup }} + - "-enable-nodefeature-group=false" + {{- end }} {{- if not .Values.enableNodeFeatureApi }} - "-port={{ .Values.master.port | default "8080" }}" - "-enable-nodefeature-api=false" diff --git a/deployment/helm/node-feature-discovery/values.yaml b/deployment/helm/node-feature-discovery/values.yaml index 66bd39787b..3836b2ad43 100644 --- a/deployment/helm/node-feature-discovery/values.yaml +++ b/deployment/helm/node-feature-discovery/values.yaml @@ -11,6 +11,7 @@ fullnameOverride: "" namespaceOverride: "" enableNodeFeatureApi: true +enableNodeFeatureGroup: true master: enable: true diff --git a/docs/reference/master-commandline-reference.md b/docs/reference/master-commandline-reference.md index d6af3111bc..4f3574c681 100644 --- a/docs/reference/master-commandline-reference.md +++ b/docs/reference/master-commandline-reference.md @@ -181,6 +181,20 @@ Example: nfd-master -enable-nodefeature-api=false ``` +### -enable-nodefeaturegroup-api + +The `-enable-nodefeaturegroup-api` flag enables/disables the +[NodeFeatureGroup](../usage/custom-resources.md#nodefeaturegroup) CRD API for +working with NodeFeatureGroups. + +Default: true + +Example: + +```bash +nfd-master -enable-nodefeaturegroup-api=false +``` + ### -enable-leader-election The `-enable-leader-election` flag enables leader election for NFD-Master. diff --git a/docs/usage/custom-resources.md b/docs/usage/custom-resources.md index b36b447b1d..770c7496a4 100644 --- a/docs/usage/custom-resources.md +++ b/docs/usage/custom-resources.md @@ -86,6 +86,54 @@ See the [Customization guide](customization-guide.md#node-feature-rule-custom-resource) for full documentation of the NodeFeatureRule resource and its usage. +## NodeFeatureGroup + +NodeFeatureGroup is an NFD-specific custom resource that is designed for +grouping Nodes by matching features rules. NFD-Master watches for +NodeFeatureGroupRules objects in the cluster and creates a NodeFeatureGroup +object for each NodeFeatureGroupRule. The NodeFeatureGroup object contains a +list of nodes that match the NodeFeatureGroupRule. + +```yaml +apiVersion: nfd.k8s-sigs.io/v1alpha1 +kind: NodeFeatureGroup +metadata: + name: my-sample-group-resource + namespace: node-feature-discovery +spec: + FeatureGroup: + name: my-sample-group-resource + nodes: + - node-1 + - node-2 + - node-3 +``` + +## NodeFeatureGroupRule + +NodeFeatureGroupRule is an NFD-specific custom resource that is designed for +grouping Nodes by matching features rules. NFD-Master watches for +NodeFeatureGroupRules objects in the cluster and creates a NodeFeatureGroup +object for each NodeFeatureGroupRule. + +NodeFeatureGroupRule is similar to NodeFeatureRule, but instead of labeling +nodes, it creates a NodeFeatureGroup object that contains a list of nodes that +match the NodeFeatureGroupRule. + +```yaml +apiVersion: nfd.k8s-sigs.io/v1alpha1 +kind: NodeFeatureGroupRule +metadata: + name: my-sample-group-resource +spec: + featureGroupRules: + - name: dummy-rule + matchFeatures: + - feature: kernel.version + matchExpressions: + major: {op: Exists} +``` + ## NodeResourceTopology When run with NFD-Topology-Updater, NFD creates NodeResourceTopology objects diff --git a/examples/nodefeaturerule.yaml b/examples/nodefeaturerule.yaml index 06fd662e66..6d00194043 100644 --- a/examples/nodefeaturerule.yaml +++ b/examples/nodefeaturerule.yaml @@ -29,3 +29,15 @@ spec: - feature: kernel.version matchExpressions: major: {op: Exists} +--- +apiVersion: nfd.k8s-sigs.io/v1alpha1 +kind: NodeFeatureGroupRule +metadata: + name: my-sample-group-resource +spec: + featureGroupRules: + - name: dummy-rule + matchFeatures: + - feature: kernel.version + matchExpressions: + major: {op: Exists} diff --git a/nf.yml b/nf.yml new file mode 100644 index 0000000000..ecda151c14 --- /dev/null +++ b/nf.yml @@ -0,0 +1,2979 @@ +apiVersion: v1 +items: +- apiVersion: nfd.k8s-sigs.io/v1alpha1 + kind: NodeFeature + metadata: + annotations: + nfd.node.kubernetes.io/worker.version: v0.15.0-devel-128-gaa0f5969-dirty + creationTimestamp: "2023-12-01T15:53:12Z" + generation: 1 + labels: + nfd.node.kubernetes.io/node-name: minikube + name: minikube + namespace: node-feature-discovery + resourceVersion: "5213" + uid: 1edfeb5f-0ca5-4f46-b3ef-8fe386b44cba + spec: + features: + attributes: + cpu.coprocessor: + elements: {} + cpu.cstate: + elements: {} + cpu.model: + elements: + family: "0" + id: "0" + vendor_id: VendorUnknown + cpu.pstate: + elements: {} + cpu.rdt: + elements: {} + cpu.security: + elements: {} + cpu.sst: + elements: {} + cpu.topology: + elements: + hardware_multithreading: "false" + kernel.config: + elements: + 9P_FS: "y" + 9P_FS_POSIX_ACL: "y" + 9P_FS_SECURITY: "y" + 9P_FSCACHE: "y" + 64BIT: "y" + 842_COMPRESS: "y" + 842_DECOMPRESS: "y" + ACPI: "y" + ACPI_APMT: "y" + ACPI_CCA_REQUIRED: "y" + ACPI_CONTAINER: "y" + ACPI_GENERIC_GSI: "y" + ACPI_GTDT: "y" + ACPI_HOTPLUG_CPU: "y" + ACPI_I2C_OPREGION: "y" + ACPI_IORT: "y" + ACPI_MCFG: "y" + ACPI_MDIO: m + ACPI_PPTT: "y" + ACPI_PROCESSOR: "y" + ACPI_PROCESSOR_IDLE: "y" + ACPI_REDUCED_HARDWARE_ONLY: "y" + ACPI_SPCR_TABLE: "y" + ADVISE_SYSCALLS: "y" + AF_UNIX_OOB: "y" + AIO: "y" + ALLOW_DEV_COREDUMP: "y" + AMPERE_ERRATUM_AC03_CPU_38: "y" + APERTURE_HELPERS: "y" + ARCH_BINFMT_ELF_EXTRA_PHDRS: "y" + ARCH_BINFMT_ELF_STATE: "y" + ARCH_CORRECT_STACKTRACE_ON_KRETPROBE: "y" + ARCH_DMA_ADDR_T_64BIT: "y" + ARCH_ENABLE_HUGEPAGE_MIGRATION: "y" + ARCH_ENABLE_MEMORY_HOTPLUG: "y" + ARCH_ENABLE_MEMORY_HOTREMOVE: "y" + ARCH_ENABLE_SPLIT_PMD_PTLOCK: "y" + ARCH_ENABLE_THP_MIGRATION: "y" + ARCH_FORCE_MAX_ORDER: "10" + ARCH_HAS_ACPI_TABLE_UPGRADE: "y" + ARCH_HAS_CACHE_LINE_SIZE: "y" + ARCH_HAS_CURRENT_STACK_POINTER: "y" + ARCH_HAS_DEBUG_VIRTUAL: "y" + ARCH_HAS_DEBUG_VM_PGTABLE: "y" + ARCH_HAS_DEBUG_WX: "y" + ARCH_HAS_DMA_PREP_COHERENT: "y" + ARCH_HAS_ELF_RANDOMIZE: "y" + ARCH_HAS_FAST_MULTIPLIER: "y" + ARCH_HAS_FORTIFY_SOURCE: "y" + ARCH_HAS_GCOV_PROFILE_ALL: "y" + ARCH_HAS_GIGANTIC_PAGE: "y" + ARCH_HAS_KCOV: "y" + ARCH_HAS_KEEPINITRD: "y" + ARCH_HAS_MEMBARRIER_SYNC_CORE: "y" + ARCH_HAS_NMI_SAFE_THIS_CPU_OPS: "y" + ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE: "y" + ARCH_HAS_PTE_DEVMAP: "y" + ARCH_HAS_PTE_SPECIAL: "y" + ARCH_HAS_RELR: "y" + ARCH_HAS_SET_DIRECT_MAP: "y" + ARCH_HAS_SET_MEMORY: "y" + ARCH_HAS_SETUP_DMA_OPS: "y" + ARCH_HAS_STRICT_KERNEL_RWX: "y" + ARCH_HAS_STRICT_MODULE_RWX: "y" + ARCH_HAS_SUBPAGE_FAULTS: "y" + ARCH_HAS_SYNC_DMA_FOR_CPU: "y" + ARCH_HAS_SYNC_DMA_FOR_DEVICE: "y" + ARCH_HAS_SYSCALL_WRAPPER: "y" + ARCH_HAS_TICK_BROADCAST: "y" + ARCH_HAS_UBSAN_SANITIZE_ALL: "y" + ARCH_HAS_ZONE_DMA_SET: "y" + ARCH_HAVE_ELF_PROT: "y" + ARCH_HAVE_NMI_SAFE_CMPXCHG: "y" + ARCH_HAVE_TRACE_MMIO_ACCESS: "y" + ARCH_HIBERNATION_POSSIBLE: "y" + ARCH_KEEP_MEMBLOCK: "y" + ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE: "y" + ARCH_MMAP_RND_BITS: "18" + ARCH_MMAP_RND_BITS_MAX: "33" + ARCH_MMAP_RND_BITS_MIN: "18" + ARCH_MMAP_RND_COMPAT_BITS_MAX: "16" + ARCH_MMAP_RND_COMPAT_BITS_MIN: "11" + ARCH_PROC_KCORE_TEXT: "y" + ARCH_SPARSEMEM_ENABLE: "y" + ARCH_STACKWALK: "y" + ARCH_SUPPORTS_ACPI: "y" + ARCH_SUPPORTS_ATOMIC_RMW: "y" + ARCH_SUPPORTS_CFI_CLANG: "y" + ARCH_SUPPORTS_DEBUG_PAGEALLOC: "y" + ARCH_SUPPORTS_HUGETLBFS: "y" + ARCH_SUPPORTS_INT128: "y" + ARCH_SUPPORTS_LTO_CLANG: "y" + ARCH_SUPPORTS_LTO_CLANG_THIN: "y" + ARCH_SUPPORTS_MEMORY_FAILURE: "y" + ARCH_SUPPORTS_NUMA_BALANCING: "y" + ARCH_SUPPORTS_PAGE_TABLE_CHECK: "y" + ARCH_SUPPORTS_PER_VMA_LOCK: "y" + ARCH_SUPPORTS_SHADOW_CALL_STACK: "y" + ARCH_SUPPORTS_UPROBES: "y" + ARCH_SUSPEND_POSSIBLE: "y" + ARCH_USE_CMPXCHG_LOCKREF: "y" + ARCH_USE_GNU_PROPERTY: "y" + ARCH_USE_MEMREMAP_PROT: "y" + ARCH_USE_MEMTEST: "y" + ARCH_USE_QUEUED_RWLOCKS: "y" + ARCH_USE_QUEUED_SPINLOCKS: "y" + ARCH_USE_SYM_ANNOTATIONS: "y" + ARCH_USES_HIGH_VMA_FLAGS: "y" + ARCH_USES_PG_ARCH_X: "y" + ARCH_WANT_DEFAULT_BPF_JIT: "y" + ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT: "y" + ARCH_WANT_FRAME_POINTERS: "y" + ARCH_WANT_HUGE_PMD_SHARE: "y" + ARCH_WANT_LD_ORPHAN_WARN: "y" + ARCH_WANTS_NO_INSTR: "y" + ARCH_WANTS_THP_SWAP: "y" + ARM_AMBA: "y" + ARM_ARCH_TIMER: "y" + ARM_ARCH_TIMER_EVTSTREAM: "y" + ARM_ARCH_TIMER_OOL_WORKAROUND: "y" + ARM_CCI: "y" + ARM_CCI_PMU: "y" + ARM_CCI5xx_PMU: "y" + ARM_CCI400_COMMON: "y" + ARM_CCI400_PMU: "y" + ARM_CCN: "y" + ARM_GIC: "y" + ARM_GIC_MAX_NR: "1" + ARM_GIC_V2M: "y" + ARM_GIC_V3: "y" + ARM_GIC_V3_ITS: "y" + ARM_GIC_V3_ITS_PCI: "y" + ARM_PMU: "y" + ARM_PMU_ACPI: "y" + ARM_PMUV3: "y" + ARM_PSCI_FW: "y" + ARM_SMCCC_SOC_ID: "y" + ARM64: "y" + ARM64_4K_PAGES: "y" + ARM64_AMU_EXTN: "y" + ARM64_AS_HAS_MTE: "y" + ARM64_BTI: "y" + ARM64_CNP: "y" + ARM64_CONT_PMD_SHIFT: "4" + ARM64_CONT_PTE_SHIFT: "4" + ARM64_E0PD: "y" + ARM64_EPAN: "y" + ARM64_ERRATUM_819472: "y" + ARM64_ERRATUM_824069: "y" + ARM64_ERRATUM_826319: "y" + ARM64_ERRATUM_827319: "y" + ARM64_ERRATUM_832075: "y" + ARM64_ERRATUM_843419: "y" + ARM64_ERRATUM_858921: "y" + ARM64_ERRATUM_1024718: "y" + ARM64_ERRATUM_1165522: "y" + ARM64_ERRATUM_1286807: "y" + ARM64_ERRATUM_1319367: "y" + ARM64_ERRATUM_1463225: "y" + ARM64_ERRATUM_1508412: "y" + ARM64_ERRATUM_1530923: "y" + ARM64_ERRATUM_1542419: "y" + ARM64_ERRATUM_2051678: "y" + ARM64_ERRATUM_2054223: "y" + ARM64_ERRATUM_2067961: "y" + ARM64_ERRATUM_2077057: "y" + ARM64_ERRATUM_2441007: "y" + ARM64_ERRATUM_2441009: "y" + ARM64_ERRATUM_2457168: "y" + ARM64_ERRATUM_2645198: "y" + ARM64_ERRATUM_2658417: "y" + ARM64_HW_AFDBM: "y" + ARM64_LD_HAS_FIX_ERRATUM_843419: "y" + ARM64_LSE_ATOMICS: "y" + ARM64_MODULE_PLTS: "y" + ARM64_MTE: "y" + ARM64_PA_BITS: "48" + ARM64_PA_BITS_48: "y" + ARM64_PAGE_SHIFT: "12" + ARM64_PAN: "y" + ARM64_PTR_AUTH: "y" + ARM64_PTR_AUTH_KERNEL: "y" + ARM64_RAS_EXTN: "y" + ARM64_SME: "y" + ARM64_SVE: "y" + ARM64_TAGGED_ADDR_ABI: "y" + ARM64_TLB_RANGE: "y" + ARM64_USE_LSE_ATOMICS: "y" + ARM64_VA_BITS: "48" + ARM64_VA_BITS_48: "y" + ARM64_WORKAROUND_CLEAN_CACHE: "y" + ARM64_WORKAROUND_REPEAT_TLBI: "y" + ARM64_WORKAROUND_SPECULATIVE_AT: "y" + ARM64_WORKAROUND_TSB_FLUSH_FAILURE: "y" + AS_HAS_ARMV8_2: "y" + AS_HAS_ARMV8_3: "y" + AS_HAS_ARMV8_4: "y" + AS_HAS_ARMV8_5: "y" + AS_HAS_CFI_NEGATE_RA_STATE: "y" + AS_HAS_LDAPR: "y" + AS_HAS_LSE_ATOMICS: "y" + AS_HAS_NON_CONST_LEB128: "y" + AS_HAS_SHA3: "y" + AS_IS_GNU: "y" + AS_VERSION: "24000" + ASM_MODVERSIONS: "y" + ASN1: "y" + ASN1_ENCODER: "y" + ASSOCIATIVE_ARRAY: "y" + ASYMMETRIC_KEY_TYPE: "y" + ASYMMETRIC_PUBLIC_KEY_SUBTYPE: "y" + ATA: "y" + ATA_ACPI: "y" + ATA_BMDMA: "y" + ATA_FORCE: "y" + ATA_GENERIC: "y" + ATA_OVER_ETH: m + ATA_SFF: "y" + AUDIT: "y" + AUDIT_ARCH_COMPAT_GENERIC: "y" + AUDIT_GENERIC: "y" + AUDITSYSCALL: "y" + BALLOON_COMPACTION: "y" + BASE_FULL: "y" + BASE_SMALL: "0" + BCMA_POSSIBLE: "y" + BFQ_GROUP_IOSCHED: "y" + BINARY_PRINTF: "y" + BINFMT_ELF: "y" + BINFMT_MISC: "y" + BINFMT_SCRIPT: "y" + BITREVERSE: "y" + BLK_CGROUP: "y" + BLK_CGROUP_PUNT_BIO: "y" + BLK_CGROUP_RWSTAT: "y" + BLK_DEBUG_FS: "y" + BLK_DEV: "y" + BLK_DEV_BSG: "y" + BLK_DEV_BSG_COMMON: "y" + BLK_DEV_BSGLIB: "y" + BLK_DEV_DM: "y" + BLK_DEV_DM_BUILTIN: "y" + BLK_DEV_DRBD: m + BLK_DEV_INITRD: "y" + BLK_DEV_INTEGRITY: "y" + BLK_DEV_INTEGRITY_T10: "y" + BLK_DEV_IO_TRACE: "y" + BLK_DEV_LOOP: "y" + BLK_DEV_LOOP_MIN_COUNT: "8" + BLK_DEV_NBD: "y" + BLK_DEV_NVME: "y" + BLK_DEV_RAM: m + BLK_DEV_RAM_COUNT: "16" + BLK_DEV_RAM_SIZE: "4096" + BLK_DEV_RBD: m + BLK_DEV_SD: "y" + BLK_DEV_SR: "y" + BLK_DEV_THROTTLING: "y" + BLK_ICQ: "y" + BLK_MQ_PCI: "y" + BLK_MQ_STACKING: "y" + BLK_MQ_VIRTIO: "y" + BLK_PM: "y" + BLOCK: "y" + BLOCK_HOLDER_DEPRECATED: "y" + BLOCK_LEGACY_AUTOLOAD: "y" + BONDING: m + BPF: "y" + BPF_EVENTS: "y" + BPF_JIT: "y" + BPF_JIT_ALWAYS_ON: "y" + BPF_JIT_DEFAULT_ON: "y" + BPF_SYSCALL: "y" + BQL: "y" + BRANCH_PROFILE_NONE: "y" + BRIDGE: "y" + BRIDGE_EBT_802_3: "y" + BRIDGE_EBT_AMONG: "y" + BRIDGE_EBT_ARP: "y" + BRIDGE_EBT_ARPREPLY: "y" + BRIDGE_EBT_BROUTE: "y" + BRIDGE_EBT_DNAT: "y" + BRIDGE_EBT_IP: "y" + BRIDGE_EBT_IP6: "y" + BRIDGE_EBT_LIMIT: "y" + BRIDGE_EBT_LOG: "y" + BRIDGE_EBT_MARK: "y" + BRIDGE_EBT_MARK_T: "y" + BRIDGE_EBT_NFLOG: "y" + BRIDGE_EBT_PKTTYPE: "y" + BRIDGE_EBT_REDIRECT: "y" + BRIDGE_EBT_SNAT: "y" + BRIDGE_EBT_STP: "y" + BRIDGE_EBT_T_FILTER: "y" + BRIDGE_EBT_T_NAT: "y" + BRIDGE_EBT_VLAN: "y" + BRIDGE_IGMP_SNOOPING: "y" + BRIDGE_NETFILTER: "y" + BRIDGE_NF_EBTABLES: "y" + BRIDGE_VLAN_FILTERING: "y" + BSD_PROCESS_ACCT: "y" + BSD_PROCESS_ACCT_V3: "y" + BTRFS_FS: m + BTRFS_FS_POSIX_ACL: "y" + BUG: "y" + BUG_ON_DATA_CORRUPTION: "y" + BUILD_SALT: "" + BUILDTIME_TABLE_SORT: "y" + BUILTIN_RETURN_ADDRESS_STRIPS_PAC: "y" + CACHEFILES: "y" + CAVIUM_ERRATUM_22375: "y" + CAVIUM_ERRATUM_23154: "y" + CAVIUM_ERRATUM_27456: "y" + CAVIUM_ERRATUM_30115: "y" + CAVIUM_TX2_ERRATUM_219: "y" + CC_CAN_LINK: "y" + CC_CAN_LINK_STATIC: "y" + CC_HAS_ASM_GOTO_OUTPUT: "y" + CC_HAS_ASM_GOTO_TIED_OUTPUT: "y" + CC_HAS_ASM_INLINE: "y" + CC_HAS_AUTO_VAR_INIT_PATTERN: "y" + CC_HAS_AUTO_VAR_INIT_ZERO: "y" + CC_HAS_AUTO_VAR_INIT_ZERO_BARE: "y" + CC_HAS_BRANCH_PROT_PAC_RET: "y" + CC_HAS_BRANCH_PROT_PAC_RET_BTI: "y" + CC_HAS_INT128: "y" + CC_HAS_KASAN_GENERIC: "y" + CC_HAS_KASAN_SW_TAGS: "y" + CC_HAS_NO_PROFILE_FN_ATTR: "y" + CC_HAS_SANCOV_TRACE_PC: "y" + CC_HAS_SIGN_RETURN_ADDRESS: "y" + CC_HAS_UBSAN_BOUNDS: "y" + CC_HAS_WORKING_NOSANITIZE_ADDRESS: "y" + CC_HAS_ZERO_CALL_USED_REGS: "y" + CC_HAVE_SHADOW_CALL_STACK: "y" + CC_HAVE_STACKPROTECTOR_SYSREG: "y" + CC_IMPLICIT_FALLTHROUGH: -Wimplicit-fallthrough=5 + CC_IS_GCC: "y" + CC_NO_ARRAY_BOUNDS: "y" + CC_OPTIMIZE_FOR_PERFORMANCE: "y" + CC_VERSION_TEXT: gcc (Alpine 12.2.1_git20220924-r10) 12.2.1 20220924 + CDROM: "y" + CEPH_FS: m + CEPH_FS_POSIX_ACL: "y" + CEPH_FSCACHE: "y" + CEPH_LIB: m + CFS_BANDWIDTH: "y" + CGROUP_BPF: "y" + CGROUP_CPUACCT: "y" + CGROUP_DEVICE: "y" + CGROUP_FREEZER: "y" + CGROUP_HUGETLB: "y" + CGROUP_NET_CLASSID: "y" + CGROUP_NET_PRIO: "y" + CGROUP_PERF: "y" + CGROUP_PIDS: "y" + CGROUP_RDMA: "y" + CGROUP_SCHED: "y" + CGROUP_WRITEBACK: "y" + CGROUPS: "y" + CHECK_SIGNATURE: "y" + CHECKPOINT_RESTORE: "y" + CHR_DEV_SG: "y" + CIFS: "y" + CIFS_DEBUG: "y" + CIFS_DFS_UPCALL: "y" + CIFS_FSCACHE: "y" + CIFS_XATTR: "y" + CLANG_VERSION: "0" + CLK_SP810: "y" + CLK_VEXPRESS_OSC: "y" + CLONE_BACKWARDS: "y" + CLS_U32_MARK: "y" + CLS_U32_PERF: "y" + CLZ_TAB: "y" + CMDLINE: "" + COMMON_CLK: "y" + COMPACT_UNEVICTABLE_DEFAULT: "1" + COMPACTION: "y" + CONFIGFS_FS: "y" + CONSOLE_LOGLEVEL_DEFAULT: "7" + CONSOLE_LOGLEVEL_QUIET: "4" + CONSOLE_TRANSLATIONS: "y" + CONTEXT_SWITCH_TRACER: "y" + CONTEXT_TRACKING: "y" + CONTEXT_TRACKING_IDLE: "y" + COREDUMP: "y" + CPU_FREQ: "y" + CPU_FREQ_DEFAULT_GOV_PERFORMANCE: "y" + CPU_FREQ_GOV_PERFORMANCE: "y" + CPU_IDLE: "y" + CPU_IDLE_GOV_MENU: "y" + CPU_ISOLATION: "y" + CPU_LITTLE_ENDIAN: "y" + CPU_PM: "y" + CPU_RMAP: "y" + CPUFREQ_DT: "y" + CPUFREQ_DT_PLATDEV: "y" + CPUSETS: "y" + CRASH_CORE: "y" + CRC_CCITT: "y" + CRC_ITU_T: "y" + CRC_T10DIF: "y" + CRC8: "y" + CRC16: "y" + CRC32: "y" + CRC32_SLICEBY8: "y" + CRC64: "y" + CRC64_ROCKSOFT: "y" + CROSS_MEMORY_ATTACH: "y" + CRYPTO: "y" + CRYPTO_842: "y" + CRYPTO_ACOMP2: "y" + CRYPTO_AEAD: "y" + CRYPTO_AEAD2: "y" + CRYPTO_AES: "y" + CRYPTO_AES_ARM64: "y" + CRYPTO_AES_ARM64_BS: "y" + CRYPTO_AES_ARM64_CE: "y" + CRYPTO_AES_ARM64_CE_BLK: "y" + CRYPTO_AES_ARM64_CE_CCM: "y" + CRYPTO_AES_ARM64_NEON_BLK: "y" + CRYPTO_AKCIPHER: "y" + CRYPTO_AKCIPHER2: "y" + CRYPTO_ALGAPI: "y" + CRYPTO_ALGAPI2: "y" + CRYPTO_ANSI_CPRNG: "y" + CRYPTO_ANUBIS: "y" + CRYPTO_ARC4: "y" + CRYPTO_ARCH_HAVE_LIB_CHACHA: "y" + CRYPTO_ARCH_HAVE_LIB_POLY1305: m + CRYPTO_AUTHENC: "y" + CRYPTO_BLAKE2B: m + CRYPTO_BLOWFISH: "y" + CRYPTO_BLOWFISH_COMMON: "y" + CRYPTO_CAMELLIA: "y" + CRYPTO_CAST_COMMON: "y" + CRYPTO_CAST5: "y" + CRYPTO_CAST6: "y" + CRYPTO_CBC: "y" + CRYPTO_CCM: "y" + CRYPTO_CHACHA20: "y" + CRYPTO_CHACHA20_NEON: "y" + CRYPTO_CHACHA20POLY1305: "y" + CRYPTO_CMAC: "y" + CRYPTO_CRC32: "y" + CRYPTO_CRC32C: "y" + CRYPTO_CRC64_ROCKSOFT: "y" + CRYPTO_CRCT10DIF: "y" + CRYPTO_CRCT10DIF_ARM64_CE: "y" + CRYPTO_CRYPTD: "y" + CRYPTO_CTR: "y" + CRYPTO_CTS: "y" + CRYPTO_DEFLATE: "y" + CRYPTO_DES: "y" + CRYPTO_DEV_CAVIUM_ZIP: m + CRYPTO_DEV_HISI_SEC: m + CRYPTO_DEV_VIRTIO: m + CRYPTO_DH: "y" + CRYPTO_DRBG: "y" + CRYPTO_DRBG_HMAC: "y" + CRYPTO_DRBG_MENU: "y" + CRYPTO_ECB: "y" + CRYPTO_ECHAINIV: "y" + CRYPTO_ENGINE: m + CRYPTO_ESSIV: "y" + CRYPTO_FCRYPT: "y" + CRYPTO_GCM: "y" + CRYPTO_GHASH: "y" + CRYPTO_GHASH_ARM64_CE: "y" + CRYPTO_HASH: "y" + CRYPTO_HASH_INFO: "y" + CRYPTO_HASH2: "y" + CRYPTO_HMAC: "y" + CRYPTO_HW: "y" + CRYPTO_JITTERENTROPY: "y" + CRYPTO_KDF800108_CTR: "y" + CRYPTO_KEYWRAP: "y" + CRYPTO_KHAZAD: "y" + CRYPTO_KPP: "y" + CRYPTO_KPP2: "y" + CRYPTO_LIB_AES: "y" + CRYPTO_LIB_ARC4: "y" + CRYPTO_LIB_BLAKE2S_GENERIC: "y" + CRYPTO_LIB_CHACHA: m + CRYPTO_LIB_CHACHA_GENERIC: "y" + CRYPTO_LIB_CHACHA20POLY1305: m + CRYPTO_LIB_CURVE25519: m + CRYPTO_LIB_CURVE25519_GENERIC: m + CRYPTO_LIB_DES: "y" + CRYPTO_LIB_GF128MUL: "y" + CRYPTO_LIB_POLY1305: m + CRYPTO_LIB_POLY1305_GENERIC: "y" + CRYPTO_LIB_POLY1305_RSIZE: "9" + CRYPTO_LIB_SHA1: "y" + CRYPTO_LIB_SHA256: "y" + CRYPTO_LIB_UTILS: "y" + CRYPTO_LRW: "y" + CRYPTO_LZ4: "y" + CRYPTO_LZ4HC: "y" + CRYPTO_LZO: "y" + CRYPTO_MANAGER: "y" + CRYPTO_MANAGER_DISABLE_TESTS: "y" + CRYPTO_MANAGER2: "y" + CRYPTO_MD4: "y" + CRYPTO_MD5: "y" + CRYPTO_MICHAEL_MIC: "y" + CRYPTO_NULL: "y" + CRYPTO_NULL2: "y" + CRYPTO_PCBC: "y" + CRYPTO_POLY1305: "y" + CRYPTO_POLY1305_NEON: m + CRYPTO_RMD160: "y" + CRYPTO_RNG: "y" + CRYPTO_RNG_DEFAULT: "y" + CRYPTO_RNG2: "y" + CRYPTO_RSA: "y" + CRYPTO_SEED: "y" + CRYPTO_SEQIV: "y" + CRYPTO_SERPENT: "y" + CRYPTO_SHA1: "y" + CRYPTO_SHA1_ARM64_CE: "y" + CRYPTO_SHA2_ARM64_CE: "y" + CRYPTO_SHA256: "y" + CRYPTO_SHA256_ARM64: "y" + CRYPTO_SHA512: "y" + CRYPTO_SHA512_ARM64: "y" + CRYPTO_SKCIPHER: "y" + CRYPTO_SKCIPHER2: "y" + CRYPTO_TEA: "y" + CRYPTO_TWOFISH: "y" + CRYPTO_TWOFISH_COMMON: "y" + CRYPTO_USER: "y" + CRYPTO_USER_API: "y" + CRYPTO_USER_API_AEAD: "y" + CRYPTO_USER_API_ENABLE_OBSOLETE: "y" + CRYPTO_USER_API_HASH: "y" + CRYPTO_USER_API_RNG: "y" + CRYPTO_USER_API_SKCIPHER: "y" + CRYPTO_VMAC: "y" + CRYPTO_WP512: "y" + CRYPTO_XCBC: "y" + CRYPTO_XTS: "y" + CRYPTO_XXHASH: m + CUSE: "y" + DAX: "y" + DCACHE_WORD_ACCESS: "y" + DEBUG_BUGVERBOSE: "y" + DEBUG_CREDENTIALS: "y" + DEBUG_FS: "y" + DEBUG_FS_ALLOW_ALL: "y" + DEBUG_INFO: "y" + DEBUG_INFO_BTF: "y" + DEBUG_INFO_BTF_MODULES: "y" + DEBUG_INFO_COMPRESSED_NONE: "y" + DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT: "y" + DEBUG_KERNEL: "y" + DEBUG_LIST: "y" + DEBUG_MEMORY_INIT: "y" + DEBUG_MISC: "y" + DEBUG_NOTIFIERS: "y" + DEBUG_PREEMPT: "y" + DECOMPRESS_GZIP: "y" + DECOMPRESS_ZSTD: "y" + DEFAULT_HOSTNAME: (none) + DEFAULT_HUNG_TASK_TIMEOUT: "120" + DEFAULT_INIT: "" + DEFAULT_MMAP_MIN_ADDR: "32768" + DEFAULT_SECURITY_DAC: "y" + DEFAULT_TCP_CONG: cubic + DETECT_HUNG_TASK: "y" + DEVFREQ_GOV_SIMPLE_ONDEMAND: "y" + DEVMEM: "y" + DEVPORT: "y" + DEVTMPFS: "y" + DM_BIO_PRISON: "y" + DM_BUFIO: "y" + DM_CRYPT: "y" + DM_MULTIPATH: m + DM_MULTIPATH_QL: m + DM_MULTIPATH_ST: m + DM_PERSISTENT_DATA: "y" + DM_SNAPSHOT: "y" + DM_THIN_PROVISIONING: "y" + DMA_ACPI: "y" + DMA_COHERENT_POOL: "y" + DMA_DECLARE_COHERENT: "y" + DMA_DIRECT_REMAP: "y" + DMA_ENGINE: "y" + DMA_NONCOHERENT_MMAP: "y" + DMA_OF: "y" + DMADEVICES: "y" + DMI: "y" + DMI_SYSFS: "y" + DMIID: "y" + DNOTIFY: "y" + DNS_RESOLVER: "y" + DQL: "y" + DRM_PANEL_ORIENTATION_QUIRKS: "y" + DST_CACHE: "y" + DTC: "y" + DUMMY: m + DUMMY_CONSOLE: "y" + DUMMY_CONSOLE_COLUMNS: "80" + DUMMY_CONSOLE_ROWS: "25" + DYNAMIC_EVENTS: "y" + DYNAMIC_FTRACE: "y" + DYNAMIC_FTRACE_WITH_ARGS: "y" + DYNAMIC_FTRACE_WITH_CALL_OPS: "y" + DYNAMIC_FTRACE_WITH_DIRECT_CALLS: "y" + EDAC_SUPPORT: "y" + EFI: "y" + EFI_ARMSTUB_DTB_LOADER: "y" + EFI_CUSTOM_SSDT_OVERLAYS: "y" + EFI_EARLYCON: "y" + EFI_ESRT: "y" + EFI_GENERIC_STUB: "y" + EFI_PARAMS_FROM_FDT: "y" + EFI_PARTITION: "y" + EFI_RUNTIME_WRAPPERS: "y" + EFI_STUB: "y" + EFI_VARS_PSTORE: "y" + EFIVAR_FS: "y" + ELF_CORE: "y" + ELFCORE: "y" + ENCRYPTED_KEYS: "y" + EPOLL: "y" + EROFS_FS: "y" + EROFS_FS_PCPU_KTHREAD: "y" + EROFS_FS_PCPU_KTHREAD_HIPRI: "y" + EROFS_FS_POSIX_ACL: "y" + EROFS_FS_SECURITY: "y" + EROFS_FS_XATTR: "y" + EROFS_FS_ZIP: "y" + EROFS_FS_ZIP_LZMA: "y" + ETHERNET: "y" + ETHTOOL_NETLINK: "y" + EVENT_TRACING: "y" + EVENTFD: "y" + EVM: "y" + EVM_ATTR_FSUUID: "y" + EXCLUSIVE_SYSTEM_RAM: "y" + EXPERT: "y" + EXPORTFS: "y" + EXT4_FS: "y" + EXT4_FS_POSIX_ACL: "y" + EXT4_FS_SECURITY: "y" + EXT4_USE_FOR_EXT2: "y" + EXTCON: "y" + EXTRA_FIRMWARE: "" + FAILOVER: "y" + FAIR_GROUP_SCHED: "y" + FANOTIFY: "y" + FAT_DEFAULT_CODEPAGE: "437" + FAT_DEFAULT_IOCHARSET: utf8 + FAT_FS: "y" + FB: "y" + FB_CFB_COPYAREA: "y" + FB_CFB_FILLRECT: "y" + FB_CFB_IMAGEBLIT: "y" + FB_EFI: "y" + FB_NOTIFY: "y" + FB_SIMPLE: "y" + FHANDLE: "y" + FIB_RULES: "y" + FILE_LOCKING: "y" + FIRMWARE_MEMMAP: "y" + FIX_EARLYCON_MEM: "y" + FIXED_PHY: m + FONT_8x8: "y" + FONT_8x16: "y" + FONT_SUPPORT: "y" + FORTIFY_SOURCE: "y" + FRAME_POINTER: "y" + FRAME_WARN: "1024" + FRAMEBUFFER_CONSOLE: "y" + FRAMEBUFFER_CONSOLE_DETECT_PRIMARY: "y" + FREEZER: "y" + FS_ENCRYPTION: "y" + FS_ENCRYPTION_ALGS: "y" + FS_IOMAP: "y" + FS_MBCACHE: "y" + FS_POSIX_ACL: "y" + FSCACHE: "y" + FSCACHE_STATS: "y" + FSL_ERRATUM_A008585: "y" + FSNOTIFY: "y" + FTRACE: "y" + FTRACE_MCOUNT_RECORD: "y" + FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY: "y" + FTRACE_SYSCALLS: "y" + FUJITSU_ERRATUM_010001: "y" + FUNCTION_ALIGNMENT: "8" + FUNCTION_ALIGNMENT_4B: "y" + FUNCTION_ALIGNMENT_8B: "y" + FUNCTION_ERROR_INJECTION: "y" + FUNCTION_GRAPH_TRACER: "y" + FUNCTION_PROFILER: "y" + FUNCTION_TRACER: "y" + FUSE_FS: "y" + FUSION: "y" + FUSION_MAX_SGE: "128" + FUSION_SPI: "y" + FUTEX: "y" + FUTEX_PI: "y" + FW_LOADER: "y" + FWNODE_MDIO: m + GACT_PROB: "y" + GCC_PLUGIN_STACKLEAK: "y" + GCC_PLUGINS: "y" + GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS: "y" + GCC_VERSION: "120201" + GCC11_NO_ARRAY_BOUNDS: "y" + GENERIC_ALLOCATOR: "y" + GENERIC_ARCH_TOPOLOGY: "y" + GENERIC_BUG: "y" + GENERIC_BUG_RELATIVE_POINTERS: "y" + GENERIC_CALIBRATE_DELAY: "y" + GENERIC_CLOCKEVENTS: "y" + GENERIC_CLOCKEVENTS_BROADCAST: "y" + GENERIC_CPU_AUTOPROBE: "y" + GENERIC_CPU_VULNERABILITIES: "y" + GENERIC_CSUM: "y" + GENERIC_EARLY_IOREMAP: "y" + GENERIC_GETTIMEOFDAY: "y" + GENERIC_HWEIGHT: "y" + GENERIC_IDLE_POLL_SETUP: "y" + GENERIC_IOREMAP: "y" + GENERIC_IRQ_EFFECTIVE_AFF_MASK: "y" + GENERIC_IRQ_IPI: "y" + GENERIC_IRQ_MIGRATION: "y" + GENERIC_IRQ_PROBE: "y" + GENERIC_IRQ_SHOW: "y" + GENERIC_IRQ_SHOW_LEVEL: "y" + GENERIC_LIB_DEVMEM_IS_ALLOWED: "y" + GENERIC_MSI_IRQ: "y" + GENERIC_NET_UTILS: "y" + GENERIC_PCI_IOMAP: "y" + GENERIC_PHY: "y" + GENERIC_PTDUMP: "y" + GENERIC_SCHED_CLOCK: "y" + GENERIC_SMP_IDLE_THREAD: "y" + GENERIC_STRNCPY_FROM_USER: "y" + GENERIC_STRNLEN_USER: "y" + GENERIC_TIME_VSYSCALL: "y" + GENERIC_TRACER: "y" + GENERIC_VDSO_TIME_NS: "y" + GENEVE: m + GLOB: "y" + GPIO_ACPI: "y" + GPIO_CDEV: "y" + GPIO_CDEV_V1: "y" + GPIO_GENERIC: "y" + GPIO_GENERIC_PLATFORM: "y" + GPIO_PL061: "y" + GPIOLIB: "y" + GPIOLIB_FASTPATH_LIMIT: "512" + GPIOLIB_IRQCHIP: "y" + GRACE_PERIOD: m + GRO_CELLS: "y" + HARDENED_USERCOPY: "y" + HARDIRQS_SW_RESEND: "y" + HAS_DMA: "y" + HAS_IOMEM: "y" + HAS_IOPORT: "y" + HAS_IOPORT_MAP: "y" + HAVE_ACPI_APEI: "y" + HAVE_ARCH_AUDITSYSCALL: "y" + HAVE_ARCH_BITREVERSE: "y" + HAVE_ARCH_COMPILER_H: "y" + HAVE_ARCH_HUGE_VMALLOC: "y" + HAVE_ARCH_HUGE_VMAP: "y" + HAVE_ARCH_JUMP_LABEL: "y" + HAVE_ARCH_JUMP_LABEL_RELATIVE: "y" + HAVE_ARCH_KASAN: "y" + HAVE_ARCH_KASAN_HW_TAGS: "y" + HAVE_ARCH_KASAN_SW_TAGS: "y" + HAVE_ARCH_KASAN_VMALLOC: "y" + HAVE_ARCH_KCSAN: "y" + HAVE_ARCH_KFENCE: "y" + HAVE_ARCH_KGDB: "y" + HAVE_ARCH_MMAP_RND_BITS: "y" + HAVE_ARCH_PREL32_RELOCATIONS: "y" + HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET: "y" + HAVE_ARCH_SECCOMP: "y" + HAVE_ARCH_SECCOMP_FILTER: "y" + HAVE_ARCH_STACKLEAK: "y" + HAVE_ARCH_THREAD_STRUCT_WHITELIST: "y" + HAVE_ARCH_TRACEHOOK: "y" + HAVE_ARCH_TRANSPARENT_HUGEPAGE: "y" + HAVE_ARCH_VMAP_STACK: "y" + HAVE_ARM_SMCCC: "y" + HAVE_ARM_SMCCC_DISCOVERY: "y" + HAVE_ASM_MODVERSIONS: "y" + HAVE_C_RECORDMCOUNT: "y" + HAVE_CLK: "y" + HAVE_CLK_PREPARE: "y" + HAVE_CMPXCHG_DOUBLE: "y" + HAVE_CMPXCHG_LOCAL: "y" + HAVE_CONTEXT_TRACKING_USER: "y" + HAVE_DEBUG_KMEMLEAK: "y" + HAVE_DMA_CONTIGUOUS: "y" + HAVE_DYNAMIC_FTRACE: "y" + HAVE_DYNAMIC_FTRACE_WITH_ARGS: "y" + HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS: "y" + HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS: "y" + HAVE_EBPF_JIT: "y" + HAVE_EFFICIENT_UNALIGNED_ACCESS: "y" + HAVE_FAST_GUP: "y" + HAVE_FTRACE_MCOUNT_RECORD: "y" + HAVE_FUNCTION_ARG_ACCESS_API: "y" + HAVE_FUNCTION_ERROR_INJECTION: "y" + HAVE_FUNCTION_GRAPH_TRACER: "y" + HAVE_FUNCTION_TRACER: "y" + HAVE_GCC_PLUGINS: "y" + HAVE_GENERIC_VDSO: "y" + HAVE_HARDENED_USERCOPY_ALLOCATOR: "y" + HAVE_HW_BREAKPOINT: "y" + HAVE_IOREMAP_PROT: "y" + HAVE_IRQ_TIME_ACCOUNTING: "y" + HAVE_KCSAN_COMPILER: "y" + HAVE_KPROBES: "y" + HAVE_KRETPROBES: "y" + HAVE_KVM: "y" + HAVE_MOD_ARCH_SPECIFIC: "y" + HAVE_MOVE_PMD: "y" + HAVE_MOVE_PUD: "y" + HAVE_NMI: "y" + HAVE_PCI: "y" + HAVE_PERF_EVENTS: "y" + HAVE_PERF_REGS: "y" + HAVE_PERF_USER_STACK_DUMP: "y" + HAVE_POSIX_CPU_TIMERS_TASK_WORK: "y" + HAVE_PREEMPT_DYNAMIC: "y" + HAVE_PREEMPT_DYNAMIC_KEY: "y" + HAVE_REGS_AND_STACK_ACCESS_API: "y" + HAVE_RSEQ: "y" + HAVE_SOFTIRQ_ON_OWN_STACK: "y" + HAVE_STACKPROTECTOR: "y" + HAVE_SYSCALL_TRACEPOINTS: "y" + HAVE_VIRT_CPU_ACCOUNTING_GEN: "y" + HID: "y" + HID_GENERIC: "y" + HID_SUPPORT: "y" + HIGH_RES_TIMERS: "y" + HISILICON_ERRATUM_161010101: "y" + HISILICON_ERRATUM_161600802: "y" + HOTPLUG_CPU: "y" + HOTPLUG_PCI: "y" + HOTPLUG_PCI_ACPI: "y" + HOTPLUG_PCI_PCIE: "y" + HUGETLB_PAGE: "y" + HUGETLBFS: "y" + HVC_DRIVER: "y" + HW_CONSOLE: "y" + HW_PERF_EVENTS: "y" + HW_RANDOM: "y" + HW_RANDOM_ARM_SMCCC_TRNG: "y" + HW_RANDOM_CN10K: "y" + HW_RANDOM_VIRTIO: "y" + HWMON: "y" + HZ: "1000" + HZ_1000: "y" + I2C: "y" + I2C_BOARDINFO: "y" + I2C_CHARDEV: "y" + I2C_COMPAT: "y" + I2C_HELPER_AUTO: "y" + I2C_HID: "y" + I2C_MUX: "y" + I2C_SMBUS: m + I2C_THUNDERX: m + IKCONFIG: "y" + IKCONFIG_PROC: "y" + ILLEGAL_POINTER_VALUE: "0xdead000000000000" + IMA: "y" + IMA_APPRAISE: "y" + IMA_APPRAISE_BOOTPARAM: "y" + IMA_DEFAULT_HASH: sha256 + IMA_DEFAULT_HASH_SHA256: "y" + IMA_DEFAULT_TEMPLATE: ima-ng + IMA_MEASURE_ASYMMETRIC_KEYS: "y" + IMA_MEASURE_PCR_IDX: "10" + IMA_NG_TEMPLATE: "y" + IMA_READ_POLICY: "y" + INET: "y" + INET_AH: m + INET_DIAG: "y" + INET_ESP: m + INET_IPCOMP: m + INET_SCTP_DIAG: m + INET_TABLE_PERTURB_ORDER: "16" + INET_TCP_DIAG: "y" + INET_TUNNEL: "y" + INET_UDP_DIAG: "y" + INET_XFRM_TUNNEL: m + INET6_AH: m + INET6_ESP: m + INET6_IPCOMP: m + INET6_TUNNEL: "y" + INET6_XFRM_TUNNEL: m + INIT_ENV_ARG_LIMIT: "32" + INIT_STACK_ALL_ZERO: "y" + INITRAMFS_PRESERVE_MTIME: "y" + INITRAMFS_SOURCE: "" + INOTIFY_USER: "y" + INPUT: "y" + INPUT_EVDEV: "y" + INPUT_FF_MEMLESS: "y" + INPUT_JOYDEV: "y" + INPUT_KEYBOARD: "y" + INPUT_MISC: "y" + INPUT_MOUSEDEV: "y" + INPUT_MOUSEDEV_PSAUX: "y" + INPUT_MOUSEDEV_SCREEN_X: "1024" + INPUT_MOUSEDEV_SCREEN_Y: "768" + INPUT_SPARSEKMAP: "y" + INPUT_UINPUT: "y" + INPUT_VIVALDIFMAP: "y" + INTEGRITY: "y" + INTEGRITY_ASYMMETRIC_KEYS: "y" + INTEGRITY_AUDIT: "y" + INTEGRITY_SIGNATURE: "y" + IO_URING: "y" + IO_WQ: "y" + IOSCHED_BFQ: "y" + IP_ADVANCED_ROUTER: "y" + IP_FIB_TRIE_STATS: "y" + IP_MROUTE: "y" + IP_MROUTE_COMMON: "y" + IP_MROUTE_MULTIPLE_TABLES: "y" + IP_MULTICAST: "y" + IP_MULTIPLE_TABLES: "y" + IP_NF_ARP_MANGLE: "y" + IP_NF_ARPFILTER: "y" + IP_NF_ARPTABLES: "y" + IP_NF_FILTER: "y" + IP_NF_IPTABLES: "y" + IP_NF_MANGLE: "y" + IP_NF_MATCH_AH: "y" + IP_NF_MATCH_ECN: "y" + IP_NF_MATCH_RPFILTER: "y" + IP_NF_MATCH_TTL: "y" + IP_NF_NAT: "y" + IP_NF_RAW: "y" + IP_NF_SECURITY: "y" + IP_NF_TARGET_ECN: "y" + IP_NF_TARGET_MASQUERADE: "y" + IP_NF_TARGET_NETMAP: "y" + IP_NF_TARGET_REDIRECT: "y" + IP_NF_TARGET_REJECT: "y" + IP_NF_TARGET_SYNPROXY: "y" + IP_NF_TARGET_TTL: "y" + IP_PIMSM_V1: "y" + IP_PIMSM_V2: "y" + IP_PNP: "y" + IP_PNP_DHCP: "y" + IP_ROUTE_CLASSID: "y" + IP_ROUTE_MULTIPATH: "y" + IP_ROUTE_VERBOSE: "y" + IP_SCTP: m + IP_SET: "y" + IP_SET_BITMAP_IP: "y" + IP_SET_BITMAP_IPMAC: "y" + IP_SET_BITMAP_PORT: "y" + IP_SET_HASH_IP: "y" + IP_SET_HASH_IPPORT: "y" + IP_SET_HASH_IPPORTIP: "y" + IP_SET_HASH_IPPORTNET: "y" + IP_SET_HASH_NET: "y" + IP_SET_HASH_NETIFACE: "y" + IP_SET_HASH_NETPORT: "y" + IP_SET_LIST_SET: "y" + IP_SET_MAX: "256" + IP_VS: "y" + IP_VS_DEBUG: "y" + IP_VS_DH: "y" + IP_VS_FO: "y" + IP_VS_FTP: "y" + IP_VS_IPV6: "y" + IP_VS_LBLC: "y" + IP_VS_LBLCR: "y" + IP_VS_LC: "y" + IP_VS_MH: "y" + IP_VS_MH_TAB_INDEX: "12" + IP_VS_NFCT: "y" + IP_VS_NQ: "y" + IP_VS_OVF: "y" + IP_VS_PE_SIP: "y" + IP_VS_PROTO_AH: "y" + IP_VS_PROTO_AH_ESP: "y" + IP_VS_PROTO_ESP: "y" + IP_VS_PROTO_SCTP: "y" + IP_VS_PROTO_TCP: "y" + IP_VS_PROTO_UDP: "y" + IP_VS_RR: "y" + IP_VS_SED: "y" + IP_VS_SH: "y" + IP_VS_SH_TAB_BITS: "8" + IP_VS_TAB_BITS: "12" + IP_VS_WLC: "y" + IP_VS_WRR: "y" + IP6_NF_FILTER: "y" + IP6_NF_IPTABLES: "y" + IP6_NF_MANGLE: "y" + IP6_NF_MATCH_AH: "y" + IP6_NF_MATCH_EUI64: "y" + IP6_NF_MATCH_FRAG: "y" + IP6_NF_MATCH_HL: "y" + IP6_NF_MATCH_IPV6HEADER: "y" + IP6_NF_MATCH_MH: "y" + IP6_NF_MATCH_OPTS: "y" + IP6_NF_MATCH_RPFILTER: "y" + IP6_NF_MATCH_RT: "y" + IP6_NF_NAT: "y" + IP6_NF_RAW: "y" + IP6_NF_SECURITY: "y" + IP6_NF_TARGET_HL: "y" + IP6_NF_TARGET_MASQUERADE: "y" + IP6_NF_TARGET_NPT: "y" + IP6_NF_TARGET_REJECT: "y" + IP6_NF_TARGET_SYNPROXY: "y" + IPC_NS: "y" + IPV6: "y" + IPV6_FOU: "y" + IPV6_FOU_TUNNEL: "y" + IPV6_GRE: m + IPV6_ILA: m + IPV6_MIP6: m + IPV6_MULTIPLE_TABLES: "y" + IPV6_NDISC_NODETYPE: "y" + IPV6_ROUTER_PREF: "y" + IPV6_SIT: m + IPV6_SIT_6RD: "y" + IPV6_SUBTREES: "y" + IPV6_TUNNEL: "y" + IPV6_VTI: m + IPVLAN: "y" + IPVLAN_L3S: "y" + IRQ_DOMAIN: "y" + IRQ_DOMAIN_HIERARCHY: "y" + IRQ_FORCED_THREADING: "y" + IRQ_POLL: "y" + IRQ_WORK: "y" + IRQCHIP: "y" + ISCSI_TCP: m + ISO9660_FS: "y" + JBD2: "y" + JUMP_LABEL: "y" + KALLSYMS: "y" + KALLSYMS_BASE_RELATIVE: "y" + KCMP: "y" + KERNEL_MODE_NEON: "y" + KERNFS: "y" + KEY_DH_OPERATIONS: "y" + KEYBOARD_ATKBD: "y" + KEYS: "y" + KPROBE_EVENTS: "y" + KPROBES: "y" + KRETPROBES: "y" + KSM: "y" + L2TP: m + LD_IS_BFD: "y" + LD_ORPHAN_WARN: "y" + LD_ORPHAN_WARN_LEVEL: warn + LD_VERSION: "24000" + LDISC_AUTOLOAD: "y" + LEGACY_DIRECT_IO: "y" + LEGACY_TIOCSTI: "y" + LIBCRC32C: "y" + LIBFDT: "y" + LLC: "y" + LLD_VERSION: "0" + LOCALVERSION: -linuxkit + LOCK_DEBUGGING_SUPPORT: "y" + LOCK_MM_AND_FIND_VMA: "y" + LOCK_SPIN_ON_OWNER: "y" + LOCKD: m + LOCKD_V4: "y" + LOCKDEP_SUPPORT: "y" + LOG_BUF_SHIFT: "17" + LOG_CPU_MAX_BUF_SHIFT: "12" + LRU_CACHE: m + LSM: yama,loadpin,safesetid,integrity + LTO_NONE: "y" + LWTUNNEL: "y" + LWTUNNEL_BPF: "y" + LZ4_COMPRESS: "y" + LZ4_DECOMPRESS: "y" + LZ4HC_COMPRESS: "y" + LZO_COMPRESS: "y" + LZO_DECOMPRESS: "y" + MACVLAN: "y" + MACVTAP: "y" + MAGIC_SYSRQ: "y" + MAGIC_SYSRQ_DEFAULT_ENABLE: "0x1" + MAGIC_SYSRQ_SERIAL: "y" + MAGIC_SYSRQ_SERIAL_SEQUENCE: "" + MAILBOX: "y" + MAX_SKB_FRAGS: "17" + MD: "y" + MDIO_BUS: m + MDIO_CAVIUM: m + MDIO_DEVICE: m + MDIO_DEVRES: m + MDIO_THUNDER: m + MEGARAID_SAS: "y" + MEMBARRIER: "y" + MEMCG: "y" + MEMCG_KMEM: "y" + MEMFD_CREATE: "y" + MEMORY_BALLOON: "y" + MESSAGE_LOGLEVEL_DEFAULT: "4" + MFD_CORE: "y" + MFD_SYSCON: "y" + MFD_VEXPRESS_SYSREG: "y" + MICROCHIP_PHY: m + MIGRATION: "y" + MISC_FILESYSTEMS: "y" + MITIGATE_SPECTRE_BRANCH_HISTORY: "y" + MMC: m + MMC_BLOCK: m + MMC_BLOCK_MINORS: "8" + MMC_SDHCI: m + MMC_SDHCI_PLTFM: m + MMU: "y" + MMU_GATHER_RCU_TABLE_FREE: "y" + MMU_GATHER_TABLE_FREE: "y" + MMU_LAZY_TLB_REFCOUNT: "y" + MODPROBE_PATH: /sbin/modprobe + MODULE_COMPRESS_NONE: "y" + MODULE_UNLOAD: "y" + MODULES: "y" + MODULES_TREE_LOOKUP: "y" + MODULES_USE_ELF_RELA: "y" + MODVERSIONS: "y" + MPILIB: "y" + MPLS: "y" + MPLS_IPTUNNEL: m + MPLS_ROUTING: m + MQ_IOSCHED_DEADLINE: "y" + MQ_IOSCHED_KYBER: "y" + MSDOS_FS: "y" + MSDOS_PARTITION: "y" + MULTIUSER: "y" + MUTEX_SPIN_ON_OWNER: "y" + NAMESPACES: "y" + NEED_DMA_MAP_STATE: "y" + NEED_SG_DMA_LENGTH: "y" + NET: "y" + NET_9P: "y" + NET_9P_FD: "y" + NET_9P_VIRTIO: "y" + NET_ACT_BPF: "y" + NET_ACT_CSUM: "y" + NET_ACT_GACT: "y" + NET_ACT_IPT: "y" + NET_ACT_MIRRED: "y" + NET_ACT_NAT: "y" + NET_ACT_PEDIT: "y" + NET_ACT_POLICE: "y" + NET_ACT_SIMP: "y" + NET_ACT_SKBEDIT: "y" + NET_CLS: "y" + NET_CLS_ACT: "y" + NET_CLS_BASIC: "y" + NET_CLS_BPF: "y" + NET_CLS_CGROUP: "y" + NET_CLS_FLOW: "y" + NET_CLS_FW: "y" + NET_CLS_MATCHALL: "y" + NET_CLS_ROUTE4: "y" + NET_CLS_U32: "y" + NET_CORE: "y" + NET_EGRESS: "y" + NET_EMATCH: "y" + NET_EMATCH_CMP: "y" + NET_EMATCH_IPSET: "y" + NET_EMATCH_META: "y" + NET_EMATCH_NBYTE: "y" + NET_EMATCH_STACK: "32" + NET_EMATCH_TEXT: "y" + NET_EMATCH_U32: "y" + NET_FAILOVER: "y" + NET_FLOW_LIMIT: "y" + NET_FOU: "y" + NET_FOU_IP_TUNNELS: "y" + NET_HANDSHAKE: "y" + NET_INGRESS: "y" + NET_IP_TUNNEL: "y" + NET_IPGRE: m + NET_IPGRE_BROADCAST: "y" + NET_IPGRE_DEMUX: "y" + NET_IPIP: "y" + NET_IPVTI: m + NET_KEY: m + NET_KEY_MIGRATE: "y" + NET_L3_MASTER_DEV: "y" + NET_MPLS_GSO: m + NET_NS: "y" + NET_NSH: m + NET_PTP_CLASSIFY: "y" + NET_RX_BUSY_POLL: "y" + NET_SCH_CHOKE: m + NET_SCH_DRR: m + NET_SCH_FIFO: "y" + NET_SCH_GRED: m + NET_SCH_HFSC: m + NET_SCH_HTB: m + NET_SCH_INGRESS: m + NET_SCH_MQPRIO: m + NET_SCH_MQPRIO_LIB: m + NET_SCH_MULTIQ: m + NET_SCH_NETEM: m + NET_SCH_PRIO: m + NET_SCH_QFQ: m + NET_SCH_RED: m + NET_SCH_SFB: m + NET_SCH_SFQ: m + NET_SCH_TBF: m + NET_SCH_TEQL: m + NET_SCHED: "y" + NET_SELFTESTS: m + NET_SOCK_MSG: "y" + NET_SWITCHDEV: "y" + NET_TEAM: m + NET_TEAM_MODE_ACTIVEBACKUP: m + NET_TEAM_MODE_BROADCAST: m + NET_TEAM_MODE_LOADBALANCE: m + NET_TEAM_MODE_RANDOM: m + NET_TEAM_MODE_ROUNDROBIN: m + NET_UDP_TUNNEL: "y" + NETDEVICES: "y" + NETFILTER: "y" + NETFILTER_ADVANCED: "y" + NETFILTER_BPF_LINK: "y" + NETFILTER_CONNCOUNT: "y" + NETFILTER_EGRESS: "y" + NETFILTER_FAMILY_ARP: "y" + NETFILTER_FAMILY_BRIDGE: "y" + NETFILTER_INGRESS: "y" + NETFILTER_NETLINK: "y" + NETFILTER_NETLINK_ACCT: "y" + NETFILTER_NETLINK_GLUE_CT: "y" + NETFILTER_NETLINK_LOG: "y" + NETFILTER_NETLINK_OSF: "y" + NETFILTER_NETLINK_QUEUE: "y" + NETFILTER_SKIP_EGRESS: "y" + NETFILTER_SYNPROXY: "y" + NETFILTER_XT_CONNMARK: "y" + NETFILTER_XT_MARK: "y" + NETFILTER_XT_MATCH_ADDRTYPE: "y" + NETFILTER_XT_MATCH_BPF: "y" + NETFILTER_XT_MATCH_CGROUP: "y" + NETFILTER_XT_MATCH_CLUSTER: "y" + NETFILTER_XT_MATCH_COMMENT: "y" + NETFILTER_XT_MATCH_CONNBYTES: "y" + NETFILTER_XT_MATCH_CONNLABEL: "y" + NETFILTER_XT_MATCH_CONNLIMIT: "y" + NETFILTER_XT_MATCH_CONNMARK: "y" + NETFILTER_XT_MATCH_CONNTRACK: "y" + NETFILTER_XT_MATCH_CPU: "y" + NETFILTER_XT_MATCH_DCCP: "y" + NETFILTER_XT_MATCH_DEVGROUP: "y" + NETFILTER_XT_MATCH_DSCP: "y" + NETFILTER_XT_MATCH_ECN: "y" + NETFILTER_XT_MATCH_ESP: "y" + NETFILTER_XT_MATCH_HASHLIMIT: "y" + NETFILTER_XT_MATCH_HELPER: "y" + NETFILTER_XT_MATCH_HL: "y" + NETFILTER_XT_MATCH_IPCOMP: "y" + NETFILTER_XT_MATCH_IPRANGE: "y" + NETFILTER_XT_MATCH_IPVS: "y" + NETFILTER_XT_MATCH_L2TP: "y" + NETFILTER_XT_MATCH_LENGTH: "y" + NETFILTER_XT_MATCH_LIMIT: "y" + NETFILTER_XT_MATCH_MAC: "y" + NETFILTER_XT_MATCH_MARK: "y" + NETFILTER_XT_MATCH_MULTIPORT: "y" + NETFILTER_XT_MATCH_NFACCT: "y" + NETFILTER_XT_MATCH_OSF: "y" + NETFILTER_XT_MATCH_OWNER: "y" + NETFILTER_XT_MATCH_PHYSDEV: "y" + NETFILTER_XT_MATCH_PKTTYPE: "y" + NETFILTER_XT_MATCH_POLICY: "y" + NETFILTER_XT_MATCH_QUOTA: "y" + NETFILTER_XT_MATCH_RATEEST: "y" + NETFILTER_XT_MATCH_REALM: "y" + NETFILTER_XT_MATCH_RECENT: "y" + NETFILTER_XT_MATCH_SCTP: "y" + NETFILTER_XT_MATCH_SOCKET: "y" + NETFILTER_XT_MATCH_STATE: "y" + NETFILTER_XT_MATCH_STATISTIC: "y" + NETFILTER_XT_MATCH_STRING: "y" + NETFILTER_XT_MATCH_TCPMSS: "y" + NETFILTER_XT_MATCH_TIME: "y" + NETFILTER_XT_MATCH_U32: "y" + NETFILTER_XT_NAT: "y" + NETFILTER_XT_SET: "y" + NETFILTER_XT_TARGET_CHECKSUM: "y" + NETFILTER_XT_TARGET_CLASSIFY: "y" + NETFILTER_XT_TARGET_CONNMARK: "y" + NETFILTER_XT_TARGET_CT: "y" + NETFILTER_XT_TARGET_DSCP: "y" + NETFILTER_XT_TARGET_HL: "y" + NETFILTER_XT_TARGET_HMARK: "y" + NETFILTER_XT_TARGET_IDLETIMER: "y" + NETFILTER_XT_TARGET_LOG: "y" + NETFILTER_XT_TARGET_MARK: "y" + NETFILTER_XT_TARGET_MASQUERADE: "y" + NETFILTER_XT_TARGET_NETMAP: "y" + NETFILTER_XT_TARGET_NFLOG: "y" + NETFILTER_XT_TARGET_NFQUEUE: "y" + NETFILTER_XT_TARGET_NOTRACK: "y" + NETFILTER_XT_TARGET_RATEEST: "y" + NETFILTER_XT_TARGET_REDIRECT: "y" + NETFILTER_XT_TARGET_TCPMSS: "y" + NETFILTER_XT_TARGET_TCPOPTSTRIP: "y" + NETFILTER_XT_TARGET_TEE: "y" + NETFILTER_XT_TARGET_TPROXY: "y" + NETFILTER_XT_TARGET_TRACE: "y" + NETFILTER_XTABLES: "y" + NETFS_STATS: "y" + NETFS_SUPPORT: "y" + NETLABEL: "y" + NETLINK_DIAG: "y" + NETWORK_FILESYSTEMS: "y" + NETWORK_SECMARK: "y" + NF_CONNTRACK: "y" + NF_CONNTRACK_AMANDA: "y" + NF_CONNTRACK_BROADCAST: "y" + NF_CONNTRACK_EVENTS: "y" + NF_CONNTRACK_FTP: "y" + NF_CONNTRACK_H323: "y" + NF_CONNTRACK_IRC: "y" + NF_CONNTRACK_LABELS: "y" + NF_CONNTRACK_MARK: "y" + NF_CONNTRACK_NETBIOS_NS: "y" + NF_CONNTRACK_OVS: "y" + NF_CONNTRACK_PPTP: "y" + NF_CONNTRACK_PROCFS: "y" + NF_CONNTRACK_SANE: "y" + NF_CONNTRACK_SIP: "y" + NF_CONNTRACK_SNMP: "y" + NF_CONNTRACK_TFTP: "y" + NF_CONNTRACK_TIMEOUT: "y" + NF_CONNTRACK_TIMESTAMP: "y" + NF_CONNTRACK_ZONES: "y" + NF_CT_NETLINK: "y" + NF_CT_NETLINK_HELPER: "y" + NF_CT_NETLINK_TIMEOUT: "y" + NF_CT_PROTO_DCCP: "y" + NF_CT_PROTO_GRE: "y" + NF_CT_PROTO_SCTP: "y" + NF_CT_PROTO_UDPLITE: "y" + NF_DEFRAG_IPV4: "y" + NF_DEFRAG_IPV6: "y" + NF_DUP_IPV4: "y" + NF_DUP_IPV6: "y" + NF_DUP_NETDEV: "y" + NF_LOG_ARP: "y" + NF_LOG_IPV4: "y" + NF_LOG_IPV6: "y" + NF_LOG_SYSLOG: "y" + NF_NAT: "y" + NF_NAT_AMANDA: "y" + NF_NAT_FTP: "y" + NF_NAT_H323: "y" + NF_NAT_IRC: "y" + NF_NAT_MASQUERADE: "y" + NF_NAT_OVS: "y" + NF_NAT_PPTP: "y" + NF_NAT_REDIRECT: "y" + NF_NAT_SIP: "y" + NF_NAT_SNMP_BASIC: "y" + NF_NAT_TFTP: "y" + NF_REJECT_IPV4: "y" + NF_REJECT_IPV6: "y" + NF_SOCKET_IPV4: "y" + NF_SOCKET_IPV6: "y" + NF_TABLES: "y" + NF_TABLES_ARP: "y" + NF_TABLES_BRIDGE: "y" + NF_TABLES_INET: "y" + NF_TABLES_IPV4: "y" + NF_TABLES_IPV6: "y" + NF_TABLES_NETDEV: "y" + NF_TPROXY_IPV4: "y" + NF_TPROXY_IPV6: "y" + NFS_COMMON: "y" + NFS_DISABLE_UDP_SUPPORT: "y" + NFS_FS: m + NFS_FSCACHE: "y" + NFS_USE_KERNEL_DNS: "y" + NFS_V3: m + NFS_V4: m + NFS_V4_1: "y" + NFS_V4_1_IMPLEMENTATION_ID_DOMAIN: kernel.org + NFS_V4_2: "y" + NFS_V4_2_SSC_HELPER: "y" + NFS_V4_SECURITY_LABEL: "y" + NFSD: m + NFSD_V4: "y" + NFT_BRIDGE_REJECT: "y" + NFT_COMPAT: "y" + NFT_CONNLIMIT: "y" + NFT_CT: "y" + NFT_DUP_IPV4: "y" + NFT_DUP_IPV6: "y" + NFT_DUP_NETDEV: "y" + NFT_FWD_NETDEV: "y" + NFT_HASH: "y" + NFT_LIMIT: "y" + NFT_LOG: "y" + NFT_MASQ: "y" + NFT_NAT: "y" + NFT_OSF: "y" + NFT_QUEUE: "y" + NFT_REDIR: "y" + NFT_REJECT: "y" + NFT_REJECT_INET: "y" + NFT_REJECT_IPV4: "y" + NFT_REJECT_IPV6: "y" + NFT_TPROXY: "y" + NFT_TUNNEL: "y" + NLATTR: "y" + NLMON: "y" + NLS: "y" + NLS_ASCII: "y" + NLS_CODEPAGE_437: "y" + NLS_DEFAULT: iso8859-1 + NLS_ISO8859_1: "y" + NLS_UTF8: "y" + NO_HZ: "y" + NO_HZ_COMMON: "y" + NO_HZ_IDLE: "y" + NOP_TRACER: "y" + NOP_USB_XCEIV: m + NR_CPUS: "64" + NTFS_FS: m + NVIDIA_CARMEL_CNP_ERRATUM: "y" + NVME_CORE: "y" + NVMEM: "y" + NVMEM_SYSFS: "y" + OF: "y" + OF_ADDRESS: "y" + OF_DYNAMIC: "y" + OF_EARLY_FLATTREE: "y" + OF_FLATTREE: "y" + OF_GPIO: "y" + OF_IRQ: "y" + OF_KOBJ: "y" + OF_MDIO: m + OF_OVERLAY: "y" + OF_RESERVED_MEM: "y" + OF_RESOLVE: "y" + OID_REGISTRY: "y" + OPENVSWITCH: m + OPENVSWITCH_GENEVE: m + OPENVSWITCH_GRE: m + OPENVSWITCH_VXLAN: m + OVERLAY_FS: "y" + OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW: "y" + PACKET: "y" + PACKET_DIAG: "y" + PAGE_COUNTER: "y" + PAGE_EXTENSION: "y" + PAGE_POISONING: "y" + PAGE_POOL: "y" + PAGE_POOL_STATS: "y" + PAGE_REPORTING: "y" + PAGE_SIZE_LESS_THAN_64KB: "y" + PAGE_SIZE_LESS_THAN_256KB: "y" + PAHOLE_HAS_LANG_EXCLUDE: "y" + PAHOLE_HAS_SPLIT_BTF: "y" + PAHOLE_VERSION: "125" + PANIC_ON_OOPS: "y" + PANIC_ON_OOPS_VALUE: "1" + PANIC_TIMEOUT: "0" + PARAVIRT: "y" + PARTITION_ADVANCED: "y" + PARTITION_PERCPU: "y" + PATA_ACPI: "y" + PATA_OF_PLATFORM: "y" + PATA_PLATFORM: "y" + PATA_SIS: "y" + PATA_TIMINGS: "y" + PCI: "y" + PCI_ATS: "y" + PCI_DOMAINS: "y" + PCI_DOMAINS_GENERIC: "y" + PCI_ECAM: "y" + PCI_HISI: "y" + PCI_HOST_COMMON: "y" + PCI_HOST_GENERIC: "y" + PCI_HOST_THUNDER_ECAM: "y" + PCI_HOST_THUNDER_PEM: "y" + PCI_IOV: "y" + PCI_LABEL: "y" + PCI_MSI: "y" + PCI_PASID: "y" + PCI_PRI: "y" + PCI_QUIRKS: "y" + PCI_REALLOC_ENABLE_AUTO: "y" + PCI_STUB: "y" + PCI_SYSCALL: "y" + PCIE_BUS_DEFAULT: "y" + PCIE_DW: "y" + PCIE_DW_HOST: "y" + PCIE_PME: "y" + PCIEASPM: "y" + PCIEASPM_DEFAULT: "y" + PCIEPORTBUS: "y" + PCPU_DEV_REFCNT: "y" + PER_VMA_LOCK: "y" + PERF_EVENTS: "y" + PERSISTENT_KEYRINGS: "y" + PGTABLE_LEVELS: "4" + PHYLIB: m + PHYS_ADDR_T_64BIT: "y" + PID_NS: "y" + PINCTRL: "y" + PKCS7_MESSAGE_PARSER: "y" + PM: "y" + PM_CLK: "y" + PM_DEVFREQ: "y" + PM_OPP: "y" + PNFS_BLOCK: m + PNFS_FILE_LAYOUT: m + PNFS_FLEXFILE_LAYOUT: m + PNP: "y" + PNP_DEBUG_MESSAGES: "y" + PNPACPI: "y" + POSIX_CPU_TIMERS_TASK_WORK: "y" + POSIX_MQUEUE: "y" + POSIX_MQUEUE_SYSCTL: "y" + POSIX_TIMERS: "y" + POWER_RESET: "y" + POWER_RESET_VEXPRESS: "y" + POWER_SUPPLY: "y" + POWER_SUPPLY_HWMON: "y" + PPP: m + PPP_ASYNC: m + PPP_BSDCOMP: m + PPP_DEFLATE: m + PPP_FILTER: "y" + PPP_MPPE: m + PPP_MULTILINK: "y" + PPP_SYNC_TTY: m + PPPOE: m + PPPOL2TP: m + PPS: "y" + PPTP: m + PREEMPT: "y" + PREEMPT_BUILD: "y" + PREEMPT_COUNT: "y" + PREEMPT_RCU: "y" + PREEMPTION: "y" + PREVENT_FIRMWARE_BUILD: "y" + PRINTK: "y" + PRINTK_TIME: "y" + PROBE_EVENTS: "y" + PROC_CHILDREN: "y" + PROC_FS: "y" + PROC_KCORE: "y" + PROC_PAGE_MONITOR: "y" + PROC_PID_CPUSET: "y" + PROC_SYSCTL: "y" + PROFILING: "y" + PSTORE: "y" + PSTORE_COMPRESS: "y" + PSTORE_COMPRESS_DEFAULT: deflate + PSTORE_DEFAULT_KMSG_BYTES: "10240" + PSTORE_DEFLATE_COMPRESS: "y" + PSTORE_DEFLATE_COMPRESS_DEFAULT: "y" + PTP_1588_CLOCK: "y" + PTP_1588_CLOCK_KVM: "y" + PTP_1588_CLOCK_OPTIONAL: "y" + PWM: "y" + PWM_SYSFS: "y" + PWRSEQ_EMMC: m + PWRSEQ_SIMPLE: m + QCOM_FALKOR_ERRATUM_1003: "y" + QCOM_FALKOR_ERRATUM_1009: "y" + QCOM_FALKOR_ERRATUM_E1041: "y" + QCOM_QDF2400_ERRATUM_0065: "y" + QUEUED_RWLOCKS: "y" + QUEUED_SPINLOCKS: "y" + QUOTA: "y" + QUOTA_NETLINK_INTERFACE: "y" + QUOTACTL: "y" + RAID_ATTRS: m + RAID6_PQ: m + RAID6_PQ_BENCHMARK: "y" + RANDOMIZE_BASE: "y" + RANDOMIZE_KSTACK_OFFSET: "y" + RANDOMIZE_KSTACK_OFFSET_DEFAULT: "y" + RANDOMIZE_MODULE_REGION_FULL: "y" + RANDSTRUCT_NONE: "y" + RATIONAL: "y" + RCU_CPU_STALL_TIMEOUT: "60" + RCU_EXP_CPU_STALL_TIMEOUT: "0" + RCU_NEED_SEGCBLIST: "y" + RCU_STALL_COMMON: "y" + RD_GZIP: "y" + RD_ZSTD: "y" + REGMAP: "y" + REGMAP_I2C: "y" + REGMAP_MMIO: "y" + RELAY: "y" + RELOCATABLE: "y" + RESET_ATTACK_MITIGATION: "y" + RESET_CONTROLLER: "y" + RESET_SIMPLE: "y" + RFS_ACCEL: "y" + RING_BUFFER: "y" + ROCKCHIP_ERRATUM_3588001: "y" + RODATA_FULL_DEFAULT_ENABLED: "y" + RPCSEC_GSS_KRB5: m + RPCSEC_GSS_KRB5_CRYPTOSYSTEM: "y" + RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1: "y" + RPS: "y" + RSEQ: "y" + RT_GROUP_SCHED: "y" + RT_MUTEXES: "y" + RTC_CLASS: "y" + RTC_DRV_DS3232: "y" + RTC_DRV_DS3232_HWMON: "y" + RTC_DRV_EFI: "y" + RTC_DRV_PL031: "y" + RTC_HCTOSYS: "y" + RTC_HCTOSYS_DEVICE: rtc0 + RTC_I2C_AND_SPI: "y" + RTC_INTF_DEV: "y" + RTC_INTF_PROC: "y" + RTC_INTF_SYSFS: "y" + RTC_LIB: "y" + RTC_NVMEM: "y" + RTC_SYSTOHC: "y" + RTC_SYSTOHC_DEVICE: rtc0 + RUNTIME_TESTING_MENU: "y" + RWSEM_SPIN_ON_OWNER: "y" + SATA_AHCI: "y" + SATA_AHCI_PLATFORM: "y" + SATA_HOST: "y" + SATA_MOBILE_LPM_POLICY: "0" + SBITMAP: "y" + SCHED_AUTOGROUP: "y" + SCHED_DEBUG: "y" + SCHED_HRTICK: "y" + SCHED_INFO: "y" + SCHED_MC: "y" + SCHED_MM_CID: "y" + SCSI: "y" + SCSI_COMMON: "y" + SCSI_DMA: "y" + SCSI_HISI_SAS: "y" + SCSI_HPSA: m + SCSI_ISCSI_ATTRS: m + SCSI_LOWLEVEL: "y" + SCSI_MOD: "y" + SCSI_SAS_ATTRS: "y" + SCSI_SAS_HOST_SMP: "y" + SCSI_SAS_LIBSAS: "y" + SCSI_SMARTPQI: m + SCSI_SPI_ATTRS: "y" + SCSI_VIRTIO: "y" + SCTP_COOKIE_HMAC_MD5: "y" + SCTP_DEFAULT_COOKIE_HMAC_MD5: "y" + SECCOMP: "y" + SECCOMP_FILTER: "y" + SECRETMEM: "y" + SECTION_MISMATCH_WARN_ONLY: "y" + SECURITY: "y" + SECURITY_DMESG_RESTRICT: "y" + SECURITY_NETWORK: "y" + SECURITY_NETWORK_XFRM: "y" + SECURITY_PATH: "y" + SECURITY_YAMA: "y" + SECURITYFS: "y" + SERIAL_8250: "y" + SERIAL_8250_CONSOLE: "y" + SERIAL_8250_DEPRECATED_OPTIONS: "y" + SERIAL_8250_DMA: "y" + SERIAL_8250_DW: "y" + SERIAL_8250_DWLIB: "y" + SERIAL_8250_EXAR: "y" + SERIAL_8250_EXTENDED: "y" + SERIAL_8250_FSL: "y" + SERIAL_8250_NR_UARTS: "4" + SERIAL_8250_PCI: "y" + SERIAL_8250_PCILIB: "y" + SERIAL_8250_PERICOM: "y" + SERIAL_8250_PNP: "y" + SERIAL_8250_RUNTIME_UARTS: "4" + SERIAL_8250_SHARE_IRQ: "y" + SERIAL_AMBA_PL011: "y" + SERIAL_AMBA_PL011_CONSOLE: "y" + SERIAL_CORE: "y" + SERIAL_CORE_CONSOLE: "y" + SERIAL_DEV_BUS: "y" + SERIAL_DEV_CTRL_TTYPORT: "y" + SERIAL_EARLYCON: "y" + SERIAL_MCTRL_GPIO: "y" + SERIAL_OF_PLATFORM: "y" + SERIO: "y" + SERIO_AMBAKMI: "y" + SERIO_LIBPS2: "y" + SERIO_SERPORT: "y" + SG_POOL: "y" + SG_SPLIT: "y" + SGL_ALLOC: "y" + SHMEM: "y" + SIGNALFD: "y" + SIGNATURE: "y" + SKB_EXTENSIONS: "y" + SLAB: "y" + SLAB_FREELIST_RANDOM: "y" + SLAB_MERGE_DEFAULT: "y" + SLHC: m + SMBFS: "y" + SMP: "y" + SMSC_PHY: m + SOC_BUS: "y" + SOCIONEXT_SYNQUACER_PREITS: "y" + SOCK_CGROUP_DATA: "y" + SOCK_RX_QUEUE_MAPPING: "y" + SOFTIRQ_ON_OWN_STACK: "y" + SPARSE_IRQ: "y" + SPARSEMEM: "y" + SPARSEMEM_EXTREME: "y" + SPARSEMEM_VMEMMAP: "y" + SPARSEMEM_VMEMMAP_ENABLE: "y" + SPLIT_PTLOCK_CPUS: "4" + SQUASHFS: "y" + SQUASHFS_COMPILE_DECOMP_SINGLE: "y" + SQUASHFS_DECOMP_SINGLE: "y" + SQUASHFS_FILE_CACHE: "y" + SQUASHFS_FRAGMENT_CACHE_SIZE: "3" + SQUASHFS_LZ4: "y" + SQUASHFS_LZO: "y" + SQUASHFS_XATTR: "y" + SQUASHFS_XZ: "y" + SQUASHFS_ZLIB: "y" + SQUASHFS_ZSTD: "y" + SSB_POSSIBLE: "y" + STACK_TRACER: "y" + STACKLEAK_TRACK_MIN_SIZE: "100" + STACKPROTECTOR: "y" + STACKPROTECTOR_PER_TASK: "y" + STACKPROTECTOR_STRONG: "y" + STACKTRACE: "y" + STACKTRACE_SUPPORT: "y" + STANDALONE: "y" + STATIC_USERMODEHELPER: "y" + STATIC_USERMODEHELPER_PATH: /sbin/usermode-helper + STP: "y" + STRICT_DEVMEM: "y" + STRICT_KERNEL_RWX: "y" + STRICT_MODULE_RWX: "y" + SUNRPC: m + SUNRPC_BACKCHANNEL: "y" + SUNRPC_GSS: m + SWAP: "y" + SWIOTLB: "y" + SWPHY: "y" + SYMBOLIC_ERRNAME: "y" + SYN_COOKIES: "y" + SYSCTL: "y" + SYSCTL_EXCEPTION_TRACE: "y" + SYSFB: "y" + SYSFS: "y" + SYSFS_SYSCALL: "y" + SYSVIPC: "y" + SYSVIPC_SYSCTL: "y" + TAP: "y" + TASK_DELAY_ACCT: "y" + TASK_IO_ACCOUNTING: "y" + TASK_XACCT: "y" + TASKS_RCU: "y" + TASKS_RCU_GENERIC: "y" + TASKS_RUDE_RCU: "y" + TASKS_TRACE_RCU: "y" + TASKSTATS: "y" + TCG_CRB: "y" + TCG_TPM: "y" + TCP_CONG_CUBIC: "y" + TCP_MD5SIG: "y" + TEXTSEARCH: "y" + TEXTSEARCH_BM: "y" + TEXTSEARCH_FSM: "y" + TEXTSEARCH_KMP: "y" + THERMAL: "y" + THERMAL_DEFAULT_GOV_STEP_WISE: "y" + THERMAL_EMERGENCY_POWEROFF_DELAY_MS: "0" + THERMAL_EMULATION: "y" + THERMAL_GOV_STEP_WISE: "y" + THERMAL_HWMON: "y" + THERMAL_OF: "y" + THP_SWAP: "y" + THREAD_INFO_IN_TASK: "y" + TICK_CPU_ACCOUNTING: "y" + TICK_ONESHOT: "y" + TIME_NS: "y" + TIMER_ACPI: "y" + TIMER_OF: "y" + TIMER_PROBE: "y" + TIMERFD: "y" + TMPFS: "y" + TMPFS_XATTR: "y" + TRACE_CLOCK: "y" + TRACE_IRQFLAGS_NMI_SUPPORT: "y" + TRACE_IRQFLAGS_SUPPORT: "y" + TRACEPOINTS: "y" + TRACING: "y" + TRACING_SUPPORT: "y" + TRANSPARENT_HUGEPAGE: "y" + TRANSPARENT_HUGEPAGE_ALWAYS: "y" + TREE_RCU: "y" + TREE_SRCU: "y" + TRUSTED_KEYS: "y" + TRUSTED_KEYS_TPM: "y" + TTY: "y" + TUN: "y" + UBSAN: "y" + UBSAN_BOOL: "y" + UBSAN_BOUNDS: "y" + UBSAN_ENUM: "y" + UBSAN_ONLY_BOUNDS: "y" + UBSAN_SHIFT: "y" + UCS2_STRING: "y" + UEVENT_HELPER: "y" + UEVENT_HELPER_PATH: "" + UIO: m + UNINLINE_SPIN_UNLOCK: "y" + UNIX: "y" + UNIX_DIAG: "y" + UNIX_SCM: "y" + UNIX98_PTYS: "y" + UNMAP_KERNEL_AT_EL0: "y" + UPROBE_EVENTS: "y" + UPROBES: "y" + USB: "y" + USB_ANNOUNCE_NEW_DEVICES: "y" + USB_ARCH_HAS_HCD: "y" + USB_AUTOSUSPEND_DELAY: "2" + USB_COMMON: "y" + USB_DEFAULT_PERSIST: "y" + USB_DWC2: m + USB_DWC2_HOST: "y" + USB_EHCI_HCD: m + USB_EHCI_PCI: m + USB_EHCI_TT_NEWSCHED: "y" + USB_HID: "y" + USB_OHCI_HCD: m + USB_OHCI_HCD_PCI: m + USB_OHCI_LITTLE_ENDIAN: "y" + USB_OTG: "y" + USB_PCI: "y" + USB_PHY: "y" + USB_ROLE_SWITCH: m + USB_STORAGE: m + USB_SUPPORT: "y" + USB_UHCI_HCD: m + USB_XHCI_HCD: m + USB_XHCI_PCI: m + USER_NS: "y" + UTS_NS: "y" + VALIDATE_FS_PARSER: "y" + VETH: "y" + VEXPRESS_CONFIG: "y" + VFAT_FS: "y" + VHOST: m + VHOST_IOTLB: m + VHOST_MENU: "y" + VHOST_NET: m + VHOST_TASK: "y" + VHOST_VSOCK: m + VIDEO_CMDLINE: "y" + VIRTIO: "y" + VIRTIO_ANCHOR: "y" + VIRTIO_BALLOON: "y" + VIRTIO_BLK: "y" + VIRTIO_CONSOLE: "y" + VIRTIO_FS: "y" + VIRTIO_INPUT: "y" + VIRTIO_MENU: "y" + VIRTIO_MMIO: "y" + VIRTIO_MMIO_CMDLINE_DEVICES: "y" + VIRTIO_NET: "y" + VIRTIO_PCI: "y" + VIRTIO_PCI_LEGACY: "y" + VIRTIO_PCI_LIB: "y" + VIRTIO_PCI_LIB_LEGACY: "y" + VIRTIO_VSOCKETS: m + VIRTIO_VSOCKETS_COMMON: m + VLAN_8021Q: "y" + VM_EVENT_COUNTERS: "y" + VMAP_STACK: "y" + VSOCKETS: m + VSOCKETS_DIAG: m + VSOCKETS_LOOPBACK: m + VT: "y" + VT_CONSOLE: "y" + VT_HW_CONSOLE_BINDING: "y" + VXLAN: "y" + WIREGUARD: m + WQ_WATCHDOG: "y" + X509_CERTIFICATE_PARSER: "y" + XARRAY_MULTI: "y" + XDP_SOCKETS: "y" + XFRM: "y" + XFRM_AH: m + XFRM_ALGO: m + XFRM_ESP: m + XFRM_IPCOMP: m + XFRM_MIGRATE: "y" + XFRM_STATISTICS: "y" + XFRM_SUB_POLICY: "y" + XFRM_USER: m + XFS_FS: "y" + XFS_POSIX_ACL: "y" + XFS_QUOTA: "y" + XFS_SUPPORT_ASCII_CI: "y" + XFS_SUPPORT_V4: "y" + XOR_BLOCKS: m + XPS: "y" + XXHASH: "y" + XZ_DEC: "y" + XZ_DEC_ARM: "y" + XZ_DEC_ARMTHUMB: "y" + XZ_DEC_BCJ: "y" + XZ_DEC_IA64: "y" + XZ_DEC_MICROLZMA: "y" + XZ_DEC_POWERPC: "y" + XZ_DEC_SPARC: "y" + XZ_DEC_X86: "y" + ZLIB_DEFLATE: "y" + ZLIB_INFLATE: "y" + ZONE_DMA: "y" + ZONE_DMA32: "y" + ZSTD_COMMON: "y" + ZSTD_COMPRESS: m + ZSTD_DECOMPRESS: "y" + kernel.selinux: + elements: + enabled: "false" + kernel.version: + elements: + full: 6.4.16-linuxkit + major: "6" + minor: "4" + revision: "16" + local.feature: + elements: {} + local.label: + elements: {} + system.name: + elements: + nodename: minikube + system.osrelease: + elements: + BUG_REPORT_URL: https://bugs.launchpad.net/ubuntu/ + HOME_URL: https://www.ubuntu.com/ + ID: ubuntu + ID_LIKE: debian + NAME: Ubuntu + PRETTY_NAME: Ubuntu 22.04.3 LTS + PRIVACY_POLICY_URL: https://www.ubuntu.com/legal/terms-and-policies/privacy-policy + SUPPORT_URL: https://help.ubuntu.com/ + UBUNTU_CODENAME: jammy + VERSION: 22.04.3 LTS (Jammy Jellyfish) + VERSION_CODENAME: jammy + VERSION_ID: "22.04" + VERSION_ID.major: "22" + VERSION_ID.minor: "04" + flags: + cpu.cpuid: + elements: + AES: {} + ASIMD: {} + ASIMDDP: {} + ASIMDFHM: {} + ASIMDHP: {} + ASIMDRDM: {} + ATOMICS: {} + CPUID: {} + CRC32: {} + DCPODP: {} + DCPOP: {} + DIT: {} + EVTSTRM: {} + FCMA: {} + FLAGM: {} + FLAGM2: {} + FP: {} + FPHP: {} + FRINT: {} + ILRCPC: {} + JSCVT: {} + LRCPC: {} + PACA: {} + PACG: {} + PMULL: {} + SB: {} + SHA1: {} + SHA2: {} + SHA3: {} + SHA512: {} + SSBS: {} + USCAT: {} + kernel.enabledmodule: + elements: + 9p: {} + 9pnet: {} + 9pnet_fd: {} + 9pnet_virtio: {} + "842": {} + 842_compress: {} + 842_decompress: {} + 8021q: {} + "8250": {} + 8250_base: {} + 8250_dw: {} + 8250_exar: {} + 8250_of: {} + 8250_pci: {} + 8250_pericom: {} + act_bpf: {} + act_csum: {} + act_gact: {} + act_ipt: {} + act_mirred: {} + act_nat: {} + act_pedit: {} + act_police: {} + act_simple: {} + act_skbedit: {} + aead: {} + aes-arm64: {} + aes-ce-ccm: {} + aes-ce-cipher: {} + aes-glue-ce: {} + aes-glue-neon: {} + aes-neon-bs: {} + aes_generic: {} + af_alg: {} + af_packet: {} + af_packet_diag: {} + ahci: {} + ahci_platform: {} + akcipher: {} + algif_aead: {} + algif_hash: {} + algif_rng: {} + algif_skcipher: {} + amba-pl011: {} + ambakmi: {} + ansi_cprng: {} + anubis: {} + arc4: {} + arm-cci: {} + arm-ccn: {} + arm_smccc_trng: {} + arp_tables: {} + arpt_mangle: {} + arptable_filter: {} + asn1_decoder: {} + asn1_encoder: {} + ata_generic: {} + atkbd: {} + auth_rpcgss: {} + authenc: {} + authencesn: {} + bfq: {} + binfmt_misc: {} + binfmt_script: {} + blowfish_common: {} + blowfish_generic: {} + br_netfilter: {} + bridge: {} + bsg: {} + cachefiles: {} + camellia_generic: {} + cast_common: {} + cast5_generic: {} + cast6_generic: {} + cbc: {} + ccm: {} + cdrom: {} + cfbcopyarea: {} + cfbfillrect: {} + cfbimgblt: {} + chacha-neon: {} + chacha_generic: {} + chacha20poly1305: {} + cifs: {} + cifs_arc4: {} + cifs_md4: {} + clk-vexpress-osc: {} + cls_basic: {} + cls_bpf: {} + cls_cgroup: {} + cls_flow: {} + cls_fw: {} + cls_matchall: {} + cls_route: {} + cls_u32: {} + cmac: {} + cn10k-rng: {} + configfs: {} + configs: {} + cpufreq-dt: {} + cpufreq_performance: {} + crc-ccitt: {} + crc-itu-t: {} + crc-t10dif: {} + crc8: {} + crc16: {} + crc32: {} + crc32_generic: {} + crc32c_generic: {} + crc64: {} + crc64-rocksoft: {} + crc64_rocksoft_generic: {} + crct10dif-ce: {} + crct10dif_common: {} + crct10dif_generic: {} + cryptd: {} + crypto: {} + crypto_acompress: {} + crypto_algapi: {} + crypto_hash: {} + crypto_null: {} + crypto_user: {} + cryptomgr: {} + ctr: {} + cts: {} + cuse: {} + dax: {} + deflate: {} + des_generic: {} + dh_generic: {} + digsig: {} + dm-bio-prison: {} + dm-bufio: {} + dm-crypt: {} + dm-mod: {} + dm-persistent-data: {} + dm-snapshot: {} + dm-thin-pool: {} + dmi-sysfs: {} + dns_resolver: {} + drbg: {} + drm_panel_orientation_quirks: {} + ebt_802_3: {} + ebt_among: {} + ebt_arp: {} + ebt_arpreply: {} + ebt_dnat: {} + ebt_ip: {} + ebt_ip6: {} + ebt_limit: {} + ebt_log: {} + ebt_mark: {} + ebt_mark_m: {} + ebt_nflog: {} + ebt_pkttype: {} + ebt_redirect: {} + ebt_snat: {} + ebt_stp: {} + ebt_vlan: {} + ebtable_broute: {} + ebtable_filter: {} + ebtable_nat: {} + ebtables: {} + ecb: {} + echainiv: {} + efi-pstore: {} + efivarfs: {} + em_cmp: {} + em_ipset: {} + em_meta: {} + em_nbyte: {} + em_text: {} + em_u32: {} + encrypted-keys: {} + erofs: {} + essiv: {} + evdev: {} + exportfs: {} + ext4: {} + extcon-core: {} + failover: {} + fakeowner: {} + fat: {} + fb: {} + fcrypt: {} + ff-memless: {} + firmware_class: {} + font: {} + fou: {} + fou6: {} + fscache: {} + fuse: {} + gcm: {} + geniv: {} + gf128mul: {} + ghash-ce: {} + ghash-generic: {} + glob: {} + governor_simpleondemand: {} + gpio-generic: {} + gpio-pl061: {} + grace: {} + gre: {} + grpcfuse: {} + hid: {} + hid-generic: {} + hisi_sas_main: {} + hisi_sas_v1_hw: {} + hisi_sas_v2_hw: {} + hmac: {} + hwmon: {} + i2c-core: {} + i2c-dev: {} + i2c-mux: {} + inet_diag: {} + input-core: {} + ip_set: {} + ip_set_bitmap_ip: {} + ip_set_bitmap_ipmac: {} + ip_set_bitmap_port: {} + ip_set_hash_ip: {} + ip_set_hash_ipport: {} + ip_set_hash_ipportip: {} + ip_set_hash_ipportnet: {} + ip_set_hash_net: {} + ip_set_hash_netiface: {} + ip_set_hash_netport: {} + ip_set_list_set: {} + ip_tables: {} + ip_tunnel: {} + ip_vs: {} + ip_vs_dh: {} + ip_vs_fo: {} + ip_vs_ftp: {} + ip_vs_lblc: {} + ip_vs_lblcr: {} + ip_vs_lc: {} + ip_vs_mh: {} + ip_vs_nq: {} + ip_vs_ovf: {} + ip_vs_pe_sip: {} + ip_vs_rr: {} + ip_vs_sed: {} + ip_vs_sh: {} + ip_vs_wlc: {} + ip_vs_wrr: {} + ip6_tables: {} + ip6_tunnel: {} + ip6_udp_tunnel: {} + ip6t_NPT: {} + ip6t_REJECT: {} + ip6t_SYNPROXY: {} + ip6t_ah: {} + ip6t_eui64: {} + ip6t_frag: {} + ip6t_hbh: {} + ip6t_ipv6header: {} + ip6t_mh: {} + ip6t_rpfilter: {} + ip6t_rt: {} + ip6table_filter: {} + ip6table_mangle: {} + ip6table_nat: {} + ip6table_raw: {} + ip6table_security: {} + ipip: {} + ipt_ECN: {} + ipt_REJECT: {} + ipt_SYNPROXY: {} + ipt_ah: {} + ipt_rpfilter: {} + iptable_filter: {} + iptable_mangle: {} + iptable_nat: {} + iptable_raw: {} + iptable_security: {} + ipv6: {} + ipvlan: {} + isofs: {} + jbd2: {} + jitterentropy_rng: {} + joydev: {} + kdf_sp800108: {} + keywrap: {} + khazad: {} + kpp: {} + kyber-iosched: {} + libaes: {} + libahci: {} + libahci_platform: {} + libarc4: {} + libata: {} + libchacha: {} + libcrc32c: {} + libcryptoutils: {} + libdes: {} + libpoly1305: {} + libps2: {} + libsas: {} + libsha1: {} + libsha256: {} + llc: {} + lockd: {} + loop: {} + lrw: {} + lz4: {} + lz4_compress: {} + lz4_decompress: {} + lz4hc: {} + lz4hc_compress: {} + lzo: {} + lzo-rle: {} + lzo_compress: {} + lzo_decompress: {} + macvlan: {} + macvtap: {} + mbcache: {} + md4: {} + md5: {} + megaraid_sas: {} + mfd-core: {} + michael_mic: {} + mousedev: {} + mpi: {} + mptbase: {} + mptscsih: {} + mptspi: {} + mq-deadline: {} + msdos: {} + n_null: {} + nbd: {} + net_failover: {} + netfs: {} + netlink_diag: {} + nf_conncount: {} + nf_conntrack: {} + nf_conntrack_amanda: {} + nf_conntrack_broadcast: {} + nf_conntrack_ftp: {} + nf_conntrack_h323: {} + nf_conntrack_irc: {} + nf_conntrack_netbios_ns: {} + nf_conntrack_netlink: {} + nf_conntrack_pptp: {} + nf_conntrack_sane: {} + nf_conntrack_sip: {} + nf_conntrack_snmp: {} + nf_conntrack_tftp: {} + nf_defrag_ipv4: {} + nf_defrag_ipv6: {} + nf_dup_ipv4: {} + nf_dup_ipv6: {} + nf_dup_netdev: {} + nf_log_syslog: {} + nf_nat: {} + nf_nat_amanda: {} + nf_nat_ftp: {} + nf_nat_h323: {} + nf_nat_irc: {} + nf_nat_pptp: {} + nf_nat_sip: {} + nf_nat_snmp_basic: {} + nf_nat_tftp: {} + nf_reject_ipv4: {} + nf_reject_ipv6: {} + nf_socket_ipv4: {} + nf_socket_ipv6: {} + nf_synproxy_core: {} + nf_tables: {} + nf_tproxy_ipv4: {} + nf_tproxy_ipv6: {} + nfnetlink: {} + nfnetlink_acct: {} + nfnetlink_cthelper: {} + nfnetlink_cttimeout: {} + nfnetlink_log: {} + nfnetlink_osf: {} + nfnetlink_queue: {} + nfs: {} + nfsd: {} + nft_chain_nat: {} + nft_compat: {} + nft_connlimit: {} + nft_ct: {} + nft_dup_ipv4: {} + nft_dup_ipv6: {} + nft_dup_netdev: {} + nft_fwd_netdev: {} + nft_hash: {} + nft_limit: {} + nft_log: {} + nft_masq: {} + nft_nat: {} + nft_osf: {} + nft_queue: {} + nft_redir: {} + nft_reject: {} + nft_reject_bridge: {} + nft_reject_inet: {} + nft_reject_ipv4: {} + nft_reject_ipv6: {} + nft_tproxy: {} + nft_tunnel: {} + nlmon: {} + nls_ascii: {} + nls_base: {} + nls_cp437: {} + nls_iso8859-1: {} + nls_utf8: {} + nvme: {} + nvme-core: {} + oid_registry: {} + overlay: {} + p8022: {} + pata_acpi: {} + pata_of_platform: {} + pata_platform: {} + pata_sis: {} + pcbc: {} + pci-host-common: {} + pci-host-generic: {} + pci-stub: {} + pkcs7_message: {} + poly1305_generic: {} + pps_core: {} + processor: {} + psnap: {} + pstore: {} + ptp: {} + ptp_kvm: {} + public_key: {} + rational: {} + regmap-i2c: {} + regmap-mmio: {} + rmd160: {} + rng: {} + rng-core: {} + rsa_generic: {} + rtc-ds3232: {} + rtc-efi: {} + rtc-pl031: {} + scsi_common: {} + scsi_mod: {} + scsi_transport_sas: {} + scsi_transport_spi: {} + sd_mod: {} + seed: {} + seqiv: {} + serdev: {} + serial_core: {} + serial_mctrl_gpio: {} + serio: {} + serpent_generic: {} + serport: {} + sg: {} + sha1-ce: {} + sha1_generic: {} + sha2-ce: {} + sha256-arm64: {} + sha256_generic: {} + sha512-arm64: {} + sha512_generic: {} + shiftfs: {} + simplefb: {} + skcipher: {} + sparse-keymap: {} + squashfs: {} + sr_mod: {} + stp: {} + sunrpc: {} + t10-pi: {} + tap: {} + tcp_cubic: {} + tcp_diag: {} + tea: {} + tpm: {} + tpm_crb: {} + trusted: {} + ts_bm: {} + ts_fsm: {} + ts_kmp: {} + tun: {} + tunnel4: {} + tunnel6: {} + twofish_common: {} + twofish_generic: {} + ucs2_string: {} + udp_diag: {} + udp_tunnel: {} + uinput: {} + unix: {} + unix_diag: {} + usb-common: {} + usbcore: {} + usbhid: {} + veth: {} + vexpress-config: {} + vexpress-sysreg: {} + vfat: {} + virtio: {} + virtio-rng: {} + virtio_balloon: {} + virtio_blk: {} + virtio_console: {} + virtio_input: {} + virtio_mmio: {} + virtio_net: {} + virtio_pci: {} + virtio_pci_legacy_dev: {} + virtio_pci_modern_dev: {} + virtio_ring: {} + virtio_scsi: {} + virtiofs: {} + vivaldi-fmap: {} + vmac: {} + vmw_vsock_virtio_transport: {} + vmw_vsock_virtio_transport_common: {} + vsock: {} + vxlan: {} + wp512: {} + x_tables: {} + x509_key_parser: {} + xcbc: {} + xfrm_algo: {} + xfrm_user: {} + xfs: {} + xt_CHECKSUM: {} + xt_CLASSIFY: {} + xt_CT: {} + xt_DSCP: {} + xt_HL: {} + xt_HMARK: {} + xt_IDLETIMER: {} + xt_LOG: {} + xt_MASQUERADE: {} + xt_NETMAP: {} + xt_NFLOG: {} + xt_NFQUEUE: {} + xt_RATEEST: {} + xt_REDIRECT: {} + xt_TCPMSS: {} + xt_TCPOPTSTRIP: {} + xt_TEE: {} + xt_TPROXY: {} + xt_TRACE: {} + xt_addrtype: {} + xt_bpf: {} + xt_cgroup: {} + xt_cluster: {} + xt_comment: {} + xt_connbytes: {} + xt_connlabel: {} + xt_connlimit: {} + xt_connmark: {} + xt_conntrack: {} + xt_cpu: {} + xt_dccp: {} + xt_devgroup: {} + xt_dscp: {} + xt_ecn: {} + xt_esp: {} + xt_hashlimit: {} + xt_helper: {} + xt_hl: {} + xt_ipcomp: {} + xt_iprange: {} + xt_ipvs: {} + xt_l2tp: {} + xt_length: {} + xt_limit: {} + xt_mac: {} + xt_mark: {} + xt_multiport: {} + xt_nat: {} + xt_nfacct: {} + xt_osf: {} + xt_owner: {} + xt_physdev: {} + xt_pkttype: {} + xt_policy: {} + xt_quota: {} + xt_rateest: {} + xt_realm: {} + xt_recent: {} + xt_sctp: {} + xt_set: {} + xt_socket: {} + xt_state: {} + xt_statistic: {} + xt_string: {} + xt_tcpmss: {} + xt_tcpudp: {} + xt_time: {} + xt_u32: {} + xts: {} + xxhash: {} + xz_dec: {} + zlib_deflate: {} + zlib_inflate: {} + zstd_common: {} + zstd_decompress: {} + kernel.loadedmodule: + elements: + auth_rpcgss: {} + fakeowner: {} + grace: {} + grpcfuse: {} + lockd: {} + nfs: {} + nfsd: {} + shiftfs: {} + sunrpc: {} + vmw_vsock_virtio_transport: {} + vmw_vsock_virtio_transport_common: {} + vsock: {} + xfrm_algo: {} + xfrm_user: {} + instances: + memory.nv: + elements: [] + network.device: + elements: [] + pci.device: + elements: + - attributes: + class: "0600" + device: 1a05 + subsystem_device: "0000" + subsystem_vendor: "0000" + vendor: 106b + - attributes: + class: "0200" + device: "1041" + subsystem_device: "0041" + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0200" + device: "1041" + subsystem_device: "0041" + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0780" + device: "1043" + subsystem_device: "0043" + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0180" + device: "1042" + subsystem_device: "0042" + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0180" + device: "1042" + subsystem_device: "0042" + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0180" + device: 105a + subsystem_device: 005a + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0180" + device: 105a + subsystem_device: 005a + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0180" + device: 105a + subsystem_device: 005a + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0180" + device: 105a + subsystem_device: 005a + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0180" + device: 105a + subsystem_device: 005a + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0180" + device: 105a + subsystem_device: 005a + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0780" + device: "1053" + subsystem_device: "0053" + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "1000" + device: "1044" + subsystem_device: "0044" + subsystem_vendor: 1af4 + vendor: 1af4 + - attributes: + class: "0580" + device: "1045" + subsystem_device: "0045" + subsystem_vendor: 1af4 + vendor: 1af4 + storage.block: + elements: + - attributes: + dax: "0" + name: loop0 + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: loop1 + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: loop2 + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: loop3 + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: loop4 + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: loop5 + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: loop6 + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: loop7 + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: nbd0 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd1 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd10 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd11 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd12 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd13 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd14 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd15 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd2 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd3 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd4 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd5 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd6 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd7 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd8 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: nbd9 + nr_zones: "0" + rotational: "0" + zoned: none + - attributes: + dax: "0" + name: vda + nr_zones: "0" + rotational: "1" + zoned: none + - attributes: + dax: "0" + name: vdb + nr_zones: "0" + rotational: "1" + zoned: none + usb.device: + elements: [] + labels: + cpu-cpuid.AES: "true" + cpu-cpuid.ASIMD: "true" + cpu-cpuid.ASIMDDP: "true" + cpu-cpuid.ASIMDFHM: "true" + cpu-cpuid.ASIMDHP: "true" + cpu-cpuid.ASIMDRDM: "true" + cpu-cpuid.ATOMICS: "true" + cpu-cpuid.CPUID: "true" + cpu-cpuid.CRC32: "true" + cpu-cpuid.DCPODP: "true" + cpu-cpuid.DCPOP: "true" + cpu-cpuid.DIT: "true" + cpu-cpuid.EVTSTRM: "true" + cpu-cpuid.FCMA: "true" + cpu-cpuid.FLAGM: "true" + cpu-cpuid.FLAGM2: "true" + cpu-cpuid.FP: "true" + cpu-cpuid.FPHP: "true" + cpu-cpuid.FRINT: "true" + cpu-cpuid.ILRCPC: "true" + cpu-cpuid.JSCVT: "true" + cpu-cpuid.LRCPC: "true" + cpu-cpuid.PACA: "true" + cpu-cpuid.PACG: "true" + cpu-cpuid.PMULL: "true" + cpu-cpuid.SB: "true" + cpu-cpuid.SHA1: "true" + cpu-cpuid.SHA2: "true" + cpu-cpuid.SHA3: "true" + cpu-cpuid.SHA512: "true" + cpu-cpuid.SSBS: "true" + cpu-cpuid.USCAT: "true" + cpu-hardware_multithreading: "false" + cpu-model.family: "0" + cpu-model.id: "0" + cpu-model.vendor_id: VendorUnknown + kernel-config.NO_HZ: "true" + kernel-config.NO_HZ_IDLE: "true" + kernel-config.PREEMPT: "true" + kernel-version.full: 6.4.16-linuxkit + kernel-version.major: "6" + kernel-version.minor: "4" + kernel-version.revision: "16" + storage-nonrotationaldisk: "true" + system-os_release.ID: ubuntu + system-os_release.VERSION_ID: "22.04" + system-os_release.VERSION_ID.major: "22" + system-os_release.VERSION_ID.minor: "04" +kind: List +metadata: + resourceVersion: "" diff --git a/pkg/apis/nfd/v1alpha1/annotations_labels.go b/pkg/apis/nfd/v1alpha1/const.go similarity index 58% rename from pkg/apis/nfd/v1alpha1/annotations_labels.go rename to pkg/apis/nfd/v1alpha1/const.go index b1f848245f..9ceba68eb4 100644 --- a/pkg/apis/nfd/v1alpha1/annotations_labels.go +++ b/pkg/apis/nfd/v1alpha1/const.go @@ -1,5 +1,5 @@ /* -Copyright 2022 The Kubernetes Authors. +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. @@ -16,6 +16,7 @@ limitations under the License. package v1alpha1 +// Default values for annotations and labels. const ( // FeatureLabelNs is the (default) namespace for feature labels. FeatureLabelNs = "feature.node.kubernetes.io" @@ -69,9 +70,62 @@ const ( // label for filtering features designated for a certain node. NodeFeatureObjNodeNameLabel = "nfd.node.kubernetes.io/node-name" + // FeatureGroupObjLabel is the label that specifies current cluster name + FeatureGroupObjLabel = "nfd.node.kubernetes.io/feature-group" + // FeatureAnnotationNs is the (default) namespace for feature annotations. FeatureAnnotationNs = "feature.node.kubernetes.io" // FeatureAnnotationSubNsSuffix is the suffix for allowed feature annotation sub-namespaces. FeatureAnnotationSubNsSuffix = "." + FeatureAnnotationNs ) + +const ( + // MatchAny returns always true. + MatchAny MatchOp = "" + // MatchIn returns true if any of the values stored in the expression is + // equal to the input. + MatchIn MatchOp = "In" + // MatchNotIn returns true if none of the values in the expression are + // equal to the input. + MatchNotIn MatchOp = "NotIn" + // MatchInRegexp treats values of the expression as regular expressions and + // returns true if any of them matches the input. + MatchInRegexp MatchOp = "InRegexp" + // MatchExists returns true if the input is valid. The expression must not + // have any values. + MatchExists MatchOp = "Exists" + // MatchDoesNotExist returns true if the input is not valid. The expression + // must not have any values. + MatchDoesNotExist MatchOp = "DoesNotExist" + // MatchGt returns true if the input is greater than the value of the + // expression (number of values in the expression must be exactly one). + // Both the input and value must be integer numbers, otherwise an error is + // returned. + MatchGt MatchOp = "Gt" + // MatchLt returns true if the input is less than the value of the + // expression (number of values in the expression must be exactly one). + // Both the input and value must be integer numbers, otherwise an error is + // returned. + MatchLt MatchOp = "Lt" + // MatchGtLt returns true if the input is between two values, i.e. greater + // than the first value and less than the second value of the expression + // (number of values in the expression must be exactly two). Both the input + // and values must be integer numbers, otherwise an error is returned. + MatchGtLt MatchOp = "GtLt" + // MatchIsTrue returns true if the input holds the value "true". The + // expression must not have any values. + MatchIsTrue MatchOp = "IsTrue" + // MatchIsFalse returns true if the input holds the value "false". The + // expression must not have any values. + MatchIsFalse MatchOp = "IsFalse" +) + +const ( + // RuleBackrefDomain is the special feature domain for backreferencing + // output of preceding rules. + RuleBackrefDomain = "rule" + // RuleBackrefFeature is the special feature name for backreferencing + // output of preceding rules. + RuleBackrefFeature = "matched" +) diff --git a/pkg/apis/nfd/v1alpha1/expression.go b/pkg/apis/nfd/v1alpha1/expression.go index b80654b40d..f290bf4253 100644 --- a/pkg/apis/nfd/v1alpha1/expression.go +++ b/pkg/apis/nfd/v1alpha1/expression.go @@ -5,7 +5,7 @@ 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 + 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, diff --git a/pkg/apis/nfd/v1alpha1/types.go b/pkg/apis/nfd/v1alpha1/nodefeature_types.go similarity index 79% rename from pkg/apis/nfd/v1alpha1/types.go rename to pkg/apis/nfd/v1alpha1/nodefeature_types.go index 10f069ad79..e5755c4501 100644 --- a/pkg/apis/nfd/v1alpha1/types.go +++ b/pkg/apis/nfd/v1alpha1/nodefeature_types.go @@ -238,53 +238,3 @@ type MatchOp string // MatchValue is the list of values associated with a MatchExpression. type MatchValue []string - -const ( - // MatchAny returns always true. - MatchAny MatchOp = "" - // MatchIn returns true if any of the values stored in the expression is - // equal to the input. - MatchIn MatchOp = "In" - // MatchNotIn returns true if none of the values in the expression are - // equal to the input. - MatchNotIn MatchOp = "NotIn" - // MatchInRegexp treats values of the expression as regular expressions and - // returns true if any of them matches the input. - MatchInRegexp MatchOp = "InRegexp" - // MatchExists returns true if the input is valid. The expression must not - // have any values. - MatchExists MatchOp = "Exists" - // MatchDoesNotExist returns true if the input is not valid. The expression - // must not have any values. - MatchDoesNotExist MatchOp = "DoesNotExist" - // MatchGt returns true if the input is greater than the value of the - // expression (number of values in the expression must be exactly one). - // Both the input and value must be integer numbers, otherwise an error is - // returned. - MatchGt MatchOp = "Gt" - // MatchLt returns true if the input is less than the value of the - // expression (number of values in the expression must be exactly one). - // Both the input and value must be integer numbers, otherwise an error is - // returned. - MatchLt MatchOp = "Lt" - // MatchGtLt returns true if the input is between two values, i.e. greater - // than the first value and less than the second value of the expression - // (number of values in the expression must be exactly two). Both the input - // and values must be integer numbers, otherwise an error is returned. - MatchGtLt MatchOp = "GtLt" - // MatchIsTrue returns true if the input holds the value "true". The - // expression must not have any values. - MatchIsTrue MatchOp = "IsTrue" - // MatchIsFalse returns true if the input holds the value "false". The - // expression must not have any values. - MatchIsFalse MatchOp = "IsFalse" -) - -const ( - // RuleBackrefDomain is the special feature domain for backreferencing - // output of preceding rules. - RuleBackrefDomain = "rule" - // RuleBackrefFeature is the special feature name for backreferencing - // output of preceding rules. - RuleBackrefFeature = "matched" -) diff --git a/pkg/apis/nfd/v1alpha1/nodefeaturegroup_types.go b/pkg/apis/nfd/v1alpha1/nodefeaturegroup_types.go new file mode 100644 index 0000000000..c85335a408 --- /dev/null +++ b/pkg/apis/nfd/v1alpha1/nodefeaturegroup_types.go @@ -0,0 +1,91 @@ +/* +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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// NodeFeatureGroup resource holds Node pools by featureGroup +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Namespaced,shortName=nfg +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient +type NodeFeatureGroup struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec NodeFeatureGroupSpec `json:"spec"` +} + +// NodeFeatureGroupSpec describes a NodeFeatureGroup object. +type NodeFeatureGroupSpec struct { + // FeatureGroupRules is a list of feature group rules. + // Feature group rules are used to group nodes into feature groups. + // +optional + FeatureGroup `json:"FeatureGroup"` + // Features is the set of features that are shared by all nodes in the feature group + // +optional + Features map[string]string `json:"Features"` +} + +type FeatureGroup struct { + // Name is the name of the feature group + Name string `json:"name"` + // Nodes is the list of nodes in the cluster that belong to this feature group + // +optional + Nodes []string `json:"nodes"` +} + +// NodeFeatureGroupList contains a list of NodeFeatureGroup objects. +// +kubebuilder:object:root=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type NodeFeatureGroupList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []NodeFeatureGroup `json:"spec"` +} + +// NodeFeatureGroupRule resource specifies a configuration for feature-based +// node grouping. +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName=nfgr +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient +// +genclient:nonNamespaced +type NodeFeatureGroupRule struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec NodeFeatureGroupRuleSpec `json:"spec"` +} + +// NodeFeatureGroupRuleSpec describes a NodeFeatureGroupRule. +type NodeFeatureGroupRuleSpec struct { + FeatureGroupRules []Rule `json:"featureGroupRules"` +} + +// NodeFeatureGroupRuleList contains a list of NodeFeatureGroupRule objects. +// +kubebuilder:object:root=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type NodeFeatureGroupRuleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []NodeFeatureGroupRule `json:"spec"` +} diff --git a/pkg/apis/nfd/v1alpha1/register.go b/pkg/apis/nfd/v1alpha1/register.go index 8c1d41f5b6..7acf96d6f7 100644 --- a/pkg/apis/nfd/v1alpha1/register.go +++ b/pkg/apis/nfd/v1alpha1/register.go @@ -42,6 +42,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &NodeFeature{}, &NodeFeatureRule{}, + &NodeFeatureGroup{}, + &NodeFeatureGroupRule{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/nfd/v1alpha1/rule.go b/pkg/apis/nfd/v1alpha1/rule.go index 3ac58658bc..da4a8141ca 100644 --- a/pkg/apis/nfd/v1alpha1/rule.go +++ b/pkg/apis/nfd/v1alpha1/rule.go @@ -108,6 +108,41 @@ func (r *Rule) Execute(features *Features) (RuleOutput, error) { return ret, nil } +// Evaluate the rule against a set of input features, and return true if the +// rule matches. +func (r *Rule) Evaluate(features *Features) (bool, error) { + matched := false + if len(r.MatchAny) > 0 { + // Logical OR over the matchAny matchers + for _, matcher := range r.MatchAny { + if isMatch, matches, err := matcher.match(features); err != nil { + return false, err + } else if isMatch { + matched = true + klog.V(4).InfoS("matchAny matched", "ruleName", r.Name, "matchedFeatures", utils.DelayedDumper(matches)) + // there's no need to evaluate other matchers in MatchAny + // One match is enough for MatchAny + break + } + } + if !matched { + return false, nil + } + } + + if len(r.MatchFeatures) > 0 { + if isMatch, _, err := r.MatchFeatures.match(features); err != nil { + return false, err + } else if !isMatch { + klog.V(2).InfoS("rule did not match", "ruleName", r.Name) + return false, nil + } + } + + klog.V(2).InfoS("rule matched", "ruleName", r.Name) + return true, nil +} + func (r *Rule) executeLabelsTemplate(in matchedFeatures, out map[string]string) error { if r.LabelsTemplate == "" { return nil diff --git a/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go index b114b94277..b8d85db328 100644 --- a/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go @@ -32,6 +32,26 @@ func (in *AttributeFeatureSet) DeepCopy() *AttributeFeatureSet { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FeatureGroup) DeepCopyInto(out *FeatureGroup) { + *out = *in + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeatureGroup. +func (in *FeatureGroup) DeepCopy() *FeatureGroup { + if in == nil { + return nil + } + out := new(FeatureGroup) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in FeatureMatcher) DeepCopyInto(out *FeatureMatcher) { { @@ -317,6 +337,167 @@ func (in *NodeFeature) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeFeatureGroup) DeepCopyInto(out *NodeFeatureGroup) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureGroup. +func (in *NodeFeatureGroup) DeepCopy() *NodeFeatureGroup { + if in == nil { + return nil + } + out := new(NodeFeatureGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeFeatureGroup) 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 *NodeFeatureGroupList) DeepCopyInto(out *NodeFeatureGroupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NodeFeatureGroup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureGroupList. +func (in *NodeFeatureGroupList) DeepCopy() *NodeFeatureGroupList { + if in == nil { + return nil + } + out := new(NodeFeatureGroupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeFeatureGroupList) 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 *NodeFeatureGroupRule) DeepCopyInto(out *NodeFeatureGroupRule) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureGroupRule. +func (in *NodeFeatureGroupRule) DeepCopy() *NodeFeatureGroupRule { + if in == nil { + return nil + } + out := new(NodeFeatureGroupRule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeFeatureGroupRule) 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 *NodeFeatureGroupRuleList) DeepCopyInto(out *NodeFeatureGroupRuleList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]NodeFeatureGroupRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureGroupRuleList. +func (in *NodeFeatureGroupRuleList) DeepCopy() *NodeFeatureGroupRuleList { + if in == nil { + return nil + } + out := new(NodeFeatureGroupRuleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeFeatureGroupRuleList) 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 *NodeFeatureGroupRuleSpec) DeepCopyInto(out *NodeFeatureGroupRuleSpec) { + *out = *in + if in.FeatureGroupRules != nil { + in, out := &in.FeatureGroupRules, &out.FeatureGroupRules + *out = make([]Rule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureGroupRuleSpec. +func (in *NodeFeatureGroupRuleSpec) DeepCopy() *NodeFeatureGroupRuleSpec { + if in == nil { + return nil + } + out := new(NodeFeatureGroupRuleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeFeatureGroupSpec) DeepCopyInto(out *NodeFeatureGroupSpec) { + *out = *in + in.FeatureGroup.DeepCopyInto(&out.FeatureGroup) + if in.Features != nil { + in, out := &in.Features, &out.Features + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeFeatureGroupSpec. +func (in *NodeFeatureGroupSpec) DeepCopy() *NodeFeatureGroupSpec { + if in == nil { + return nil + } + out := new(NodeFeatureGroupSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NodeFeatureList) DeepCopyInto(out *NodeFeatureList) { *out = *in diff --git a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go index bc748c80e3..1deb7d3b44 100644 --- a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go +++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nfd_client.go @@ -32,6 +32,14 @@ func (c *FakeNfdV1alpha1) NodeFeatures(namespace string) v1alpha1.NodeFeatureInt return &FakeNodeFeatures{c, namespace} } +func (c *FakeNfdV1alpha1) NodeFeatureGroups(namespace string) v1alpha1.NodeFeatureGroupInterface { + return &FakeNodeFeatureGroups{c, namespace} +} + +func (c *FakeNfdV1alpha1) NodeFeatureGroupRules() v1alpha1.NodeFeatureGroupRuleInterface { + return &FakeNodeFeatureGroupRules{c} +} + func (c *FakeNfdV1alpha1) NodeFeatureRules() v1alpha1.NodeFeatureRuleInterface { return &FakeNodeFeatureRules{c} } diff --git a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegroup.go b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegroup.go new file mode 100644 index 0000000000..107979c7cd --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegroup.go @@ -0,0 +1,129 @@ +/* +Copyright 2023 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/pkg/apis/nfd/v1alpha1" +) + +// FakeNodeFeatureGroups implements NodeFeatureGroupInterface +type FakeNodeFeatureGroups struct { + Fake *FakeNfdV1alpha1 + ns string +} + +var nodefeaturegroupsResource = v1alpha1.SchemeGroupVersion.WithResource("nodefeaturegroups") + +var nodefeaturegroupsKind = v1alpha1.SchemeGroupVersion.WithKind("NodeFeatureGroup") + +// Get takes name of the nodeFeatureGroup, and returns the corresponding nodeFeatureGroup object, and an error if there is any. +func (c *FakeNodeFeatureGroups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeFeatureGroup, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(nodefeaturegroupsResource, c.ns, name), &v1alpha1.NodeFeatureGroup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NodeFeatureGroup), err +} + +// List takes label and field selectors, and returns the list of NodeFeatureGroups that match those selectors. +func (c *FakeNodeFeatureGroups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeFeatureGroupList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(nodefeaturegroupsResource, nodefeaturegroupsKind, c.ns, opts), &v1alpha1.NodeFeatureGroupList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.NodeFeatureGroupList{ListMeta: obj.(*v1alpha1.NodeFeatureGroupList).ListMeta} + for _, item := range obj.(*v1alpha1.NodeFeatureGroupList).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 nodeFeatureGroups. +func (c *FakeNodeFeatureGroups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(nodefeaturegroupsResource, c.ns, opts)) + +} + +// Create takes the representation of a nodeFeatureGroup and creates it. Returns the server's representation of the nodeFeatureGroup, and an error, if there is any. +func (c *FakeNodeFeatureGroups) Create(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.CreateOptions) (result *v1alpha1.NodeFeatureGroup, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(nodefeaturegroupsResource, c.ns, nodeFeatureGroup), &v1alpha1.NodeFeatureGroup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NodeFeatureGroup), err +} + +// Update takes the representation of a nodeFeatureGroup and updates it. Returns the server's representation of the nodeFeatureGroup, and an error, if there is any. +func (c *FakeNodeFeatureGroups) Update(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureGroup, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(nodefeaturegroupsResource, c.ns, nodeFeatureGroup), &v1alpha1.NodeFeatureGroup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NodeFeatureGroup), err +} + +// Delete takes name of the nodeFeatureGroup and deletes it. Returns an error if one occurs. +func (c *FakeNodeFeatureGroups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(nodefeaturegroupsResource, c.ns, name, opts), &v1alpha1.NodeFeatureGroup{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNodeFeatureGroups) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(nodefeaturegroupsResource, c.ns, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.NodeFeatureGroupList{}) + return err +} + +// Patch applies the patch and returns the patched nodeFeatureGroup. +func (c *FakeNodeFeatureGroups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureGroup, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(nodefeaturegroupsResource, c.ns, name, pt, data, subresources...), &v1alpha1.NodeFeatureGroup{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NodeFeatureGroup), err +} diff --git a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegrouprule.go b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegrouprule.go new file mode 100644 index 0000000000..3aa9e8bb28 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturegrouprule.go @@ -0,0 +1,121 @@ +/* +Copyright 2023 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/pkg/apis/nfd/v1alpha1" +) + +// FakeNodeFeatureGroupRules implements NodeFeatureGroupRuleInterface +type FakeNodeFeatureGroupRules struct { + Fake *FakeNfdV1alpha1 +} + +var nodefeaturegrouprulesResource = v1alpha1.SchemeGroupVersion.WithResource("nodefeaturegrouprules") + +var nodefeaturegrouprulesKind = v1alpha1.SchemeGroupVersion.WithKind("NodeFeatureGroupRule") + +// Get takes name of the nodeFeatureGroupRule, and returns the corresponding nodeFeatureGroupRule object, and an error if there is any. +func (c *FakeNodeFeatureGroupRules) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeFeatureGroupRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(nodefeaturegrouprulesResource, name), &v1alpha1.NodeFeatureGroupRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NodeFeatureGroupRule), err +} + +// List takes label and field selectors, and returns the list of NodeFeatureGroupRules that match those selectors. +func (c *FakeNodeFeatureGroupRules) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeFeatureGroupRuleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(nodefeaturegrouprulesResource, nodefeaturegrouprulesKind, opts), &v1alpha1.NodeFeatureGroupRuleList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.NodeFeatureGroupRuleList{ListMeta: obj.(*v1alpha1.NodeFeatureGroupRuleList).ListMeta} + for _, item := range obj.(*v1alpha1.NodeFeatureGroupRuleList).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 nodeFeatureGroupRules. +func (c *FakeNodeFeatureGroupRules) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(nodefeaturegrouprulesResource, opts)) +} + +// Create takes the representation of a nodeFeatureGroupRule and creates it. Returns the server's representation of the nodeFeatureGroupRule, and an error, if there is any. +func (c *FakeNodeFeatureGroupRules) Create(ctx context.Context, nodeFeatureGroupRule *v1alpha1.NodeFeatureGroupRule, opts v1.CreateOptions) (result *v1alpha1.NodeFeatureGroupRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(nodefeaturegrouprulesResource, nodeFeatureGroupRule), &v1alpha1.NodeFeatureGroupRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NodeFeatureGroupRule), err +} + +// Update takes the representation of a nodeFeatureGroupRule and updates it. Returns the server's representation of the nodeFeatureGroupRule, and an error, if there is any. +func (c *FakeNodeFeatureGroupRules) Update(ctx context.Context, nodeFeatureGroupRule *v1alpha1.NodeFeatureGroupRule, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureGroupRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(nodefeaturegrouprulesResource, nodeFeatureGroupRule), &v1alpha1.NodeFeatureGroupRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NodeFeatureGroupRule), err +} + +// Delete takes name of the nodeFeatureGroupRule and deletes it. Returns an error if one occurs. +func (c *FakeNodeFeatureGroupRules) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(nodefeaturegrouprulesResource, name, opts), &v1alpha1.NodeFeatureGroupRule{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeNodeFeatureGroupRules) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(nodefeaturegrouprulesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.NodeFeatureGroupRuleList{}) + return err +} + +// Patch applies the patch and returns the patched nodeFeatureGroupRule. +func (c *FakeNodeFeatureGroupRules) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureGroupRule, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(nodefeaturegrouprulesResource, name, pt, data, subresources...), &v1alpha1.NodeFeatureGroupRule{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.NodeFeatureGroupRule), err +} diff --git a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go index 30853f1cac..b9f85b793f 100644 --- a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go +++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/generated_expansion.go @@ -20,4 +20,8 @@ package v1alpha1 type NodeFeatureExpansion interface{} +type NodeFeatureGroupExpansion interface{} + +type NodeFeatureGroupRuleExpansion interface{} + type NodeFeatureRuleExpansion interface{} diff --git a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go index 5a0a853cfd..5d6a8e355b 100644 --- a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go +++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go @@ -29,6 +29,8 @@ import ( type NfdV1alpha1Interface interface { RESTClient() rest.Interface NodeFeaturesGetter + NodeFeatureGroupsGetter + NodeFeatureGroupRulesGetter NodeFeatureRulesGetter } @@ -41,6 +43,14 @@ func (c *NfdV1alpha1Client) NodeFeatures(namespace string) NodeFeatureInterface return newNodeFeatures(c, namespace) } +func (c *NfdV1alpha1Client) NodeFeatureGroups(namespace string) NodeFeatureGroupInterface { + return newNodeFeatureGroups(c, namespace) +} + +func (c *NfdV1alpha1Client) NodeFeatureGroupRules() NodeFeatureGroupRuleInterface { + return newNodeFeatureGroupRules(c) +} + func (c *NfdV1alpha1Client) NodeFeatureRules() NodeFeatureRuleInterface { return newNodeFeatureRules(c) } diff --git a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go new file mode 100644 index 0000000000..7e9a435a62 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegroup.go @@ -0,0 +1,178 @@ +/* +Copyright 2023 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" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" + scheme "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned/scheme" +) + +// NodeFeatureGroupsGetter has a method to return a NodeFeatureGroupInterface. +// A group's client should implement this interface. +type NodeFeatureGroupsGetter interface { + NodeFeatureGroups(namespace string) NodeFeatureGroupInterface +} + +// NodeFeatureGroupInterface has methods to work with NodeFeatureGroup resources. +type NodeFeatureGroupInterface interface { + Create(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.CreateOptions) (*v1alpha1.NodeFeatureGroup, error) + Update(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (*v1alpha1.NodeFeatureGroup, 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.NodeFeatureGroup, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.NodeFeatureGroupList, 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.NodeFeatureGroup, err error) + NodeFeatureGroupExpansion +} + +// nodeFeatureGroups implements NodeFeatureGroupInterface +type nodeFeatureGroups struct { + client rest.Interface + ns string +} + +// newNodeFeatureGroups returns a NodeFeatureGroups +func newNodeFeatureGroups(c *NfdV1alpha1Client, namespace string) *nodeFeatureGroups { + return &nodeFeatureGroups{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the nodeFeatureGroup, and returns the corresponding nodeFeatureGroup object, and an error if there is any. +func (c *nodeFeatureGroups) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeFeatureGroup, err error) { + result = &v1alpha1.NodeFeatureGroup{} + err = c.client.Get(). + Namespace(c.ns). + Resource("nodefeaturegroups"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of NodeFeatureGroups that match those selectors. +func (c *nodeFeatureGroups) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeFeatureGroupList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.NodeFeatureGroupList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("nodefeaturegroups"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested nodeFeatureGroups. +func (c *nodeFeatureGroups) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("nodefeaturegroups"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a nodeFeatureGroup and creates it. Returns the server's representation of the nodeFeatureGroup, and an error, if there is any. +func (c *nodeFeatureGroups) Create(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.CreateOptions) (result *v1alpha1.NodeFeatureGroup, err error) { + result = &v1alpha1.NodeFeatureGroup{} + err = c.client.Post(). + Namespace(c.ns). + Resource("nodefeaturegroups"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(nodeFeatureGroup). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a nodeFeatureGroup and updates it. Returns the server's representation of the nodeFeatureGroup, and an error, if there is any. +func (c *nodeFeatureGroups) Update(ctx context.Context, nodeFeatureGroup *v1alpha1.NodeFeatureGroup, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureGroup, err error) { + result = &v1alpha1.NodeFeatureGroup{} + err = c.client.Put(). + Namespace(c.ns). + Resource("nodefeaturegroups"). + Name(nodeFeatureGroup.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(nodeFeatureGroup). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the nodeFeatureGroup and deletes it. Returns an error if one occurs. +func (c *nodeFeatureGroups) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("nodefeaturegroups"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *nodeFeatureGroups) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("nodefeaturegroups"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched nodeFeatureGroup. +func (c *nodeFeatureGroups) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureGroup, err error) { + result = &v1alpha1.NodeFeatureGroup{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("nodefeaturegroups"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegrouprule.go b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegrouprule.go new file mode 100644 index 0000000000..34159f2f00 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nodefeaturegrouprule.go @@ -0,0 +1,168 @@ +/* +Copyright 2023 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" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" + scheme "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned/scheme" +) + +// NodeFeatureGroupRulesGetter has a method to return a NodeFeatureGroupRuleInterface. +// A group's client should implement this interface. +type NodeFeatureGroupRulesGetter interface { + NodeFeatureGroupRules() NodeFeatureGroupRuleInterface +} + +// NodeFeatureGroupRuleInterface has methods to work with NodeFeatureGroupRule resources. +type NodeFeatureGroupRuleInterface interface { + Create(ctx context.Context, nodeFeatureGroupRule *v1alpha1.NodeFeatureGroupRule, opts v1.CreateOptions) (*v1alpha1.NodeFeatureGroupRule, error) + Update(ctx context.Context, nodeFeatureGroupRule *v1alpha1.NodeFeatureGroupRule, opts v1.UpdateOptions) (*v1alpha1.NodeFeatureGroupRule, 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.NodeFeatureGroupRule, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.NodeFeatureGroupRuleList, 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.NodeFeatureGroupRule, err error) + NodeFeatureGroupRuleExpansion +} + +// nodeFeatureGroupRules implements NodeFeatureGroupRuleInterface +type nodeFeatureGroupRules struct { + client rest.Interface +} + +// newNodeFeatureGroupRules returns a NodeFeatureGroupRules +func newNodeFeatureGroupRules(c *NfdV1alpha1Client) *nodeFeatureGroupRules { + return &nodeFeatureGroupRules{ + client: c.RESTClient(), + } +} + +// Get takes name of the nodeFeatureGroupRule, and returns the corresponding nodeFeatureGroupRule object, and an error if there is any. +func (c *nodeFeatureGroupRules) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeFeatureGroupRule, err error) { + result = &v1alpha1.NodeFeatureGroupRule{} + err = c.client.Get(). + Resource("nodefeaturegrouprules"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of NodeFeatureGroupRules that match those selectors. +func (c *nodeFeatureGroupRules) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeFeatureGroupRuleList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.NodeFeatureGroupRuleList{} + err = c.client.Get(). + Resource("nodefeaturegrouprules"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested nodeFeatureGroupRules. +func (c *nodeFeatureGroupRules) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("nodefeaturegrouprules"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a nodeFeatureGroupRule and creates it. Returns the server's representation of the nodeFeatureGroupRule, and an error, if there is any. +func (c *nodeFeatureGroupRules) Create(ctx context.Context, nodeFeatureGroupRule *v1alpha1.NodeFeatureGroupRule, opts v1.CreateOptions) (result *v1alpha1.NodeFeatureGroupRule, err error) { + result = &v1alpha1.NodeFeatureGroupRule{} + err = c.client.Post(). + Resource("nodefeaturegrouprules"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(nodeFeatureGroupRule). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a nodeFeatureGroupRule and updates it. Returns the server's representation of the nodeFeatureGroupRule, and an error, if there is any. +func (c *nodeFeatureGroupRules) Update(ctx context.Context, nodeFeatureGroupRule *v1alpha1.NodeFeatureGroupRule, opts v1.UpdateOptions) (result *v1alpha1.NodeFeatureGroupRule, err error) { + result = &v1alpha1.NodeFeatureGroupRule{} + err = c.client.Put(). + Resource("nodefeaturegrouprules"). + Name(nodeFeatureGroupRule.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(nodeFeatureGroupRule). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the nodeFeatureGroupRule and deletes it. Returns an error if one occurs. +func (c *nodeFeatureGroupRules) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("nodefeaturegrouprules"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *nodeFeatureGroupRules) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("nodefeaturegrouprules"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched nodeFeatureGroupRule. +func (c *nodeFeatureGroupRules) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.NodeFeatureGroupRule, err error) { + result = &v1alpha1.NodeFeatureGroupRule{} + err = c.client.Patch(pt). + Resource("nodefeaturegrouprules"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go index 8139775712..5dc6a323eb 100644 --- a/pkg/generated/informers/externalversions/generic.go +++ b/pkg/generated/informers/externalversions/generic.go @@ -55,6 +55,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=nfd.k8s-sigs.io, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithResource("nodefeatures"): return &genericInformer{resource: resource.GroupResource(), informer: f.Nfd().V1alpha1().NodeFeatures().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("nodefeaturegroups"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Nfd().V1alpha1().NodeFeatureGroups().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("nodefeaturegrouprules"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Nfd().V1alpha1().NodeFeatureGroupRules().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("nodefeaturerules"): return &genericInformer{resource: resource.GroupResource(), informer: f.Nfd().V1alpha1().NodeFeatureRules().Informer()}, nil diff --git a/pkg/generated/informers/externalversions/nfd/v1alpha1/interface.go b/pkg/generated/informers/externalversions/nfd/v1alpha1/interface.go index 5292d87ae3..ab5eefcd95 100644 --- a/pkg/generated/informers/externalversions/nfd/v1alpha1/interface.go +++ b/pkg/generated/informers/externalversions/nfd/v1alpha1/interface.go @@ -26,6 +26,10 @@ import ( type Interface interface { // NodeFeatures returns a NodeFeatureInformer. NodeFeatures() NodeFeatureInformer + // NodeFeatureGroups returns a NodeFeatureGroupInformer. + NodeFeatureGroups() NodeFeatureGroupInformer + // NodeFeatureGroupRules returns a NodeFeatureGroupRuleInformer. + NodeFeatureGroupRules() NodeFeatureGroupRuleInformer // NodeFeatureRules returns a NodeFeatureRuleInformer. NodeFeatureRules() NodeFeatureRuleInformer } @@ -46,6 +50,16 @@ func (v *version) NodeFeatures() NodeFeatureInformer { return &nodeFeatureInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// NodeFeatureGroups returns a NodeFeatureGroupInformer. +func (v *version) NodeFeatureGroups() NodeFeatureGroupInformer { + return &nodeFeatureGroupInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// NodeFeatureGroupRules returns a NodeFeatureGroupRuleInformer. +func (v *version) NodeFeatureGroupRules() NodeFeatureGroupRuleInformer { + return &nodeFeatureGroupRuleInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + // NodeFeatureRules returns a NodeFeatureRuleInformer. func (v *version) NodeFeatureRules() NodeFeatureRuleInformer { return &nodeFeatureRuleInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} diff --git a/pkg/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegroup.go b/pkg/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegroup.go new file mode 100644 index 0000000000..60f2d28bbb --- /dev/null +++ b/pkg/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegroup.go @@ -0,0 +1,90 @@ +/* +Copyright 2023 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" + nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" + versioned "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned" + internalinterfaces "sigs.k8s.io/node-feature-discovery/pkg/generated/informers/externalversions/internalinterfaces" + v1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/generated/listers/nfd/v1alpha1" +) + +// NodeFeatureGroupInformer provides access to a shared informer and lister for +// NodeFeatureGroups. +type NodeFeatureGroupInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.NodeFeatureGroupLister +} + +type nodeFeatureGroupInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewNodeFeatureGroupInformer constructs a new informer for NodeFeatureGroup 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 NewNodeFeatureGroupInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredNodeFeatureGroupInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredNodeFeatureGroupInformer constructs a new informer for NodeFeatureGroup 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 NewFilteredNodeFeatureGroupInformer(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().NodeFeatureGroups(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NfdV1alpha1().NodeFeatureGroups(namespace).Watch(context.TODO(), options) + }, + }, + &nfdv1alpha1.NodeFeatureGroup{}, + resyncPeriod, + indexers, + ) +} + +func (f *nodeFeatureGroupInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredNodeFeatureGroupInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *nodeFeatureGroupInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&nfdv1alpha1.NodeFeatureGroup{}, f.defaultInformer) +} + +func (f *nodeFeatureGroupInformer) Lister() v1alpha1.NodeFeatureGroupLister { + return v1alpha1.NewNodeFeatureGroupLister(f.Informer().GetIndexer()) +} diff --git a/pkg/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegrouprule.go b/pkg/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegrouprule.go new file mode 100644 index 0000000000..b23dd502db --- /dev/null +++ b/pkg/generated/informers/externalversions/nfd/v1alpha1/nodefeaturegrouprule.go @@ -0,0 +1,89 @@ +/* +Copyright 2023 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" + nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" + versioned "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned" + internalinterfaces "sigs.k8s.io/node-feature-discovery/pkg/generated/informers/externalversions/internalinterfaces" + v1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/generated/listers/nfd/v1alpha1" +) + +// NodeFeatureGroupRuleInformer provides access to a shared informer and lister for +// NodeFeatureGroupRules. +type NodeFeatureGroupRuleInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.NodeFeatureGroupRuleLister +} + +type nodeFeatureGroupRuleInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewNodeFeatureGroupRuleInformer constructs a new informer for NodeFeatureGroupRule 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 NewNodeFeatureGroupRuleInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredNodeFeatureGroupRuleInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredNodeFeatureGroupRuleInformer constructs a new informer for NodeFeatureGroupRule 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 NewFilteredNodeFeatureGroupRuleInformer(client versioned.Interface, 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().NodeFeatureGroupRules().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NfdV1alpha1().NodeFeatureGroupRules().Watch(context.TODO(), options) + }, + }, + &nfdv1alpha1.NodeFeatureGroupRule{}, + resyncPeriod, + indexers, + ) +} + +func (f *nodeFeatureGroupRuleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredNodeFeatureGroupRuleInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *nodeFeatureGroupRuleInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&nfdv1alpha1.NodeFeatureGroupRule{}, f.defaultInformer) +} + +func (f *nodeFeatureGroupRuleInformer) Lister() v1alpha1.NodeFeatureGroupRuleLister { + return v1alpha1.NewNodeFeatureGroupRuleLister(f.Informer().GetIndexer()) +} diff --git a/pkg/generated/listers/nfd/v1alpha1/expansion_generated.go b/pkg/generated/listers/nfd/v1alpha1/expansion_generated.go index b12e45a004..0cb0d3b8f5 100644 --- a/pkg/generated/listers/nfd/v1alpha1/expansion_generated.go +++ b/pkg/generated/listers/nfd/v1alpha1/expansion_generated.go @@ -26,6 +26,18 @@ type NodeFeatureListerExpansion interface{} // NodeFeatureNamespaceLister. type NodeFeatureNamespaceListerExpansion interface{} +// NodeFeatureGroupListerExpansion allows custom methods to be added to +// NodeFeatureGroupLister. +type NodeFeatureGroupListerExpansion interface{} + +// NodeFeatureGroupNamespaceListerExpansion allows custom methods to be added to +// NodeFeatureGroupNamespaceLister. +type NodeFeatureGroupNamespaceListerExpansion interface{} + +// NodeFeatureGroupRuleListerExpansion allows custom methods to be added to +// NodeFeatureGroupRuleLister. +type NodeFeatureGroupRuleListerExpansion interface{} + // NodeFeatureRuleListerExpansion allows custom methods to be added to // NodeFeatureRuleLister. type NodeFeatureRuleListerExpansion interface{} diff --git a/pkg/generated/listers/nfd/v1alpha1/nodefeaturegroup.go b/pkg/generated/listers/nfd/v1alpha1/nodefeaturegroup.go new file mode 100644 index 0000000000..77a1cc7c4e --- /dev/null +++ b/pkg/generated/listers/nfd/v1alpha1/nodefeaturegroup.go @@ -0,0 +1,99 @@ +/* +Copyright 2023 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/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" +) + +// NodeFeatureGroupLister helps list NodeFeatureGroups. +// All objects returned here must be treated as read-only. +type NodeFeatureGroupLister interface { + // List lists all NodeFeatureGroups in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.NodeFeatureGroup, err error) + // NodeFeatureGroups returns an object that can list and get NodeFeatureGroups. + NodeFeatureGroups(namespace string) NodeFeatureGroupNamespaceLister + NodeFeatureGroupListerExpansion +} + +// nodeFeatureGroupLister implements the NodeFeatureGroupLister interface. +type nodeFeatureGroupLister struct { + indexer cache.Indexer +} + +// NewNodeFeatureGroupLister returns a new NodeFeatureGroupLister. +func NewNodeFeatureGroupLister(indexer cache.Indexer) NodeFeatureGroupLister { + return &nodeFeatureGroupLister{indexer: indexer} +} + +// List lists all NodeFeatureGroups in the indexer. +func (s *nodeFeatureGroupLister) List(selector labels.Selector) (ret []*v1alpha1.NodeFeatureGroup, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.NodeFeatureGroup)) + }) + return ret, err +} + +// NodeFeatureGroups returns an object that can list and get NodeFeatureGroups. +func (s *nodeFeatureGroupLister) NodeFeatureGroups(namespace string) NodeFeatureGroupNamespaceLister { + return nodeFeatureGroupNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// NodeFeatureGroupNamespaceLister helps list and get NodeFeatureGroups. +// All objects returned here must be treated as read-only. +type NodeFeatureGroupNamespaceLister interface { + // List lists all NodeFeatureGroups in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.NodeFeatureGroup, err error) + // Get retrieves the NodeFeatureGroup from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.NodeFeatureGroup, error) + NodeFeatureGroupNamespaceListerExpansion +} + +// nodeFeatureGroupNamespaceLister implements the NodeFeatureGroupNamespaceLister +// interface. +type nodeFeatureGroupNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all NodeFeatureGroups in the indexer for a given namespace. +func (s nodeFeatureGroupNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.NodeFeatureGroup, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.NodeFeatureGroup)) + }) + return ret, err +} + +// Get retrieves the NodeFeatureGroup from the indexer for a given namespace and name. +func (s nodeFeatureGroupNamespaceLister) Get(name string) (*v1alpha1.NodeFeatureGroup, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("nodefeaturegroup"), name) + } + return obj.(*v1alpha1.NodeFeatureGroup), nil +} diff --git a/pkg/generated/listers/nfd/v1alpha1/nodefeaturegrouprule.go b/pkg/generated/listers/nfd/v1alpha1/nodefeaturegrouprule.go new file mode 100644 index 0000000000..fd2271870f --- /dev/null +++ b/pkg/generated/listers/nfd/v1alpha1/nodefeaturegrouprule.go @@ -0,0 +1,68 @@ +/* +Copyright 2023 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/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" +) + +// NodeFeatureGroupRuleLister helps list NodeFeatureGroupRules. +// All objects returned here must be treated as read-only. +type NodeFeatureGroupRuleLister interface { + // List lists all NodeFeatureGroupRules in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.NodeFeatureGroupRule, err error) + // Get retrieves the NodeFeatureGroupRule from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.NodeFeatureGroupRule, error) + NodeFeatureGroupRuleListerExpansion +} + +// nodeFeatureGroupRuleLister implements the NodeFeatureGroupRuleLister interface. +type nodeFeatureGroupRuleLister struct { + indexer cache.Indexer +} + +// NewNodeFeatureGroupRuleLister returns a new NodeFeatureGroupRuleLister. +func NewNodeFeatureGroupRuleLister(indexer cache.Indexer) NodeFeatureGroupRuleLister { + return &nodeFeatureGroupRuleLister{indexer: indexer} +} + +// List lists all NodeFeatureGroupRules in the indexer. +func (s *nodeFeatureGroupRuleLister) List(selector labels.Selector) (ret []*v1alpha1.NodeFeatureGroupRule, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.NodeFeatureGroupRule)) + }) + return ret, err +} + +// Get retrieves the NodeFeatureGroupRule from the index for a given name. +func (s *nodeFeatureGroupRuleLister) Get(name string) (*v1alpha1.NodeFeatureGroupRule, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("nodefeaturegrouprule"), name) + } + return obj.(*v1alpha1.NodeFeatureGroupRule), nil +} diff --git a/pkg/nfd-gc/nfd-gc.go b/pkg/nfd-gc/nfd-gc.go index ac48805aba..7d82e91b38 100644 --- a/pkg/nfd-gc/nfd-gc.go +++ b/pkg/nfd-gc/nfd-gc.go @@ -91,6 +91,23 @@ func (n *nfdGarbageCollector) deleteNodeFeature(namespace, name string) { objectsDeleted.WithLabelValues(kind).Inc() } +func (n *nfdGarbageCollector) deleteNodeFeatureGroup(namespace, name string) { + kind := "NodeFeatureGroup" + if err := n.nfdClient.NfdV1alpha1().NodeFeatureGroups(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil { + if errors.IsNotFound(err) { + klog.V(2).InfoS("NodeFeatureGroup not found, omitting deletion", "nodefeaturegroup", klog.KRef(namespace, name)) + return + } else { + klog.ErrorS(err, "failed to delete NodeFeatureGroup object", "nodefeaturegroup", klog.KRef(namespace, name)) + objectDeleteErrors.WithLabelValues(kind).Inc() + return + } + } + + klog.InfoS("NodeFeatureGroup object has been deleted", "nodefeaturegroup", klog.KRef(namespace, name)) + objectsDeleted.WithLabelValues(kind).Inc() +} + func (n *nfdGarbageCollector) deleteNRT(nodeName string) { kind := "NodeResourceTopology" if err := n.topoClient.TopologyV1alpha2().NodeResourceTopologies().Delete(context.TODO(), nodeName, metav1.DeleteOptions{}); err != nil { @@ -165,6 +182,24 @@ func (n *nfdGarbageCollector) garbageCollect() { } } + // Handle NodeFeatureGroup objects + nfgs, err := n.nfdClient.NfdV1alpha1().NodeFeatureGroups("").List(context.TODO(), metav1.ListOptions{}) + if errors.IsNotFound(err) { + klog.V(2).InfoS("NodeFeatureGroup CRD does not exist") + } else if err != nil { + klog.ErrorS(err, "failed to list NodeFeatureGroup objects") + } else { + for _, nfg := range nfgs.Items { + _, err := n.nfdClient.NfdV1alpha1().NodeFeatureGroupRules().Get(context.TODO(), nfg.Name, metav1.GetOptions{}) + if errors.IsNotFound(err) { + klog.V(2).InfoS("no NodeFeatureGroupRule found for NodeFeatureGroup", "nodefeaturegroup", klog.KObj(&nfg)) + n.deleteNodeFeatureGroup(nfg.Namespace, nfg.Name) + } else if err != nil { + klog.ErrorS(err, "failed to get NodeFeatureGroupRule object", "nodefeaturegroup", klog.KObj(&nfg)) + } + } + } + // Handle NodeResourceTopology objects nrts, err := n.topoClient.TopologyV1alpha2().NodeResourceTopologies().List(context.TODO(), metav1.ListOptions{}) if errors.IsNotFound(err) { diff --git a/pkg/nfd-master/metrics.go b/pkg/nfd-master/metrics.go index a8afdc3097..bcfd3c8af7 100644 --- a/pkg/nfd-master/metrics.go +++ b/pkg/nfd-master/metrics.go @@ -23,15 +23,16 @@ import ( // When adding metric names, see https://prometheus.io/docs/practices/naming/#metric-names const ( - buildInfoQuery = "nfd_master_build_info" - nodeUpdateRequestsQuery = "nfd_node_update_requests_total" - nodeUpdatesQuery = "nfd_node_updates_total" - nodeUpdateFailuresQuery = "nfd_node_update_failures_total" - nodeLabelsRejectedQuery = "nfd_node_labels_rejected_total" - nodeERsRejectedQuery = "nfd_node_extendedresources_rejected_total" - nodeTaintsRejectedQuery = "nfd_node_taints_rejected_total" - nfrProcessingTimeQuery = "nfd_nodefeaturerule_processing_duration_seconds" - nfrProcessingErrorsQuery = "nfd_nodefeaturerule_processing_errors_total" + buildInfoQuery = "nfd_master_build_info" + nodeFeatureGroupUpdateRequestsQuery = "nfd_cluster_feature_update_requests_total" + nodeUpdateRequestsQuery = "nfd_node_update_requests_total" + nodeUpdatesQuery = "nfd_node_updates_total" + nodeUpdateFailuresQuery = "nfd_node_update_failures_total" + nodeLabelsRejectedQuery = "nfd_node_labels_rejected_total" + nodeERsRejectedQuery = "nfd_node_extendedresources_rejected_total" + nodeTaintsRejectedQuery = "nfd_node_taints_rejected_total" + nfrProcessingTimeQuery = "nfd_nodefeaturerule_processing_duration_seconds" + nfrProcessingErrorsQuery = "nfd_nodefeaturerule_processing_errors_total" ) var ( @@ -42,6 +43,10 @@ var ( "version": version.Get(), }, }) + nodeFeatureGroupUpdateRequests = prometheus.NewCounter(prometheus.CounterOpts{ + Name: nodeFeatureGroupUpdateRequestsQuery, + Help: "Number of cluster feature update requests processed by the master.", + }) nodeUpdateRequests = prometheus.NewCounter(prometheus.CounterOpts{ Name: nodeUpdateRequestsQuery, Help: "Number of node update requests processed by the master.", diff --git a/pkg/nfd-master/nfd-api-controller.go b/pkg/nfd-master/nfd-api-controller.go index 00c606eee8..7c9e89f9dd 100644 --- a/pkg/nfd-master/nfd-api-controller.go +++ b/pkg/nfd-master/nfd-api-controller.go @@ -38,22 +38,30 @@ type nfdController struct { featureLister nfdlisters.NodeFeatureLister ruleLister nfdlisters.NodeFeatureRuleLister + featureGroupLister nfdlisters.NodeFeatureGroupLister + featureGroupRuleLister nfdlisters.NodeFeatureGroupRuleLister + stopChan chan struct{} - updateAllNodesChan chan struct{} - updateOneNodeChan chan string + updateAllNodesChan chan struct{} + updateOneNodeChan chan string + updateAllNodeFeatureGroupsChan chan struct{} + updateNodeFeatureGroupChan chan string } type nfdApiControllerOptions struct { - DisableNodeFeature bool - ResyncPeriod time.Duration + DisableNodeFeature bool + DisableNodeFeatureGroup bool + ResyncPeriod time.Duration } func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiControllerOptions) (*nfdController, error) { c := &nfdController{ - stopChan: make(chan struct{}, 1), - updateAllNodesChan: make(chan struct{}, 1), - updateOneNodeChan: make(chan string), + stopChan: make(chan struct{}, 1), + updateAllNodesChan: make(chan struct{}, 1), + updateOneNodeChan: make(chan string), + updateNodeFeatureGroupChan: make(chan string), + updateAllNodeFeatureGroupsChan: make(chan struct{}, 1), } nfdClient := nfdclientset.NewForConfigOrDie(config) @@ -69,16 +77,19 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC nfr := obj.(*nfdv1alpha1.NodeFeature) klog.V(2).InfoS("NodeFeature added", "nodefeature", klog.KObj(nfr)) c.updateOneNode("NodeFeature", nfr) + c.updateAllNodeFeatureGroups() }, UpdateFunc: func(oldObj, newObj interface{}) { nfr := newObj.(*nfdv1alpha1.NodeFeature) klog.V(2).InfoS("NodeFeature updated", "nodefeature", klog.KObj(nfr)) c.updateOneNode("NodeFeature", nfr) + c.updateAllNodeFeatureGroups() }, DeleteFunc: func(obj interface{}) { nfr := obj.(*nfdv1alpha1.NodeFeature) klog.V(2).InfoS("NodeFeature deleted", "nodefeature", klog.KObj(nfr)) c.updateOneNode("NodeFeature", nfr) + c.updateAllNodeFeatureGroups() }, }); err != nil { return nil, err @@ -87,8 +98,8 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC } // Add informer for NodeFeatureRule objects - ruleInformer := informerFactory.Nfd().V1alpha1().NodeFeatureRules() - if _, err := ruleInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + nodeRuleInformer := informerFactory.Nfd().V1alpha1().NodeFeatureRules() + if _, err := nodeRuleInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(object interface{}) { klog.V(2).InfoS("NodeFeatureRule added", "nodefeaturerule", klog.KObj(object.(metav1.Object))) if !nfdApiControllerOptions.DisableNodeFeature { @@ -113,7 +124,61 @@ func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiC }); err != nil { return nil, err } - c.ruleLister = ruleInformer.Lister() + c.ruleLister = nodeRuleInformer.Lister() + + // Add informer for NodeFeatureGroup objects + if !nfdApiControllerOptions.DisableNodeFeatureGroup { + nodeFeatureGroupInformer := informerFactory.Nfd().V1alpha1().NodeFeatureGroups() + if _, err := nodeFeatureGroupInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + nfg := obj.(*nfdv1alpha1.NodeFeatureGroup) + klog.V(2).InfoS("NodeFeatureGroup added", "nodeFeatureGroup", klog.KObj(nfg)) + c.updateNodeFeatureGroup(nfg.Name) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + nfg := newObj.(*nfdv1alpha1.NodeFeatureGroup) + klog.V(2).InfoS("NodeFeatureGroup updated", "nodeFeatureGroup", klog.KObj(nfg)) + c.updateNodeFeatureGroup(nfg.Name) + }, + DeleteFunc: func(obj interface{}) { + nfg := obj.(*nfdv1alpha1.NodeFeatureGroup) + klog.V(2).InfoS("NodeFeatureGroup deleted", "nodeFeatureGroup", klog.KObj(nfg)) + c.updateNodeFeatureGroup(nfg.Name) + }, + }); err != nil { + return nil, err + } + c.featureGroupLister = nodeFeatureGroupInformer.Lister() + } + + // add informer for NodeFeatureGroupRules objects + nodeFeatureGroupRulesInformer := informerFactory.Nfd().V1alpha1().NodeFeatureGroupRules() + if _, err := nodeFeatureGroupRulesInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + klog.V(2).InfoS("NodeFeatureGroupRules added", "nodeFeatureGroupRules", klog.KObj(obj.(metav1.Object))) + nfgr := obj.(*nfdv1alpha1.NodeFeatureGroupRule) + if !nfdApiControllerOptions.DisableNodeFeatureGroup { + c.updateNodeFeatureGroup(nfgr.Name) + } + }, + UpdateFunc: func(oldObject, newObject interface{}) { + klog.V(2).InfoS("NodeFeatureGroupRules updated", "nodeFeatureGroupRules", klog.KObj(newObject.(metav1.Object))) + nfgr := newObject.(*nfdv1alpha1.NodeFeatureGroupRule) + if !nfdApiControllerOptions.DisableNodeFeatureGroup { + c.updateNodeFeatureGroup(nfgr.Name) + } + }, + DeleteFunc: func(obj interface{}) { + klog.V(2).InfoS("NodeFeatureGroupRules deleted", "nodeFeatureGroupRules", klog.KObj(obj.(metav1.Object))) + nfgr := obj.(*nfdv1alpha1.NodeFeatureGroupRule) + if !nfdApiControllerOptions.DisableNodeFeatureGroup { + c.updateNodeFeatureGroup(nfgr.Name) + } + }, + }); err != nil { + return nil, err + } + c.featureGroupRuleLister = nodeFeatureGroupRulesInformer.Lister() // Start informers informerFactory.Start(c.stopChan) @@ -138,6 +203,17 @@ func (c *nfdController) updateOneNode(typ string, obj metav1.Object) { c.updateOneNodeChan <- nodeName } +func (c *nfdController) updateNodeFeatureGroup(nodeFeatureGroupRule string) { + c.updateNodeFeatureGroupChan <- nodeFeatureGroupRule +} + +func (c *nfdController) updateAllNodeFeatureGroups() { + select { + case c.updateAllNodeFeatureGroupsChan <- struct{}{}: + default: + } +} + func getNodeNameForObj(obj metav1.Object) (string, error) { nodeName, ok := obj.GetLabels()[nfdv1alpha1.NodeFeatureObjNodeNameLabel] if !ok { diff --git a/pkg/nfd-master/nfd-master-internal_test.go b/pkg/nfd-master/nfd-master-internal_test.go index 4268ce3872..953817e31b 100644 --- a/pkg/nfd-master/nfd-master-internal_test.go +++ b/pkg/nfd-master/nfd-master-internal_test.go @@ -77,9 +77,11 @@ func mockNodeList() *corev1.NodeList { func newMockNfdAPIController(client *fake.Clientset) *nfdController { c := &nfdController{ - stopChan: make(chan struct{}, 1), - updateAllNodesChan: make(chan struct{}, 1), - updateOneNodeChan: make(chan string), + stopChan: make(chan struct{}, 1), + updateAllNodesChan: make(chan struct{}, 1), + updateOneNodeChan: make(chan string), + updateNodeFeatureGroupChan: make(chan string), + updateAllNodeFeatureGroupsChan: make(chan struct{}, 1), } informerFactory := nfdinformers.NewSharedInformerFactory(client, 1*time.Hour) diff --git a/pkg/nfd-master/nfd-master.go b/pkg/nfd-master/nfd-master.go index caad5fb2ca..f29601e8ce 100644 --- a/pkg/nfd-master/nfd-master.go +++ b/pkg/nfd-master/nfd-master.go @@ -37,7 +37,10 @@ import ( "google.golang.org/grpc/health" "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/peer" + corev1 "k8s.io/api/core/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" k8sQuantity "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" k8sLabels "k8s.io/apimachinery/pkg/labels" @@ -48,6 +51,7 @@ import ( "k8s.io/client-go/tools/leaderelection/resourcelock" "k8s.io/klog/v2" controller "k8s.io/kubernetes/pkg/controller" + nfdclientset "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned" klogutils "sigs.k8s.io/node-feature-discovery/pkg/utils/klog" taintutils "k8s.io/kubernetes/pkg/util/taints" @@ -105,21 +109,22 @@ type ConfigOverrideArgs struct { // Args holds command line arguments type Args struct { - CaFile string - CertFile string - ConfigFile string - Instance string - KeyFile string - Klog map[string]*utils.KlogFlagVal - Kubeconfig string - CrdController bool - EnableNodeFeatureApi bool - Port int - Prune bool - VerifyNodeName bool - Options string - EnableLeaderElection bool - MetricsPort int + CaFile string + CertFile string + ConfigFile string + Instance string + KeyFile string + Klog map[string]*utils.KlogFlagVal + Kubeconfig string + CrdController bool + EnableNodeFeatureApi bool + EnableNodeFeatureGroupApi bool + Port int + Prune bool + VerifyNodeName bool + Options string + EnableLeaderElection bool + MetricsPort int Overrides ConfigOverrideArgs } @@ -138,16 +143,17 @@ type NfdMaster interface { type nfdMaster struct { *nfdController - args Args - namespace string - nodeName string - configFilePath string - server *grpc.Server - stop chan struct{} - ready chan bool - apihelper apihelper.APIHelpers - kubeconfig *restclient.Config - nodeUpdaterPool *nodeUpdaterPool + args Args + namespace string + nodeName string + configFilePath string + server *grpc.Server + stop chan struct{} + ready chan bool + apihelper apihelper.APIHelpers + kubeconfig *restclient.Config + nodeUpdaterPool *nodeUpdaterPool + nodeFeatureGroupUpdaterPool *nodeFeatureGroupUpdaterPool deniedNs config *NFDConfig } @@ -187,6 +193,7 @@ func NewNfdMaster(args *Args) (NfdMaster, error) { } nfd.nodeUpdaterPool = newNodeUpdaterPool(nfd) + nfd.nodeFeatureGroupUpdaterPool = newNodeFeatureGroupUpdaterPool(nfd) return nfd, nil } @@ -236,6 +243,7 @@ func (m *nfdMaster) Run() error { } m.nodeUpdaterPool.start(m.config.NfdApiParallelism) + m.nodeFeatureGroupUpdaterPool.start(m.config.NfdApiParallelism) // Create watcher for config file configWatch, err := utils.CreateFsWatcher(time.Second, m.configFilePath) @@ -267,7 +275,7 @@ func (m *nfdMaster) Run() error { defer m.Stop() } - // Run gRPC server + //ss Run gRPC server grpcErr := make(chan error, 1) go m.runGrpcServer(grpcErr) @@ -313,7 +321,9 @@ func (m *nfdMaster) Run() error { } // Restart the node updater pool m.nodeUpdaterPool.stop() + m.nodeFeatureGroupUpdaterPool.stop() m.nodeUpdaterPool.start(m.config.NfdApiParallelism) + m.nodeFeatureGroupUpdaterPool.start(m.config.NfdApiParallelism) case <-m.stop: klog.InfoS("shutting down nfd-master") @@ -390,6 +400,8 @@ func (m *nfdMaster) nfdAPIUpdateHandler() { // disabled (i.e. NodeFeature API is enabled) updateAll := m.args.EnableNodeFeatureApi updateNodes := make(map[string]struct{}) + nodeFeatureGroup := make(map[string]struct{}) + updateAllNodeFeatureGroups := false rateLimit := time.After(time.Second) for { select { @@ -397,7 +409,12 @@ func (m *nfdMaster) nfdAPIUpdateHandler() { updateAll = true case nodeName := <-m.nfdController.updateOneNodeChan: updateNodes[nodeName] = struct{}{} + case <-m.nfdController.updateAllNodeFeatureGroupsChan: + updateAllNodeFeatureGroups = true + case nodeFeatureGroupName := <-m.nfdController.updateNodeFeatureGroupChan: + nodeFeatureGroup[nodeFeatureGroupName] = struct{}{} case <-rateLimit: + // NodeFeature errUpdateAll := false if updateAll { if err := m.nfdAPIUpdateAllNodes(); err != nil { @@ -409,10 +426,21 @@ func (m *nfdMaster) nfdAPIUpdateHandler() { m.nodeUpdaterPool.queue.Add(nodeName) } } - - // Reset "work queue" and timer + // NodeFeatureGroup + if updateAllNodeFeatureGroups { + if err := m.nfdAPIUpdateAllNodeFeatureGroups(); err != nil { + klog.ErrorS(err, "failed to update NodeFeatureGroups") + } + } else { + for nodeFeatureGroupName := range nodeFeatureGroup { + m.nodeFeatureGroupUpdaterPool.queue.Add(nodeFeatureGroupName) + } + } + // Reset "work queues" and timer updateAll = errUpdateAll + updateAllNodeFeatureGroups = false updateNodes = map[string]struct{}{} + nodeFeatureGroup = map[string]struct{}{} rateLimit = time.After(time.Second) } } @@ -722,6 +750,105 @@ func (m *nfdMaster) nfdAPIUpdateAllNodes() error { return nil } +func (m *nfdMaster) nfdAPIUpdateAllNodeFeatureGroups() error { + klog.InfoS("updating All NodeFeatureGroups, will process all nodeFeatureGroupRules") + + nodeFeatureGroupRules, err := m.nfdController.featureGroupRuleLister.List(k8sLabels.Everything()) + if err != nil { + return fmt.Errorf("failed to get nodeFeatureGroupRules resources: %w", err) + } + + for _, nodeFeatureGroupRule := range nodeFeatureGroupRules { + m.nodeUpdaterPool.queue.Add(nodeFeatureGroupRule.Name) + } + + return nil +} + +func (m *nfdMaster) nfdAPIUpdateNodeFeatureGroup(nodeFeatureGroupName string) error { + klog.V(1).InfoS("processing of nodeFeatureGroup", "nodeFeatureGroup", nodeFeatureGroupName) + nodeGroupValidator := make(map[string]bool) + var err error + + kubeconfig, err := m.getKubeconfig() + if err != nil { + return err + } + nfdClient := nfdclientset.NewForConfigOrDie(kubeconfig) + + nodeFeatures, err := m.nfdController.featureLister.List(k8sLabels.Everything()) + if err != nil { + return fmt.Errorf("failed to get NodeFeatures resources: %w", err) + } + + nodeFeatureGroupRule, err := nfdClient.NfdV1alpha1().NodeFeatureGroupRules().Get(context.Background(), nodeFeatureGroupName, metav1.GetOptions{}) + if errors.IsNotFound(err) { + klog.InfoS("nodeFeatureGroupRule not found", "nodeFeatureGroupRule", nodeFeatureGroupName) + return nil + } else if err != nil { + return fmt.Errorf("failed to get NodeFeatureGroupRules resources: %w", err) + } + + // Evaluate rules and create matching groups + featureGroup := nfdv1alpha1.FeatureGroup{ + Name: nodeFeatureGroupRule.Name, + } + for _, rule := range nodeFeatureGroupRule.Spec.FeatureGroupRules { + for _, feature := range nodeFeatures { + match, err := rule.Evaluate(&feature.Spec.Features) + if err != nil { + return fmt.Errorf("failed to evaluate rule %q: %w", rule.Name, err) + } + + if match { + klog.InfoS("node matched rule", "nodeName", feature.Name, "ruleName", rule.Name) + system := feature.Spec.Features.Attributes["system.name"] + nodeName := system.Elements["nodename"] + if _, ok := nodeGroupValidator[nodeName]; !ok { + featureGroup.Nodes = append(featureGroup.Nodes, nodeName) + nodeGroupValidator[nodeName] = true + } + } + } + } + + // Update the NodeFeatureGroup object with the updated featureGroupRules + if NodeFeatureGroup, err := nfdClient.NfdV1alpha1().NodeFeatureGroups(m.namespace).Get(context.Background(), nodeFeatureGroupName, metav1.GetOptions{}); errors.IsNotFound(err) { + klog.InfoS("creating NodeFeatureGroup object", "nodeFeatureGroup", klog.KObj(NodeFeatureGroup)) + nfg := &nfdv1alpha1.NodeFeatureGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: nodeFeatureGroupName, + Annotations: map[string]string{nfdv1alpha1.MasterVersionAnnotation: version.Get()}, + Labels: map[string]string{nfdv1alpha1.FeatureGroupObjLabel: nodeFeatureGroupName}, + }, + } + nfg.Spec.FeatureGroup = featureGroup + + cfCreated, err := nfdClient.NfdV1alpha1().NodeFeatureGroups(m.namespace).Create(context.Background(), nfg, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create NodeFeatureGroup object %q: %w", cfCreated.Name, err) + } + klog.V(4).InfoS("NodeFeatureGroup object created", "nodeFeatureGroup", utils.DelayedDumper(cfCreated)) + } else if err != nil { + return fmt.Errorf("failed to get NodeFeatureGroup object: %w", err) + } else { + NodeFeatureGroupUpdated := NodeFeatureGroup.DeepCopy() + NodeFeatureGroupUpdated.Spec.FeatureGroup = featureGroup + if !apiequality.Semantic.DeepEqual(NodeFeatureGroup, NodeFeatureGroupUpdated) { + klog.InfoS("updating NodeFeatureGroup object", "nodeFeatureGroup", klog.KObj(NodeFeatureGroup)) + NodeFeatureGroupUpdated, err = nfdClient.NfdV1alpha1().NodeFeatureGroups(m.namespace).Update(context.Background(), NodeFeatureGroupUpdated, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("failed to update NodeFeatureGroup object: %w", err) + } + klog.V(4).InfoS("NodeFeatureGroup object updated", "nodeFeatureGroup", utils.DelayedDumper(NodeFeatureGroupUpdated)) + } else { + klog.V(1).InfoS("no changes in NodeFeatureGroup, object is up to date", "nodeFeatureGroup", klog.KObj(NodeFeatureGroup)) + } + } + + return nil +} + func (m *nfdMaster) nfdAPIUpdateOneNode(nodeName string) error { if m.nfdController == nil || m.nfdController.featureLister == nil { return nil @@ -1383,8 +1510,9 @@ func (m *nfdMaster) startNfdApiController() error { } klog.InfoS("starting the nfd api controller") m.nfdController, err = newNfdController(kubeconfig, nfdApiControllerOptions{ - DisableNodeFeature: !m.args.EnableNodeFeatureApi, - ResyncPeriod: m.config.ResyncPeriod.Duration, + DisableNodeFeature: !m.args.EnableNodeFeatureApi, + DisableNodeFeatureGroup: !m.args.EnableNodeFeatureGroupApi, + ResyncPeriod: m.config.ResyncPeriod.Duration, }) if err != nil { return fmt.Errorf("failed to initialize CRD controller: %w", err) diff --git a/pkg/nfd-master/nfg-updater-pool.go b/pkg/nfd-master/nfg-updater-pool.go new file mode 100644 index 0000000000..cc4cc30bbc --- /dev/null +++ b/pkg/nfd-master/nfg-updater-pool.go @@ -0,0 +1,108 @@ +/* +Copyright 2023 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 ( + "sync" + "time" + + "golang.org/x/time/rate" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog/v2" +) + +type nodeFeatureGroupUpdaterPool struct { + queue workqueue.RateLimitingInterface + sync.Mutex + + wg sync.WaitGroup + nfdMaster *nfdMaster +} + +func newNodeFeatureGroupUpdaterPool(nfdMaster *nfdMaster) *nodeFeatureGroupUpdaterPool { + return &nodeFeatureGroupUpdaterPool{ + nfdMaster: nfdMaster, + wg: sync.WaitGroup{}, + } +} + +func (u *nodeFeatureGroupUpdaterPool) processNodeFeatureGroupUpdateRequest(queue workqueue.RateLimitingInterface) bool { + nodeName, quit := queue.Get() + if quit { + return false + } + + defer queue.Done(nodeName) + + nodeFeatureGroupUpdateRequests.Inc() + if err := u.nfdMaster.nfdAPIUpdateNodeFeatureGroup(nodeName.(string)); err != nil { + if queue.NumRequeues(nodeName) < 15 { + klog.InfoS("retrying NodeFeatureGroup update") + queue.AddRateLimited(nodeName) + return true + } else { + klog.ErrorS(err, "failed to update NodeFeatureGroup") + } + } + queue.Forget(nodeName) + return true +} + +func (u *nodeFeatureGroupUpdaterPool) runNodeFeatureGroupUpdater(queue workqueue.RateLimitingInterface) { + for u.processNodeFeatureGroupUpdateRequest(queue) { + } + u.wg.Done() +} + +func (u *nodeFeatureGroupUpdaterPool) start(parallelism int) { + u.Lock() + defer u.Unlock() + + if u.queue != nil && !u.queue.ShuttingDown() { + klog.InfoS("the NFD master NodeFeatureGroup updater pool is already running.") + return + } + + klog.InfoS("starting the NFD master NodeFeatureGroup updater pool", "parallelism", parallelism) + + // Create ratelimiter. Mimic workqueue.DefaultControllerRateLimiter() but + // with modified per-item (node) rate limiting parameters. + rl := workqueue.NewMaxOfRateLimiter( + workqueue.NewItemExponentialFailureRateLimiter(50*time.Millisecond, 100*time.Second), + &workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)}, + ) + u.queue = workqueue.NewRateLimitingQueue(rl) + + for i := 0; i < parallelism; i++ { + u.wg.Add(1) + go u.runNodeFeatureGroupUpdater(u.queue) + } +} + +func (u *nodeFeatureGroupUpdaterPool) stop() { + u.Lock() + defer u.Unlock() + + if u.queue == nil || u.queue.ShuttingDown() { + klog.InfoS("the NFD master NodeFeatureGroup updater pool is not running.") + return + } + + klog.InfoS("stopping the NFD master NodeFeatureGroup updater pool") + u.queue.ShutDown() + u.wg.Wait() +} diff --git a/pkg/nfd-master/nfg-updater-pool_test.go b/pkg/nfd-master/nfg-updater-pool_test.go new file mode 100644 index 0000000000..6193907699 --- /dev/null +++ b/pkg/nfd-master/nfg-updater-pool_test.go @@ -0,0 +1,102 @@ +/* +Copyright 2023 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 ( + "sync" + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" + "github.com/stretchr/testify/mock" + k8sclient "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "sigs.k8s.io/node-feature-discovery/pkg/apihelper" + "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned/fake" +) + +func newMockNodeFeatureGroupUpdaterPool(nfdMaster *nfdMaster) *nodeFeatureGroupUpdaterPool { + return &nodeFeatureGroupUpdaterPool{ + nfdMaster: nfdMaster, + wg: sync.WaitGroup{}, + } +} + +func TestNodeFeatureGroupUpdaterStart(t *testing.T) { + mockHelper := &apihelper.MockAPIHelpers{} + mockMaster := newMockMaster(mockHelper) + mockNodeUpdaterPool := newMockNodeUpdaterPool(mockMaster) + + Convey("When starting the nodeFeatureGroup updater pool", t, func() { + mockNodeUpdaterPool.start(10) + q := mockNodeUpdaterPool.queue + Convey("NodeFeatureGroup updater pool queue properties should change", func() { + So(q, ShouldNotBeNil) + So(q.ShuttingDown(), ShouldBeFalse) + }) + + mockNodeUpdaterPool.start(10) + Convey("NodeFeatureGroup updater pool queue should not change", func() { + So(mockNodeUpdaterPool.queue, ShouldEqual, q) + }) + }) +} + +func TestNodeFeatureGroupUpdaterStop(t *testing.T) { + mockHelper := &apihelper.MockAPIHelpers{} + mockMaster := newMockMaster(mockHelper) + mockNodeUpdaterPool := newMockNodeFeatureGroupUpdaterPool(mockMaster) + + mockNodeUpdaterPool.start(10) + + Convey("When stoping the NodeFeatureGroup updater pool", t, func() { + mockNodeUpdaterPool.stop() + Convey("NodeFeatureGroup updater pool queue should be removed", func() { + // Wait for the wg.Done() + So(func() interface{} { + return mockNodeUpdaterPool.queue.ShuttingDown() + }, withTimeout, 2*time.Second, ShouldBeTrue) + }) + }) +} + +func TestRunNodeFeatureGroupUpdater(t *testing.T) { + mockAPIHelper := &apihelper.MockAPIHelpers{} + mockMaster := newMockMaster(mockAPIHelper) + mockMaster.kubeconfig = &rest.Config{} + mockMaster.nfdController = newMockNfdAPIController(fake.NewSimpleClientset()) + mockClient := &k8sclient.Clientset{} + mockNode := newMockNode() + mockNodeUpdaterPool := newMockNodeFeatureGroupUpdaterPool(mockMaster) + statusPatches := []apihelper.JsonPatch{} + metadataPatches := []apihelper.JsonPatch{} + + mockAPIHelper.On("GetClient").Return(mockClient, nil) + mockAPIHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil) + mockAPIHelper.On("PatchNodeStatus", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(statusPatches))).Return(nil) + mockAPIHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(metadataPatches))).Return(nil) + + mockNodeUpdaterPool.start(10) + Convey("Queue has no element", t, func() { + So(mockNodeUpdaterPool.queue.Len(), ShouldEqual, 0) + }) + mockNodeUpdaterPool.queue.Add(mockNodeName) + Convey("Added element to the queue should be removed", t, func() { + So(func() interface{} { return mockNodeUpdaterPool.queue.Len() }, + withTimeout, 2*time.Second, ShouldEqual, 0) + }) +} diff --git a/pkg/nfd-master/node-updater-pool.go b/pkg/nfd-master/nfr-updater-pool.go similarity index 100% rename from pkg/nfd-master/node-updater-pool.go rename to pkg/nfd-master/nfr-updater-pool.go diff --git a/pkg/nfd-master/node-updater-pool_test.go b/pkg/nfd-master/nfr-updater-pool_test.go similarity index 100% rename from pkg/nfd-master/node-updater-pool_test.go rename to pkg/nfd-master/nfr-updater-pool_test.go diff --git a/test/e2e/data/nodefeaturegrouprule-1.yaml b/test/e2e/data/nodefeaturegrouprule-1.yaml new file mode 100644 index 0000000000..813fc0ac7d --- /dev/null +++ b/test/e2e/data/nodefeaturegrouprule-1.yaml @@ -0,0 +1,11 @@ +apiVersion: nfd.k8s-sigs.io/v1alpha1 +kind: NodeFeatureGroupRule +metadata: + name: e2e-test-1 +spec: + featureGroupRules: + - name: "e2e-attribute-test-1" + matchFeatures: + - feature: kernel.version + matchExpressions: + major: {op: Exists} \ No newline at end of file diff --git a/test/e2e/node_feature_discovery_test.go b/test/e2e/node_feature_discovery_test.go index 5493acd754..9dd6997b99 100644 --- a/test/e2e/node_feature_discovery_test.go +++ b/test/e2e/node_feature_discovery_test.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "path/filepath" + "reflect" "strings" "time" @@ -41,6 +42,7 @@ import ( admissionapi "k8s.io/pod-security-admission/api" "sigs.k8s.io/node-feature-discovery/pkg/apihelper" + "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" nfdclient "sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned" "sigs.k8s.io/node-feature-discovery/source/custom" @@ -174,6 +176,28 @@ func cleanupCRs(ctx context.Context, cli *nfdclient.Clientset, namespace string) Expect(err).NotTo(HaveOccurred()) } } + + nfgrs, err := cli.NfdV1alpha1().NodeFeatureGroupRules().List(ctx, metav1.ListOptions{}) + Expect(err).NotTo(HaveOccurred()) + + if len(nfgrs.Items) != 0 { + By("Deleting NodeFeatureGroupRule objects from the cluster") + for _, nfgr := range nfgrs.Items { + err = cli.NfdV1alpha1().NodeFeatureGroupRules().Delete(ctx, nfgr.Name, metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + } + } + + nfgs, err := cli.NfdV1alpha1().NodeFeatureGroups(namespace).List(ctx, metav1.ListOptions{}) + Expect(err).NotTo(HaveOccurred()) + + if len(nfgs.Items) != 0 { + By("Deleting NodeFeatureGroup objects from namespace " + namespace) + for _, nfg := range nfgs.Items { + err = cli.NfdV1alpha1().NodeFeatureGroups(namespace).Delete(ctx, nfg.Name, metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + } + } } // Actual test suite @@ -839,6 +863,66 @@ core: }) }) + // Test NodeFeatureGroupRule + Context("and NodeFeatureGroupRules objects deployed", func() { + BeforeEach(func(ctx context.Context) { + // We need a NodeFeature from the node, can't be a fake one + if !useNodeFeatureApi { + Skip("NodeFeature API not enabled") + } + }) + It("custom NodeFeatureGroup from the NodeFeatureGroupRule rules should be created", func(ctx context.Context) { + nodes, err := getNonControlPlaneNodes(ctx, f.ClientSet) + Expect(err).NotTo(HaveOccurred()) + + targetNodeName := nodes[0].Name + Expect(targetNodeName).ToNot(BeEmpty(), "No suitable worker node found") + + By("Creating nfd-worker config") + cm := testutils.NewConfigMap("nfd-worker-conf", "nfd-worker.conf", ` +core: + sleepInterval: "1s" +`) + _, err = f.ClientSet.CoreV1().ConfigMaps(f.Namespace.Name).Create(ctx, cm, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + By("Creating nfd-worker daemonset") + podSpecOpts := createPodSpecOpts( + 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()) + + checkNodeFeatureObject(ctx, targetNodeName) + + By("Creating NodeFeatureGroupRules #1") + Expect(testutils.CreateNodeFeatureGroupRulesFromFile(ctx, nfdClient, "nodefeaturegrouprule-1.yaml")).NotTo(HaveOccurred()) + + By("Verifying NodeFeatureGroup from NodeFeatureRules #1") + expectedGroup := v1alpha1.NodeFeatureGroup{ + Spec: v1alpha1.NodeFeatureGroupSpec{ + FeatureGroup: v1alpha1.FeatureGroup{ + Nodes: []string{targetNodeName}, + }, + }, + } + Eventually(func() bool { + group, err := nfdClient.NfdV1alpha1().NodeFeatureGroups(f.Namespace.Name).Get(ctx, "e2e-test-1", metav1.GetOptions{}) + if err != nil { + return false + } + return reflect.DeepEqual(group.Spec.FeatureGroup.Nodes, expectedGroup.Spec.FeatureGroup.Nodes) + }, 5*time.Minute, 5*time.Second).Should(BeTrue()) + + By("Deleting nfd-worker daemonset") + err = f.ClientSet.AppsV1().DaemonSets(f.Namespace.Name).Delete(ctx, workerDS.Name, metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + }) + }) + Context("and check whether master config passed successfully or not", func() { BeforeEach(func(ctx context.Context) { extraMasterPodSpecOpts = []testpod.SpecOption{ diff --git a/test/e2e/utils/crd.go b/test/e2e/utils/crd.go index 0f36f54abe..90bd237748 100644 --- a/test/e2e/utils/crd.go +++ b/test/e2e/utils/crd.go @@ -123,6 +123,21 @@ func CreateNodeFeatureRulesFromFile(ctx context.Context, cli nfdclientset.Interf return nil } +// CreateNodeFeatureGroupRuleFromFile creates a NodeFeatureGroupRule object from a given file located under test data directory. +func CreateNodeFeatureGroupRulesFromFile(ctx context.Context, cli nfdclientset.Interface, filename string) error { + objs, err := nodeFeatureGroupRulesFromFile(filepath.Join(packagePath, "..", "data", filename)) + if err != nil { + return err + } + + for _, obj := range objs { + if _, err = cli.NfdV1alpha1().NodeFeatureGroupRules().Create(ctx, obj, metav1.CreateOptions{}); err != nil { + return err + } + } + return nil +} + // UpdateNodeFeatureRulesFromFile updates existing NodeFeatureRule object from a given file located under test data directory. func UpdateNodeFeatureRulesFromFile(ctx context.Context, cli nfdclientset.Interface, filename string) error { objs, err := nodeFeatureRulesFromFile(filepath.Join(packagePath, "..", "data", filename)) @@ -238,6 +253,25 @@ func nodeFeatureRulesFromFile(path string) ([]*nfdv1alpha1.NodeFeatureRule, erro return crs, nil } +func nodeFeatureGroupRulesFromFile(path string) ([]*nfdv1alpha1.NodeFeatureGroupRule, error) { + objs, err := apiObjsFromFile(path, nfdscheme.Codecs.UniversalDeserializer()) + if err != nil { + return nil, err + } + + crs := make([]*nfdv1alpha1.NodeFeatureGroupRule, len(objs)) + + for i, obj := range objs { + var ok bool + crs[i], ok = obj.(*nfdv1alpha1.NodeFeatureGroupRule) + 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 8549256aa3..f8deaab603 100644 --- a/test/e2e/utils/rbac.go +++ b/test/e2e/utils/rbac.go @@ -176,6 +176,11 @@ func createClusterRoleMaster(ctx context.Context, cs clientset.Interface) (*rbac Resources: []string{"nodefeatures", "nodefeaturerules"}, Verbs: []string{"get", "list", "watch"}, }, + { + APIGroups: []string{"nfd.k8s-sigs.io"}, + Resources: []string{"nodefeaturegroups", "nodefeaturegrouprules"}, + Verbs: []string{"get", "list", "watch", "update", "create"}, + }, }, } if *openShift {