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

nfd-master: allow profile.node.kubernetes.io label ns

Add a separate label namespace for profile labels, intended for
user-specified higher level "meta features". Also sub-namespaces of this
(i.e. <sub-ns>.profile.node.kubernetes.io) are allowed.
This commit is contained in:
Markus Lehtonen 2021-07-06 15:03:50 +03:00
parent c3760fbbab
commit 55bd633425
4 changed files with 32 additions and 13 deletions

View file

@ -175,8 +175,9 @@ nfd-master -label-whitelist='.*cpuid\.'
The `-extra-label-ns` flag specifies a comma-separated list of allowed feature The `-extra-label-ns` flag specifies a comma-separated list of allowed feature
label namespaces. By default, nfd-master only allows creating labels in the label namespaces. By default, nfd-master only allows creating labels in the
default `feature.node.kubernetes.io` label namespace and its sub-namespaces default `feature.node.kubernetes.io` and `profile.node.kubernetes.io` label
(e.g. `vendor.feature.node.kubernetes.io`). This option can be used to allow namespaces and their sub-namespaces (e.g. `vendor.feature.node.kubernetes.io`
and `sub.ns.profile.node.kubernetes.io`). This option can be used to allow
other vendor or application specific namespaces for custom labels from the other vendor or application specific namespaces for custom labels from the
local and custom feature sources. local and custom feature sources.

View file

@ -31,8 +31,9 @@ The published node labels encode a few pieces of information:
- all built-in labels use `feature.node.kubernetes.io` - all built-in labels use `feature.node.kubernetes.io`
- user-specified custom labels ([custom](#custom) and - user-specified custom labels ([custom](#custom) and
[local](#local--user-specific-features) feature sources) [local](#local--user-specific-features) feature sources)
- `feature.node.kubernetes.io` and its sub-namespaces (e.g. - `feature.node.kubernetes.io` and `profile.node.kubernetes.io` plus their
`vendor.profile.node.kubernetes.io`) are allowed by default sub-namespaces (e.g. `vendor.profile.node.kubernetes.io` and
`sub.ns.profile.node.kubernetes.io`) are allowed by default
- additional namespaces may be enabled with the - additional namespaces may be enabled with the
[`--extra-label-ns`](../advanced/master-commandline-reference#-extra-label-ns) [`--extra-label-ns`](../advanced/master-commandline-reference#-extra-label-ns)
command line flag of nfd-master command line flag of nfd-master
@ -376,7 +377,7 @@ custom:
matchOn: matchOn:
- kConfig: ["GCC_VERSION=100101"] - kConfig: ["GCC_VERSION=100101"]
loadedKMod: ["kmod1"] loadedKMod: ["kmod1"]
- name: "my.datacenter" - name: "profile.node.kubernetes.io/my-datacenter"
value: "datacenter-1" value: "datacenter-1"
matchOn: matchOn:
- nodename: [ "node-datacenter1-rack.*-server.*" ] - nodename: [ "node-datacenter1-rack.*-server.*" ]
@ -413,7 +414,7 @@ __In the example above:__
in-tree `kmod1` kernel module is loaded __AND__ it's built with in-tree `kmod1` kernel module is loaded __AND__ it's built with
`GCC_VERSION=100101`. `GCC_VERSION=100101`.
- A node would contain the label: - A node would contain the label:
`feature.node.kubernetes.io/my.datacenter=datacenter-1` if the node's name `profile.node.kubernetes.io/my-datacenter=datacenter-1` if the node's name
matches the `node-datacenter1-rack.*-server.*` pattern, e.g. matches the `node-datacenter1-rack.*-server.*` pattern, e.g.
`node-datacenter1-rack2-server42` `node-datacenter1-rack2-server42`
@ -577,7 +578,8 @@ e.g. for overriding labels created by other feature sources.
You can also override the default namespace of your labels using this format: You can also override the default namespace of your labels using this format:
`<namespace>/<name>[=<value>]`. If using something else than `<namespace>/<name>[=<value>]`. If using something else than
`[<sub-ns>.]feature.node.kubernetes.io`, you must whitelist your namespace `[<sub-ns>.]feature.node.kubernetes.io` or
`[<sub-ns>.]profile.node.kubernetes.io`, you must whitelist your namespace
using the `-extra-label-ns` option on the master. using the `-extra-label-ns` option on the master.
In this case, the name of the In this case, the name of the
file will not be added to the label name. For example, if you want to add the file will not be added to the label name. For example, if you want to add the

View file

@ -63,7 +63,11 @@ func newMockMaster(apihelper apihelper.APIHelpers) *nfdMaster {
func TestUpdateNodeFeatures(t *testing.T) { func TestUpdateNodeFeatures(t *testing.T) {
Convey("When I update the node using fake client", t, func() { Convey("When I update the node using fake client", t, func() {
fakeFeatureLabels := map[string]string{FeatureLabelNs + "/source-feature.1": "1", FeatureLabelNs + "/source-feature.2": "2", FeatureLabelNs + "/source-feature.3": "val3"} fakeFeatureLabels := map[string]string{
FeatureLabelNs + "/source-feature.1": "1",
FeatureLabelNs + "/source-feature.2": "2",
FeatureLabelNs + "/source-feature.3": "val3",
ProfileLabelNs + "/profile-a": "val4"}
fakeAnnotations := map[string]string{"my-annotation": "my-val"} fakeAnnotations := map[string]string{"my-annotation": "my-val"}
fakeExtResources := ExtendedResources{FeatureLabelNs + "/source-feature.1": "1", FeatureLabelNs + "/source-feature.2": "2"} fakeExtResources := ExtendedResources{FeatureLabelNs + "/source-feature.1": "1", FeatureLabelNs + "/source-feature.2": "2"}
@ -354,18 +358,23 @@ func TestSetLabels(t *testing.T) {
Convey("When --extra-label-ns and --instance are specified", func() { Convey("When --extra-label-ns and --instance are specified", func() {
// In the gRPC request the label names may omit the default ns // In the gRPC request the label names may omit the default ns
instance := "foo" instance := "foo"
vendorLabel := "vendor." + FeatureLabelNs + "/feature-4" vendorFeatureLabel := "vendor." + FeatureLabelNs + "/feature-4"
vendorProfileLabel := "vendor." + ProfileLabelNs + "/feature-5"
mockLabels := map[string]string{"feature-1": "val-1", mockLabels := map[string]string{"feature-1": "val-1",
"valid.ns/feature-2": "val-2", "valid.ns/feature-2": "val-2",
"invalid.ns/feature-3": "val-3", "invalid.ns/feature-3": "val-3",
vendorLabel: " val-4"} vendorFeatureLabel: " val-4",
vendorProfileLabel: " val-5"}
expectedPatches := []apihelper.JsonPatch{ expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+wvAnnotation, workerVer), apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+wvAnnotation, workerVer),
apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+flAnnotation, "feature-1,valid.ns/feature-2,"+vendorLabel), apihelper.NewJsonPatch("add", "/metadata/annotations",
instance+"."+flAnnotation,
"feature-1,valid.ns/feature-2,"+vendorFeatureLabel+","+vendorProfileLabel),
apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+erAnnotation, ""), apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+erAnnotation, ""),
apihelper.NewJsonPatch("add", "/metadata/labels", FeatureLabelNs+"/feature-1", mockLabels["feature-1"]), apihelper.NewJsonPatch("add", "/metadata/labels", FeatureLabelNs+"/feature-1", mockLabels["feature-1"]),
apihelper.NewJsonPatch("add", "/metadata/labels", "valid.ns/feature-2", mockLabels["valid.ns/feature-2"]), apihelper.NewJsonPatch("add", "/metadata/labels", "valid.ns/feature-2", mockLabels["valid.ns/feature-2"]),
apihelper.NewJsonPatch("add", "/metadata/labels", vendorLabel, mockLabels[vendorLabel]), apihelper.NewJsonPatch("add", "/metadata/labels", vendorFeatureLabel, mockLabels[vendorFeatureLabel]),
apihelper.NewJsonPatch("add", "/metadata/labels", vendorProfileLabel, mockLabels[vendorProfileLabel]),
} }
mockMaster.args.ExtraLabelNs = map[string]struct{}{"valid.ns": {}} mockMaster.args.ExtraLabelNs = map[string]struct{}{"valid.ns": {}}

View file

@ -49,6 +49,12 @@ const (
// FeatureLabelSubNsSuffix is the suffix for allowed feature label sub-namespaces // FeatureLabelSubNsSuffix is the suffix for allowed feature label sub-namespaces
FeatureLabelSubNsSuffix = "." + FeatureLabelNs FeatureLabelSubNsSuffix = "." + FeatureLabelNs
// ProfileLabelNs is the namespace for profile labels
ProfileLabelNs = "profile.node.kubernetes.io"
// ProfileLabelSubNsSuffix is the suffix for allowed profile label sub-namespaces
ProfileLabelSubNsSuffix = "." + ProfileLabelNs
// AnnotationNsBase namespace for all NFD-related annotations // AnnotationNsBase namespace for all NFD-related annotations
AnnotationNsBase = "nfd.node.kubernetes.io" AnnotationNsBase = "nfd.node.kubernetes.io"
@ -317,7 +323,8 @@ func filterFeatureLabels(labels Labels, extraLabelNs map[string]struct{}, labelW
ns, name := splitNs(label) ns, name := splitNs(label)
// Check label namespace, filter out if ns is not whitelisted // Check label namespace, filter out if ns is not whitelisted
if ns != FeatureLabelNs && !strings.HasSuffix(ns, FeatureLabelSubNsSuffix) { if ns != FeatureLabelNs && ns != ProfileLabelNs &&
!strings.HasSuffix(ns, FeatureLabelSubNsSuffix) && !strings.HasSuffix(ns, ProfileLabelSubNsSuffix) {
if _, ok := extraLabelNs[ns]; !ok { if _, ok := extraLabelNs[ns]; !ok {
klog.Errorf("Namespace %q is not allowed. Ignoring label %q\n", ns, label) klog.Errorf("Namespace %q is not allowed. Ignoring label %q\n", ns, label)
continue continue