From 96262a3784448ecd6922343017f88881f53db16c Mon Sep 17 00:00:00 2001 From: Markus Lehtonen Date: Mon, 3 Mar 2025 15:02:31 +0200 Subject: [PATCH] nodefeaturegroup: implement vars Implement handling of Vars and VarsTemplate fields or NodeFeatureGroup. --- pkg/apis/nfd/nodefeaturerule/rule.go | 37 ++++++++++++++++++++++------ pkg/nfd-master/nfd-master.go | 17 +++++++------ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/pkg/apis/nfd/nodefeaturerule/rule.go b/pkg/apis/nfd/nodefeaturerule/rule.go index 21e052b0e..a02647dfa 100644 --- a/pkg/apis/nfd/nodefeaturerule/rule.go +++ b/pkg/apis/nfd/nodefeaturerule/rule.go @@ -147,50 +147,71 @@ func Execute(r *nfdv1alpha1.Rule, features *nfdv1alpha1.Features, failFast bool) 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 // 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 ( matchStatus MatchStatus isMatch bool ) + vars := make(map[string]string) + if n := len(r.MatchAny); n > 0 { matchStatus.MatchAny = make([]*MatchFeatureStatus, 0, n) // Logical OR over the matchAny matchers for _, matcher := range r.MatchAny { matched, featureStatus, err := evaluateMatchAnyElem(&matcher, features, failFast) if err != nil { - return matchStatus, err + return GroupRuleOutput{}, err } else if matched { isMatch = true 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 + // if there are no templates to be executed on them break } + + if err := executeTemplate(r.VarsTemplate, featureStatus.MatchedFeatures, vars); err != nil { + return GroupRuleOutput{}, err + } } matchStatus.MatchAny = append(matchStatus.MatchAny, featureStatus) } if !isMatch && failFast { - return matchStatus, nil + return GroupRuleOutput{MatchStatus: &matchStatus}, nil } } if len(r.MatchFeatures) > 0 { var err error if isMatch, matchStatus.MatchFeatureStatus, err = evaluateFeatureMatcher(&r.MatchFeatures, features, failFast); err != nil { - return matchStatus, err + return GroupRuleOutput{}, err } else if !isMatch { 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 - klog.V(2).InfoS("rule matched", "ruleName", r.Name) - return matchStatus, nil + ret := GroupRuleOutput{ + 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 { diff --git a/pkg/nfd-master/nfd-master.go b/pkg/nfd-master/nfd-master.go index 51e02345d..fbe12e040 100644 --- a/pkg/nfd-master/nfd-master.go +++ b/pkg/nfd-master/nfd-master.go @@ -717,7 +717,7 @@ func (m *nfdMaster) nfdAPIUpdateNodeFeatureGroup(nfdClient nfdclientset.Interfac if err != nil { return fmt.Errorf("failed to get nodes: %w", err) } - nodeFeaturesList := make([]*nfdv1alpha1.NodeFeature, 0) + nodeFeaturesList := make([]*nfdv1alpha1.Features, 0) for _, node := range nodes.Items { // Merge all NodeFeature objects into a single NodeFeatureSpec nodeFeatures, err := m.getAndMergeNodeFeatures(node.Name) @@ -728,22 +728,22 @@ func (m *nfdMaster) nfdAPIUpdateNodeFeatureGroup(nfdClient nfdclientset.Interfac // Nothing to do for this node continue } - nodeFeaturesList = append(nodeFeaturesList, nodeFeatures) + nodeFeaturesList = append(nodeFeaturesList, &nodeFeatures.Spec.Features) } // Execute rules and create matching groups nodePool := make([]nfdv1alpha1.FeatureGroupNode, 0) nodeGroupValidator := make(map[string]bool) - for _, rule := range nodeFeatureGroup.Spec.Rules { - for _, feature := range nodeFeaturesList { - match, err := nodefeaturerule.ExecuteGroupRule(&rule, &feature.Spec.Features, true) + for _, features := range nodeFeaturesList { + for _, rule := range nodeFeatureGroup.Spec.Rules { + ruleOut, err := nodefeaturerule.ExecuteGroupRule(&rule, features, true) if err != nil { klog.ErrorS(err, "failed to evaluate rule", "ruleName", rule.Name) continue } - if match.IsMatch { - system := feature.Spec.Features.Attributes["system.name"] + if ruleOut.MatchStatus.IsMatch { + system := features.Attributes["system.name"] nodeName := system.Elements["nodename"] if _, ok := nodeGroupValidator[nodeName]; !ok { nodePool = append(nodePool, nfdv1alpha1.FeatureGroupNode{ @@ -752,6 +752,9 @@ func (m *nfdMaster) nfdAPIUpdateNodeFeatureGroup(nfdClient nfdclientset.Interfac 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) } }