mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-15 17:50:49 +00:00
Merge pull request #1468 from marquiz/devel/nfr-template-fix
apis/nfd: fix multiple matcher terms targeting the same feature
This commit is contained in:
commit
7154458524
5 changed files with 48 additions and 101 deletions
|
@ -288,16 +288,15 @@ func (m *MatchExpressionSet) MatchKeys(keys map[string]Nil) (bool, error) {
|
|||
return matched, err
|
||||
}
|
||||
|
||||
// MatchedKey holds one matched key.
|
||||
type MatchedKey struct {
|
||||
Name string
|
||||
}
|
||||
// MatchedElement holds one matched Instance.
|
||||
// +k8s:deepcopy-gen=false
|
||||
type MatchedElement map[string]string
|
||||
|
||||
// MatchGetKeys evaluates the MatchExpressionSet against a set of keys and
|
||||
// returns all matched keys or nil if no match was found. Note that an empty
|
||||
// MatchExpressionSet returns a match with an empty slice of matched features.
|
||||
func (m *MatchExpressionSet) MatchGetKeys(keys map[string]Nil) (bool, []MatchedKey, error) {
|
||||
ret := make([]MatchedKey, 0, len(*m))
|
||||
func (m *MatchExpressionSet) MatchGetKeys(keys map[string]Nil) (bool, []MatchedElement, error) {
|
||||
ret := make([]MatchedElement, 0, len(*m))
|
||||
|
||||
for n, e := range *m {
|
||||
match, err := e.MatchKeys(n, keys)
|
||||
|
@ -307,10 +306,8 @@ func (m *MatchExpressionSet) MatchGetKeys(keys map[string]Nil) (bool, []MatchedK
|
|||
if !match {
|
||||
return false, nil, nil
|
||||
}
|
||||
ret = append(ret, MatchedKey{Name: n})
|
||||
ret = append(ret, MatchedElement{"Name": n})
|
||||
}
|
||||
// Sort for reproducible output
|
||||
sort.Slice(ret, func(i, j int) bool { return ret[i].Name < ret[j].Name })
|
||||
return true, ret, nil
|
||||
}
|
||||
|
||||
|
@ -320,17 +317,11 @@ func (m *MatchExpressionSet) MatchValues(values map[string]string) (bool, error)
|
|||
return matched, err
|
||||
}
|
||||
|
||||
// MatchedValue holds one matched key-value pair.
|
||||
type MatchedValue struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
// MatchGetValues evaluates the MatchExpressionSet against a set of key-value
|
||||
// pairs and returns all matched key-value pairs. Note that an empty
|
||||
// MatchExpressionSet returns a match with an empty slice of matched features.
|
||||
func (m *MatchExpressionSet) MatchGetValues(values map[string]string) (bool, []MatchedValue, error) {
|
||||
ret := make([]MatchedValue, 0, len(*m))
|
||||
func (m *MatchExpressionSet) MatchGetValues(values map[string]string) (bool, []MatchedElement, error) {
|
||||
ret := make([]MatchedElement, 0, len(*m))
|
||||
|
||||
for n, e := range *m {
|
||||
match, err := e.MatchValues(n, values)
|
||||
|
@ -340,10 +331,8 @@ func (m *MatchExpressionSet) MatchGetValues(values map[string]string) (bool, []M
|
|||
if !match {
|
||||
return false, nil, nil
|
||||
}
|
||||
ret = append(ret, MatchedValue{Name: n, Value: values[n]})
|
||||
ret = append(ret, MatchedElement{"Name": n, "Value": values[n]})
|
||||
}
|
||||
// Sort for reproducible output
|
||||
sort.Slice(ret, func(i, j int) bool { return ret[i].Name < ret[j].Name })
|
||||
return true, ret, nil
|
||||
}
|
||||
|
||||
|
@ -355,15 +344,12 @@ func (m *MatchExpressionSet) MatchInstances(instances []InstanceFeature) (bool,
|
|||
return len(v) > 0, err
|
||||
}
|
||||
|
||||
// MatchedInstance holds one matched Instance.
|
||||
type MatchedInstance map[string]string
|
||||
|
||||
// MatchGetInstances evaluates the MatchExpressionSet against a set of instance
|
||||
// features, each of which is an individual set of key-value pairs
|
||||
// (attributes). A slice containing all matching instances is returned. An
|
||||
// empty (non-nil) slice is returned if no matching instances were found.
|
||||
func (m *MatchExpressionSet) MatchGetInstances(instances []InstanceFeature) ([]MatchedInstance, error) {
|
||||
ret := []MatchedInstance{}
|
||||
func (m *MatchExpressionSet) MatchGetInstances(instances []InstanceFeature) ([]MatchedElement, error) {
|
||||
ret := []MatchedElement{}
|
||||
|
||||
for _, i := range instances {
|
||||
if match, err := m.MatchValues(i.Attributes); err != nil {
|
||||
|
|
|
@ -290,8 +290,8 @@ func TestMatchValues(t *testing.T) {
|
|||
|
||||
func TestMESMatchKeys(t *testing.T) {
|
||||
type I = map[string]api.Nil
|
||||
type MK = api.MatchedKey
|
||||
type O = []MK
|
||||
type ME = api.MatchedElement
|
||||
type O = []ME
|
||||
type TC struct {
|
||||
mes string
|
||||
input I
|
||||
|
@ -312,7 +312,7 @@ foo: { op: DoesNotExist }
|
|||
bar: { op: Exists }
|
||||
`,
|
||||
input: I{"bar": {}, "baz": {}, "buzz": {}},
|
||||
output: O{MK{Name: "bar"}, MK{Name: "foo"}},
|
||||
output: O{ME{"Name": "bar"}, ME{"Name": "foo"}},
|
||||
result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
|
@ -351,8 +351,8 @@ bar: { op: Exists }
|
|||
|
||||
func TestMESMatchValues(t *testing.T) {
|
||||
type I = map[string]string
|
||||
type MV = api.MatchedValue
|
||||
type O = []MV
|
||||
type ME = api.MatchedElement
|
||||
type O = []ME
|
||||
type TC struct {
|
||||
mes string
|
||||
input I
|
||||
|
@ -382,7 +382,7 @@ bar: { op: In, value: ["val", "wal"] }
|
|||
baz: { op: Gt, value: ["10"] }
|
||||
`,
|
||||
input: I{"foo": "1", "bar": "val", "baz": "123", "buzz": "light"},
|
||||
output: O{MV{Name: "bar", Value: "val"}, MV{Name: "baz", Value: "123"}, MV{Name: "foo", Value: "1"}},
|
||||
output: O{ME{"Name": "bar", "Value": "val"}, ME{"Name": "baz", "Value": "123"}, ME{"Name": "foo", "Value": "1"}},
|
||||
result: assert.Truef, err: assert.Nilf},
|
||||
|
||||
{mes: `
|
||||
|
@ -413,8 +413,8 @@ baz: { op: Gt, value: ["10"] }
|
|||
|
||||
func TestMESMatchInstances(t *testing.T) {
|
||||
type I = api.InstanceFeature
|
||||
type MI = api.MatchedInstance
|
||||
type O = []MI
|
||||
type ME = api.MatchedElement
|
||||
type O = []ME
|
||||
type A = map[string]string
|
||||
type TC struct {
|
||||
mes string
|
||||
|
|
|
@ -155,7 +155,7 @@ func (r *Rule) executeVarsTemplate(in matchedFeatures, out map[string]string) er
|
|||
|
||||
type matchedFeatures map[string]domainMatchedFeatures
|
||||
|
||||
type domainMatchedFeatures map[string]interface{}
|
||||
type domainMatchedFeatures map[string][]MatchedElement
|
||||
|
||||
func (e *MatchAnyElem) match(features *Features) (bool, matchedFeatures, error) {
|
||||
return e.MatchFeatures.match(features)
|
||||
|
@ -175,30 +175,26 @@ func (m *FeatureMatcher) match(features *Features) (bool, matchedFeatures, error
|
|||
nameSplit = []string{featureName, ""}
|
||||
}
|
||||
|
||||
if _, ok := matches[nameSplit[0]]; !ok {
|
||||
matches[nameSplit[0]] = make(domainMatchedFeatures)
|
||||
dom := nameSplit[0]
|
||||
nam := nameSplit[1]
|
||||
if _, ok := matches[dom]; !ok {
|
||||
matches[dom] = make(domainMatchedFeatures)
|
||||
}
|
||||
|
||||
var isMatch bool
|
||||
var matchedElems []MatchedElement
|
||||
var err error
|
||||
if f, ok := features.Flags[featureName]; ok {
|
||||
m, v, e := term.MatchExpressions.MatchGetKeys(f.Elements)
|
||||
isMatch = m
|
||||
err = e
|
||||
matches[nameSplit[0]][nameSplit[1]] = v
|
||||
isMatch, matchedElems, err = term.MatchExpressions.MatchGetKeys(f.Elements)
|
||||
} else if f, ok := features.Attributes[featureName]; ok {
|
||||
m, v, e := term.MatchExpressions.MatchGetValues(f.Elements)
|
||||
isMatch = m
|
||||
err = e
|
||||
matches[nameSplit[0]][nameSplit[1]] = v
|
||||
isMatch, matchedElems, err = term.MatchExpressions.MatchGetValues(f.Elements)
|
||||
} else if f, ok := features.Instances[featureName]; ok {
|
||||
v, e := term.MatchExpressions.MatchGetInstances(f.Elements)
|
||||
isMatch = len(v) > 0
|
||||
err = e
|
||||
matches[nameSplit[0]][nameSplit[1]] = v
|
||||
matchedElems, err = term.MatchExpressions.MatchGetInstances(f.Elements)
|
||||
isMatch = len(matchedElems) > 0
|
||||
} else {
|
||||
return false, nil, fmt.Errorf("feature %q not available", featureName)
|
||||
}
|
||||
matches[dom][nam] = append(matches[dom][nam], matchedElems...)
|
||||
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
|
|
|
@ -246,6 +246,13 @@ func TestTemplating(t *testing.T) {
|
|||
"attr-2": "val-200",
|
||||
},
|
||||
},
|
||||
{
|
||||
Attributes: map[string]string{
|
||||
"attr-1": "1000",
|
||||
"attr-2": "val-2000",
|
||||
"attr-3": "3000",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -290,6 +297,14 @@ var-2=
|
|||
"attr-1": MustCreateMatchExpression(MatchLt, "100"),
|
||||
},
|
||||
},
|
||||
FeatureMatcherTerm{
|
||||
Feature: "domain_1.if_1",
|
||||
MatchExpressions: MatchExpressionSet{
|
||||
"attr-1": MustCreateMatchExpression(MatchExists),
|
||||
"attr-2": MustCreateMatchExpression(MatchExists),
|
||||
"attr-3": MustCreateMatchExpression(MatchExists),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -311,6 +326,7 @@ var-2=
|
|||
// From if_1 template
|
||||
"if-1_val-2": "present",
|
||||
"if-10_val-20": "present",
|
||||
"if-1000_val-2000": "present",
|
||||
}
|
||||
expectedVars := map[string]string{
|
||||
"var-1": "var-val-1",
|
||||
|
|
|
@ -276,57 +276,6 @@ func (in MatchValue) DeepCopy() MatchValue {
|
|||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in MatchedInstance) DeepCopyInto(out *MatchedInstance) {
|
||||
{
|
||||
in := &in
|
||||
*out = make(MatchedInstance, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchedInstance.
|
||||
func (in MatchedInstance) DeepCopy() MatchedInstance {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MatchedInstance)
|
||||
in.DeepCopyInto(out)
|
||||
return *out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MatchedKey) DeepCopyInto(out *MatchedKey) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchedKey.
|
||||
func (in *MatchedKey) DeepCopy() *MatchedKey {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MatchedKey)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MatchedValue) DeepCopyInto(out *MatchedValue) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchedValue.
|
||||
func (in *MatchedValue) DeepCopy() *MatchedValue {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(MatchedValue)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Nil) DeepCopyInto(out *Nil) {
|
||||
*out = *in
|
||||
|
|
Loading…
Reference in a new issue