Repository: kubernetes-sigs/node-feature-discovery
Pull request #845 (2022-07-07 18:15:13)

Revert type hack in api
- Revert the hack that was a workaround for issues with k8s deepcopy-gen.
  New deepcopy-gen is able to generate code correctly without issues so
  this is not needed anymore.

  Also, removing this hack solves issues with object validation when
  creating NodeFeatureRules programmatically with nfd go-client. This is
  needed later with NodeFeatureRules e2e-tests.
- Update controller-gen and k8s code-generator to the latest releases.
- Refresh auto-generated files

Depends on #829 

marquiz: /hold
marquiz: /retitle Revert type hack in api
marquiz: #829 was merged ->
/unhold

Patch:
diff --git a/Dockerfile_generator b/Dockerfile_generator
index c0865e990..02178bc4b 100644
--- a/Dockerfile_generator
+++ b/Dockerfile_generator
@@ -2,9 +2,9 @@ FROM golang:1.18-buster as builder
 
 # Install tools
 RUN go install github.com/vektra/mockery/v2@v2.13.0 && \
-    go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.7.0 && \
-    git clone https://github.com/kubernetes/code-generator -b v0.20.7 --depth 1 && \
-    go install k8s.io/code-generator/cmd/...@v0.20.7 && \
+    go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.9.2 && \
+    git clone https://github.com/kubernetes/code-generator -b v0.24.3 --depth 1 && \
+    go install k8s.io/code-generator/cmd/...@v0.24.3 && \
     go install golang.org/x/tools/cmd/goimports@v0.1.1 && \
     go install github.com/golang/protobuf/protoc-gen-go@v1.4.3
 
diff --git a/deployment/base/nfd-crds/nodefeaturerule-crd.yaml b/deployment/base/nfd-crds/nodefeaturerule-crd.yaml
index cd9b48bf4..c40af9119 100644
--- a/deployment/base/nfd-crds/nodefeaturerule-crd.yaml
+++ b/deployment/base/nfd-crds/nodefeaturerule-crd.yaml
@@ -1,10 +1,9 @@
-
 ---
 apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.7.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: nodefeaturerules.nfd.k8s-sigs.io
 spec:
@@ -79,9 +78,9 @@ spec:
                                       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. NB: Validate()
-                                      must be called if Op or Value fields are modified
-                                      or if a new     instance is created from scratch
+                                      for creating new instances. 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:
@@ -144,9 +143,9 @@ spec:
                                 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
+                                MustCreateMatchExpression() should be used for creating
                                 new instances. NB: Validate() must be called if Op
-                                or Value fields are modified or if a new     instance
+                                or Value fields are modified or if a new instance
                                 is created from scratch without using the helper functions."
                               properties:
                                 op:
@@ -215,9 +214,3 @@ spec:
         type: object
     served: true
     storage: true
-status:
-  acceptedNames:
-    kind: ""
-    plural: ""
-  conditions: []
-  storedVersions: []
diff --git a/deployment/helm/node-feature-discovery/manifests/nodefeaturerule-crd.yaml b/deployment/helm/node-feature-discovery/manifests/nodefeaturerule-crd.yaml
index cd9b48bf4..c40af9119 100644
--- a/deployment/helm/node-feature-discovery/manifests/nodefeaturerule-crd.yaml
+++ b/deployment/helm/node-feature-discovery/manifests/nodefeaturerule-crd.yaml
@@ -1,10 +1,9 @@
-
 ---
 apiVersion: apiextensions.k8s.io/v1
 kind: CustomResourceDefinition
 metadata:
   annotations:
-    controller-gen.kubebuilder.io/version: v0.7.0
+    controller-gen.kubebuilder.io/version: v0.9.2
   creationTimestamp: null
   name: nodefeaturerules.nfd.k8s-sigs.io
 spec:
@@ -79,9 +78,9 @@ spec:
                                       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. NB: Validate()
-                                      must be called if Op or Value fields are modified
-                                      or if a new     instance is created from scratch
+                                      for creating new instances. 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:
@@ -144,9 +143,9 @@ spec:
                                 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
+                                MustCreateMatchExpression() should be used for creating
                                 new instances. NB: Validate() must be called if Op
-                                or Value fields are modified or if a new     instance
+                                or Value fields are modified or if a new instance
                                 is created from scratch without using the helper functions."
                               properties:
                                 op:
@@ -215,9 +214,3 @@ spec:
         type: object
     served: true
     storage: true
-status:
-  acceptedNames:
-    kind: ""
-    plural: ""
-  conditions: []
-  storedVersions: []
diff --git a/pkg/api/feature/generated.pb.go b/pkg/api/feature/generated.pb.go
index cfe7c772b..4b9c8556b 100644
--- a/pkg/api/feature/generated.pb.go
+++ b/pkg/api/feature/generated.pb.go
@@ -230,38 +230,38 @@ func init() { proto.RegisterFile("feature/generated.proto", fileDescriptor_870e6
 
 var fileDescriptor_870e6eafce4d2482 = []byte{
 	// 503 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xc1, 0x6e, 0xd3, 0x40,
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0x6e, 0xd3, 0x40,
 	0x10, 0x86, 0xbd, 0x71, 0x5b, 0xea, 0x49, 0x9b, 0x94, 0x15, 0x02, 0xcb, 0x48, 0xdb, 0x10, 0x50,
-	0x95, 0x03, 0x75, 0x44, 0x4f, 0x08, 0xc4, 0x81, 0x40, 0x2b, 0x55, 0x91, 0x8a, 0xe4, 0x22, 0x10,
-	0xa8, 0x17, 0xa7, 0x4c, 0x83, 0x55, 0xc7, 0x46, 0xf6, 0x1a, 0xc9, 0x37, 0x1e, 0x81, 0x87, 0xe0,
-	0xcc, 0x73, 0xe4, 0xd8, 0x63, 0x4f, 0x15, 0x31, 0xaf, 0xc1, 0x01, 0x65, 0xbd, 0x76, 0xed, 0xc4,
-	0x06, 0xf5, 0xe6, 0xdd, 0xfd, 0xff, 0x6f, 0xff, 0x99, 0x1d, 0x19, 0xee, 0x9d, 0xa1, 0xcd, 0xa3,
-	0x00, 0xfb, 0x63, 0xf4, 0x30, 0xb0, 0x39, 0x7e, 0x32, 0xbf, 0x04, 0x3e, 0xf7, 0xe9, 0x2d, 0x79,
-	0x60, 0xec, 0x8e, 0x1d, 0xfe, 0x39, 0x1a, 0x99, 0xa7, 0xfe, 0xa4, 0x3f, 0xf6, 0xc7, 0x7e, 0x5f,
-	0x9c, 0x8f, 0xa2, 0x33, 0xb1, 0x12, 0x0b, 0xf1, 0x95, 0xfa, 0xba, 0x7f, 0x54, 0x68, 0xbd, 0xf6,
-	0x27, 0xb6, 0xe3, 0x1d, 0xa4, 0x80, 0x90, 0xbe, 0x82, 0x95, 0x73, 0x8c, 0x43, 0x9d, 0x74, 0xd4,
-	0x5e, 0x73, 0xef, 0x81, 0x29, 0xc9, 0x66, 0x59, 0x66, 0x0e, 0x31, 0x0e, 0xf7, 0x3d, 0x1e, 0xc4,
-	0x83, 0x8d, 0xe9, 0xd5, 0xb6, 0x92, 0x5c, 0x6d, 0xaf, 0xcc, 0xb7, 0x2c, 0x61, 0xa6, 0x43, 0x58,
-	0xfb, 0x6a, 0xbb, 0x11, 0x86, 0x7a, 0x43, 0x60, 0x1e, 0xd6, 0x61, 0xde, 0x09, 0x55, 0x0a, 0x6a,
-	0x49, 0xd0, 0x5a, 0xba, 0x69, 0x49, 0x04, 0x7d, 0x0f, 0x9a, 0xe3, 0x85, 0xdc, 0xf6, 0x4e, 0x31,
-	0xd4, 0x55, 0xc1, 0xdb, 0xa9, 0xe3, 0x1d, 0x66, 0xc2, 0x14, 0x79, 0x5b, 0x22, 0xb5, 0x7c, 0xdf,
-	0xba, 0x66, 0x19, 0x6f, 0x40, 0xcb, 0xcb, 0xa0, 0x5b, 0xa0, 0x9e, 0x63, 0xac, 0x93, 0x0e, 0xe9,
-	0x69, 0xd6, 0xfc, 0x93, 0x3e, 0x86, 0x55, 0x91, 0x40, 0x6f, 0x74, 0x48, 0xaf, 0xb9, 0x77, 0x37,
-	0xbf, 0x73, 0x88, 0xb1, 0xbc, 0xf0, 0x18, 0xb9, 0x95, 0x8a, 0x9e, 0x35, 0x9e, 0x12, 0xe3, 0x18,
-	0x9a, 0x85, 0x82, 0x2a, 0x90, 0x66, 0x19, 0xa9, 0xe7, 0x48, 0x61, 0xab, 0x86, 0x7e, 0x80, 0x56,
-	0xb9, 0xaa, 0x0a, 0xee, 0x93, 0x32, 0xf7, 0x7e, 0xce, 0xcd, 0x9c, 0x95, 0xe8, 0xee, 0x4f, 0x02,
-	0xed, 0x05, 0x05, 0x3d, 0x01, 0xb0, 0x39, 0x0f, 0x9c, 0x51, 0xc4, 0x31, 0x9b, 0x82, 0x5e, 0x1d,
-	0xcf, 0x7c, 0x99, 0x4b, 0xd3, 0x86, 0x53, 0xd9, 0x70, 0xb8, 0x3e, 0xb0, 0x0a, 0x3c, 0xe3, 0x05,
-	0xb4, 0x17, 0x2c, 0x15, 0xd5, 0xdc, 0x29, 0x56, 0xa3, 0x15, 0x03, 0x9f, 0x00, 0x5d, 0xae, 0x88,
-	0x1e, 0xc0, 0x3a, 0xba, 0x38, 0x41, 0x8f, 0x67, 0x81, 0xf5, 0xba, 0xc0, 0x83, 0x2d, 0x19, 0x70,
-	0x7d, 0x5f, 0x3a, 0xac, 0xdc, 0x3b, 0x6f, 0xc7, 0x66, 0xe9, 0x6d, 0xa9, 0xb5, 0x44, 0x7e, 0x54,
-	0x3d, 0x05, 0x66, 0x86, 0x4b, 0xdb, 0xf0, 0x8f, 0x5b, 0x8c, 0x43, 0xd8, 0x2c, 0x89, 0x2b, 0x1a,
-	0xd0, 0x2d, 0x3f, 0xe7, 0x46, 0x7e, 0xe7, 0x91, 0xe3, 0x16, 0xdb, 0xb1, 0x0a, 0xea, 0x91, 0xe3,
-	0x76, 0x7f, 0x10, 0x68, 0x2f, 0x0c, 0x10, 0x7d, 0xbb, 0x94, 0x7c, 0xa7, 0x6e, 0xd8, 0x6e, 0x90,
-	0xfd, 0xf9, 0xff, 0xb3, 0xd7, 0x3e, 0xde, 0x60, 0x77, 0x3a, 0x63, 0xca, 0xc5, 0x8c, 0x29, 0x97,
-	0x33, 0xa6, 0x7c, 0x4b, 0x18, 0x99, 0x26, 0x8c, 0x5c, 0x24, 0x8c, 0x5c, 0x26, 0x8c, 0xfc, 0x4a,
-	0x18, 0xf9, 0xfe, 0x9b, 0x29, 0x1f, 0xb3, 0x5f, 0xd9, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1f,
-	0x6e, 0x71, 0x14, 0xed, 0x04, 0x00, 0x00,
+	0x95, 0x03, 0xac, 0x45, 0x4f, 0x08, 0xc4, 0x81, 0x40, 0x2b, 0x55, 0x91, 0x8a, 0xe4, 0x22, 0x10,
+	0xa8, 0x17, 0xa7, 0x6c, 0x83, 0xd5, 0xc4, 0x46, 0xf6, 0x1a, 0xc9, 0x37, 0x1e, 0x81, 0x87, 0xe0,
+	0xcc, 0x73, 0xe4, 0xd8, 0x63, 0x4f, 0x15, 0x31, 0xaf, 0xc1, 0x01, 0x65, 0xbd, 0xde, 0xd8, 0x89,
+	0x0d, 0xe2, 0x66, 0xef, 0xfe, 0xff, 0x37, 0xff, 0xcc, 0x0e, 0xdc, 0x39, 0x67, 0x2e, 0x8f, 0x43,
+	0x66, 0x8f, 0x98, 0xcf, 0x42, 0x97, 0xb3, 0x8f, 0xf4, 0x73, 0x18, 0xf0, 0x00, 0xdf, 0x90, 0x17,
+	0xd6, 0xa3, 0x91, 0xc7, 0x3f, 0xc5, 0x43, 0x7a, 0x16, 0x4c, 0xec, 0x51, 0x30, 0x0a, 0x6c, 0x71,
+	0x3f, 0x8c, 0xcf, 0xc5, 0x9f, 0xf8, 0x11, 0x5f, 0x99, 0xaf, 0xfb, 0x5b, 0x87, 0xd6, 0xab, 0x60,
+	0xe2, 0x7a, 0xfe, 0x61, 0x06, 0x88, 0xf0, 0x4b, 0x58, 0xbb, 0x60, 0x49, 0x64, 0xa2, 0x8e, 0xde,
+	0x6b, 0xee, 0xdf, 0xa3, 0x92, 0x4c, 0xcb, 0x32, 0x3a, 0x60, 0x49, 0x74, 0xe0, 0xf3, 0x30, 0xe9,
+	0x6f, 0x4d, 0xaf, 0x77, 0xb5, 0xf4, 0x7a, 0x77, 0x6d, 0x7e, 0xe4, 0x08, 0x33, 0x1e, 0xc0, 0xc6,
+	0x17, 0x77, 0x1c, 0xb3, 0xc8, 0x6c, 0x08, 0xcc, 0xfd, 0x3a, 0xcc, 0x5b, 0xa1, 0xca, 0x40, 0x2d,
+	0x09, 0xda, 0xc8, 0x0e, 0x1d, 0x89, 0xc0, 0xef, 0xc0, 0xf0, 0xfc, 0x88, 0xbb, 0xfe, 0x19, 0x8b,
+	0x4c, 0x5d, 0xf0, 0xf6, 0xea, 0x78, 0x47, 0xb9, 0x30, 0x43, 0xde, 0x94, 0x48, 0x43, 0x9d, 0x3b,
+	0x0b, 0x96, 0xf5, 0x1a, 0x0c, 0xd5, 0x06, 0xde, 0x01, 0xfd, 0x82, 0x25, 0x26, 0xea, 0xa0, 0x9e,
+	0xe1, 0xcc, 0x3f, 0xf1, 0x43, 0x58, 0x17, 0x09, 0xcc, 0x46, 0x07, 0xf5, 0x9a, 0xfb, 0xb7, 0x55,
+	0xcd, 0x01, 0x4b, 0x64, 0xc1, 0x13, 0xc6, 0x9d, 0x4c, 0xf4, 0xb4, 0xf1, 0x04, 0x59, 0x27, 0xd0,
+	0x2c, 0x34, 0x54, 0x81, 0xa4, 0x65, 0xa4, 0xa9, 0x90, 0xc2, 0x56, 0x0d, 0x7d, 0x0f, 0xad, 0x72,
+	0x57, 0x15, 0xdc, 0xc7, 0x65, 0xee, 0x5d, 0xc5, 0xcd, 0x9d, 0x95, 0xe8, 0xee, 0x0f, 0x04, 0xed,
+	0x25, 0x05, 0x3e, 0x05, 0x70, 0x39, 0x0f, 0xbd, 0x61, 0xcc, 0x59, 0xbe, 0x05, 0xbd, 0x3a, 0x1e,
+	0x7d, 0xa1, 0xa4, 0xd9, 0xc0, 0xb1, 0x1c, 0x38, 0x2c, 0x2e, 0x9c, 0x02, 0xcf, 0x7a, 0x0e, 0xed,
+	0x25, 0x4b, 0x45, 0x37, 0xb7, 0x8a, 0xdd, 0x18, 0xc5, 0xc0, 0xa7, 0x80, 0x57, 0x3b, 0xc2, 0x87,
+	0xb0, 0xc9, 0xc6, 0x6c, 0xc2, 0x7c, 0x9e, 0x07, 0x36, 0xeb, 0x02, 0xf7, 0x77, 0x64, 0xc0, 0xcd,
+	0x03, 0xe9, 0x70, 0x94, 0x77, 0x3e, 0x8e, 0xed, 0xd2, 0xdb, 0x62, 0x67, 0x85, 0xfc, 0xa0, 0x7a,
+	0x0b, 0x68, 0x8e, 0xcb, 0xc6, 0xf0, 0x97, 0x2a, 0xd6, 0x11, 0x6c, 0x97, 0xc4, 0x15, 0x03, 0xe8,
+	0x96, 0x9f, 0x73, 0x4b, 0xd5, 0x3c, 0xf6, 0xc6, 0xc5, 0x71, 0xac, 0x83, 0x7e, 0xec, 0x8d, 0xbb,
+	0xdf, 0x11, 0xb4, 0x97, 0x16, 0x08, 0xbf, 0x59, 0x49, 0xbe, 0x57, 0xb7, 0x6c, 0xff, 0x91, 0xfd,
+	0xd9, 0xbf, 0xb3, 0xd7, 0x3e, 0x5e, 0xdf, 0x9e, 0xce, 0x88, 0x76, 0x39, 0x23, 0xda, 0xd5, 0x8c,
+	0x68, 0x5f, 0x53, 0x82, 0xa6, 0x29, 0x41, 0x97, 0x29, 0x41, 0x57, 0x29, 0x41, 0x3f, 0x53, 0x82,
+	0xbe, 0xfd, 0x22, 0xda, 0x07, 0x83, 0xda, 0x32, 0xe7, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x83,
+	0x7e, 0xe5, 0x1f, 0xef, 0x04, 0x00, 0x00,
 }
 
 func (m *DomainFeatures) Marshal() (dAtA []byte, err error) {
diff --git a/pkg/apis/nfd/v1alpha1/expression.go b/pkg/apis/nfd/v1alpha1/expression.go
index 41a032b40..b0e1f5884 100644
--- a/pkg/apis/nfd/v1alpha1/expression.go
+++ b/pkg/apis/nfd/v1alpha1/expression.go
@@ -45,16 +45,6 @@ var matchOps = map[MatchOp]struct{}{
 
 type valueRegexpCache []*regexp.Regexp
 
-// NewMatchExpressionSet returns a new MatchExpressionSet instance.
-func NewMatchExpressionSet() *MatchExpressionSet {
-	return &MatchExpressionSet{Expressions: make(Expressions)}
-}
-
-// Len returns the number of expressions.
-func (e *Expressions) Len() int {
-	return len(*e)
-}
-
 // CreateMatchExpression creates a new MatchExpression instance. Returns an
 // error if validation fails.
 func CreateMatchExpression(op MatchOp, values ...string) (*MatchExpression, error) {
@@ -329,9 +319,9 @@ type MatchedKey struct {
 // an empty MatchExpressionSet and an empty set of keys returns an empty slice
 // which is not nil and is treated as a match.
 func (m *MatchExpressionSet) MatchGetKeys(keys map[string]feature.Nil) (bool, []MatchedKey, error) {
-	ret := make([]MatchedKey, 0, m.Len())
+	ret := make([]MatchedKey, 0, len(*m))
 
-	for n, e := range (*m).Expressions {
+	for n, e := range *m {
 		match, err := e.MatchKeys(n, keys)
 		if err != nil {
 			return false, nil, err
@@ -364,9 +354,9 @@ type MatchedValue struct {
 // MatchExpressionSet and an empty set of values returns an empty non-nil map
 // which is treated as a match.
 func (m *MatchExpressionSet) MatchGetValues(values map[string]string) (bool, []MatchedValue, error) {
-	ret := make([]MatchedValue, 0, m.Len())
+	ret := make([]MatchedValue, 0, len(*m))
 
-	for n, e := range (*m).Expressions {
+	for n, e := range *m {
 		match, err := e.MatchValues(n, values)
 		if err != nil {
 			return false, nil, err
@@ -411,7 +401,7 @@ func (m *MatchExpressionSet) MatchGetInstances(instances []feature.InstanceFeatu
 
 // UnmarshalJSON implements the Unmarshaler interface of "encoding/json".
 func (m *MatchExpressionSet) UnmarshalJSON(data []byte) error {
-	*m = *NewMatchExpressionSet()
+	*m = MatchExpressionSet{}
 
 	names := make([]string, 0)
 	if err := json.Unmarshal(data, &names); err == nil {
@@ -419,9 +409,9 @@ func (m *MatchExpressionSet) UnmarshalJSON(data []byte) error {
 		for _, name := range names {
 			split := strings.SplitN(name, "=", 2)
 			if len(split) == 1 {
-				(*m).Expressions[split[0]] = newMatchExpression(MatchExists)
+				(*m)[split[0]] = newMatchExpression(MatchExists)
 			} else {
-				(*m).Expressions[split[0]] = newMatchExpression(MatchIn, split[1])
+				(*m)[split[0]] = newMatchExpression(MatchIn, split[1])
 			}
 		}
 	} else {
@@ -432,9 +422,9 @@ func (m *MatchExpressionSet) UnmarshalJSON(data []byte) error {
 		}
 		for k, v := range expressions {
 			if v != nil {
-				(*m).Expressions[k] = v
+				(*m)[k] = v
 			} else {
-				(*m).Expressions[k] = newMatchExpression(MatchExists)
+				(*m)[k] = newMatchExpression(MatchExists)
 			}
 		}
 	}
diff --git a/pkg/apis/nfd/v1alpha1/types.go b/pkg/apis/nfd/v1alpha1/types.go
index b8982b49e..dafdaf851 100644
--- a/pkg/apis/nfd/v1alpha1/types.go
+++ b/pkg/apis/nfd/v1alpha1/types.go
@@ -111,12 +111,9 @@ type FeatureMatcherTerm struct {
 
 // MatchExpressionSet contains a set of MatchExpressions, each of which is
 // evaluated against a set of input values.
-type MatchExpressionSet struct {
-	Expressions `json:",inline"`
-}
+type MatchExpressionSet map[string]*MatchExpression
 
 // Expressions is a helper type to work around issues with k8s deepcopy-gen
-type Expressions map[string]*MatchExpression
 
 // MatchExpression specifies an expression to evaluate against a set of input
 // values. It contains an operator that is applied when matching the input and
diff --git a/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go
index ece20769a..ff8f19f12 100644
--- a/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go
@@ -9,35 +9,6 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 )
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in Expressions) DeepCopyInto(out *Expressions) {
-	{
-		in := &in
-		*out = make(Expressions, len(*in))
-		for key, val := range *in {
-			var outVal *MatchExpression
-			if val == nil {
-				(*out)[key] = nil
-			} else {
-				in, out := &val, &outVal
-				*out = new(MatchExpression)
-				(*in).DeepCopyInto(*out)
-			}
-			(*out)[key] = outVal
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Expressions.
-func (in Expressions) DeepCopy() Expressions {
-	if in == nil {
-		return nil
-	}
-	out := new(Expressions)
-	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) {
 	{
@@ -62,7 +33,21 @@ func (in FeatureMatcher) DeepCopy() FeatureMatcher {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *FeatureMatcherTerm) DeepCopyInto(out *FeatureMatcherTerm) {
 	*out = *in
-	in.MatchExpressions.DeepCopyInto(&out.MatchExpressions)
+	if in.MatchExpressions != nil {
+		in, out := &in.MatchExpressions, &out.MatchExpressions
+		*out = make(MatchExpressionSet, len(*in))
+		for key, val := range *in {
+			var outVal *MatchExpression
+			if val == nil {
+				(*out)[key] = nil
+			} else {
+				in, out := &val, &outVal
+				*out = new(MatchExpression)
+				(*in).DeepCopyInto(*out)
+			}
+			(*out)[key] = outVal
+		}
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeatureMatcherTerm.
@@ -119,11 +104,10 @@ func (in *MatchExpression) DeepCopy() *MatchExpression {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MatchExpressionSet) DeepCopyInto(out *MatchExpressionSet) {
-	*out = *in
-	if in.Expressions != nil {
-		in, out := &in.Expressions, &out.Expressions
-		*out = make(Expressions, len(*in))
+func (in MatchExpressionSet) DeepCopyInto(out *MatchExpressionSet) {
+	{
+		in := &in
+		*out = make(MatchExpressionSet, len(*in))
 		for key, val := range *in {
 			var outVal *MatchExpression
 			if val == nil {
@@ -139,13 +123,13 @@ func (in *MatchExpressionSet) DeepCopyInto(out *MatchExpressionSet) {
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchExpressionSet.
-func (in *MatchExpressionSet) DeepCopy() *MatchExpressionSet {
+func (in MatchExpressionSet) DeepCopy() MatchExpressionSet {
 	if in == nil {
 		return nil
 	}
 	out := new(MatchExpressionSet)
 	in.DeepCopyInto(out)
-	return out
+	return *out
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go
index 75330a9d9..e61b0938b 100644
--- a/pkg/generated/clientset/versioned/clientset.go
+++ b/pkg/generated/clientset/versioned/clientset.go
@@ -20,6 +20,7 @@ package versioned
 
 import (
 	"fmt"
+	"net/http"
 
 	discovery "k8s.io/client-go/discovery"
 	rest "k8s.io/client-go/rest"
@@ -55,22 +56,45 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface {
 // NewForConfig creates a new Clientset for the given config.
 // If config's RateLimiter is not set and QPS and Burst are acceptable,
 // NewForConfig will generate a rate-limiter in configShallowCopy.
+// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
+// where httpClient was generated with rest.HTTPClientFor(c).
 func NewForConfig(c *rest.Config) (*Clientset, error) {
 	configShallowCopy := *c
+
+	if configShallowCopy.UserAgent == "" {
+		configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent()
+	}
+
+	// share the transport between all clients
+	httpClient, err := rest.HTTPClientFor(&configShallowCopy)
+	if err != nil {
+		return nil, err
+	}
+
+	return NewForConfigAndClient(&configShallowCopy, httpClient)
+}
+
+// NewForConfigAndClient creates a new Clientset for the given config and http client.
+// Note the http client provided takes precedence over the configured transport values.
+// If config's RateLimiter is not set and QPS and Burst are acceptable,
+// NewForConfigAndClient will generate a rate-limiter in configShallowCopy.
+func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) {
+	configShallowCopy := *c
 	if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
 		if configShallowCopy.Burst <= 0 {
 			return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
 		}
 		configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
 	}
+
 	var cs Clientset
 	var err error
-	cs.nfdV1alpha1, err = nfdv1alpha1.NewForConfig(&configShallowCopy)
+	cs.nfdV1alpha1, err = nfdv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
 	if err != nil {
 		return nil, err
 	}
 
-	cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
+	cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient)
 	if err != nil {
 		return nil, err
 	}
@@ -80,11 +104,11 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
 // NewForConfigOrDie creates a new Clientset for the given config and
 // panics if there is an error in the config.
 func NewForConfigOrDie(c *rest.Config) *Clientset {
-	var cs Clientset
-	cs.nfdV1alpha1 = nfdv1alpha1.NewForConfigOrDie(c)
-
-	cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
-	return &cs
+	cs, err := NewForConfig(c)
+	if err != nil {
+		panic(err)
+	}
+	return cs
 }
 
 // New creates a new Clientset for the given RESTClient.
diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/pkg/generated/clientset/versioned/fake/clientset_generated.go
index a38a480cf..9ba9e8390 100644
--- a/pkg/generated/clientset/versioned/fake/clientset_generated.go
+++ b/pkg/generated/clientset/versioned/fake/clientset_generated.go
@@ -74,7 +74,10 @@ func (c *Clientset) Tracker() testing.ObjectTracker {
 	return c.tracker
 }
 
-var _ clientset.Interface = &Clientset{}
+var (
+	_ clientset.Interface = &Clientset{}
+	_ testing.FakeClient  = &Clientset{}
+)
 
 // NfdV1alpha1 retrieves the NfdV1alpha1Client
 func (c *Clientset) NfdV1alpha1() nfdv1alpha1.NfdV1alpha1Interface {
diff --git a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go
index b4afd87f9..158ff71a1 100644
--- a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go
+++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/fake/fake_nodefeaturerule.go
@@ -99,7 +99,7 @@ func (c *FakeNodeFeatureRules) Update(ctx context.Context, nodeFeatureRule *v1al
 // Delete takes name of the nodeFeatureRule and deletes it. Returns an error if one occurs.
 func (c *FakeNodeFeatureRules) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
 	_, err := c.Fake.
-		Invokes(testing.NewRootDeleteAction(nodefeaturerulesResource, name), &v1alpha1.NodeFeatureRule{})
+		Invokes(testing.NewRootDeleteActionWithOptions(nodefeaturerulesResource, name, opts), &v1alpha1.NodeFeatureRule{})
 	return err
 }
 
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 653f75df2..034d5cbe7 100644
--- a/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go
+++ b/pkg/generated/clientset/versioned/typed/nfd/v1alpha1/nfd_client.go
@@ -19,6 +19,8 @@ limitations under the License.
 package v1alpha1
 
 import (
+	"net/http"
+
 	rest "k8s.io/client-go/rest"
 	v1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/generated/clientset/versioned/scheme"
@@ -39,12 +41,28 @@ func (c *NfdV1alpha1Client) NodeFeatureRules() NodeFeatureRuleInterface {
 }
 
 // NewForConfig creates a new NfdV1alpha1Client for the given config.
+// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
+// where httpClient was generated with rest.HTTPClientFor(c).
 func NewForConfig(c *rest.Config) (*NfdV1alpha1Client, error) {
 	config := *c
 	if err := setConfigDefaults(&config); err != nil {
 		return nil, err
 	}
-	client, err := rest.RESTClientFor(&config)
+	httpClient, err := rest.HTTPClientFor(&config)
+	if err != nil {
+		return nil, err
+	}
+	return NewForConfigAndClient(&config, httpClient)
+}
+
+// NewForConfigAndClient creates a new NfdV1alpha1Client for the given config and http client.
+// Note the http client provided takes precedence over the configured transport values.
+func NewForConfigAndClient(c *rest.Config, h *http.Client) (*NfdV1alpha1Client, error) {
+	config := *c
+	if err := setConfigDefaults(&config); err != nil {
+		return nil, err
+	}
+	client, err := rest.RESTClientForConfigAndClient(&config, h)
 	if err != nil {
 		return nil, err
 	}
diff --git a/source/custom/static_features.go b/source/custom/static_features.go
index db1856c9f..fed8a22c5 100644
--- a/source/custom/static_features.go
+++ b/source/custom/static_features.go
@@ -32,9 +32,7 @@ func getStaticFeatureConfig() []CustomRule {
 					{
 						PciID: &rules.PciIDRule{
 							MatchExpressionSet: nfdv1alpha1.MatchExpressionSet{
-								Expressions: nfdv1alpha1.Expressions{
-									"vendor": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "15b3"),
-								},
+								"vendor": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchIn, "15b3"),
 							},
 						},
 					},
@@ -48,10 +46,8 @@ func getStaticFeatureConfig() []CustomRule {
 					{
 						LoadedKMod: &rules.LoadedKModRule{
 							MatchExpressionSet: nfdv1alpha1.MatchExpressionSet{
-								Expressions: nfdv1alpha1.Expressions{
-									"ib_uverbs": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists),
-									"rdma_ucm":  nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists),
-								},
+								"ib_uverbs": nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists),
+								"rdma_ucm":  nfdv1alpha1.MustCreateMatchExpression(nfdv1alpha1.MatchExists),
 							},
 						},
 					},


Test patch:
diff --git a/pkg/apis/nfd/v1alpha1/rule_test.go b/pkg/apis/nfd/v1alpha1/rule_test.go
index 87d9c7b3b..144999cdb 100644
--- a/pkg/apis/nfd/v1alpha1/rule_test.go
+++ b/pkg/apis/nfd/v1alpha1/rule_test.go
@@ -33,7 +33,7 @@ func TestRule(t *testing.T) {
 			FeatureMatcherTerm{
 				Feature: "domain-1.kf-1",
 				MatchExpressions: MatchExpressionSet{
-					Expressions: Expressions{"key-1": MustCreateMatchExpression(MatchExists)},
+					"key-1": MustCreateMatchExpression(MatchExists),
 				},
 			},
 		},
@@ -111,7 +111,7 @@ func TestRule(t *testing.T) {
 			FeatureMatcherTerm{
 				Feature: "domain-1.vf-1",
 				MatchExpressions: MatchExpressionSet{
-					Expressions: Expressions{"key-1": MustCreateMatchExpression(MatchIn, "val-1")},
+					"key-1": MustCreateMatchExpression(MatchIn, "val-1"),
 				},
 			},
 		},
@@ -132,7 +132,7 @@ func TestRule(t *testing.T) {
 			FeatureMatcherTerm{
 				Feature: "domain-1.if-1",
 				MatchExpressions: MatchExpressionSet{
-					Expressions: Expressions{"attr-1": MustCreateMatchExpression(MatchIn, "val-1")},
+					"attr-1": MustCreateMatchExpression(MatchIn, "val-1"),
 				},
 			},
 		},
@@ -153,13 +153,13 @@ func TestRule(t *testing.T) {
 			FeatureMatcherTerm{
 				Feature: "domain-1.vf-1",
 				MatchExpressions: MatchExpressionSet{
-					Expressions: Expressions{"key-1": MustCreateMatchExpression(MatchIn, "val-x")},
+					"key-1": MustCreateMatchExpression(MatchIn, "val-x"),
 				},
 			},
 			FeatureMatcherTerm{
 				Feature: "domain-1.if-1",
 				MatchExpressions: MatchExpressionSet{
-					Expressions: Expressions{"attr-1": MustCreateMatchExpression(MatchIn, "val-1")},
+					"attr-1": MustCreateMatchExpression(MatchIn, "val-1"),
 				},
 			},
 		},
@@ -168,7 +168,7 @@ func TestRule(t *testing.T) {
 	assert.Nilf(t, err, "unexpected error: %v", err)
 	assert.Nil(t, m.Labels, "instances should not have matched")
 
-	r5.MatchFeatures[0].MatchExpressions.Expressions["key-1"] = MustCreateMatchExpression(MatchIn, "val-1")
+	r5.MatchFeatures[0].MatchExpressions["key-1"] = MustCreateMatchExpression(MatchIn, "val-1")
 	m, err = r5.Execute(f)
 	assert.Nilf(t, err, "unexpected error: %v", err)
 	assert.Equal(t, r5.Labels, m.Labels, "instances should have matched")
@@ -180,7 +180,7 @@ func TestRule(t *testing.T) {
 				FeatureMatcherTerm{
 					Feature: "domain-1.kf-1",
 					MatchExpressions: MatchExpressionSet{
-						Expressions: Expressions{"key-na": MustCreateMatchExpression(MatchExists)},
+						"key-na": MustCreateMatchExpression(MatchExists),
 					},
 				},
 			},
@@ -196,12 +196,12 @@ func TestRule(t *testing.T) {
 				FeatureMatcherTerm{
 					Feature: "domain-1.kf-1",
 					MatchExpressions: MatchExpressionSet{
-						Expressions: Expressions{"key-1": MustCreateMatchExpression(MatchExists)},
+						"key-1": MustCreateMatchExpression(MatchExists),
 					},
 				},
 			},
 		})
-	r5.MatchFeatures[0].MatchExpressions.Expressions["key-1"] = MustCreateMatchExpression(MatchIn, "val-1")
+	r5.MatchFeatures[0].MatchExpressions["key-1"] = MustCreateMatchExpression(MatchIn, "val-1")
 	m, err = r5.Execute(f)
 	assert.Nilf(t, err, "unexpected error: %v", err)
 	assert.Equal(t, r5.Labels, m.Labels, "instances should have matched")
@@ -275,27 +275,24 @@ var-2=
 		MatchFeatures: FeatureMatcher{
 			FeatureMatcherTerm{
 				Feature: "domain_1.kf_1",
-				MatchExpressions: MatchExpressionSet{Expressions: Expressions{
+				MatchExpressions: MatchExpressionSet{
 					"key-a": MustCreateMatchExpression(MatchExists),
 					"key-c": MustCreateMatchExpression(MatchExists),
 					"foo":   MustCreateMatchExpression(MatchDoesNotExist),
 				},
-				},
 			},
 			FeatureMatcherTerm{
 				Feature: "domain_1.vf_1",
-				MatchExpressions: MatchExpressionSet{Expressions: Expressions{
+				MatchExpressions: MatchExpressionSet{
 					"key-1": MustCreateMatchExpression(MatchIn, "val-1", "val-2"),
 					"bar":   MustCreateMatchExpression(MatchDoesNotExist),
 				},
-				},
 			},
 			FeatureMatcherTerm{
 				Feature: "domain_1.if_1",
-				MatchExpressions: MatchExpressionSet{Expressions: Expressions{
+				MatchExpressions: MatchExpressionSet{
 					"attr-1": MustCreateMatchExpression(MatchLt, "100"),
 				},
-				},
 			},
 		},
 	}
@@ -337,10 +334,9 @@ var-2=
 			// Use a simple empty matchexpression set to match anything.
 			FeatureMatcherTerm{
 				Feature: "domain_1.kf_1",
-				MatchExpressions: MatchExpressionSet{Expressions: Expressions{
+				MatchExpressions: MatchExpressionSet{
 					"key-a": MustCreateMatchExpression(MatchExists),
 				},
-				},
 			},
 		},
 	}