1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-28 10:47:23 +00:00

Merge pull request #925 from marquiz/devel/feature-api-flatten

apis/nfd: flatten the structure of features data type
This commit is contained in:
Kubernetes Prow Robot 2022-10-24 01:14:26 -07:00 committed by GitHub
commit a65ee959b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 1006 additions and 364 deletions

View file

@ -0,0 +1,334 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: nodefeatures.nfd.k8s-sigs.io
spec:
group: nfd.k8s-sigs.io
names:
kind: NodeFeature
listKind: NodeFeatureList
plural: nodefeatures
singular: nodefeature
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: NodeFeature resource holds the features discovered for one node
in the cluster.
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: NodeFeatureSpec describes a NodeFeature object.
properties:
domains:
description: Features is a list per-domain feature sets. This is the
full "raw" features data that nfd-worker has discovered.
items:
description: DomainFeatures is the collection of all discovered
features of one domain.
properties:
attributes:
additionalProperties:
description: AttributeFeatureSet is a set of features having
string value.
properties:
elements:
additionalProperties:
type: string
type: object
required:
- elements
type: object
type: object
flags:
additionalProperties:
description: FlagFeatureSet is a set of simple features only
containing names without values.
properties:
elements:
additionalProperties:
description: Nil is a dummy empty struct for protobuf
compatibility
type: object
type: object
required:
- elements
type: object
type: object
instances:
additionalProperties:
description: InstanceFeatureSet is a set of features each
of which is an instance having multiple attributes.
properties:
elements:
items:
description: InstanceFeature represents one instance
of a complex features, e.g. a device.
properties:
attributes:
additionalProperties:
type: string
type: object
required:
- attributes
type: object
type: array
required:
- elements
type: object
type: object
name:
type: string
required:
- attributes
- flags
- instances
- name
type: object
type: array
labelsRequest:
additionalProperties:
type: string
description: LabelsRequest is the set of node labels that are requested
to be generatd.
type: object
required:
- domains
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.9.2
creationTimestamp: null
name: nodefeaturerules.nfd.k8s-sigs.io
spec:
group: nfd.k8s-sigs.io
names:
kind: NodeFeatureRule
listKind: NodeFeatureRuleList
plural: nodefeaturerules
singular: nodefeaturerule
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: NodeFeatureRule resource specifies a configuration for feature-based
customization of node objects, such as node labeling.
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: NodeFeatureRuleSpec describes a NodeFeatureRule.
properties:
rules:
description: Rules is a list of node customization rules.
items:
description: Rule defines a rule for node customization such as
labeling.
properties:
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 (<key>[=<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. 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. 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
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 (<key>[=<value>])
separated by newlines.
type: string
required:
- name
type: object
type: array
required:
- rules
type: object
required:
- spec
type: object
served: true
storage: true

View file

@ -0,0 +1,334 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: nodefeatures.nfd.k8s-sigs.io
spec:
group: nfd.k8s-sigs.io
names:
kind: NodeFeature
listKind: NodeFeatureList
plural: nodefeatures
singular: nodefeature
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: NodeFeature resource holds the features discovered for one node
in the cluster.
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: NodeFeatureSpec describes a NodeFeature object.
properties:
domains:
description: Features is a list per-domain feature sets. This is the
full "raw" features data that nfd-worker has discovered.
items:
description: DomainFeatures is the collection of all discovered
features of one domain.
properties:
attributes:
additionalProperties:
description: AttributeFeatureSet is a set of features having
string value.
properties:
elements:
additionalProperties:
type: string
type: object
required:
- elements
type: object
type: object
flags:
additionalProperties:
description: FlagFeatureSet is a set of simple features only
containing names without values.
properties:
elements:
additionalProperties:
description: Nil is a dummy empty struct for protobuf
compatibility
type: object
type: object
required:
- elements
type: object
type: object
instances:
additionalProperties:
description: InstanceFeatureSet is a set of features each
of which is an instance having multiple attributes.
properties:
elements:
items:
description: InstanceFeature represents one instance
of a complex features, e.g. a device.
properties:
attributes:
additionalProperties:
type: string
type: object
required:
- attributes
type: object
type: array
required:
- elements
type: object
type: object
name:
type: string
required:
- attributes
- flags
- instances
- name
type: object
type: array
labelsRequest:
additionalProperties:
type: string
description: LabelsRequest is the set of node labels that are requested
to be generatd.
type: object
required:
- domains
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.9.2
creationTimestamp: null
name: nodefeaturerules.nfd.k8s-sigs.io
spec:
group: nfd.k8s-sigs.io
names:
kind: NodeFeatureRule
listKind: NodeFeatureRuleList
plural: nodefeaturerules
singular: nodefeaturerule
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: NodeFeatureRule resource specifies a configuration for feature-based
customization of node objects, such as node labeling.
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: NodeFeatureRuleSpec describes a NodeFeatureRule.
properties:
rules:
description: Rules is a list of node customization rules.
items:
description: Rule defines a rule for node customization such as
labeling.
properties:
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 (<key>[=<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. 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. 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
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 (<key>[=<value>])
separated by newlines.
type: string
required:
- name
type: object
type: array
required:
- rules
type: object
required:
- spec
type: object
served: true
storage: true

View file

@ -6,7 +6,7 @@ import (
mock "github.com/stretchr/testify/mock"
kubernetes "k8s.io/client-go/kubernetes"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
versioned "github.com/k8stopologyawareschedwg/noderesourcetopology-api/pkg/generated/clientset/versioned"
)
@ -40,15 +40,15 @@ func (_m *MockAPIHelpers) GetClient() (*kubernetes.Clientset, error) {
}
// GetNode provides a mock function with given fields: _a0, _a1
func (_m *MockAPIHelpers) GetNode(_a0 *kubernetes.Clientset, _a1 string) (*corev1.Node, error) {
func (_m *MockAPIHelpers) GetNode(_a0 *kubernetes.Clientset, _a1 string) (*v1.Node, error) {
ret := _m.Called(_a0, _a1)
var r0 *corev1.Node
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset, string) *corev1.Node); ok {
var r0 *v1.Node
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset, string) *v1.Node); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*corev1.Node)
r0 = ret.Get(0).(*v1.Node)
}
}
@ -63,15 +63,15 @@ func (_m *MockAPIHelpers) GetNode(_a0 *kubernetes.Clientset, _a1 string) (*corev
}
// GetNodes provides a mock function with given fields: _a0
func (_m *MockAPIHelpers) GetNodes(_a0 *kubernetes.Clientset) (*corev1.NodeList, error) {
func (_m *MockAPIHelpers) GetNodes(_a0 *kubernetes.Clientset) (*v1.NodeList, error) {
ret := _m.Called(_a0)
var r0 *corev1.NodeList
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset) *corev1.NodeList); ok {
var r0 *v1.NodeList
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset) *v1.NodeList); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*corev1.NodeList)
r0 = ret.Get(0).(*v1.NodeList)
}
}
@ -86,15 +86,15 @@ func (_m *MockAPIHelpers) GetNodes(_a0 *kubernetes.Clientset) (*corev1.NodeList,
}
// GetPod provides a mock function with given fields: _a0, _a1, _a2
func (_m *MockAPIHelpers) GetPod(_a0 *kubernetes.Clientset, _a1 string, _a2 string) (*corev1.Pod, error) {
func (_m *MockAPIHelpers) GetPod(_a0 *kubernetes.Clientset, _a1 string, _a2 string) (*v1.Pod, error) {
ret := _m.Called(_a0, _a1, _a2)
var r0 *corev1.Pod
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset, string, string) *corev1.Pod); ok {
var r0 *v1.Pod
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset, string, string) *v1.Pod); ok {
r0 = rf(_a0, _a1, _a2)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*corev1.Pod)
r0 = ret.Get(0).(*v1.Pod)
}
}
@ -160,11 +160,11 @@ func (_m *MockAPIHelpers) PatchNodeStatus(_a0 *kubernetes.Clientset, _a1 string,
}
// UpdateNode provides a mock function with given fields: _a0, _a1
func (_m *MockAPIHelpers) UpdateNode(_a0 *kubernetes.Clientset, _a1 *corev1.Node) error {
func (_m *MockAPIHelpers) UpdateNode(_a0 *kubernetes.Clientset, _a1 *v1.Node) error {
ret := _m.Called(_a0, _a1)
var r0 error
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset, *corev1.Node) error); ok {
if rf, ok := ret.Get(0).(func(*kubernetes.Clientset, *v1.Node) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)

View file

@ -16,10 +16,10 @@ limitations under the License.
package v1alpha1
// NewDomainFeatures creates a new instance of Features, initializing specified
// features to empty values
func NewDomainFeatures() *DomainFeatures {
return &DomainFeatures{
// NewFeatures creates a new instance of Features, initializing all feature
// types (flags, attributes and instances) to empty values.
func NewFeatures() *Features {
return &Features{
Flags: make(map[string]FlagFeatureSet),
Attributes: make(map[string]AttributeFeatureSet),
Instances: make(map[string]InstanceFeatureSet)}
@ -56,16 +56,29 @@ func NewInstanceFeature(attrs map[string]string) *InstanceFeature {
}
// InsertAttributeFeatures inserts new values into a specific feature.
func InsertAttributeFeatures(f Features, domain, feature string, values map[string]string) {
if _, ok := f[domain]; !ok {
f[domain] = NewDomainFeatures()
}
if _, ok := f[domain].Attributes[feature]; !ok {
f[domain].Attributes[feature] = NewAttributeFeatures(values)
func (f *Features) InsertAttributeFeatures(domain, feature string, values map[string]string) {
key := domain + "." + feature
if _, ok := f.Attributes[key]; !ok {
f.Attributes[key] = NewAttributeFeatures(values)
return
}
for k, v := range values {
f[domain].Attributes[feature].Elements[k] = v
f.Attributes[key].Elements[k] = v
}
}
// Exists returns a non-empty string if a feature exists. The return value is
// the type of the feautre, i.e. "flag", "attribute" or "instance".
func (f *Features) Exists(name string) string {
if _, ok := f.Flags[name]; ok {
return "flag"
}
if _, ok := f.Attributes[name]; ok {
return "attribute"
}
if _, ok := f.Instances[name]; ok {
return "instance"
}
return ""
}

View file

@ -71,15 +71,15 @@ func (m *AttributeFeatureSet) XXX_DiscardUnknown() {
var xxx_messageInfo_AttributeFeatureSet proto.InternalMessageInfo
func (m *DomainFeatures) Reset() { *m = DomainFeatures{} }
func (*DomainFeatures) ProtoMessage() {}
func (*DomainFeatures) Descriptor() ([]byte, []int) {
func (m *Features) Reset() { *m = Features{} }
func (*Features) ProtoMessage() {}
func (*Features) Descriptor() ([]byte, []int) {
return fileDescriptor_6f67d44e41cfe439, []int{1}
}
func (m *DomainFeatures) XXX_Unmarshal(b []byte) error {
func (m *Features) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *DomainFeatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
func (m *Features) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
@ -87,17 +87,17 @@ func (m *DomainFeatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro
}
return b[:n], nil
}
func (m *DomainFeatures) XXX_Merge(src proto.Message) {
xxx_messageInfo_DomainFeatures.Merge(m, src)
func (m *Features) XXX_Merge(src proto.Message) {
xxx_messageInfo_Features.Merge(m, src)
}
func (m *DomainFeatures) XXX_Size() int {
func (m *Features) XXX_Size() int {
return m.Size()
}
func (m *DomainFeatures) XXX_DiscardUnknown() {
xxx_messageInfo_DomainFeatures.DiscardUnknown(m)
func (m *Features) XXX_DiscardUnknown() {
xxx_messageInfo_Features.DiscardUnknown(m)
}
var xxx_messageInfo_DomainFeatures proto.InternalMessageInfo
var xxx_messageInfo_Features proto.InternalMessageInfo
func (m *FlagFeatureSet) Reset() { *m = FlagFeatureSet{} }
func (*FlagFeatureSet) ProtoMessage() {}
@ -214,10 +214,10 @@ var xxx_messageInfo_Nil proto.InternalMessageInfo
func init() {
proto.RegisterType((*AttributeFeatureSet)(nil), "v1alpha1.AttributeFeatureSet")
proto.RegisterMapType((map[string]string)(nil), "v1alpha1.AttributeFeatureSet.ElementsEntry")
proto.RegisterType((*DomainFeatures)(nil), "v1alpha1.DomainFeatures")
proto.RegisterMapType((map[string]FlagFeatureSet)(nil), "v1alpha1.DomainFeatures.FlagsEntry")
proto.RegisterMapType((map[string]InstanceFeatureSet)(nil), "v1alpha1.DomainFeatures.InstancesEntry")
proto.RegisterMapType((map[string]AttributeFeatureSet)(nil), "v1alpha1.DomainFeatures.VattributesEntry")
proto.RegisterType((*Features)(nil), "v1alpha1.Features")
proto.RegisterMapType((map[string]FlagFeatureSet)(nil), "v1alpha1.Features.FlagsEntry")
proto.RegisterMapType((map[string]InstanceFeatureSet)(nil), "v1alpha1.Features.InstancesEntry")
proto.RegisterMapType((map[string]AttributeFeatureSet)(nil), "v1alpha1.Features.VattributesEntry")
proto.RegisterType((*FlagFeatureSet)(nil), "v1alpha1.FlagFeatureSet")
proto.RegisterMapType((map[string]Nil)(nil), "v1alpha1.FlagFeatureSet.ElementsEntry")
proto.RegisterType((*InstanceFeature)(nil), "v1alpha1.InstanceFeature")
@ -231,42 +231,41 @@ func init() {
}
var fileDescriptor_6f67d44e41cfe439 = []byte{
// 546 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xcf, 0x6e, 0xd3, 0x40,
0x10, 0xc6, 0xb3, 0x4d, 0x23, 0x25, 0x13, 0x25, 0x0d, 0x0b, 0x07, 0x13, 0x81, 0x5b, 0xa5, 0x12,
0x14, 0xa1, 0xd8, 0x6a, 0xb8, 0x44, 0x20, 0x0e, 0xad, 0x68, 0x29, 0x1c, 0x7a, 0x30, 0x08, 0x41,
0xa5, 0x80, 0x36, 0xc9, 0xc6, 0x5d, 0xc5, 0xb1, 0x23, 0xef, 0x3a, 0x52, 0x6e, 0x3c, 0x02, 0x0f,
0xc1, 0x15, 0x21, 0xf1, 0x14, 0x39, 0xf6, 0xd8, 0x53, 0x45, 0xcc, 0x8b, 0xa0, 0xf8, 0x4f, 0x6c,
0x27, 0x76, 0x2a, 0xb8, 0xed, 0x4e, 0xbe, 0xf9, 0xcd, 0xcc, 0xb7, 0x13, 0xc3, 0x19, 0x67, 0x3a,
0x57, 0x86, 0x6d, 0xae, 0x30, 0x4b, 0x35, 0xad, 0x3e, 0x6d, 0x0e, 0x28, 0x11, 0x8e, 0x4d, 0x9b,
0x7d, 0xc6, 0x7b, 0xd6, 0x84, 0xda, 0x53, 0x75, 0x3c, 0xd4, 0x55, 0x32, 0x66, 0x5c, 0x35, 0x07,
0x7d, 0x75, 0x72, 0x48, 0x8c, 0xf1, 0x25, 0x39, 0x54, 0x75, 0x6a, 0x52, 0x9b, 0x08, 0xda, 0x57,
0xc6, 0xb6, 0x25, 0x2c, 0x5c, 0x0c, 0x7f, 0xa9, 0x37, 0x75, 0x26, 0x2e, 0x9d, 0xae, 0xd2, 0xb3,
0x46, 0xaa, 0x6e, 0xe9, 0x96, 0xea, 0x09, 0xba, 0xce, 0xc0, 0xbb, 0x79, 0x17, 0xef, 0xe4, 0x27,
0x36, 0x7e, 0x20, 0xb8, 0x7b, 0x24, 0x84, 0xcd, 0xba, 0x8e, 0xa0, 0xa7, 0x7e, 0xf5, 0x77, 0x54,
0xe0, 0x4f, 0x50, 0xa4, 0x06, 0x1d, 0x51, 0x53, 0x70, 0x09, 0xed, 0xe5, 0x0f, 0xca, 0xad, 0xa7,
0x4a, 0x58, 0x43, 0x49, 0x49, 0x50, 0x4e, 0x02, 0xf5, 0x89, 0x29, 0xec, 0xe9, 0x71, 0x6d, 0x76,
0xb3, 0x9b, 0x73, 0x6f, 0x76, 0x8b, 0x61, 0x58, 0x5b, 0xe2, 0xea, 0x2f, 0xa0, 0x92, 0x10, 0xe3,
0x1a, 0xe4, 0x87, 0x74, 0x2a, 0xa1, 0x3d, 0x74, 0x50, 0xd2, 0x16, 0x47, 0x7c, 0x0f, 0x0a, 0x13,
0x62, 0x38, 0x54, 0xda, 0xf2, 0x62, 0xfe, 0xe5, 0xf9, 0x56, 0x1b, 0x35, 0xbe, 0x6f, 0x43, 0xf5,
0x95, 0x35, 0x22, 0xcc, 0x0c, 0x6a, 0x73, 0x7c, 0x06, 0x85, 0x81, 0x41, 0x74, 0x2e, 0x6d, 0x79,
0x7d, 0xee, 0x47, 0x7d, 0x26, 0x85, 0xca, 0xe9, 0x42, 0xe5, 0xf7, 0x57, 0x09, 0xfa, 0x2b, 0x78,
0x31, 0xcd, 0x07, 0xe0, 0x2f, 0x50, 0x9e, 0x90, 0x70, 0x36, 0x2e, 0xe5, 0x3d, 0xde, 0x93, 0x4c,
0xde, 0x87, 0x48, 0xeb, 0x53, 0x71, 0x40, 0x85, 0xa5, 0x41, 0x5c, 0x8b, 0x13, 0xf1, 0x47, 0x28,
0x31, 0x93, 0x0b, 0x62, 0xf6, 0x28, 0x97, 0xb6, 0x3d, 0xfc, 0xe3, 0x4c, 0xfc, 0x9b, 0x50, 0xe9,
0xc3, 0xef, 0x04, 0xf0, 0xd2, 0x32, 0xae, 0x45, 0xb0, 0xba, 0x06, 0x10, 0x8d, 0x97, 0xe2, 0xa8,
0x12, 0x77, 0xb4, 0xdc, 0x92, 0xa2, 0xaa, 0x8b, 0xb4, 0xe8, 0x1d, 0x63, 0x5e, 0xd7, 0x3b, 0x50,
0x5b, 0x1d, 0x31, 0x85, 0xfc, 0x2c, 0x49, 0x7e, 0xb8, 0x71, 0x4d, 0xe2, 0xf8, 0x0b, 0xa8, 0x26,
0x47, 0x4c, 0x81, 0xb7, 0x92, 0xf0, 0x07, 0x11, 0x3c, 0x4c, 0x4d, 0x65, 0x37, 0x7e, 0x21, 0xa8,
0x26, 0x07, 0xc3, 0xef, 0xd7, 0x36, 0xfa, 0x51, 0x96, 0x09, 0xff, 0xb0, 0xcc, 0x6f, 0x6f, 0x5f,
0xe6, 0xfd, 0xe4, 0x0c, 0x95, 0xa8, 0xea, 0x39, 0x33, 0xe2, 0x4d, 0xff, 0x44, 0xb0, 0xb3, 0x32,
0x16, 0xee, 0x00, 0xc4, 0x36, 0x12, 0xad, 0x6e, 0xe4, 0x8a, 0x3c, 0xb2, 0x7c, 0xc3, 0x46, 0xc6,
0x80, 0xf5, 0x97, 0xb0, 0x73, 0x74, 0xeb, 0x0b, 0x67, 0xff, 0x1b, 0x3b, 0x80, 0xd7, 0xdf, 0x01,
0xbf, 0x5e, 0x73, 0xfa, 0x7e, 0x66, 0xc7, 0x9b, 0xcc, 0x6d, 0x14, 0x20, 0x7f, 0xce, 0x8c, 0xe3,
0xcf, 0xb3, 0xb9, 0x9c, 0xbb, 0x9a, 0xcb, 0xb9, 0xeb, 0xb9, 0x9c, 0xfb, 0xea, 0xca, 0x68, 0xe6,
0xca, 0xe8, 0xca, 0x95, 0xd1, 0xb5, 0x2b, 0xa3, 0xdf, 0xae, 0x8c, 0xbe, 0xfd, 0x91, 0x73, 0x17,
0xed, 0xff, 0xfd, 0x98, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x75, 0x9e, 0xef, 0x0b, 0x87, 0x05,
0x00, 0x00,
// 539 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xcd, 0x6e, 0xda, 0x40,
0x10, 0xc7, 0xbd, 0x50, 0x24, 0x18, 0x44, 0x42, 0xb7, 0x3d, 0xb8, 0x56, 0xe3, 0xa4, 0x44, 0xaa,
0x52, 0x55, 0xd8, 0x0a, 0xbd, 0xa0, 0x56, 0x3d, 0x04, 0x29, 0xe9, 0xc7, 0x21, 0x07, 0xb7, 0xaa,
0x94, 0x48, 0x54, 0x5a, 0x60, 0x71, 0x56, 0x38, 0x36, 0xf2, 0xae, 0x91, 0xb8, 0xf5, 0x01, 0x7a,
0xe8, 0x8b, 0x54, 0x95, 0xfa, 0x14, 0x1c, 0x73, 0xcc, 0x29, 0x2a, 0xee, 0x8b, 0x54, 0xf1, 0x07,
0xb6, 0x83, 0x01, 0x35, 0x37, 0xef, 0xec, 0xcc, 0x6f, 0xe6, 0xff, 0xdf, 0x01, 0x78, 0xcf, 0x99,
0xc9, 0xb5, 0x51, 0x9b, 0x6b, 0xcc, 0xd1, 0x6d, 0x67, 0x40, 0x9b, 0x43, 0x4a, 0x84, 0xe7, 0xd2,
0xe6, 0x80, 0xf1, 0xbe, 0x33, 0xa1, 0xee, 0x54, 0x1f, 0x8f, 0x4c, 0x9d, 0x8c, 0x19, 0xd7, 0xed,
0xe1, 0x40, 0x9f, 0x1c, 0x12, 0x6b, 0x7c, 0x41, 0x0e, 0x75, 0x93, 0xda, 0xd4, 0x25, 0x82, 0x0e,
0xb4, 0xb1, 0xeb, 0x08, 0x07, 0x97, 0xe3, 0x1b, 0xa5, 0x69, 0x32, 0x71, 0xe1, 0xf5, 0xb4, 0xbe,
0x73, 0xa9, 0x9b, 0x8e, 0xe9, 0xe8, 0x41, 0x42, 0xcf, 0x1b, 0x06, 0xa7, 0xe0, 0x10, 0x7c, 0x85,
0x85, 0x8d, 0x9f, 0x08, 0x1e, 0x1d, 0x09, 0xe1, 0xb2, 0x9e, 0x27, 0xe8, 0x49, 0xd8, 0xfd, 0x13,
0x15, 0xf8, 0x0c, 0xca, 0xd4, 0xa2, 0x97, 0xd4, 0x16, 0x5c, 0x46, 0x7b, 0xc5, 0x83, 0x6a, 0xeb,
0xa5, 0x16, 0xf7, 0xd0, 0x72, 0x0a, 0xb4, 0xe3, 0x28, 0xfb, 0xd8, 0x16, 0xee, 0xb4, 0x53, 0x9f,
0xdd, 0xec, 0x4a, 0xfe, 0xcd, 0x6e, 0x39, 0x0e, 0x1b, 0x0b, 0x9c, 0xf2, 0x06, 0x6a, 0x99, 0x64,
0x5c, 0x87, 0xe2, 0x88, 0x4e, 0x65, 0xb4, 0x87, 0x0e, 0x2a, 0xc6, 0xed, 0x27, 0x7e, 0x0c, 0xa5,
0x09, 0xb1, 0x3c, 0x2a, 0x17, 0x82, 0x58, 0x78, 0x78, 0x5d, 0x68, 0xa3, 0xc6, 0xf7, 0x07, 0x50,
0x8e, 0xba, 0x72, 0xdc, 0x81, 0xd2, 0xd0, 0x22, 0x66, 0x3c, 0xe1, 0x4e, 0x32, 0x61, 0x9c, 0xa2,
0x9d, 0xdc, 0xde, 0x87, 0x33, 0xd5, 0xa2, 0x99, 0x4a, 0x41, 0xcc, 0x08, 0x4b, 0xf1, 0x19, 0x54,
0x27, 0x24, 0xd6, 0xc3, 0xe5, 0x42, 0x40, 0xda, 0xcf, 0x21, 0x7d, 0x49, 0xb2, 0x42, 0x1e, 0x8e,
0x78, 0xb0, 0xb0, 0x83, 0x1b, 0x69, 0x16, 0x36, 0xa0, 0xc2, 0x6c, 0x2e, 0x88, 0xdd, 0xa7, 0x5c,
0x2e, 0x06, 0xe0, 0x67, 0x39, 0xe0, 0x0f, 0x71, 0x4e, 0x88, 0x7d, 0x18, 0x61, 0x2b, 0x8b, 0xb8,
0x91, 0x60, 0x14, 0x03, 0x20, 0x91, 0x94, 0xe3, 0x9c, 0x96, 0x76, 0xae, 0xda, 0x92, 0x53, 0xfd,
0x2c, 0x62, 0x26, 0xef, 0x95, 0xf2, 0x54, 0xe9, 0x42, 0xfd, 0xae, 0xb8, 0x1c, 0xf2, 0xab, 0x2c,
0x79, 0x67, 0xed, 0x3a, 0xa4, 0xf1, 0xe7, 0xb0, 0x95, 0x95, 0x98, 0x03, 0x6f, 0x65, 0xe1, 0x4f,
0x13, 0x78, 0x5c, 0x9a, 0xcb, 0x6e, 0xfc, 0x46, 0xb0, 0x95, 0x15, 0x86, 0x3f, 0x2f, 0x6d, 0xee,
0xf3, 0x55, 0x26, 0xfc, 0xc7, 0xd2, 0x7e, 0xdc, 0xbc, 0xb4, 0xfb, 0x59, 0x0d, 0xb5, 0xa4, 0xeb,
0x29, 0xb3, 0xd2, 0x43, 0xff, 0x42, 0xb0, 0x7d, 0x47, 0x16, 0xee, 0x02, 0xa4, 0xb6, 0x30, 0x9c,
0xfb, 0xc5, 0x4a, 0x17, 0x12, 0xcb, 0xd7, 0xec, 0x62, 0x0a, 0xa8, 0xbc, 0x85, 0xed, 0xa3, 0x8d,
0x2f, 0xbc, 0xfa, 0x57, 0xd7, 0x05, 0xbc, 0xfc, 0x0e, 0xf8, 0xdd, 0x92, 0xd3, 0x4f, 0x56, 0x4e,
0xbc, 0xce, 0xdc, 0x46, 0x09, 0x8a, 0xa7, 0xcc, 0xea, 0x7c, 0x9d, 0xcd, 0x55, 0xe9, 0x6a, 0xae,
0x4a, 0xd7, 0x73, 0x55, 0xfa, 0xe6, 0xab, 0x68, 0xe6, 0xab, 0xe8, 0xca, 0x57, 0xd1, 0xb5, 0xaf,
0xa2, 0x3f, 0xbe, 0x8a, 0x7e, 0xfc, 0x55, 0xa5, 0xf3, 0xf6, 0x7d, 0xff, 0x34, 0xff, 0x05, 0x00,
0x00, 0xff, 0xff, 0xa9, 0x81, 0xcf, 0x6d, 0x6f, 0x05, 0x00, 0x00,
}
func (m *AttributeFeatureSet) Marshal() (dAtA []byte, err error) {
@ -316,7 +315,7 @@ func (m *AttributeFeatureSet) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *DomainFeatures) Marshal() (dAtA []byte, err error) {
func (m *Features) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
@ -326,12 +325,12 @@ func (m *DomainFeatures) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
func (m *DomainFeatures) MarshalTo(dAtA []byte) (int, error) {
func (m *Features) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *DomainFeatures) MarshalToSizedBuffer(dAtA []byte) (int, error) {
func (m *Features) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
@ -362,7 +361,7 @@ func (m *DomainFeatures) MarshalToSizedBuffer(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i = encodeVarintGenerated(dAtA, i, uint64(baseI-i))
i--
dAtA[i] = 0x22
dAtA[i] = 0x1a
}
}
if len(m.Attributes) > 0 {
@ -391,7 +390,7 @@ func (m *DomainFeatures) MarshalToSizedBuffer(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i = encodeVarintGenerated(dAtA, i, uint64(baseI-i))
i--
dAtA[i] = 0x1a
dAtA[i] = 0x12
}
}
if len(m.Flags) > 0 {
@ -420,7 +419,7 @@ func (m *DomainFeatures) MarshalToSizedBuffer(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i = encodeVarintGenerated(dAtA, i, uint64(baseI-i))
i--
dAtA[i] = 0x12
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
@ -613,7 +612,7 @@ func (m *AttributeFeatureSet) Size() (n int) {
return n
}
func (m *DomainFeatures) Size() (n int) {
func (m *Features) Size() (n int) {
if m == nil {
return 0
}
@ -734,7 +733,7 @@ func (this *AttributeFeatureSet) String() string {
}, "")
return s
}
func (this *DomainFeatures) String() string {
func (this *Features) String() string {
if this == nil {
return "nil"
}
@ -768,7 +767,7 @@ func (this *DomainFeatures) String() string {
mapStringForInstances += fmt.Sprintf("%v: %v,", k, this.Instances[k])
}
mapStringForInstances += "}"
s := strings.Join([]string{`&DomainFeatures{`,
s := strings.Join([]string{`&Features{`,
`Flags:` + mapStringForFlags + `,`,
`Attributes:` + mapStringForAttributes + `,`,
`Instances:` + mapStringForInstances + `,`,
@ -1025,7 +1024,7 @@ func (m *AttributeFeatureSet) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *DomainFeatures) Unmarshal(dAtA []byte) error {
func (m *Features) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
@ -1048,13 +1047,13 @@ func (m *DomainFeatures) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: DomainFeatures: wiretype end group for non-group")
return fmt.Errorf("proto: Features: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: DomainFeatures: illegal tag %d (wire type %d)", fieldNum, wire)
return fmt.Errorf("proto: Features: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 2:
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType)
}
@ -1183,7 +1182,7 @@ func (m *DomainFeatures) Unmarshal(dAtA []byte) error {
}
m.Flags[mapkey] = *mapvalue
iNdEx = postIndex
case 3:
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType)
}
@ -1312,7 +1311,7 @@ func (m *DomainFeatures) Unmarshal(dAtA []byte) error {
}
m.Attributes[mapkey] = *mapvalue
iNdEx = postIndex
case 4:
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Instances", wireType)
}

View file

@ -31,15 +31,15 @@ message AttributeFeatureSet {
map<string, string> elements = 1;
}
// DomainFeatures is the collection of all discovered features of one domain.
// Features is the collection of all discovered features.
//
// +protobuf=true
message DomainFeatures {
map<string, FlagFeatureSet> flags = 2;
message Features {
map<string, FlagFeatureSet> flags = 1;
map<string, AttributeFeatureSet> vattributes = 3;
map<string, AttributeFeatureSet> vattributes = 2;
map<string, InstanceFeatureSet> instances = 4;
map<string, InstanceFeatureSet> instances = 3;
}
// FlagFeatureSet is a set of simple features only containing names without values.

View file

@ -35,7 +35,7 @@ type RuleOutput struct {
}
// Execute the rule against a set of input features.
func (r *Rule) Execute(features Features) (RuleOutput, error) {
func (r *Rule) Execute(features *Features) (RuleOutput, error) {
labels := make(map[string]string)
vars := make(map[string]string)
@ -145,55 +145,39 @@ func (r *Rule) executeVarsTemplate(in matchedFeatures, out map[string]string) er
return nil
}
type matchedFeatures map[string]domainMatchedFeatures
type matchedFeatures map[string]interface{}
type domainMatchedFeatures map[string]interface{}
func (e *MatchAnyElem) match(features map[string]*DomainFeatures) (bool, matchedFeatures, error) {
func (e *MatchAnyElem) match(features *Features) (bool, matchedFeatures, error) {
return e.MatchFeatures.match(features)
}
func (m *FeatureMatcher) match(features map[string]*DomainFeatures) (bool, matchedFeatures, error) {
func (m *FeatureMatcher) match(features *Features) (bool, matchedFeatures, error) {
matches := make(matchedFeatures, len(*m))
// Logical AND over the terms
for _, term := range *m {
split := strings.SplitN(term.Feature, ".", 2)
if len(split) != 2 {
return false, nil, fmt.Errorf("invalid feature %q: must be <domain>.<feature>", term.Feature)
}
domain := split[0]
// Ignore case
featureName := strings.ToLower(split[1])
domainFeatures, ok := features[domain]
if !ok {
return false, nil, fmt.Errorf("unknown feature source/domain %q", domain)
}
if _, ok := matches[domain]; !ok {
matches[domain] = make(domainMatchedFeatures)
}
featureName := strings.ToLower(term.Feature)
var isMatch bool
var err error
if f, ok := domainFeatures.Flags[featureName]; ok {
if f, ok := features.Flags[featureName]; ok {
m, v, e := term.MatchExpressions.MatchGetKeys(f.Elements)
isMatch = m
err = e
matches[domain][featureName] = v
} else if f, ok := domainFeatures.Attributes[featureName]; ok {
matches[featureName] = v
} else if f, ok := features.Attributes[featureName]; ok {
m, v, e := term.MatchExpressions.MatchGetValues(f.Elements)
isMatch = m
err = e
matches[domain][featureName] = v
} else if f, ok := domainFeatures.Instances[featureName]; ok {
matches[featureName] = v
} else if f, ok := features.Instances[featureName]; ok {
v, e := term.MatchExpressions.MatchGetInstances(f.Elements)
isMatch = len(v) > 0
err = e
matches[domain][featureName] = v
matches[featureName] = v
} else {
return false, nil, fmt.Errorf("%q feature of source/domain %q not available", featureName, domain)
return false, nil, fmt.Errorf("feature %q not available", featureName)
}
if err != nil {

View file

@ -23,14 +23,14 @@ import (
)
func TestRule(t *testing.T) {
f := map[string]*DomainFeatures{}
f := &Features{}
r1 := Rule{Labels: map[string]string{"label-1": "", "label-2": "true"}}
r2 := Rule{
Labels: map[string]string{"label-1": "label-val-1"},
Vars: map[string]string{"var-1": "var-val-1"},
MatchFeatures: FeatureMatcher{
FeatureMatcherTerm{
Feature: "domain-1.kf-1",
Feature: "kf-1",
MatchExpressions: MatchExpressionSet{
"key-1": MustCreateMatchExpression(MatchExists),
},
@ -44,11 +44,10 @@ func TestRule(t *testing.T) {
assert.Equal(t, r1.Labels, m.Labels, "empty matcher should have matched empty features")
_, err = r2.Execute(f)
assert.Error(t, err, "matching against a missing domain should have returned an error")
assert.Error(t, err, "matching against a missing feature should have returned an error")
// Test empty domain
d := NewDomainFeatures()
f["domain-1"] = d
// Test properly initialized empty features
f = NewFeatures()
m, err = r1.Execute(f)
assert.Nilf(t, err, "unexpected error: %v", err)
@ -59,9 +58,9 @@ func TestRule(t *testing.T) {
assert.Error(t, err, "matching against a missing feature type should have returned an error")
// Test empty feature sets
d.Flags["kf-1"] = NewFlagFeatures()
d.Attributes["vf-1"] = NewAttributeFeatures(nil)
d.Instances["if-1"] = NewInstanceFeatures(nil)
f.Flags["kf-1"] = NewFlagFeatures()
f.Attributes["vf-1"] = NewAttributeFeatures(nil)
f.Instances["if-1"] = NewInstanceFeatures(nil)
m, err = r1.Execute(f)
assert.Nilf(t, err, "unexpected error: %v", err)
@ -72,9 +71,9 @@ func TestRule(t *testing.T) {
assert.Nil(t, m.Labels, "unexpected match")
// Test non-empty feature sets
d.Flags["kf-1"].Elements["key-x"] = Nil{}
d.Attributes["vf-1"].Elements["key-1"] = "val-x"
d.Instances["if-1"] = NewInstanceFeatures([]InstanceFeature{
f.Flags["kf-1"].Elements["key-x"] = Nil{}
f.Attributes["vf-1"].Elements["key-1"] = "val-x"
f.Instances["if-1"] = NewInstanceFeatures([]InstanceFeature{
*NewInstanceFeature(map[string]string{"attr-1": "val-x"})})
m, err = r1.Execute(f)
@ -84,7 +83,7 @@ func TestRule(t *testing.T) {
// Test empty MatchExpressions
r1.MatchFeatures = FeatureMatcher{
FeatureMatcherTerm{
Feature: "domain-1.kf-1",
Feature: "kf-1",
MatchExpressions: MatchExpressionSet{},
},
}
@ -97,7 +96,7 @@ func TestRule(t *testing.T) {
assert.Nilf(t, err, "unexpected error: %v", err)
assert.Nil(t, m.Labels, "keys should not have matched")
d.Flags["kf-1"].Elements["key-1"] = Nil{}
f.Flags["kf-1"].Elements["key-1"] = Nil{}
m, err = r2.Execute(f)
assert.Nilf(t, err, "unexpected error: %v", err)
assert.Equal(t, r2.Labels, m.Labels, "keys should have matched")
@ -108,7 +107,7 @@ func TestRule(t *testing.T) {
Labels: map[string]string{"label-3": "label-val-3", "empty": ""},
MatchFeatures: FeatureMatcher{
FeatureMatcherTerm{
Feature: "domain-1.vf-1",
Feature: "vf-1",
MatchExpressions: MatchExpressionSet{
"key-1": MustCreateMatchExpression(MatchIn, "val-1"),
},
@ -119,7 +118,7 @@ func TestRule(t *testing.T) {
assert.Nilf(t, err, "unexpected error: %v", err)
assert.Nil(t, m.Labels, "values should not have matched")
d.Attributes["vf-1"].Elements["key-1"] = "val-1"
f.Attributes["vf-1"].Elements["key-1"] = "val-1"
m, err = r3.Execute(f)
assert.Nilf(t, err, "unexpected error: %v", err)
assert.Equal(t, r3.Labels, m.Labels, "values should have matched")
@ -129,7 +128,7 @@ func TestRule(t *testing.T) {
Labels: map[string]string{"label-4": "label-val-4"},
MatchFeatures: FeatureMatcher{
FeatureMatcherTerm{
Feature: "domain-1.if-1",
Feature: "if-1",
MatchExpressions: MatchExpressionSet{
"attr-1": MustCreateMatchExpression(MatchIn, "val-1"),
},
@ -140,7 +139,7 @@ func TestRule(t *testing.T) {
assert.Nilf(t, err, "unexpected error: %v", err)
assert.Nil(t, m.Labels, "instances should not have matched")
d.Instances["if-1"].Elements[0].Attributes["attr-1"] = "val-1"
f.Instances["if-1"].Elements[0].Attributes["attr-1"] = "val-1"
m, err = r4.Execute(f)
assert.Nilf(t, err, "unexpected error: %v", err)
assert.Equal(t, r4.Labels, m.Labels, "instances should have matched")
@ -150,13 +149,13 @@ func TestRule(t *testing.T) {
Labels: map[string]string{"label-5": "label-val-5"},
MatchFeatures: FeatureMatcher{
FeatureMatcherTerm{
Feature: "domain-1.vf-1",
Feature: "vf-1",
MatchExpressions: MatchExpressionSet{
"key-1": MustCreateMatchExpression(MatchIn, "val-x"),
},
},
FeatureMatcherTerm{
Feature: "domain-1.if-1",
Feature: "if-1",
MatchExpressions: MatchExpressionSet{
"attr-1": MustCreateMatchExpression(MatchIn, "val-1"),
},
@ -177,7 +176,7 @@ func TestRule(t *testing.T) {
{
MatchFeatures: FeatureMatcher{
FeatureMatcherTerm{
Feature: "domain-1.kf-1",
Feature: "kf-1",
MatchExpressions: MatchExpressionSet{
"key-na": MustCreateMatchExpression(MatchExists),
},
@ -193,7 +192,7 @@ func TestRule(t *testing.T) {
MatchAnyElem{
MatchFeatures: FeatureMatcher{
FeatureMatcherTerm{
Feature: "domain-1.kf-1",
Feature: "kf-1",
MatchExpressions: MatchExpressionSet{
"key-1": MustCreateMatchExpression(MatchExists),
},
@ -207,46 +206,44 @@ func TestRule(t *testing.T) {
}
func TestTemplating(t *testing.T) {
f := map[string]*DomainFeatures{
"domain_1": &DomainFeatures{
Flags: map[string]FlagFeatureSet{
"kf_1": FlagFeatureSet{
Elements: map[string]Nil{
"key-a": {},
"key-b": {},
"key-c": {},
},
f := &Features{
Flags: map[string]FlagFeatureSet{
"kf_1": {
Elements: map[string]Nil{
"key-a": {},
"key-b": {},
"key-c": {},
},
},
Attributes: map[string]AttributeFeatureSet{
"vf_1": AttributeFeatureSet{
Elements: map[string]string{
"key-1": "val-1",
"keu-2": "val-2",
"key-3": "val-3",
},
},
Attributes: map[string]AttributeFeatureSet{
"vf_1": {
Elements: map[string]string{
"key-1": "val-1",
"keu-2": "val-2",
"key-3": "val-3",
},
},
Instances: map[string]InstanceFeatureSet{
"if_1": InstanceFeatureSet{
Elements: []InstanceFeature{
{
Attributes: map[string]string{
"attr-1": "1",
"attr-2": "val-2",
},
},
Instances: map[string]InstanceFeatureSet{
"if_1": {
Elements: []InstanceFeature{
{
Attributes: map[string]string{
"attr-1": "1",
"attr-2": "val-2",
},
{
Attributes: map[string]string{
"attr-1": "10",
"attr-2": "val-20",
},
},
{
Attributes: map[string]string{
"attr-1": "10",
"attr-2": "val-20",
},
{
Attributes: map[string]string{
"attr-1": "100",
"attr-2": "val-200",
},
},
{
Attributes: map[string]string{
"attr-1": "100",
"attr-2": "val-200",
},
},
},
@ -259,21 +256,21 @@ func TestTemplating(t *testing.T) {
LabelsTemplate: `
label-1=will-be-overridden
label-2=
{{range .domain_1.kf_1}}kf-{{.Name}}=present
{{range .kf_1}}kf-{{.Name}}=present
{{end}}
{{range .domain_1.vf_1}}vf-{{.Name}}=vf-{{.Value}}
{{range .vf_1}}vf-{{.Name}}=vf-{{.Value}}
{{end}}
{{range .domain_1.if_1}}if-{{index . "attr-1"}}_{{index . "attr-2"}}=present
{{range .if_1}}if-{{index . "attr-1"}}_{{index . "attr-2"}}=present
{{end}}`,
Vars: map[string]string{"var-1": "var-val-1"},
VarsTemplate: `
var-1=value-will-be-overridden-by-vars
var-2=
{{range .domain_1.kf_1}}kf-{{.Name}}=true
{{range .kf_1}}kf-{{.Name}}=true
{{end}}`,
MatchFeatures: FeatureMatcher{
FeatureMatcherTerm{
Feature: "domain_1.kf_1",
Feature: "kf_1",
MatchExpressions: MatchExpressionSet{
"key-a": MustCreateMatchExpression(MatchExists),
"key-c": MustCreateMatchExpression(MatchExists),
@ -281,14 +278,14 @@ var-2=
},
},
FeatureMatcherTerm{
Feature: "domain_1.vf_1",
Feature: "vf_1",
MatchExpressions: MatchExpressionSet{
"key-1": MustCreateMatchExpression(MatchIn, "val-1", "val-2"),
"bar": MustCreateMatchExpression(MatchDoesNotExist),
},
},
FeatureMatcherTerm{
Feature: "domain_1.if_1",
Feature: "if_1",
MatchExpressions: MatchExpressionSet{
"attr-1": MustCreateMatchExpression(MatchLt, "100"),
},
@ -342,7 +339,7 @@ var-2=
// We need at least one matcher to match to execute the template.
// Use a simple empty matchexpression set to match anything.
FeatureMatcherTerm{
Feature: "domain_1.kf_1",
Feature: "kf_1",
MatchExpressions: MatchExpressionSet{
"key-a": MustCreateMatchExpression(MatchExists),
},

View file

@ -20,18 +20,13 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Features is a collection of all features of the system, arranged by domain.
// Features is the collection of all discovered features.
//
// +protobuf=true
type Features map[string]*DomainFeatures
// DomainFeatures is the collection of all discovered features of one domain.
//
// +protobuf=true
type DomainFeatures struct {
Flags map[string]FlagFeatureSet `json:"flags" protobuf:"bytes,2,rep,name=flags"`
Attributes map[string]AttributeFeatureSet `json:"attributes" protobuf:"bytes,3,rep,name=vattributes"`
Instances map[string]InstanceFeatureSet `json:"instances" protobuf:"bytes,4,rep,name=instances"`
type Features struct {
Flags map[string]FlagFeatureSet `json:"flags" protobuf:"bytes,1,rep,name=flags"`
Attributes map[string]AttributeFeatureSet `json:"attributes" protobuf:"bytes,2,rep,name=vattributes"`
Instances map[string]InstanceFeatureSet `json:"instances" protobuf:"bytes,3,rep,name=instances"`
}
// FlagFeatureSet is a set of simple features only containing names without values.

View file

@ -31,42 +31,6 @@ 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 *DomainFeatures) DeepCopyInto(out *DomainFeatures) {
*out = *in
if in.Flags != nil {
in, out := &in.Flags, &out.Flags
*out = make(map[string]FlagFeatureSet, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.Attributes != nil {
in, out := &in.Attributes, &out.Attributes
*out = make(map[string]AttributeFeatureSet, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.Instances != nil {
in, out := &in.Instances, &out.Instances
*out = make(map[string]InstanceFeatureSet, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainFeatures.
func (in *DomainFeatures) DeepCopy() *DomainFeatures {
if in == nil {
return nil
}
out := new(DomainFeatures)
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) {
{
@ -119,32 +83,39 @@ func (in *FeatureMatcherTerm) DeepCopy() *FeatureMatcherTerm {
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in Features) DeepCopyInto(out *Features) {
{
in := &in
*out = make(Features, len(*in))
func (in *Features) DeepCopyInto(out *Features) {
*out = *in
if in.Flags != nil {
in, out := &in.Flags, &out.Flags
*out = make(map[string]FlagFeatureSet, len(*in))
for key, val := range *in {
var outVal *DomainFeatures
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = new(DomainFeatures)
(*in).DeepCopyInto(*out)
}
(*out)[key] = outVal
(*out)[key] = *val.DeepCopy()
}
}
if in.Attributes != nil {
in, out := &in.Attributes, &out.Attributes
*out = make(map[string]AttributeFeatureSet, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.Instances != nil {
in, out := &in.Instances, &out.Instances
*out = make(map[string]InstanceFeatureSet, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Features.
func (in Features) DeepCopy() Features {
func (in *Features) DeepCopy() *Features {
if in == nil {
return nil
}
out := new(Features)
in.DeepCopyInto(out)
return *out
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

View file

@ -50,10 +50,10 @@ type SetLabelsRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
NfdVersion string `protobuf:"bytes,1,opt,name=nfd_version,json=nfdVersion,proto3" json:"nfd_version,omitempty"`
NodeName string `protobuf:"bytes,2,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Features map[string]*v1alpha1.DomainFeatures `protobuf:"bytes,4,rep,name=features,proto3" json:"features,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
NfdVersion string `protobuf:"bytes,1,opt,name=nfd_version,json=nfdVersion,proto3" json:"nfd_version,omitempty"`
NodeName string `protobuf:"bytes,2,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Features *v1alpha1.Features `protobuf:"bytes,4,opt,name=features,proto3" json:"features,omitempty"`
}
func (x *SetLabelsRequest) Reset() {
@ -109,7 +109,7 @@ func (x *SetLabelsRequest) GetLabels() map[string]string {
return nil
}
func (x *SetLabelsRequest) GetFeatures() map[string]*v1alpha1.DomainFeatures {
func (x *SetLabelsRequest) GetFeatures() *v1alpha1.Features {
if x != nil {
return x.Features
}
@ -161,7 +161,7 @@ var file_labeler_proto_rawDesc = []byte{
0x07, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x1a, 0x25, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70,
0x69, 0x73, 0x2f, 0x6e, 0x66, 0x64, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f,
0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
0xe6, 0x02, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71,
0xfa, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x66, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x66, 0x64, 0x56, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61,
@ -170,30 +170,23 @@ var file_labeler_proto_rawDesc = []byte{
0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74,
0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61,
0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c,
0x73, 0x12, 0x43, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x04, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65,
0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46,
0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x66, 0x65,
0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x1a, 0x55, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44,
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x10, 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x4c,
0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, 0x4c, 0x0a, 0x07, 0x4c, 0x61,
0x62, 0x65, 0x6c, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65,
0x6c, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74,
0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e,
0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c,
0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x30, 0x5a, 0x2e, 0x73, 0x69, 0x67, 0x73,
0x2e, 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2d, 0x66, 0x65, 0x61,
0x74, 0x75, 0x72, 0x65, 0x2d, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x70,
0x6b, 0x67, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
0x73, 0x12, 0x2e, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x04, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x46,
0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65,
0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x10, 0x0a, 0x0e,
0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, 0x4c,
0x0a, 0x07, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x09, 0x53, 0x65, 0x74,
0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72,
0x2e, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x4c,
0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x30, 0x5a, 0x2e,
0x73, 0x69, 0x67, 0x73, 0x2e, 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65,
0x2d, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2d, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65,
0x72, 0x79, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -208,25 +201,23 @@ func file_labeler_proto_rawDescGZIP() []byte {
return file_labeler_proto_rawDescData
}
var file_labeler_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_labeler_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_labeler_proto_goTypes = []interface{}{
(*SetLabelsRequest)(nil), // 0: labeler.SetLabelsRequest
(*SetLabelsReply)(nil), // 1: labeler.SetLabelsReply
nil, // 2: labeler.SetLabelsRequest.LabelsEntry
nil, // 3: labeler.SetLabelsRequest.FeaturesEntry
(*v1alpha1.DomainFeatures)(nil), // 4: v1alpha1.DomainFeatures
(*SetLabelsRequest)(nil), // 0: labeler.SetLabelsRequest
(*SetLabelsReply)(nil), // 1: labeler.SetLabelsReply
nil, // 2: labeler.SetLabelsRequest.LabelsEntry
(*v1alpha1.Features)(nil), // 3: v1alpha1.Features
}
var file_labeler_proto_depIdxs = []int32{
2, // 0: labeler.SetLabelsRequest.labels:type_name -> labeler.SetLabelsRequest.LabelsEntry
3, // 1: labeler.SetLabelsRequest.features:type_name -> labeler.SetLabelsRequest.FeaturesEntry
4, // 2: labeler.SetLabelsRequest.FeaturesEntry.value:type_name -> v1alpha1.DomainFeatures
0, // 3: labeler.Labeler.SetLabels:input_type -> labeler.SetLabelsRequest
1, // 4: labeler.Labeler.SetLabels:output_type -> labeler.SetLabelsReply
4, // [4:5] is the sub-list for method output_type
3, // [3:4] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
3, // 1: labeler.SetLabelsRequest.features:type_name -> v1alpha1.Features
0, // 2: labeler.Labeler.SetLabels:input_type -> labeler.SetLabelsRequest
1, // 3: labeler.Labeler.SetLabels:output_type -> labeler.SetLabelsReply
3, // [3:4] is the sub-list for method output_type
2, // [2:3] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_labeler_proto_init() }
@ -266,7 +257,7 @@ func file_labeler_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_labeler_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumMessages: 3,
NumExtensions: 0,
NumServices: 1,
},

View file

@ -30,7 +30,7 @@ message SetLabelsRequest {
string nfd_version = 1;
string node_name = 2;
map<string, string> labels = 3;
map<string, v1alpha1.DomainFeatures> features = 4;
v1alpha1.Features features = 4;
}
message SetLabelsReply {

View file

@ -31,7 +31,6 @@ import (
"k8s.io/klog/v2"
"sigs.k8s.io/yaml"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
pb "sigs.k8s.io/node-feature-discovery/pkg/labeler"
clientcommon "sigs.k8s.io/node-feature-discovery/pkg/nfd-client"
"sigs.k8s.io/node-feature-discovery/pkg/utils"
@ -532,17 +531,6 @@ func getFeatureLabels(source source.LabelSource, labelWhiteList regexp.Regexp) (
return labels, nil
}
// getFeatures returns raw features from all feature sources
func getFeatures() map[string]*nfdv1alpha1.DomainFeatures {
features := make(map[string]*nfdv1alpha1.DomainFeatures)
for name, src := range source.GetAllFeatureSources() {
features[name] = src.GetFeatures()
}
return features
}
// advertiseFeatureLabels advertises the feature labels to a Kubernetes node
// via the NFD server.
func (w *nfdWorker) advertiseFeatureLabels(labels Labels) error {
@ -552,7 +540,7 @@ func (w *nfdWorker) advertiseFeatureLabels(labels Labels) error {
klog.Infof("sending labeling request to nfd-master")
labelReq := pb.SetLabelsRequest{Labels: labels,
Features: getFeatures(),
Features: source.GetAllFeatures(),
NfdVersion: version.Get(),
NodeName: clientcommon.NodeName()}

View file

@ -501,6 +501,9 @@ func (m *nfdMaster) crLabels(r *pb.SetLabelsRequest) map[string]string {
return nil
}
// Helper struct for rule processing
features := r.GetFeatures()
// Process all rule CRs
for _, spec := range ruleSpecs {
switch {
@ -511,7 +514,7 @@ func (m *nfdMaster) crLabels(r *pb.SetLabelsRequest) map[string]string {
klog.Infof("executing NodeFeatureRule %q", spec.ObjectMeta.Name)
}
for _, rule := range spec.Spec.Rules {
ruleOut, err := rule.Execute(r.Features)
ruleOut, err := rule.Execute(features)
if err != nil {
klog.Errorf("failed to process Rule %q: %v", rule.Name, err)
continue
@ -522,8 +525,8 @@ func (m *nfdMaster) crLabels(r *pb.SetLabelsRequest) map[string]string {
}
// Feed back rule output to features map for subsequent rules to match
nfdv1alpha1.InsertAttributeFeatures(r.Features, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
nfdv1alpha1.InsertAttributeFeatures(r.Features, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
}
}

View file

@ -102,7 +102,7 @@ type keyFilter struct {
type cpuSource struct {
config *Config
cpuidFilter *keyFilter
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
}
// Singleton source instance
@ -197,7 +197,7 @@ func (s *cpuSource) GetLabels() (source.FeatureLabels, error) {
// Discover method of the FeatureSource Interface
func (s *cpuSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
// Detect CPUID
s.features.Flags[CpuidFeature] = nfdv1alpha1.NewFlagFeatures(getCpuidFlags()...)
@ -252,9 +252,9 @@ func (s *cpuSource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface
func (s *cpuSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *cpuSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -107,10 +107,7 @@ func (s *customSource) Priority() int { return 10 }
// GetLabels method of the LabelSource interface
func (s *customSource) GetLabels() (source.FeatureLabels, error) {
// Get raw features from all sources
domainFeatures := make(map[string]*nfdv1alpha1.DomainFeatures)
for n, s := range source.GetAllFeatureSources() {
domainFeatures[n] = s.GetFeatures()
}
features := source.GetAllFeatures()
labels := source.FeatureLabels{}
allFeatureConfig := append(getStaticFeatureConfig(), *s.config...)
@ -118,7 +115,7 @@ func (s *customSource) GetLabels() (source.FeatureLabels, error) {
utils.KlogDump(2, "custom features configuration:", " ", allFeatureConfig)
// Iterate over features
for _, rule := range allFeatureConfig {
ruleOut, err := rule.execute(domainFeatures)
ruleOut, err := rule.execute(features)
if err != nil {
klog.Error(err)
continue
@ -128,15 +125,15 @@ func (s *customSource) GetLabels() (source.FeatureLabels, error) {
labels[n] = v
}
// Feed back rule output to features map for subsequent rules to match
nfdv1alpha1.InsertAttributeFeatures(domainFeatures, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
nfdv1alpha1.InsertAttributeFeatures(domainFeatures, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
}
return labels, nil
}
func (r *CustomRule) execute(features map[string]*nfdv1alpha1.DomainFeatures) (nfdv1alpha1.RuleOutput, error) {
func (r *CustomRule) execute(features *nfdv1alpha1.Features) (nfdv1alpha1.RuleOutput, error) {
if r.LegacyRule != nil {
ruleOut, err := r.LegacyRule.execute(features)
ruleOut, err := r.LegacyRule.execute()
if err != nil {
return nfdv1alpha1.RuleOutput{}, fmt.Errorf("failed to execute legacy rule %s: %w", r.LegacyRule.Name, err)
}
@ -154,7 +151,7 @@ func (r *CustomRule) execute(features map[string]*nfdv1alpha1.DomainFeatures) (n
return nfdv1alpha1.RuleOutput{}, fmt.Errorf("BUG: an empty rule, this really should not happen")
}
func (r *LegacyRule) execute(features map[string]*nfdv1alpha1.DomainFeatures) (map[string]string, error) {
func (r *LegacyRule) execute() (map[string]string, error) {
if len(r.MatchOn) > 0 {
// Logical OR over the legacy rules
matched := false

View file

@ -84,7 +84,7 @@ func newDefaultConfig() *Config {
// fakeSource implements the FeatureSource, LabelSource and ConfigurableSource interfaces.
type fakeSource struct {
config *Config
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
}
// Singleton source instance
@ -116,7 +116,7 @@ func (s *fakeSource) SetConfig(conf source.Config) {
// Discover method of the FeatureSource interface
func (s *fakeSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
s.features.Flags[FlagFeature] = nfdv1alpha1.NewFlagFeatures(s.config.FlagFeatures...)
s.features.Attributes[AttributeFeature] = nfdv1alpha1.NewAttributeFeatures(s.config.AttributeFeatures)
@ -133,9 +133,9 @@ func (s *fakeSource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface.
func (s *fakeSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *fakeSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -58,7 +58,7 @@ func newDefaultConfig() *Config {
// kernelSource implements the FeatureSource, LabelSource and ConfigurableSource interfaces.
type kernelSource struct {
config *Config
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
// legacyKconfig contains mangled kconfig values used for
// kernel.config-<flag> labels and legacy kConfig custom rules.
legacyKconfig map[string]string
@ -117,7 +117,7 @@ func (s *kernelSource) GetLabels() (source.FeatureLabels, error) {
// Discover method of the FeatureSource interface
func (s *kernelSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
// Read kernel version
if version, err := parseVersion(); err != nil {
@ -153,9 +153,9 @@ func (s *kernelSource) Discover() error {
return nil
}
func (s *kernelSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *kernelSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -45,7 +45,7 @@ var (
// localSource implements the FeatureSource and LabelSource interfaces.
type localSource struct {
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
config *Config
}
@ -103,7 +103,7 @@ func newDefaultConfig() *Config {
// Discover method of the FeatureSource interface
func (s *localSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
featuresFromFiles, err := getFeaturesFromFiles()
if err != nil {
@ -137,9 +137,9 @@ func (s *localSource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface
func (s *localSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *localSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -42,7 +42,7 @@ const NumaFeature = "numa"
// memorySource implements the FeatureSource and LabelSource interfaces.
type memorySource struct {
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
}
// Singleton source instance
@ -84,7 +84,7 @@ func (s *memorySource) GetLabels() (source.FeatureLabels, error) {
// Discover method of the FeatureSource interface
func (s *memorySource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
// Detect NUMA
if numa, err := detectNuma(); err != nil {
@ -106,9 +106,9 @@ func (s *memorySource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface.
func (s *memorySource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *memorySource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -40,7 +40,7 @@ const sysfsBaseDir = "class/net"
// networkSource implements the FeatureSource and LabelSource interfaces.
type networkSource struct {
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
}
// Singleton source instance
@ -91,7 +91,7 @@ func (s *networkSource) GetLabels() (source.FeatureLabels, error) {
// Discover method of the FeatureSource interface.
func (s *networkSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
devs, err := detectNetDevices()
if err != nil {
@ -105,9 +105,9 @@ func (s *networkSource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface.
func (s *networkSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *networkSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -50,7 +50,7 @@ func newDefaultConfig() *Config {
// pciSource implements the FeatureSource, LabelSource and ConfigurableSource interfaces.
type pciSource struct {
config *Config
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
}
// Singleton source instance
@ -140,7 +140,7 @@ func (s *pciSource) GetLabels() (source.FeatureLabels, error) {
// Discover method of the FeatureSource interface
func (s *pciSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
devs, err := detectPci()
if err != nil {
@ -154,9 +154,9 @@ func (s *pciSource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface
func (s *pciSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *pciSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -21,6 +21,8 @@ package source
import (
"fmt"
"k8s.io/klog/v2"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
)
@ -38,7 +40,7 @@ type FeatureSource interface {
Discover() error
// GetFeatures returns discovered features in raw form
GetFeatures() *nfdv1alpha1.DomainFeatures
GetFeatures() *nfdv1alpha1.Features
}
// LabelSource represents a source of node feature labels
@ -154,3 +156,37 @@ func GetAllConfigurableSources() map[string]ConfigurableSource {
}
return all
}
// GetAllFeatures returns a combined set of all features from all feature
// sources.
func GetAllFeatures() *nfdv1alpha1.Features {
features := nfdv1alpha1.NewFeatures()
for n, s := range GetAllFeatureSources() {
f := s.GetFeatures()
for k, v := range f.Flags {
// Prefix feature with the name of the source
k = n + "." + k
if typ := features.Exists(k); typ != "" {
klog.Exitf("feature source %q returned flag feature %q which already exists (type %q)", n, k, typ)
}
features.Flags[k] = v
}
for k, v := range f.Attributes {
// Prefix feature with the name of the source
k = n + "." + k
if typ := features.Exists(k); typ != "" {
klog.Exitf("feature source %q returned attribute feature %q which already exists (type %q)", n, k, typ)
}
features.Attributes[k] = v
}
for k, v := range f.Instances {
// Prefix feature with the name of the source
k = n + "." + k
if typ := features.Exists(k); typ != "" {
klog.Exitf("feature source %q returned instance feature %q which already exists (type %q)", n, k, typ)
}
features.Instances[k] = v
}
}
return features
}

View file

@ -37,7 +37,7 @@ const BlockFeature = "block"
// storageSource implements the FeatureSource and LabelSource interfaces.
type storageSource struct {
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
}
// Singleton source instance
@ -73,7 +73,7 @@ func (s *storageSource) GetLabels() (source.FeatureLabels, error) {
// Discover method of the FeatureSource interface
func (s *storageSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
devs, err := detectBlock()
if err != nil {
@ -87,9 +87,9 @@ func (s *storageSource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface.
func (s *storageSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *storageSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -47,7 +47,7 @@ const (
// systemSource implements the FeatureSource and LabelSource interfaces.
type systemSource struct {
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
}
// Singleton source instance
@ -78,7 +78,7 @@ func (s *systemSource) GetLabels() (source.FeatureLabels, error) {
// Discover method of the FeatureSource interface
func (s *systemSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
// Get node name
s.features.Attributes[NameFeature] = nfdv1alpha1.NewAttributeFeatures(nil)
@ -107,9 +107,9 @@ func (s *systemSource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface
func (s *systemSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *systemSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}

View file

@ -53,7 +53,7 @@ func defaultDeviceLabelFields() []string { return []string{"class", "vendor", "d
// usbSource implements the LabelSource and ConfigurableSource interfaces.
type usbSource struct {
config *Config
features *nfdv1alpha1.DomainFeatures
features *nfdv1alpha1.Features
}
// Singleton source instance
@ -139,7 +139,7 @@ func (s *usbSource) GetLabels() (source.FeatureLabels, error) {
// Discover method of the FeatureSource interface
func (s *usbSource) Discover() error {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
devs, err := detectUsb()
if err != nil {
@ -153,9 +153,9 @@ func (s *usbSource) Discover() error {
}
// GetFeatures method of the FeatureSource Interface
func (s *usbSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
func (s *usbSource) GetFeatures() *nfdv1alpha1.Features {
if s.features == nil {
s.features = nfdv1alpha1.NewDomainFeatures()
s.features = nfdv1alpha1.NewFeatures()
}
return s.features
}