2021-08-31 11:10:12 +03:00
|
|
|
apiVersion: nfd.k8s-sigs.io/v1alpha1
|
|
|
|
kind: NodeFeatureRule
|
|
|
|
metadata:
|
|
|
|
name: my-rule
|
|
|
|
spec:
|
|
|
|
rules:
|
|
|
|
# The following feature demonstrates the capabilities of the matchFeatures and
|
|
|
|
# matchAny matchers.
|
|
|
|
- name: "my feature rule"
|
2022-11-30 00:36:32 +02:00
|
|
|
taints:
|
|
|
|
- effect: PreferNoSchedule
|
|
|
|
key: "feature.node.kubernetes.io/special-node"
|
|
|
|
value: "true"
|
|
|
|
- effect: NoExecute
|
|
|
|
key: "feature.node.kubernetes.io/dedicated-node"
|
2021-08-31 11:10:12 +03:00
|
|
|
labels:
|
|
|
|
"my-complex-feature": "my-value"
|
|
|
|
# matchFeatures implements a logical AND over feature matchers.
|
|
|
|
matchFeatures:
|
|
|
|
- feature: cpu.cpuid
|
|
|
|
matchExpressions:
|
|
|
|
AVX512F: {op: Exists}
|
|
|
|
- feature: cpu.cstate
|
|
|
|
matchExpressions:
|
|
|
|
enabled: {op: IsTrue}
|
|
|
|
- feature: cpu.pstate
|
|
|
|
matchExpressions:
|
|
|
|
no_turbo: {op: IsFalse}
|
|
|
|
scaling_governor: {op: In, value: ["performance"]}
|
|
|
|
- feature: cpu.rdt
|
|
|
|
matchExpressions:
|
|
|
|
RDTL3CA: {op: Exists}
|
|
|
|
- feature: cpu.sst
|
|
|
|
matchExpressions:
|
|
|
|
bf.enabled: {op: IsTrue}
|
|
|
|
- feature: cpu.topology
|
|
|
|
matchExpressions:
|
|
|
|
hardware_multithreading: {op: IsFalse}
|
|
|
|
|
|
|
|
- feature: kernel.config
|
|
|
|
matchExpressions:
|
|
|
|
X86: {op: Exists}
|
|
|
|
LSM: {op: InRegexp, value: ["apparmor"]}
|
|
|
|
- feature: kernel.loadedmodule
|
|
|
|
matchExpressions:
|
|
|
|
e1000e: {op: Exists}
|
|
|
|
- feature: kernel.selinux
|
|
|
|
matchExpressions:
|
|
|
|
enabled: {op: IsFalse}
|
|
|
|
- feature: kernel.version
|
|
|
|
matchExpressions:
|
|
|
|
major: {op: In, value: ["5"]}
|
|
|
|
minor: {op: Gt, value: ["10"]}
|
|
|
|
|
2021-06-24 20:35:34 +03:00
|
|
|
- feature: storage.block
|
|
|
|
matchExpressions:
|
|
|
|
rotational: {op: In, value: ["0"]}
|
|
|
|
dax: {op: In, value: ["0"]}
|
|
|
|
|
2021-06-24 22:57:46 +03:00
|
|
|
- feature: network.device
|
|
|
|
matchExpressions:
|
|
|
|
operstate: {op: In, value: ["up"]}
|
|
|
|
speed: {op: Gt, value: ["100"]}
|
|
|
|
|
2021-08-25 19:37:32 +03:00
|
|
|
- feature: memory.numa
|
|
|
|
matchExpressions:
|
|
|
|
node_count: {op: Gt, value: ["2"]}
|
|
|
|
- feature: memory.nv
|
|
|
|
matchExpressions:
|
|
|
|
devtype: {op: In, value: ["nd_dax"]}
|
|
|
|
mode: {op: In, value: ["memory"]}
|
|
|
|
|
2021-08-31 11:10:12 +03:00
|
|
|
- feature: system.osrelease
|
|
|
|
matchExpressions:
|
|
|
|
ID: {op: In, value: ["fedora", "centos"]}
|
|
|
|
- feature: system.name
|
|
|
|
matchExpressions:
|
|
|
|
nodename: {op: InRegexp, value: ["^worker-X"]}
|
|
|
|
|
|
|
|
- feature: local.label
|
|
|
|
matchExpressions:
|
|
|
|
custom-feature-knob: {op: Gt, value: ["100"]}
|
|
|
|
|
|
|
|
# matchAny implements a logical IF over all listed matchers (i.e. at
|
|
|
|
# least one must match)
|
|
|
|
matchAny:
|
|
|
|
- matchFeatures:
|
|
|
|
- feature: pci.device
|
|
|
|
matchExpressions:
|
|
|
|
vendor: {op: In, value: ["8086"]}
|
|
|
|
class: {op: In, value: ["0200"]}
|
|
|
|
- feature: usb.device
|
|
|
|
matchExpressions:
|
|
|
|
vendor: {op: In, value: ["8086"]}
|
|
|
|
class: {op: In, value: ["02"]}
|
pkg/apis/nfd: support label name templating
Support templating of label names in feature rules. It is available both
in NodeFeatureRule CRs and in custom rule configuration of nfd-worker.
This patch adds a new 'labelsTemplate' field to the rule spec, making it
possible to dynamically generate multiple labels per rule based on the
matched features. The feature relies on the golang "text/template"
package. When expanded, the template must contain labels in a raw
<key>[=<value>] format (where 'value' defaults to "true"), separated by
newlines i.e.:
- name: <rule-name>
labelsTemplate: |
<label-1>[=<value-1>]
<label-2>[=<value-2>]
...
All the matched features of 'matchFeatures' directives are available for
templating engine in a nested data structure that can be described in
yaml as:
.
<domain-1>:
<key-feature-1>:
- Name: <matched-key>
- ...
<value-feature-1:
- Name: <matched-key>
Value: <matched-value>
- ...
<instance-feature-1>:
- <attribute-1-name>: <attribute-1-value>
<attribute-2-name>: <attribute-2-value>
...
- ...
<domain-2>:
...
That is, the per-feature data available for matching depends on the type
of feature that was matched:
- "key features": only 'Name' is available
- "value features": 'Name' and 'Value' can be used
- "instance features": all attributes of the matched instance are
available
NOTE: In case of matchAny is specified, the template is executed
separately against each individual matchFeatures matcher and the
eventual set of labels is a superset of all these expansions. Consider
the following:
- name: <name>
labelsTemplate: <template>
matchAny:
- matchFeatures: <matcher#1>
- matchFeatures: <matcher#2>
matchFeatures: <matcher#3>
In the example above (assuming the overall result is a match) the
template would be executed on matcher#1 and/or matcher#2 (depending on
whether both or only one of them match), and finally on matcher#3, and
all the labels from these separate expansions would be created (i.e. the
end result would be a union of all the individual expansions).
NOTE 2: The 'labels' field has priority over 'labelsTemplate', i.e.
labels specified in the 'labels' field will override any labels
originating from the 'labelsTemplate' field.
A special case of an empty match expression set matches everything (i.e.
matches/returns all existing keys/values). This makes it simpler to
write templates that run over all values. Also, makes it possible to
later implement support for templates that run over all _keys_ of a
feature.
Some example configurations:
- name: "my-pci-template-features"
labelsTemplate: |
{{ range .pci.device }}intel-{{ .class }}-{{ .device }}=present
{{ end }}
matchFeatures:
- feature: pci.device
matchExpressions:
class: {op: InRegexp, value: ["^06"]}
vendor: ["8086"]
- name: "my-system-template-features"
labelsTemplate: |
{{ range .system.osrelease }}system-{{ .Name }}={{ .Value }}
{{ end }}
matchFeatures:
- feature: system.osRelease
matchExpressions:
ID: {op: Exists}
VERSION_ID.major: {op: Exists}
Imaginative template pipelines are possible, of course, but care must be
taken in order to produce understandable and maintainable rule sets.
2021-05-04 16:30:06 +03:00
|
|
|
|
2022-03-17 18:30:32 +02:00
|
|
|
- name: "avx wildcard rule"
|
|
|
|
labels:
|
|
|
|
"my-avx-feature": "true"
|
|
|
|
matchFeatures:
|
|
|
|
- feature: cpu.cpuid
|
|
|
|
matchName: {op: InRegexp, value: ["^AVX512"]}
|
|
|
|
|
pkg/apis/nfd: support label name templating
Support templating of label names in feature rules. It is available both
in NodeFeatureRule CRs and in custom rule configuration of nfd-worker.
This patch adds a new 'labelsTemplate' field to the rule spec, making it
possible to dynamically generate multiple labels per rule based on the
matched features. The feature relies on the golang "text/template"
package. When expanded, the template must contain labels in a raw
<key>[=<value>] format (where 'value' defaults to "true"), separated by
newlines i.e.:
- name: <rule-name>
labelsTemplate: |
<label-1>[=<value-1>]
<label-2>[=<value-2>]
...
All the matched features of 'matchFeatures' directives are available for
templating engine in a nested data structure that can be described in
yaml as:
.
<domain-1>:
<key-feature-1>:
- Name: <matched-key>
- ...
<value-feature-1:
- Name: <matched-key>
Value: <matched-value>
- ...
<instance-feature-1>:
- <attribute-1-name>: <attribute-1-value>
<attribute-2-name>: <attribute-2-value>
...
- ...
<domain-2>:
...
That is, the per-feature data available for matching depends on the type
of feature that was matched:
- "key features": only 'Name' is available
- "value features": 'Name' and 'Value' can be used
- "instance features": all attributes of the matched instance are
available
NOTE: In case of matchAny is specified, the template is executed
separately against each individual matchFeatures matcher and the
eventual set of labels is a superset of all these expansions. Consider
the following:
- name: <name>
labelsTemplate: <template>
matchAny:
- matchFeatures: <matcher#1>
- matchFeatures: <matcher#2>
matchFeatures: <matcher#3>
In the example above (assuming the overall result is a match) the
template would be executed on matcher#1 and/or matcher#2 (depending on
whether both or only one of them match), and finally on matcher#3, and
all the labels from these separate expansions would be created (i.e. the
end result would be a union of all the individual expansions).
NOTE 2: The 'labels' field has priority over 'labelsTemplate', i.e.
labels specified in the 'labels' field will override any labels
originating from the 'labelsTemplate' field.
A special case of an empty match expression set matches everything (i.e.
matches/returns all existing keys/values). This makes it simpler to
write templates that run over all values. Also, makes it possible to
later implement support for templates that run over all _keys_ of a
feature.
Some example configurations:
- name: "my-pci-template-features"
labelsTemplate: |
{{ range .pci.device }}intel-{{ .class }}-{{ .device }}=present
{{ end }}
matchFeatures:
- feature: pci.device
matchExpressions:
class: {op: InRegexp, value: ["^06"]}
vendor: ["8086"]
- name: "my-system-template-features"
labelsTemplate: |
{{ range .system.osrelease }}system-{{ .Name }}={{ .Value }}
{{ end }}
matchFeatures:
- feature: system.osRelease
matchExpressions:
ID: {op: Exists}
VERSION_ID.major: {op: Exists}
Imaginative template pipelines are possible, of course, but care must be
taken in order to produce understandable and maintainable rule sets.
2021-05-04 16:30:06 +03:00
|
|
|
# The following features demonstreate label templating capabilities
|
|
|
|
- name: "my system template feature"
|
|
|
|
labelsTemplate: |
|
|
|
|
{{ range .system.osrelease }}my-system-feature.{{ .Name }}={{ .Value }}
|
|
|
|
{{ end }}
|
|
|
|
matchFeatures:
|
|
|
|
- feature: system.osrelease
|
|
|
|
matchExpressions:
|
|
|
|
ID: {op: InRegexp, value: ["^open.*"]}
|
|
|
|
VERSION_ID.major: {op: In, value: ["13", "15"]}
|
|
|
|
|
|
|
|
- name: "my pci template feature"
|
|
|
|
labelsTemplate: |
|
|
|
|
{{ range .pci.device }}my-pci-device.{{ .class }}-{{ .device }}=with-cpuid
|
|
|
|
{{ end }}
|
|
|
|
matchFeatures:
|
|
|
|
- feature: pci.device
|
|
|
|
matchExpressions:
|
|
|
|
class: {op: InRegexp, value: ["^06"]}
|
|
|
|
vendor: {op: In, value: ["8086"]}
|
|
|
|
- feature: cpu.cpuid
|
|
|
|
matchExpressions:
|
|
|
|
AVX: {op: Exists}
|
2021-06-18 18:29:08 +03:00
|
|
|
|
|
|
|
# The following examples demonstrate vars field and back-referencing
|
|
|
|
# previous labels and vars
|
|
|
|
- name: "my dummy kernel rule"
|
|
|
|
labels:
|
|
|
|
"my.kernel.feature": "true"
|
|
|
|
matchFeatures:
|
|
|
|
- feature: kernel.version
|
|
|
|
matchExpressions:
|
|
|
|
major: {op: Gt, value: ["2"]}
|
|
|
|
|
|
|
|
- name: "my dummy rule with no labels"
|
|
|
|
vars:
|
|
|
|
"my.dummy.var": "1"
|
|
|
|
matchFeatures:
|
|
|
|
- feature: cpu.cpuid
|
|
|
|
matchExpressions: {}
|
|
|
|
|
|
|
|
- name: "my rule using backrefs"
|
|
|
|
labels:
|
|
|
|
"my.backref.feature": "true"
|
|
|
|
matchFeatures:
|
|
|
|
- feature: rule.matched
|
|
|
|
matchExpressions:
|
|
|
|
my.kernel.feature: {op: IsTrue}
|
|
|
|
my.dummy.var: {op: Gt, value: ["0"]}
|
2022-03-17 18:30:32 +02:00
|
|
|
|
|
|
|
- name: "kconfig template rule"
|
|
|
|
labelsTemplate: |
|
|
|
|
{{ range .kernel.config }}kconfig-{{ .Name }}={{ .Value }}
|
|
|
|
{{ end }}
|
|
|
|
matchFeatures:
|
|
|
|
- feature: kernel.config
|
|
|
|
matchName: {op: In, value: ["SWAP", "X86", "ARM"]}
|