1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-15 04:57:56 +00:00

apis/nfd: move annotation and label consts from nfd-master

Move consts related to NFD annotations and labels from nfd-master to the
api. Makes them more logically accessible for clients.
This commit is contained in:
Markus Lehtonen 2022-08-16 21:39:11 +03:00
parent 906aad6717
commit c1e6b41e56
4 changed files with 137 additions and 119 deletions

View file

@ -0,0 +1,46 @@
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
const (
// FeatureLabelNs is the (default) namespace for feature labels.
FeatureLabelNs = "feature.node.kubernetes.io"
// 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
// AnnotationNs namespace for all NFD-related annotations.
AnnotationNs = "nfd.node.kubernetes.io"
// ExtendedResourceAnnotation is the annotation that holds all extended resources managed by NFD.
ExtendedResourceAnnotation = AnnotationNs + "/extended-resources"
// FeatureLabelsAnnotation is the annotation that holds all feature labels managed by NFD.
FeatureLabelsAnnotation = AnnotationNs + "/feature-labels"
// MasterVersionAnnotation is the annotation that holds the version of nfd-master running on the node
MasterVersionAnnotation = AnnotationNs + "/master.version"
// WorkerVersionAnnotation is the annotation that holds the version of nfd-worker running on the node
WorkerVersionAnnotation = AnnotationNs + "/worker.version"
)

View file

@ -17,7 +17,6 @@ limitations under the License.
package nfdmaster package nfdmaster
import ( import (
"path"
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
@ -33,6 +32,7 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sclient "k8s.io/client-go/kubernetes" k8sclient "k8s.io/client-go/kubernetes"
"sigs.k8s.io/node-feature-discovery/pkg/apihelper" "sigs.k8s.io/node-feature-discovery/pkg/apihelper"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
"sigs.k8s.io/node-feature-discovery/pkg/labeler" "sigs.k8s.io/node-feature-discovery/pkg/labeler"
"sigs.k8s.io/node-feature-discovery/pkg/utils" "sigs.k8s.io/node-feature-discovery/pkg/utils"
"sigs.k8s.io/node-feature-discovery/pkg/version" "sigs.k8s.io/node-feature-discovery/pkg/version"
@ -54,32 +54,31 @@ func newMockNode() *api.Node {
func newMockMaster(apihelper apihelper.APIHelpers) *nfdMaster { func newMockMaster(apihelper apihelper.APIHelpers) *nfdMaster {
return &nfdMaster{ return &nfdMaster{
nodeName: mockNodeName, nodeName: mockNodeName,
annotationNs: AnnotationNsBase, args: Args{LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")}},
args: Args{LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")}}, apihelper: apihelper,
apihelper: apihelper,
} }
} }
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{ fakeFeatureLabels := map[string]string{
FeatureLabelNs + "/source-feature.1": "1", nfdv1alpha1.FeatureLabelNs + "/source-feature.1": "1",
FeatureLabelNs + "/source-feature.2": "2", nfdv1alpha1.FeatureLabelNs + "/source-feature.2": "2",
FeatureLabelNs + "/source-feature.3": "val3", nfdv1alpha1.FeatureLabelNs + "/source-feature.3": "val3",
ProfileLabelNs + "/profile-a": "val4"} nfdv1alpha1.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{nfdv1alpha1.FeatureLabelNs + "/source-feature.1": "1", nfdv1alpha1.FeatureLabelNs + "/source-feature.2": "2"}
fakeFeatureLabelNames := make([]string, 0, len(fakeFeatureLabels)) fakeFeatureLabelNames := make([]string, 0, len(fakeFeatureLabels))
for k := range fakeFeatureLabels { for k := range fakeFeatureLabels {
fakeFeatureLabelNames = append(fakeFeatureLabelNames, strings.TrimPrefix(k, FeatureLabelNs+"/")) fakeFeatureLabelNames = append(fakeFeatureLabelNames, strings.TrimPrefix(k, nfdv1alpha1.FeatureLabelNs+"/"))
} }
sort.Strings(fakeFeatureLabelNames) sort.Strings(fakeFeatureLabelNames)
fakeExtResourceNames := make([]string, 0, len(fakeExtResources)) fakeExtResourceNames := make([]string, 0, len(fakeExtResources))
for k := range fakeExtResources { for k := range fakeExtResources {
fakeExtResourceNames = append(fakeExtResourceNames, strings.TrimPrefix(k, FeatureLabelNs+"/")) fakeExtResourceNames = append(fakeExtResourceNames, strings.TrimPrefix(k, nfdv1alpha1.FeatureLabelNs+"/"))
} }
sort.Strings(fakeExtResourceNames) sort.Strings(fakeExtResourceNames)
@ -88,15 +87,15 @@ func TestUpdateNodeFeatures(t *testing.T) {
mockClient := &k8sclient.Clientset{} mockClient := &k8sclient.Clientset{}
// Mock node with old features // Mock node with old features
mockNode := newMockNode() mockNode := newMockNode()
mockNode.Labels[FeatureLabelNs+"/old-feature"] = "old-value" mockNode.Labels[nfdv1alpha1.FeatureLabelNs+"/old-feature"] = "old-value"
mockNode.Annotations[AnnotationNsBase+"/feature-labels"] = "old-feature" mockNode.Annotations[nfdv1alpha1.AnnotationNs+"/feature-labels"] = "old-feature"
Convey("When I successfully update the node with feature labels", func() { Convey("When I successfully update the node with feature labels", func() {
// Create a list of expected node metadata patches // Create a list of expected node metadata patches
metadataPatches := []apihelper.JsonPatch{ metadataPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("replace", "/metadata/annotations", AnnotationNsBase+"/feature-labels", strings.Join(fakeFeatureLabelNames, ",")), apihelper.NewJsonPatch("replace", "/metadata/annotations", nfdv1alpha1.AnnotationNs+"/feature-labels", strings.Join(fakeFeatureLabelNames, ",")),
apihelper.NewJsonPatch("add", "/metadata/annotations", AnnotationNsBase+"/extended-resources", strings.Join(fakeExtResourceNames, ",")), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.AnnotationNs+"/extended-resources", strings.Join(fakeExtResourceNames, ",")),
apihelper.NewJsonPatch("remove", "/metadata/labels", FeatureLabelNs+"/old-feature", ""), apihelper.NewJsonPatch("remove", "/metadata/labels", nfdv1alpha1.FeatureLabelNs+"/old-feature", ""),
} }
for k, v := range fakeFeatureLabels { for k, v := range fakeFeatureLabels {
metadataPatches = append(metadataPatches, apihelper.NewJsonPatch("add", "/metadata/labels", k, v)) metadataPatches = append(metadataPatches, apihelper.NewJsonPatch("add", "/metadata/labels", k, v))
@ -176,7 +175,7 @@ func TestUpdateMasterNode(t *testing.T) {
mockNode := newMockNode() mockNode := newMockNode()
Convey("When update operation succeeds", func() { Convey("When update operation succeeds", func() {
expectedPatches := []apihelper.JsonPatch{ expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", AnnotationNsBase+"/master.version", version.Get())} apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.AnnotationNs+"/master.version", version.Get())}
mockHelper.On("GetClient").Return(mockClient, nil) mockHelper.On("GetClient").Return(mockClient, nil)
mockHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil) mockHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil)
mockHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedPatches))).Return(nil) mockHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedPatches))).Return(nil)
@ -239,8 +238,8 @@ func TestAddingExtResources(t *testing.T) {
Convey("When the resource already exists", func() { Convey("When the resource already exists", func() {
mockNode := newMockNode() mockNode := newMockNode()
mockNode.Status.Capacity[api.ResourceName(FeatureLabelNs+"/feature-1")] = *resource.NewQuantity(1, resource.BinarySI) mockNode.Status.Capacity[api.ResourceName(nfdv1alpha1.FeatureLabelNs+"/feature-1")] = *resource.NewQuantity(1, resource.BinarySI)
mockResourceLabels := ExtendedResources{FeatureLabelNs + "/feature-1": "1"} mockResourceLabels := ExtendedResources{nfdv1alpha1.FeatureLabelNs + "/feature-1": "1"}
patches := mockMaster.createExtendedResourcePatches(mockNode, mockResourceLabels) patches := mockMaster.createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(patches), ShouldEqual, 0) So(len(patches), ShouldEqual, 0)
}) })
@ -264,28 +263,28 @@ func TestRemovingExtResources(t *testing.T) {
mockMaster := newMockMaster(nil) mockMaster := newMockMaster(nil)
Convey("When none are removed", func() { Convey("When none are removed", func() {
mockNode := newMockNode() mockNode := newMockNode()
mockResourceLabels := ExtendedResources{FeatureLabelNs + "/feature-1": "1", FeatureLabelNs + "/feature-2": "2"} mockResourceLabels := ExtendedResources{nfdv1alpha1.FeatureLabelNs + "/feature-1": "1", nfdv1alpha1.FeatureLabelNs + "/feature-2": "2"}
mockNode.Annotations[AnnotationNsBase+"/extended-resources"] = "feature-1,feature-2" mockNode.Annotations[nfdv1alpha1.AnnotationNs+"/extended-resources"] = "feature-1,feature-2"
mockNode.Status.Capacity[api.ResourceName(FeatureLabelNs+"/feature-1")] = *resource.NewQuantity(1, resource.BinarySI) mockNode.Status.Capacity[api.ResourceName(nfdv1alpha1.FeatureLabelNs+"/feature-1")] = *resource.NewQuantity(1, resource.BinarySI)
mockNode.Status.Capacity[api.ResourceName(FeatureLabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI) mockNode.Status.Capacity[api.ResourceName(nfdv1alpha1.FeatureLabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI)
patches := mockMaster.createExtendedResourcePatches(mockNode, mockResourceLabels) patches := mockMaster.createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(patches), ShouldEqual, 0) So(len(patches), ShouldEqual, 0)
}) })
Convey("When the related label is gone", func() { Convey("When the related label is gone", func() {
mockNode := newMockNode() mockNode := newMockNode()
mockResourceLabels := ExtendedResources{FeatureLabelNs + "/feature-4": "", FeatureLabelNs + "/feature-2": "2"} mockResourceLabels := ExtendedResources{nfdv1alpha1.FeatureLabelNs + "/feature-4": "", nfdv1alpha1.FeatureLabelNs + "/feature-2": "2"}
mockNode.Annotations[AnnotationNsBase+"/extended-resources"] = "feature-4,feature-2" mockNode.Annotations[nfdv1alpha1.AnnotationNs+"/extended-resources"] = "feature-4,feature-2"
mockNode.Status.Capacity[api.ResourceName(FeatureLabelNs+"/feature-4")] = *resource.NewQuantity(4, resource.BinarySI) mockNode.Status.Capacity[api.ResourceName(nfdv1alpha1.FeatureLabelNs+"/feature-4")] = *resource.NewQuantity(4, resource.BinarySI)
mockNode.Status.Capacity[api.ResourceName(FeatureLabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI) mockNode.Status.Capacity[api.ResourceName(nfdv1alpha1.FeatureLabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI)
patches := mockMaster.createExtendedResourcePatches(mockNode, mockResourceLabels) patches := mockMaster.createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(patches), ShouldBeGreaterThan, 0) So(len(patches), ShouldBeGreaterThan, 0)
}) })
Convey("When the extended resource is no longer wanted", func() { Convey("When the extended resource is no longer wanted", func() {
mockNode := newMockNode() mockNode := newMockNode()
mockNode.Status.Capacity[api.ResourceName(FeatureLabelNs+"/feature-1")] = *resource.NewQuantity(1, resource.BinarySI) mockNode.Status.Capacity[api.ResourceName(nfdv1alpha1.FeatureLabelNs+"/feature-1")] = *resource.NewQuantity(1, resource.BinarySI)
mockNode.Status.Capacity[api.ResourceName(FeatureLabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI) mockNode.Status.Capacity[api.ResourceName(nfdv1alpha1.FeatureLabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI)
mockResourceLabels := ExtendedResources{FeatureLabelNs + "/feature-2": "2"} mockResourceLabels := ExtendedResources{nfdv1alpha1.FeatureLabelNs + "/feature-2": "2"}
mockNode.Annotations[AnnotationNsBase+"/extended-resources"] = "feature-1,feature-2" mockNode.Annotations[nfdv1alpha1.AnnotationNs+"/extended-resources"] = "feature-1,feature-2"
patches := mockMaster.createExtendedResourcePatches(mockNode, mockResourceLabels) patches := mockMaster.createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(patches), ShouldBeGreaterThan, 0) So(len(patches), ShouldBeGreaterThan, 0)
}) })
@ -313,17 +312,14 @@ func TestSetLabels(t *testing.T) {
expectedStatusPatches := []apihelper.JsonPatch{} expectedStatusPatches := []apihelper.JsonPatch{}
wvAnnotation := path.Join(AnnotationNsBase, workerVersionAnnotation)
flAnnotation := path.Join(AnnotationNsBase, featureLabelAnnotation)
erAnnotation := path.Join(AnnotationNsBase, extendedResourceAnnotation)
Convey("When node update succeeds", func() { Convey("When node update succeeds", func() {
expectedPatches := []apihelper.JsonPatch{ expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", wvAnnotation, workerVer), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.WorkerVersionAnnotation, workerVer),
apihelper.NewJsonPatch("add", "/metadata/annotations", flAnnotation, strings.Join(mockLabelNames, ",")), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.FeatureLabelsAnnotation, strings.Join(mockLabelNames, ",")),
apihelper.NewJsonPatch("add", "/metadata/annotations", erAnnotation, ""), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.ExtendedResourceAnnotation, ""),
} }
for k, v := range mockLabels { for k, v := range mockLabels {
expectedPatches = append(expectedPatches, apihelper.NewJsonPatch("add", "/metadata/labels", FeatureLabelNs+"/"+k, v)) expectedPatches = append(expectedPatches, apihelper.NewJsonPatch("add", "/metadata/labels", nfdv1alpha1.FeatureLabelNs+"/"+k, v))
} }
mockHelper.On("GetClient").Return(mockClient, nil) mockHelper.On("GetClient").Return(mockClient, nil)
@ -338,10 +334,10 @@ func TestSetLabels(t *testing.T) {
Convey("When -label-whitelist is specified", func() { Convey("When -label-whitelist is specified", func() {
expectedPatches := []apihelper.JsonPatch{ expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", wvAnnotation, workerVer), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.WorkerVersionAnnotation, workerVer),
apihelper.NewJsonPatch("add", "/metadata/annotations", flAnnotation, "feature-2"), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.FeatureLabelsAnnotation, "feature-2"),
apihelper.NewJsonPatch("add", "/metadata/annotations", erAnnotation, ""), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.ExtendedResourceAnnotation, ""),
apihelper.NewJsonPatch("add", "/metadata/labels", FeatureLabelNs+"/feature-2", mockLabels["feature-2"]), apihelper.NewJsonPatch("add", "/metadata/labels", nfdv1alpha1.FeatureLabelNs+"/feature-2", mockLabels["feature-2"]),
} }
mockMaster.args.LabelWhiteList.Regexp = *regexp.MustCompile("^f.*2$") mockMaster.args.LabelWhiteList.Regexp = *regexp.MustCompile("^f.*2$")
@ -358,27 +354,27 @@ 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"
vendorFeatureLabel := "vendor." + FeatureLabelNs + "/feature-4" vendorFeatureLabel := "vendor." + nfdv1alpha1.FeatureLabelNs + "/feature-4"
vendorProfileLabel := "vendor." + ProfileLabelNs + "/feature-5" vendorProfileLabel := "vendor." + nfdv1alpha1.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",
vendorFeatureLabel: " val-4", vendorFeatureLabel: " val-4",
vendorProfileLabel: " val-5"} vendorProfileLabel: " val-5"}
expectedPatches := []apihelper.JsonPatch{ expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+wvAnnotation, workerVer), apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+nfdv1alpha1.WorkerVersionAnnotation, workerVer),
apihelper.NewJsonPatch("add", "/metadata/annotations", apihelper.NewJsonPatch("add", "/metadata/annotations",
instance+"."+flAnnotation, instance+"."+nfdv1alpha1.FeatureLabelsAnnotation,
"feature-1,valid.ns/feature-2,"+vendorFeatureLabel+","+vendorProfileLabel), "feature-1,valid.ns/feature-2,"+vendorFeatureLabel+","+vendorProfileLabel),
apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+erAnnotation, ""), apihelper.NewJsonPatch("add", "/metadata/annotations", instance+"."+nfdv1alpha1.ExtendedResourceAnnotation, ""),
apihelper.NewJsonPatch("add", "/metadata/labels", FeatureLabelNs+"/feature-1", mockLabels["feature-1"]), apihelper.NewJsonPatch("add", "/metadata/labels", nfdv1alpha1.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", vendorFeatureLabel, mockLabels[vendorFeatureLabel]), apihelper.NewJsonPatch("add", "/metadata/labels", vendorFeatureLabel, mockLabels[vendorFeatureLabel]),
apihelper.NewJsonPatch("add", "/metadata/labels", vendorProfileLabel, mockLabels[vendorProfileLabel]), apihelper.NewJsonPatch("add", "/metadata/labels", vendorProfileLabel, mockLabels[vendorProfileLabel]),
} }
mockMaster.args.ExtraLabelNs = map[string]struct{}{"valid.ns": {}} mockMaster.args.ExtraLabelNs = map[string]struct{}{"valid.ns": {}}
mockMaster.annotationNs = instance + "." + AnnotationNsBase mockMaster.args.Instance = instance
mockHelper.On("GetClient").Return(mockClient, nil) mockHelper.On("GetClient").Return(mockClient, nil)
mockHelper.On("GetNode", mockClient, workerName).Return(mockNode, nil) mockHelper.On("GetNode", mockClient, workerName).Return(mockNode, nil)
mockHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedPatches))).Return(nil) mockHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedPatches))).Return(nil)
@ -388,19 +384,19 @@ func TestSetLabels(t *testing.T) {
Convey("Error is nil", func() { Convey("Error is nil", func() {
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })
mockMaster.annotationNs = AnnotationNsBase mockMaster.args.Instance = ""
}) })
Convey("When -resource-labels is specified", func() { Convey("When -resource-labels is specified", func() {
expectedPatches := []apihelper.JsonPatch{ expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", wvAnnotation, workerVer), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.WorkerVersionAnnotation, workerVer),
apihelper.NewJsonPatch("add", "/metadata/annotations", flAnnotation, "feature-2"), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.FeatureLabelsAnnotation, "feature-2"),
apihelper.NewJsonPatch("add", "/metadata/annotations", erAnnotation, "feature-1,feature-3"), apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.ExtendedResourceAnnotation, "feature-1,feature-3"),
apihelper.NewJsonPatch("add", "/metadata/labels", FeatureLabelNs+"/feature-2", mockLabels["feature-2"]), apihelper.NewJsonPatch("add", "/metadata/labels", nfdv1alpha1.FeatureLabelNs+"/feature-2", mockLabels["feature-2"]),
} }
expectedStatusPatches := []apihelper.JsonPatch{ expectedStatusPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/status/capacity", FeatureLabelNs+"/feature-1", mockLabels["feature-1"]), apihelper.NewJsonPatch("add", "/status/capacity", nfdv1alpha1.FeatureLabelNs+"/feature-1", mockLabels["feature-1"]),
apihelper.NewJsonPatch("add", "/status/capacity", FeatureLabelNs+"/feature-3", mockLabels["feature-3"]), apihelper.NewJsonPatch("add", "/status/capacity", nfdv1alpha1.FeatureLabelNs+"/feature-3", mockLabels["feature-3"]),
} }
mockMaster.args.ResourceLabels = map[string]struct{}{"feature-3": {}, "feature-1": {}} mockMaster.args.ResourceLabels = map[string]struct{}{"feature-3": {}, "feature-1": {}}

View file

@ -52,29 +52,6 @@ import (
"sigs.k8s.io/node-feature-discovery/pkg/version" "sigs.k8s.io/node-feature-discovery/pkg/version"
) )
const (
// FeatureLabelNs is the namespace for feature labels
FeatureLabelNs = "feature.node.kubernetes.io"
// 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"
// NFD Annotations
extendedResourceAnnotation = "extended-resources"
featureLabelAnnotation = "feature-labels"
masterVersionAnnotation = "master.version"
workerVersionAnnotation = "worker.version"
)
// Labels are a Kubernetes representation of discovered features. // Labels are a Kubernetes representation of discovered features.
type Labels map[string]string type Labels map[string]string
@ -110,14 +87,13 @@ type NfdMaster interface {
type nfdMaster struct { type nfdMaster struct {
*nfdController *nfdController
args Args args Args
nodeName string nodeName string
annotationNs string server *grpc.Server
server *grpc.Server stop chan struct{}
stop chan struct{} ready chan bool
ready chan bool apihelper apihelper.APIHelpers
apihelper apihelper.APIHelpers kubeconfig *restclient.Config
kubeconfig *restclient.Config
} }
// NewNfdMaster creates a new NfdMaster server instance. // NewNfdMaster creates a new NfdMaster server instance.
@ -128,15 +104,12 @@ func NewNfdMaster(args *Args) (NfdMaster, error) {
stop: make(chan struct{}, 1), stop: make(chan struct{}, 1),
} }
if args.Instance == "" { if args.Instance != "" {
nfd.annotationNs = AnnotationNsBase
} else {
if ok, _ := regexp.MatchString(`^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$`, args.Instance); !ok { if ok, _ := regexp.MatchString(`^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$`, args.Instance); !ok {
return nfd, fmt.Errorf("invalid -instance %q: instance name "+ return nfd, fmt.Errorf("invalid -instance %q: instance name "+
"must start and end with an alphanumeric character and may only contain "+ "must start and end with an alphanumeric character and may only contain "+
"alphanumerics, `-`, `_` or `.`", args.Instance) "alphanumerics, `-`, `_` or `.`", args.Instance)
} }
nfd.annotationNs = args.Instance + "." + AnnotationNsBase
} }
// Check TLS related args // Check TLS related args
@ -311,7 +284,7 @@ func (m *nfdMaster) prune() error {
return err return err
} }
for a := range node.Annotations { for a := range node.Annotations {
if strings.HasPrefix(a, m.annotationNs) { if strings.HasPrefix(a, m.instanceAnnotation(nfdv1alpha1.AnnotationNs)) {
delete(node.Annotations, a) delete(node.Annotations, a)
} }
} }
@ -337,7 +310,7 @@ func (m *nfdMaster) updateMasterNode() error {
// Advertise NFD version as an annotation // Advertise NFD version as an annotation
p := createPatches(nil, p := createPatches(nil,
node.Annotations, node.Annotations,
Annotations{m.annotationName(masterVersionAnnotation): version.Get()}, Annotations{m.instanceAnnotation(nfdv1alpha1.MasterVersionAnnotation): version.Get()},
"/metadata/annotations") "/metadata/annotations")
err = m.apihelper.PatchNode(cli, node.Name, p) err = m.apihelper.PatchNode(cli, node.Name, p)
if err != nil { if err != nil {
@ -356,13 +329,13 @@ func filterFeatureLabels(labels Labels, extraLabelNs map[string]struct{}, labelW
for label, value := range labels { for label, value := range labels {
// Add possibly missing default ns // Add possibly missing default ns
label := addNs(label, FeatureLabelNs) label := addNs(label, nfdv1alpha1.FeatureLabelNs)
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 && ns != ProfileLabelNs && if ns != nfdv1alpha1.FeatureLabelNs && ns != nfdv1alpha1.ProfileLabelNs &&
!strings.HasSuffix(ns, FeatureLabelSubNsSuffix) && !strings.HasSuffix(ns, ProfileLabelSubNsSuffix) { !strings.HasSuffix(ns, nfdv1alpha1.FeatureLabelSubNsSuffix) && !strings.HasSuffix(ns, nfdv1alpha1.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
@ -381,7 +354,7 @@ func filterFeatureLabels(labels Labels, extraLabelNs map[string]struct{}, labelW
extendedResources := ExtendedResources{} extendedResources := ExtendedResources{}
for extendedResourceName := range extendedResourceNames { for extendedResourceName := range extendedResourceNames {
// Add possibly missing default ns // Add possibly missing default ns
extendedResourceName = addNs(extendedResourceName, FeatureLabelNs) extendedResourceName = addNs(extendedResourceName, nfdv1alpha1.FeatureLabelNs)
if value, ok := outLabels[extendedResourceName]; ok { if value, ok := outLabels[extendedResourceName]; ok {
if _, err := strconv.Atoi(value); err != nil { if _, err := strconv.Atoi(value); err != nil {
klog.Errorf("bad label value (%s: %s) encountered for extended resource: %s", extendedResourceName, value, err.Error()) klog.Errorf("bad label value (%s: %s) encountered for extended resource: %s", extendedResourceName, value, err.Error())
@ -437,7 +410,7 @@ func (m *nfdMaster) SetLabels(c context.Context, r *pb.SetLabelsRequest) (*pb.Se
if !m.args.NoPublish { if !m.args.NoPublish {
// Advertise NFD worker version as an annotation // Advertise NFD worker version as an annotation
annotations := Annotations{m.annotationName(workerVersionAnnotation): r.NfdVersion} annotations := Annotations{m.instanceAnnotation(nfdv1alpha1.WorkerVersionAnnotation): r.NfdVersion}
err := m.updateNodeFeatures(r.NodeName, labels, annotations, extendedResources) err := m.updateNodeFeatures(r.NodeName, labels, annotations, extendedResources)
if err != nil { if err != nil {
@ -561,22 +534,22 @@ func (m *nfdMaster) updateNodeFeatures(nodeName string, labels Labels, annotatio
labelKeys := make([]string, 0, len(labels)) labelKeys := make([]string, 0, len(labels))
for key := range labels { for key := range labels {
// Drop the ns part for labels in the default ns // Drop the ns part for labels in the default ns
labelKeys = append(labelKeys, strings.TrimPrefix(key, FeatureLabelNs+"/")) labelKeys = append(labelKeys, strings.TrimPrefix(key, nfdv1alpha1.FeatureLabelNs+"/"))
} }
sort.Strings(labelKeys) sort.Strings(labelKeys)
annotations[m.annotationName(featureLabelAnnotation)] = strings.Join(labelKeys, ",") annotations[m.instanceAnnotation(nfdv1alpha1.FeatureLabelsAnnotation)] = strings.Join(labelKeys, ",")
// Store names of extended resources in an annotation // Store names of extended resources in an annotation
extendedResourceKeys := make([]string, 0, len(extendedResources)) extendedResourceKeys := make([]string, 0, len(extendedResources))
for key := range extendedResources { for key := range extendedResources {
// Drop the ns part if in the default ns // Drop the ns part if in the default ns
extendedResourceKeys = append(extendedResourceKeys, strings.TrimPrefix(key, FeatureLabelNs+"/")) extendedResourceKeys = append(extendedResourceKeys, strings.TrimPrefix(key, nfdv1alpha1.FeatureLabelNs+"/"))
} }
sort.Strings(extendedResourceKeys) sort.Strings(extendedResourceKeys)
annotations[m.annotationName(extendedResourceAnnotation)] = strings.Join(extendedResourceKeys, ",") annotations[m.instanceAnnotation(nfdv1alpha1.ExtendedResourceAnnotation)] = strings.Join(extendedResourceKeys, ",")
// Create JSON patches for changes in labels and annotations // Create JSON patches for changes in labels and annotations
oldLabels := stringToNsNames(node.Annotations[m.annotationName(featureLabelAnnotation)], FeatureLabelNs) oldLabels := stringToNsNames(node.Annotations[m.instanceAnnotation(nfdv1alpha1.FeatureLabelsAnnotation)], nfdv1alpha1.FeatureLabelNs)
patches := createPatches(oldLabels, node.Labels, labels, "/metadata/labels") patches := createPatches(oldLabels, node.Labels, labels, "/metadata/labels")
patches = append(patches, createPatches(nil, node.Annotations, annotations, "/metadata/annotations")...) patches = append(patches, createPatches(nil, node.Annotations, annotations, "/metadata/annotations")...)
@ -602,10 +575,6 @@ func (m *nfdMaster) updateNodeFeatures(nodeName string, labels Labels, annotatio
return err return err
} }
func (m *nfdMaster) annotationName(name string) string {
return path.Join(m.annotationNs, name)
}
func (m *nfdMaster) getKubeconfig() (*restclient.Config, error) { func (m *nfdMaster) getKubeconfig() (*restclient.Config, error) {
var err error var err error
if m.kubeconfig == nil { if m.kubeconfig == nil {
@ -647,7 +616,7 @@ func (m *nfdMaster) createExtendedResourcePatches(n *api.Node, extendedResources
patches := []apihelper.JsonPatch{} patches := []apihelper.JsonPatch{}
// Form a list of namespaced resource names managed by us // Form a list of namespaced resource names managed by us
oldResources := stringToNsNames(n.Annotations[m.annotationName(extendedResourceAnnotation)], FeatureLabelNs) oldResources := stringToNsNames(n.Annotations[m.instanceAnnotation(nfdv1alpha1.ExtendedResourceAnnotation)], nfdv1alpha1.FeatureLabelNs)
// figure out which resources to remove // figure out which resources to remove
for _, resource := range oldResources { for _, resource := range oldResources {
@ -762,3 +731,10 @@ func (m *nfdMaster) updateCR(hostname string, tmpolicy []string, topoUpdaterZone
utils.KlogDump(2, "CR instance updated resTopo:", " ", nrtUpdated) utils.KlogDump(2, "CR instance updated resTopo:", " ", nrtUpdated)
return nil return nil
} }
func (m *nfdMaster) instanceAnnotation(name string) string {
if m.args.Instance == "" {
return name
}
return m.args.Instance + "." + name
}

View file

@ -36,7 +36,7 @@ import (
e2enetwork "k8s.io/kubernetes/test/e2e/framework/network" e2enetwork "k8s.io/kubernetes/test/e2e/framework/network"
e2epod "k8s.io/kubernetes/test/e2e/framework/pod" e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
master "sigs.k8s.io/node-feature-discovery/pkg/nfd-master" nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
"sigs.k8s.io/node-feature-discovery/source/custom" "sigs.k8s.io/node-feature-discovery/source/custom"
testutils "sigs.k8s.io/node-feature-discovery/test/e2e/utils" testutils "sigs.k8s.io/node-feature-discovery/test/e2e/utils"
) )
@ -62,7 +62,7 @@ func cleanupNode(cs clientset.Interface) {
update := false update := false
// Remove labels // Remove labels
for key := range node.Labels { for key := range node.Labels {
if strings.HasPrefix(key, master.FeatureLabelNs) { if strings.HasPrefix(key, nfdv1alpha1.FeatureLabelNs) {
delete(node.Labels, key) delete(node.Labels, key)
update = true update = true
} }
@ -70,7 +70,7 @@ func cleanupNode(cs clientset.Interface) {
// Remove annotations // Remove annotations
for key := range node.Annotations { for key := range node.Annotations {
if strings.HasPrefix(key, master.AnnotationNsBase) { if strings.HasPrefix(key, nfdv1alpha1.AnnotationNs) {
delete(node.Annotations, key) delete(node.Annotations, key)
update = true update = true
} }
@ -126,7 +126,7 @@ var _ = SIGDescribe("Node Feature Discovery", func() {
// Node running nfd-master should have master version annotation // Node running nfd-master should have master version annotation
masterPodNode, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), masterPod.Spec.NodeName, metav1.GetOptions{}) masterPodNode, err := f.ClientSet.CoreV1().Nodes().Get(context.TODO(), masterPod.Spec.NodeName, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(masterPodNode.Annotations).To(HaveKey(master.AnnotationNsBase + "/master.version")) Expect(masterPodNode.Annotations).To(HaveKey(nfdv1alpha1.AnnotationNs + "/master.version"))
By("Waiting for the nfd-master service to be up") By("Waiting for the nfd-master service to be up")
Expect(e2enetwork.WaitForService(f.ClientSet, f.Namespace.Name, nfdSvc.ObjectMeta.Name, true, time.Second, 10*time.Second)).NotTo(HaveOccurred()) Expect(e2enetwork.WaitForService(f.ClientSet, f.Namespace.Name, nfdSvc.ObjectMeta.Name, true, time.Second, 10*time.Second)).NotTo(HaveOccurred())
@ -145,9 +145,9 @@ var _ = SIGDescribe("Node Feature Discovery", func() {
It("it should decorate the node with the fake feature labels", func() { It("it should decorate the node with the fake feature labels", func() {
fakeFeatureLabels := map[string]string{ fakeFeatureLabels := map[string]string{
master.FeatureLabelNs + "/fake-fakefeature1": "true", nfdv1alpha1.FeatureLabelNs + "/fake-fakefeature1": "true",
master.FeatureLabelNs + "/fake-fakefeature2": "true", nfdv1alpha1.FeatureLabelNs + "/fake-fakefeature2": "true",
master.FeatureLabelNs + "/fake-fakefeature3": "true", nfdv1alpha1.FeatureLabelNs + "/fake-fakefeature3": "true",
} }
// Launch nfd-worker // Launch nfd-worker
@ -171,7 +171,7 @@ var _ = SIGDescribe("Node Feature Discovery", func() {
// Check that there are no unexpected NFD labels // Check that there are no unexpected NFD labels
for k := range node.Labels { for k := range node.Labels {
if strings.HasPrefix(k, master.FeatureLabelNs) { if strings.HasPrefix(k, nfdv1alpha1.FeatureLabelNs) {
Expect(fakeFeatureLabels).Should(HaveKey(k)) Expect(fakeFeatureLabels).Should(HaveKey(k))
} }
} }
@ -226,7 +226,7 @@ var _ = SIGDescribe("Node Feature Discovery", func() {
Expect(node.Labels).To(HaveKey(k)) Expect(node.Labels).To(HaveKey(k))
} }
for k := range node.Labels { for k := range node.Labels {
if strings.HasPrefix(k, master.FeatureLabelNs) { if strings.HasPrefix(k, nfdv1alpha1.FeatureLabelNs) {
if _, ok := nodeConf.ExpectedLabelValues[k]; ok { if _, ok := nodeConf.ExpectedLabelValues[k]; ok {
continue continue
} }
@ -247,7 +247,7 @@ var _ = SIGDescribe("Node Feature Discovery", func() {
Expect(node.Annotations).To(HaveKey(k)) Expect(node.Annotations).To(HaveKey(k))
} }
for k := range node.Annotations { for k := range node.Annotations {
if strings.HasPrefix(k, master.AnnotationNsBase) { if strings.HasPrefix(k, nfdv1alpha1.AnnotationNs) {
if _, ok := nodeConf.ExpectedAnnotationValues[k]; ok { if _, ok := nodeConf.ExpectedAnnotationValues[k]; ok {
continue continue
} }