From a302045e25d0833c02ed80b3a19a4f4ece6a11f9 Mon Sep 17 00:00:00 2001 From: Markus Lehtonen Date: Tue, 23 Nov 2021 23:01:22 +0200 Subject: [PATCH] pkg/apis/nfd: support templating of "vars" Support templating of var names in a similar manner as labels. Add support for a new 'varsTemplate' field to the feature rule spec which is treated similarly to the 'labelsTemplate' field. The value of the field is processed through the golang "text/template" template engine and the expanded value must contain variables in a raw [=] format (where 'value' defaults to "true"), separated by newlines i.e.: - name: varsTemplate: | [=] [=] ... Similar rules as for 'labelsTemplate' apply, i.e. 1. In case of matchAny is specified, the template is executed separately against each individual matchFeatures matcher. 2. 'vars' field has priority over 'varsTemplate' --- .../base/nfd-crds/nodefeaturerule-crd.yaml | 6 ++++ .../manifests/nodefeaturerule-crd.yaml | 6 ++++ pkg/apis/nfd/v1alpha1/rule.go | 29 ++++++++++++++++++- pkg/apis/nfd/v1alpha1/rule_test.go | 15 ++++++++++ pkg/apis/nfd/v1alpha1/types.go | 6 ++++ 5 files changed, 61 insertions(+), 1 deletion(-) diff --git a/deployment/base/nfd-crds/nodefeaturerule-crd.yaml b/deployment/base/nfd-crds/nodefeaturerule-crd.yaml index 519991bb1a..cd9b48bf46 100644 --- a/deployment/base/nfd-crds/nodefeaturerule-crd.yaml +++ b/deployment/base/nfd-crds/nodefeaturerule-crd.yaml @@ -197,6 +197,12 @@ spec: more complex rule hierarchies, without exposing intermediary output values as labels. type: object + varsTemplate: + description: VarsTemplate specifies a template to expand for + dynamically generating multiple variables. Data (after template + expansion) must be keys with an optional value ([=]) + separated by newlines. + type: string required: - name type: object diff --git a/deployment/helm/node-feature-discovery/manifests/nodefeaturerule-crd.yaml b/deployment/helm/node-feature-discovery/manifests/nodefeaturerule-crd.yaml index 519991bb1a..cd9b48bf46 100644 --- a/deployment/helm/node-feature-discovery/manifests/nodefeaturerule-crd.yaml +++ b/deployment/helm/node-feature-discovery/manifests/nodefeaturerule-crd.yaml @@ -197,6 +197,12 @@ spec: more complex rule hierarchies, without exposing intermediary output values as labels. type: object + varsTemplate: + description: VarsTemplate specifies a template to expand for + dynamically generating multiple variables. Data (after template + expansion) must be keys with an optional value ([=]) + separated by newlines. + type: string required: - name type: object diff --git a/pkg/apis/nfd/v1alpha1/rule.go b/pkg/apis/nfd/v1alpha1/rule.go index 0b02650300..ca641dec94 100644 --- a/pkg/apis/nfd/v1alpha1/rule.go +++ b/pkg/apis/nfd/v1alpha1/rule.go @@ -58,7 +58,9 @@ func (r *Rule) Execute(features feature.Features) (RuleOutput, error) { if err := r.executeLabelsTemplate(m, labels); err != nil { return RuleOutput{}, err } - + if err := r.executeVarsTemplate(m, vars); err != nil { + return RuleOutput{}, err + } } } if !matched { @@ -78,6 +80,9 @@ func (r *Rule) Execute(features feature.Features) (RuleOutput, error) { if err := r.executeLabelsTemplate(m, labels); err != nil { return RuleOutput{}, err } + if err := r.executeVarsTemplate(m, vars); err != nil { + return RuleOutput{}, err + } } } @@ -117,6 +122,28 @@ func (r *Rule) executeLabelsTemplate(in matchedFeatures, out map[string]string) return nil } +func (r *Rule) executeVarsTemplate(in matchedFeatures, out map[string]string) error { + if r.VarsTemplate == "" { + return nil + } + if r.varsTemplate == nil { + t, err := newTemplateHelper(r.VarsTemplate) + if err != nil { + return err + } + r.varsTemplate = t + } + + vars, err := r.varsTemplate.expandMap(in) + if err != nil { + return err + } + for k, v := range vars { + out[k] = v + } + return nil +} + type matchedFeatures map[string]domainMatchedFeatures type domainMatchedFeatures map[string]interface{} diff --git a/pkg/apis/nfd/v1alpha1/rule_test.go b/pkg/apis/nfd/v1alpha1/rule_test.go index db3878a6da..8d554e634e 100644 --- a/pkg/apis/nfd/v1alpha1/rule_test.go +++ b/pkg/apis/nfd/v1alpha1/rule_test.go @@ -254,6 +254,12 @@ label-2= {{range .domain_1.vf_1}}vf-{{.Name}}=vf-{{.Value}} {{end}} {{range .domain_1.if_1}}if-{{index . "attr-1"}}_{{index . "attr-2"}}=present +{{end}}`, + Vars: map[string]string{"var-1": "var-val-1"}, + VarsTemplate: ` +var-1=value-will-be-overridden-by-vars +var-2= +{{range .domain_1.kf_1}}kf-{{.Name}} {{end}}`, MatchFeatures: FeatureMatcher{ FeatureMatcherTerm{ @@ -297,8 +303,17 @@ label-2= "if-1_val-2": "present", "if-10_val-20": "present", } + expectedVars := map[string]string{ + "var-1": "var-val-1", + "var-2": "", + // From template + "kf-key-a": "true", + "kf-key-c": "true", + "kf-foo": "true", + } m, err := r1.Execute(f) assert.Nilf(t, err, "unexpected error: %v", err) assert.Equal(t, expectedLabels, m.Labels, "instances should have matched") + assert.Equal(t, expectedVars, m.Vars, "instances should have matched") } diff --git a/pkg/apis/nfd/v1alpha1/types.go b/pkg/apis/nfd/v1alpha1/types.go index 84b3d045ad..d7bf89e7df 100644 --- a/pkg/apis/nfd/v1alpha1/types.go +++ b/pkg/apis/nfd/v1alpha1/types.go @@ -72,6 +72,12 @@ type Rule struct { // +optional Vars map[string]string `json:"vars"` + // VarsTemplate specifies a template to expand for dynamically generating + // multiple variables. Data (after template expansion) must be keys with an + // optional value ([=]) separated by newlines. + // +optional + VarsTemplate string `json:"varsTemplate"` + // MatchFeatures specifies a set of matcher terms all of which must match. // +optional MatchFeatures FeatureMatcher `json:"matchFeatures"`