1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-17 13:58:21 +00:00

nodefeaturegroup: implement vars

Implement handling of Vars and VarsTemplate fields or NodeFeatureGroup.
This commit is contained in:
Markus Lehtonen 2025-03-03 15:02:31 +02:00
parent 76569bd846
commit 96262a3784
2 changed files with 39 additions and 15 deletions

View file

@ -147,50 +147,71 @@ func Execute(r *nfdv1alpha1.Rule, features *nfdv1alpha1.Features, failFast bool)
return ret, nil return ret, nil
} }
// GroupRuleOutput contains the output of group rule execution.
type GroupRuleOutput struct {
Vars map[string]string
MatchStatus *MatchStatus
}
// ExecuteGroupRule executes the GroupRule against a set of input features, and return true if the // ExecuteGroupRule executes the GroupRule against a set of input features, and return true if the
// rule matches. // rule matches.
func ExecuteGroupRule(r *nfdv1alpha1.GroupRule, features *nfdv1alpha1.Features, failFast bool) (MatchStatus, error) { func ExecuteGroupRule(r *nfdv1alpha1.GroupRule, features *nfdv1alpha1.Features, failFast bool) (GroupRuleOutput, error) {
var ( var (
matchStatus MatchStatus matchStatus MatchStatus
isMatch bool isMatch bool
) )
vars := make(map[string]string)
if n := len(r.MatchAny); n > 0 { if n := len(r.MatchAny); n > 0 {
matchStatus.MatchAny = make([]*MatchFeatureStatus, 0, n) matchStatus.MatchAny = make([]*MatchFeatureStatus, 0, n)
// Logical OR over the matchAny matchers // Logical OR over the matchAny matchers
for _, matcher := range r.MatchAny { for _, matcher := range r.MatchAny {
matched, featureStatus, err := evaluateMatchAnyElem(&matcher, features, failFast) matched, featureStatus, err := evaluateMatchAnyElem(&matcher, features, failFast)
if err != nil { if err != nil {
return matchStatus, err return GroupRuleOutput{}, err
} else if matched { } else if matched {
isMatch = true isMatch = true
klog.V(4).InfoS("matchAny matched", "ruleName", r.Name, "matchedFeatures", utils.DelayedDumper(featureStatus.MatchedFeatures)) klog.V(4).InfoS("matchAny matched", "ruleName", r.Name, "matchedFeatures", utils.DelayedDumper(featureStatus.MatchedFeatures))
if failFast { if r.VarsTemplate == "" && failFast {
// there's no need to evaluate other matchers in MatchAny // there's no need to evaluate other matchers in MatchAny
// if there are no templates to be executed on them
break break
} }
if err := executeTemplate(r.VarsTemplate, featureStatus.MatchedFeatures, vars); err != nil {
return GroupRuleOutput{}, err
}
} }
matchStatus.MatchAny = append(matchStatus.MatchAny, featureStatus) matchStatus.MatchAny = append(matchStatus.MatchAny, featureStatus)
} }
if !isMatch && failFast { if !isMatch && failFast {
return matchStatus, nil return GroupRuleOutput{MatchStatus: &matchStatus}, nil
} }
} }
if len(r.MatchFeatures) > 0 { if len(r.MatchFeatures) > 0 {
var err error var err error
if isMatch, matchStatus.MatchFeatureStatus, err = evaluateFeatureMatcher(&r.MatchFeatures, features, failFast); err != nil { if isMatch, matchStatus.MatchFeatureStatus, err = evaluateFeatureMatcher(&r.MatchFeatures, features, failFast); err != nil {
return matchStatus, err return GroupRuleOutput{}, err
} else if !isMatch { } else if !isMatch {
klog.V(2).InfoS("rule did not match", "ruleName", r.Name) klog.V(2).InfoS("rule did not match", "ruleName", r.Name)
return matchStatus, nil return GroupRuleOutput{MatchStatus: &matchStatus}, nil
}
if err := executeTemplate(r.VarsTemplate, matchStatus.MatchedFeatures, vars); err != nil {
return GroupRuleOutput{}, err
} }
} }
maps.Copy(vars, r.Vars)
matchStatus.IsMatch = true matchStatus.IsMatch = true
klog.V(2).InfoS("rule matched", "ruleName", r.Name) ret := GroupRuleOutput{
return matchStatus, nil Vars: vars,
MatchStatus: &matchStatus,
}
klog.V(2).InfoS("rule matched", "ruleName", r.Name, "ruleOutput", utils.DelayedDumper(ret))
return ret, nil
} }
func executeTemplate(tmpl string, in matchedFeatures, out map[string]string) error { func executeTemplate(tmpl string, in matchedFeatures, out map[string]string) error {

View file

@ -717,7 +717,7 @@ func (m *nfdMaster) nfdAPIUpdateNodeFeatureGroup(nfdClient nfdclientset.Interfac
if err != nil { if err != nil {
return fmt.Errorf("failed to get nodes: %w", err) return fmt.Errorf("failed to get nodes: %w", err)
} }
nodeFeaturesList := make([]*nfdv1alpha1.NodeFeature, 0) nodeFeaturesList := make([]*nfdv1alpha1.Features, 0)
for _, node := range nodes.Items { for _, node := range nodes.Items {
// Merge all NodeFeature objects into a single NodeFeatureSpec // Merge all NodeFeature objects into a single NodeFeatureSpec
nodeFeatures, err := m.getAndMergeNodeFeatures(node.Name) nodeFeatures, err := m.getAndMergeNodeFeatures(node.Name)
@ -728,22 +728,22 @@ func (m *nfdMaster) nfdAPIUpdateNodeFeatureGroup(nfdClient nfdclientset.Interfac
// Nothing to do for this node // Nothing to do for this node
continue continue
} }
nodeFeaturesList = append(nodeFeaturesList, nodeFeatures) nodeFeaturesList = append(nodeFeaturesList, &nodeFeatures.Spec.Features)
} }
// Execute rules and create matching groups // Execute rules and create matching groups
nodePool := make([]nfdv1alpha1.FeatureGroupNode, 0) nodePool := make([]nfdv1alpha1.FeatureGroupNode, 0)
nodeGroupValidator := make(map[string]bool) nodeGroupValidator := make(map[string]bool)
for _, rule := range nodeFeatureGroup.Spec.Rules { for _, features := range nodeFeaturesList {
for _, feature := range nodeFeaturesList { for _, rule := range nodeFeatureGroup.Spec.Rules {
match, err := nodefeaturerule.ExecuteGroupRule(&rule, &feature.Spec.Features, true) ruleOut, err := nodefeaturerule.ExecuteGroupRule(&rule, features, true)
if err != nil { if err != nil {
klog.ErrorS(err, "failed to evaluate rule", "ruleName", rule.Name) klog.ErrorS(err, "failed to evaluate rule", "ruleName", rule.Name)
continue continue
} }
if match.IsMatch { if ruleOut.MatchStatus.IsMatch {
system := feature.Spec.Features.Attributes["system.name"] system := features.Attributes["system.name"]
nodeName := system.Elements["nodename"] nodeName := system.Elements["nodename"]
if _, ok := nodeGroupValidator[nodeName]; !ok { if _, ok := nodeGroupValidator[nodeName]; !ok {
nodePool = append(nodePool, nfdv1alpha1.FeatureGroupNode{ nodePool = append(nodePool, nfdv1alpha1.FeatureGroupNode{
@ -752,6 +752,9 @@ func (m *nfdMaster) nfdAPIUpdateNodeFeatureGroup(nfdClient nfdclientset.Interfac
nodeGroupValidator[nodeName] = true nodeGroupValidator[nodeName] = true
} }
} }
// Feed back vars from rule output to features map for subsequent rules to match
features.InsertAttributeFeatures(nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
} }
} }