From 55bd63342510bdeb6e320761a929544a9469d3a2 Mon Sep 17 00:00:00 2001 From: Markus Lehtonen Date: Tue, 6 Jul 2021 15:03:50 +0300 Subject: [PATCH] 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. .profile.node.kubernetes.io) are allowed. --- docs/advanced/master-commandline-reference.md | 5 +++-- docs/get-started/features.md | 12 +++++++----- pkg/nfd-master/nfd-master-internal_test.go | 19 ++++++++++++++----- pkg/nfd-master/nfd-master.go | 9 ++++++++- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/docs/advanced/master-commandline-reference.md b/docs/advanced/master-commandline-reference.md index 73b9bbc82..eeaa91410 100644 --- a/docs/advanced/master-commandline-reference.md +++ b/docs/advanced/master-commandline-reference.md @@ -175,8 +175,9 @@ nfd-master -label-whitelist='.*cpuid\.' 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 -default `feature.node.kubernetes.io` label namespace and its sub-namespaces -(e.g. `vendor.feature.node.kubernetes.io`). This option can be used to allow +default `feature.node.kubernetes.io` and `profile.node.kubernetes.io` label +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 local and custom feature sources. diff --git a/docs/get-started/features.md b/docs/get-started/features.md index 158b7d638..8ea7ae5f9 100644 --- a/docs/get-started/features.md +++ b/docs/get-started/features.md @@ -31,8 +31,9 @@ The published node labels encode a few pieces of information: - all built-in labels use `feature.node.kubernetes.io` - user-specified custom labels ([custom](#custom) and [local](#local--user-specific-features) feature sources) - - `feature.node.kubernetes.io` and its sub-namespaces (e.g. - `vendor.profile.node.kubernetes.io`) are allowed by default + - `feature.node.kubernetes.io` and `profile.node.kubernetes.io` plus their + 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 [`--extra-label-ns`](../advanced/master-commandline-reference#-extra-label-ns) command line flag of nfd-master @@ -376,7 +377,7 @@ custom: matchOn: - kConfig: ["GCC_VERSION=100101"] loadedKMod: ["kmod1"] - - name: "my.datacenter" + - name: "profile.node.kubernetes.io/my-datacenter" value: "datacenter-1" matchOn: - 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 `GCC_VERSION=100101`. - 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. `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: `/[=]`. If using something else than -`[.]feature.node.kubernetes.io`, you must whitelist your namespace +`[.]feature.node.kubernetes.io` or +`[.]profile.node.kubernetes.io`, you must whitelist your namespace using the `-extra-label-ns` option on the master. In this case, the name of the file will not be added to the label name. For example, if you want to add the diff --git a/pkg/nfd-master/nfd-master-internal_test.go b/pkg/nfd-master/nfd-master-internal_test.go index f030805d1..18b3eb3db 100644 --- a/pkg/nfd-master/nfd-master-internal_test.go +++ b/pkg/nfd-master/nfd-master-internal_test.go @@ -63,7 +63,11 @@ func newMockMaster(apihelper apihelper.APIHelpers) *nfdMaster { func TestUpdateNodeFeatures(t *testing.T) { 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"} 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() { // In the gRPC request the label names may omit the default ns 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", "valid.ns/feature-2": "val-2", "invalid.ns/feature-3": "val-3", - vendorLabel: " val-4"} + vendorFeatureLabel: " val-4", + vendorProfileLabel: " val-5"} expectedPatches := []apihelper.JsonPatch{ 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/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", 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": {}} diff --git a/pkg/nfd-master/nfd-master.go b/pkg/nfd-master/nfd-master.go index 9b3bfe3e4..d54b2b869 100644 --- a/pkg/nfd-master/nfd-master.go +++ b/pkg/nfd-master/nfd-master.go @@ -49,6 +49,12 @@ const ( // FeatureLabelSubNsSuffix is the suffix for allowed feature label sub-namespaces 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 = "nfd.node.kubernetes.io" @@ -317,7 +323,8 @@ func filterFeatureLabels(labels Labels, extraLabelNs map[string]struct{}, labelW ns, name := splitNs(label) // 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 { klog.Errorf("Namespace %q is not allowed. Ignoring label %q\n", ns, label) continue