mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-14 11:57:51 +00:00
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 <key>=<value> format, separated by newlines i.e.: - name: <rule-name> varsTemplate: | <label-1>=<value-1> <label-2>=<value-2> ... 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'
This commit is contained in:
parent
f75303ce43
commit
b648d005e1
5 changed files with 81 additions and 1 deletions
|
@ -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 (<key>[=<value>])
|
||||
separated by newlines.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
|
|
|
@ -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 (<key>[=<value>])
|
||||
separated by newlines.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
|
|
|
@ -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{}
|
||||
|
|
|
@ -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}}=true
|
||||
{{end}}`,
|
||||
MatchFeatures: FeatureMatcher{
|
||||
FeatureMatcherTerm{
|
||||
|
@ -297,10 +303,19 @@ 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")
|
||||
|
||||
//
|
||||
// Test error cases
|
||||
|
@ -320,6 +335,7 @@ label-2=
|
|||
m, err = r2.Execute(f)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, map[string]string{"foo": "bar"}, m.Labels, "instances should have matched")
|
||||
assert.Empty(t, m.Vars)
|
||||
|
||||
r2.labelsTemplate = nil
|
||||
r2.LabelsTemplate = "foo"
|
||||
|
@ -330,4 +346,23 @@ label-2=
|
|||
r2.LabelsTemplate = "{{"
|
||||
_, err = r2.Execute(f)
|
||||
assert.Error(t, err)
|
||||
|
||||
r2.labelsTemplate = nil
|
||||
r2.LabelsTemplate = ""
|
||||
r2.VarsTemplate = "bar=baz"
|
||||
m, err = r2.Execute(f)
|
||||
assert.Nil(t, err)
|
||||
assert.Empty(t, m.Labels)
|
||||
assert.Equal(t, map[string]string{"bar": "baz"}, m.Vars, "instances should have matched")
|
||||
|
||||
r2.varsTemplate = nil
|
||||
r2.VarsTemplate = "bar"
|
||||
_, err = r2.Execute(f)
|
||||
assert.Error(t, err)
|
||||
|
||||
r2.varsTemplate = nil
|
||||
r2.VarsTemplate = "{{"
|
||||
_, err = r2.Execute(f)
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
||||
|
|
|
@ -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 (<key>[=<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"`
|
||||
|
|
Loading…
Reference in a new issue