Skip to content

Commit 378d2ff

Browse files
authored
Merge pull request #2028 from mfranczy/image-compatibility-nfr
Refactoring of image compatibility node validator
2 parents 4f24a38 + 99d63d3 commit 378d2ff

File tree

2 files changed

+314
-249
lines changed

2 files changed

+314
-249
lines changed

pkg/client-nfd/compat/node-validator/node-validator.go

Lines changed: 82 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package nodevalidator
1818

1919
import (
2020
"context"
21+
"fmt"
2122
"slices"
2223
"sort"
2324

@@ -62,12 +63,12 @@ func New(opts ...NodeValidatorOpts) nodeValidator {
6263
func (nv *nodeValidator) Execute(ctx context.Context) ([]*CompatibilityStatus, error) {
6364
spec, err := nv.artifactClient.FetchCompatibilitySpec(ctx)
6465
if err != nil {
65-
return nil, err
66+
return nil, fmt.Errorf("failed to fetch compatibility spec: %w", err)
6667
}
6768

6869
for _, s := range nv.sources {
6970
if err := s.Discover(); err != nil {
70-
return nil, err
71+
return nil, fmt.Errorf("error during discovery of source %s: %w", s.Name(), err)
7172
}
7273
}
7374
features := source.GetAllFeatures()
@@ -84,7 +85,7 @@ func (nv *nodeValidator) Execute(ctx context.Context) ([]*CompatibilityStatus, e
8485
if err != nil {
8586
return nil, err
8687
}
87-
compat.Rules = append(compat.Rules, evaluateRuleStatus(&r, ruleOut.MatchStatus))
88+
compat.Rules = append(compat.Rules, nv.evaluateRuleStatus(&r, ruleOut.MatchStatus))
8889

8990
// Add the 'rule.matched' feature for backreference functionality
9091
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
@@ -96,91 +97,100 @@ func (nv *nodeValidator) Execute(ctx context.Context) ([]*CompatibilityStatus, e
9697
return compats, nil
9798
}
9899

99-
func evaluateRuleStatus(rule *nfdv1alpha1.Rule, matchStatus *nodefeaturerule.MatchStatus) ProcessedRuleStatus {
100-
var matchedFeatureTerms nfdv1alpha1.FeatureMatcher
100+
func (nv *nodeValidator) evaluateRuleStatus(rule *nfdv1alpha1.Rule, matchStatus *nodefeaturerule.MatchStatus) ProcessedRuleStatus {
101101
out := ProcessedRuleStatus{Name: rule.Name, IsMatch: matchStatus.IsMatch}
102102

103-
evaluateFeatureMatcher := func(featureMatcher, matchedFeatureTerms nfdv1alpha1.FeatureMatcher) []MatchedExpression {
104-
out := []MatchedExpression{}
105-
for _, term := range featureMatcher {
106-
if term.MatchExpressions != nil {
107-
for name, exp := range *term.MatchExpressions {
108-
isMatch := false
109-
110-
// Check if the expression matches
111-
for _, processedTerm := range matchedFeatureTerms {
112-
if term.Feature != processedTerm.Feature || processedTerm.MatchExpressions == nil {
113-
continue
114-
}
115-
pexp, ok := (*processedTerm.MatchExpressions)[name]
116-
if isMatch = ok && exp.Op == pexp.Op && slices.Equal(exp.Value, pexp.Value); isMatch {
117-
break
118-
}
119-
}
120-
121-
out = append(out, MatchedExpression{
122-
Feature: term.Feature,
123-
Name: name,
124-
Expression: exp,
125-
MatcherType: MatchExpressionType,
126-
IsMatch: isMatch,
127-
})
128-
}
129-
}
103+
matchedFeatureTerms := nfdv1alpha1.FeatureMatcher{}
104+
if m := matchStatus.MatchFeatureStatus; m != nil {
105+
matchedFeatureTerms = m.MatchedFeaturesTerms
106+
}
107+
out.MatchedExpressions = nv.matchFeatureExpressions(rule.MatchFeatures, matchedFeatureTerms)
130108

131-
if term.MatchName != nil {
132-
isMatch := false
133-
for _, processedTerm := range matchStatus.MatchedFeaturesTerms {
134-
if term.Feature != processedTerm.Feature || processedTerm.MatchName == nil {
135-
continue
136-
}
137-
isMatch = term.MatchName.Op == processedTerm.MatchName.Op && slices.Equal(term.MatchName.Value, processedTerm.MatchName.Value)
138-
if isMatch {
139-
break
140-
}
141-
}
142-
out = append(out, MatchedExpression{
143-
Feature: term.Feature,
144-
Name: "",
145-
Expression: term.MatchName,
146-
MatcherType: MatchNameType,
147-
IsMatch: isMatch,
148-
})
149-
}
109+
for i, matchAnyElem := range rule.MatchAny {
110+
matchedFeatureTermsAny := nfdv1alpha1.FeatureMatcher{}
111+
if t := matchStatus.MatchAny[i].MatchedFeaturesTerms; t != nil {
112+
matchedFeatureTermsAny = t
150113
}
114+
matchedExpressions := nv.matchFeatureExpressions(matchAnyElem.MatchFeatures, matchedFeatureTermsAny)
115+
out.MatchedAny = append(out.MatchedAny, MatchAnyElem{MatchedExpressions: matchedExpressions})
116+
}
151117

152-
// For reproducible output sort by name, feature, expression.
153-
sort.Slice(out, func(i, j int) bool {
154-
if out[i].Feature != out[j].Feature {
155-
return out[i].Feature < out[j].Feature
156-
}
157-
if out[i].Name != out[j].Name {
158-
return out[i].Name < out[j].Name
159-
}
160-
return out[i].Expression.String() < out[j].Expression.String()
161-
})
118+
return out
119+
}
162120

163-
return out
164-
}
121+
func (nv *nodeValidator) matchFeatureExpressions(featureMatcher, matchedFeatureTerms nfdv1alpha1.FeatureMatcher) []MatchedExpression {
122+
var out []MatchedExpression
165123

166-
if matchFeatures := rule.MatchFeatures; matchFeatures != nil {
167-
if matchStatus.MatchFeatureStatus != nil {
168-
matchedFeatureTerms = matchStatus.MatchFeatureStatus.MatchedFeaturesTerms
124+
for _, term := range featureMatcher {
125+
if term.MatchExpressions != nil {
126+
out = append(out, nv.matchExpressions(term, matchedFeatureTerms)...)
127+
}
128+
if term.MatchName != nil {
129+
out = append(out, nv.matchName(term, matchedFeatureTerms))
169130
}
170-
out.MatchedExpressions = evaluateFeatureMatcher(matchFeatures, matchedFeatureTerms)
171131
}
172132

173-
for i, matchAnyElem := range rule.MatchAny {
174-
if matchStatus.MatchAny[i].MatchedFeaturesTerms != nil {
175-
matchedFeatureTerms = matchStatus.MatchAny[i].MatchedFeaturesTerms
133+
// For reproducible output sort by name, feature, expression.
134+
sort.Slice(out, func(i, j int) bool {
135+
if out[i].Feature != out[j].Feature {
136+
return out[i].Feature < out[j].Feature
176137
}
177-
matchedExpressions := evaluateFeatureMatcher(matchAnyElem.MatchFeatures, matchedFeatureTerms)
178-
out.MatchedAny = append(out.MatchedAny, MatchAnyElem{MatchedExpressions: matchedExpressions})
138+
if out[i].Name != out[j].Name {
139+
return out[i].Name < out[j].Name
140+
}
141+
return out[i].Expression.String() < out[j].Expression.String()
142+
})
143+
144+
return out
145+
}
146+
147+
func (nodeValidator) matchExpressions(term nfdv1alpha1.FeatureMatcherTerm, matchedFeatureTerms nfdv1alpha1.FeatureMatcher) []MatchedExpression {
148+
var out []MatchedExpression
149+
150+
for name, exp := range *term.MatchExpressions {
151+
isMatch := false
152+
for _, processedTerm := range matchedFeatureTerms {
153+
if term.Feature != processedTerm.Feature || processedTerm.MatchExpressions == nil {
154+
continue
155+
}
156+
pexp, ok := (*processedTerm.MatchExpressions)[name]
157+
if isMatch = ok && exp.Op == pexp.Op && slices.Equal(exp.Value, pexp.Value); isMatch {
158+
break
159+
}
160+
}
161+
162+
out = append(out, MatchedExpression{
163+
Feature: term.Feature,
164+
Name: name,
165+
Expression: exp,
166+
MatcherType: MatchExpressionType,
167+
IsMatch: isMatch,
168+
})
179169
}
180170

181171
return out
182172
}
183173

174+
func (nodeValidator) matchName(term nfdv1alpha1.FeatureMatcherTerm, matchedFeatureTerms nfdv1alpha1.FeatureMatcher) MatchedExpression {
175+
isMatch := false
176+
for _, processedTerm := range matchedFeatureTerms {
177+
if term.Feature != processedTerm.Feature || processedTerm.MatchName == nil {
178+
continue
179+
}
180+
isMatch = term.MatchName.Op == processedTerm.MatchName.Op && slices.Equal(term.MatchName.Value, processedTerm.MatchName.Value)
181+
if isMatch {
182+
break
183+
}
184+
}
185+
return MatchedExpression{
186+
Feature: term.Feature,
187+
Name: "",
188+
Expression: term.MatchName,
189+
MatcherType: MatchNameType,
190+
IsMatch: isMatch,
191+
}
192+
}
193+
184194
// NodeValidatorOpts applies certain options to the node validator.
185195
type NodeValidatorOpts interface {
186196
apply(*nodeValidator)

0 commit comments

Comments
 (0)