mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-14 11:57:51 +00:00
source/custom: implement matchAny directive
Implement a new 'matchAny' directive in the new rule format, building on top of the previously implemented 'matchFeatures' matcher. MatchAny applies a logical OR over multiple matchFeatures directives. That is, it allows specifying multiple alternative matchers (at least one of which must match) in a single label rule. The configuration format for the new matchers is matchAny: - matchFeatures: - feature: <domain>.<feature> matchExpressions: <attribute>: op: <operator> value: - <list-of-values> - matchFeatures: ... A configuration example. In order to require a cpu feature, kernel module and one of two specific PCI devices (taking use of the shortform notation): - name: multi-device-test labels: multi-device-feature: "true" matchFeatures: - feature: kernel.loadedmodule matchExpressions: [driver-module] - feature: cpu.cpuid matchExpressions: [AVX512F] matchAny: - matchFeatures: - feature; pci.device matchExpressions: vendor: "8086" device: "1234" - matchFeatures: - feature: pci.device matchExpressions: vendor: "8086" device: "abcd"
This commit is contained in:
parent
e206f0b86b
commit
6cbed379df
4 changed files with 101 additions and 0 deletions
|
@ -160,3 +160,27 @@
|
|||
# - feature: local.label
|
||||
# matchExpressions:
|
||||
# custom-feature-knob: {op: Gt, value: ["100"]}
|
||||
#
|
||||
# # The following feature demonstrates the capabilities of the matchAny
|
||||
# - name: "my.ng.feature.2"
|
||||
# labels:
|
||||
# my-ng-feature-2: "my-value"
|
||||
# # matchAny implements a logical IF over all elements (sub-matchers) in
|
||||
# # the list (i.e. at least one feature matcher must match)
|
||||
# matchAny:
|
||||
# - matchFeatures:
|
||||
# - feature: kernel.loadedmodule
|
||||
# matchExpressions:
|
||||
# driver-module-X: {op: Exists}
|
||||
# - feature: pci.device
|
||||
# matchExpressions:
|
||||
# vendor: {op: In, value: ["8086"]}
|
||||
# class: {op: In, value: ["0200"]}
|
||||
# - matchFeatures:
|
||||
# - feature: kernel.loadedmodule
|
||||
# matchExpressions:
|
||||
# driver-module-Y: {op: Exists}
|
||||
# - feature: usb.device
|
||||
# matchExpressions:
|
||||
# vendor: {op: In, value: ["8086"]}
|
||||
# class: {op: In, value: ["02"]}
|
||||
|
|
|
@ -246,6 +246,30 @@ worker:
|
|||
# - feature: local.label
|
||||
# matchExpressions:
|
||||
# custom-feature-knob: {op: Gt, value: ["100"]}
|
||||
#
|
||||
# # The following feature demonstrates the capabilities of the matchAny
|
||||
# - name: "my.ng.feature.2"
|
||||
# labels:
|
||||
# my-ng-feature-2: "my-value"
|
||||
# # matchAny implements a logical IF over all elements (sub-matchers) in
|
||||
# # the list (i.e. at least one feature matcher must match)
|
||||
# matchAny:
|
||||
# - matchFeatures:
|
||||
# - feature: kernel.loadedmodule
|
||||
# matchExpressions:
|
||||
# driver-module-X: {op: Exists}
|
||||
# - feature: pci.device
|
||||
# matchExpressions:
|
||||
# vendor: {op: In, value: ["8086"]}
|
||||
# class: {op: In, value: ["0200"]}
|
||||
# - matchFeatures:
|
||||
# - feature: kernel.loadedmodule
|
||||
# matchExpressions:
|
||||
# driver-module-Y: {op: Exists}
|
||||
# - feature: usb.device
|
||||
# matchExpressions:
|
||||
# vendor: {op: In, value: ["8086"]}
|
||||
# class: {op: In, value: ["02"]}
|
||||
### <NFD-WORKER-CONF-END-DO-NOT-REMOVE>
|
||||
|
||||
podSecurityContext: {}
|
||||
|
|
|
@ -54,6 +54,11 @@ type Rule struct {
|
|||
Name string `json:"name"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
MatchFeatures FeatureMatcher `json:"matchFeatures"`
|
||||
MatchAny []MatchAnyElem `json:"matchAny"`
|
||||
}
|
||||
|
||||
type MatchAnyElem struct {
|
||||
MatchFeatures FeatureMatcher
|
||||
}
|
||||
|
||||
type FeatureMatcher []FeatureMatcherTerm
|
||||
|
@ -185,6 +190,22 @@ func (r *LegacyRule) execute(features map[string]*feature.DomainFeatures) (map[s
|
|||
}
|
||||
|
||||
func (r *Rule) execute(features map[string]*feature.DomainFeatures) (map[string]string, error) {
|
||||
if len(r.MatchAny) > 0 {
|
||||
// Logical OR over the matchAny matchers
|
||||
matched := false
|
||||
for _, matcher := range r.MatchAny {
|
||||
if m, err := matcher.match(features); err != nil {
|
||||
return nil, err
|
||||
} else if m {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.MatchFeatures) > 0 {
|
||||
if m, err := r.MatchFeatures.match(features); err != nil {
|
||||
return nil, err
|
||||
|
@ -201,6 +222,10 @@ func (r *Rule) execute(features map[string]*feature.DomainFeatures) (map[string]
|
|||
return labels, nil
|
||||
}
|
||||
|
||||
func (e *MatchAnyElem) match(features map[string]*feature.DomainFeatures) (bool, error) {
|
||||
return e.MatchFeatures.match(features)
|
||||
}
|
||||
|
||||
func (m *FeatureMatcher) match(features map[string]*feature.DomainFeatures) (bool, error) {
|
||||
// Logical AND over the terms
|
||||
for _, term := range *m {
|
||||
|
|
|
@ -150,4 +150,32 @@ func TestRule(t *testing.T) {
|
|||
assert.Nilf(t, err, "unexpected error: %v", err)
|
||||
assert.Equal(t, r5.Labels, m, "instances should have matched")
|
||||
|
||||
// Test MatchAny
|
||||
r5.MatchAny = []MatchAnyElem{
|
||||
MatchAnyElem{
|
||||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.kf-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"key-na": expression.MustCreateMatchExpression(expression.MatchExists)},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
m, err = r5.execute(f)
|
||||
assert.Nilf(t, err, "unexpected error: %v", err)
|
||||
assert.Nil(t, m, "instances should not have matched")
|
||||
|
||||
r5.MatchAny = append(r5.MatchAny,
|
||||
MatchAnyElem{
|
||||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain-1.kf-1",
|
||||
MatchExpressions: expression.MatchExpressionSet{"key-1": expression.MustCreateMatchExpression(expression.MatchExists)},
|
||||
},
|
||||
},
|
||||
})
|
||||
r5.MatchFeatures[0].MatchExpressions["key-1"] = expression.MustCreateMatchExpression(expression.MatchIn, "val-1")
|
||||
m, err = r5.execute(f)
|
||||
assert.Nilf(t, err, "unexpected error: %v", err)
|
||||
assert.Equal(t, r5.Labels, m, "instances should have matched")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue