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

Merge pull request #1471 from marquiz/devel/default-ns-fix

nfd-master: predictable handling of unprefixed names
This commit is contained in:
Kubernetes Prow Robot 2023-11-24 11:33:21 +01:00 committed by GitHub
commit 4e7f8b10be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 32 deletions

View file

@ -422,20 +422,21 @@ func TestSetLabels(t *testing.T) {
vendorFeatureLabel := "vendor." + nfdv1alpha1.FeatureLabelNs + "/feature-4" vendorFeatureLabel := "vendor." + nfdv1alpha1.FeatureLabelNs + "/feature-4"
vendorProfileLabel := "vendor." + nfdv1alpha1.ProfileLabelNs + "/feature-5" vendorProfileLabel := "vendor." + nfdv1alpha1.ProfileLabelNs + "/feature-5"
mockLabels := map[string]string{ mockLabels := map[string]string{
"feature-1": "val-1", "feature-1": "val-0",
"valid.ns/feature-2": "val-2", "feature.node.kubernetes.io/feature-1": "val-1",
"random.denied.ns/feature-3": "val-3", "valid.ns/feature-2": "val-2",
"kubernetes.io/feature-4": "val-4", "random.denied.ns/feature-3": "val-3",
"sub.ns.kubernetes.io/feature-5": "val-5", "kubernetes.io/feature-4": "val-4",
vendorFeatureLabel: "val-6", "sub.ns.kubernetes.io/feature-5": "val-5",
vendorProfileLabel: "val-7", vendorFeatureLabel: "val-6",
"--invalid-name--": "valid-val", vendorProfileLabel: "val-7",
"valid-name": "--invalid-val--"} "--invalid-name--": "valid-val",
"valid-name": "--invalid-val--"}
expectedPatches := []apihelper.JsonPatch{ expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", apihelper.NewJsonPatch("add", "/metadata/annotations",
instance+"."+nfdv1alpha1.FeatureLabelsAnnotation, instance+"."+nfdv1alpha1.FeatureLabelsAnnotation,
"feature-1,valid.ns/feature-2,"+vendorFeatureLabel+","+vendorProfileLabel), "feature-1,valid.ns/feature-2,"+vendorFeatureLabel+","+vendorProfileLabel),
apihelper.NewJsonPatch("add", "/metadata/labels", nfdv1alpha1.FeatureLabelNs+"/feature-1", mockLabels["feature-1"]), apihelper.NewJsonPatch("add", "/metadata/labels", "feature.node.kubernetes.io/feature-1", mockLabels["feature.node.kubernetes.io/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]),
@ -468,7 +469,7 @@ func TestSetLabels(t *testing.T) {
apihelper.NewJsonPatch("add", "/status/capacity", nfdv1alpha1.FeatureLabelNs+"/feature-3", mockLabels["feature-3"]), apihelper.NewJsonPatch("add", "/status/capacity", nfdv1alpha1.FeatureLabelNs+"/feature-3", mockLabels["feature-3"]),
} }
mockMaster.config.ResourceLabels = map[string]struct{}{"feature-3": {}, "feature-1": {}} mockMaster.config.ResourceLabels = map[string]struct{}{"feature.node.kubernetes.io/feature-3": {}, "feature-1": {}}
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("PatchNodeStatus", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedStatusPatches))).Return(nil) mockHelper.On("PatchNodeStatus", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedStatusPatches))).Return(nil)
@ -503,7 +504,7 @@ func TestFilterLabels(t *testing.T) {
mockMaster := newMockMaster(mockHelper) mockMaster := newMockMaster(mockHelper)
Convey("When using dynamic values", t, func() { Convey("When using dynamic values", t, func() {
labelName := "testLabel" labelName := "ns/testLabel"
labelValue := "@test.feature.LSM" labelValue := "@test.feature.LSM"
features := nfdv1alpha1.Features{ features := nfdv1alpha1.Features{
Attributes: map[string]nfdv1alpha1.AttributeFeatureSet{ Attributes: map[string]nfdv1alpha1.AttributeFeatureSet{

View file

@ -523,9 +523,6 @@ func (m *nfdMaster) updateMasterNode() error {
func (m *nfdMaster) filterFeatureLabels(labels Labels, features *nfdv1alpha1.Features) (Labels, ExtendedResources) { func (m *nfdMaster) filterFeatureLabels(labels Labels, features *nfdv1alpha1.Features) (Labels, ExtendedResources) {
outLabels := Labels{} outLabels := Labels{}
for name, value := range labels { for name, value := range labels {
// Add possibly missing default ns
name := addNs(name, nfdv1alpha1.FeatureLabelNs)
if value, err := m.filterFeatureLabel(name, value, features); err != nil { if value, err := m.filterFeatureLabel(name, value, features); err != nil {
klog.ErrorS(err, "ignoring label", "labelKey", name, "labelValue", value) klog.ErrorS(err, "ignoring label", "labelKey", name, "labelValue", value)
nodeLabelsRejected.Inc() nodeLabelsRejected.Inc()
@ -537,8 +534,7 @@ func (m *nfdMaster) filterFeatureLabels(labels Labels, features *nfdv1alpha1.Fea
// Remove labels which are intended to be extended resources // Remove labels which are intended to be extended resources
extendedResources := ExtendedResources{} extendedResources := ExtendedResources{}
for extendedResourceName := range m.config.ResourceLabels { for extendedResourceName := range m.config.ResourceLabels {
// Add possibly missing default ns extendedResourceName := addNs(extendedResourceName, nfdv1alpha1.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.ErrorS(err, "bad label value encountered for extended resource", "labelKey", extendedResourceName, "labelValue", value) klog.ErrorS(err, "bad label value encountered for extended resource", "labelKey", extendedResourceName, "labelValue", value)
@ -563,6 +559,9 @@ func (m *nfdMaster) filterFeatureLabel(name, value string, features *nfdv1alpha1
// Check label namespace, filter out if ns is not whitelisted // Check label namespace, filter out if ns is not whitelisted
ns, base := splitNs(name) ns, base := splitNs(name)
if ns == "" {
return "", fmt.Errorf("labels without namespace (prefix/) not allowed")
}
if ns != nfdv1alpha1.FeatureLabelNs && ns != nfdv1alpha1.ProfileLabelNs && if ns != nfdv1alpha1.FeatureLabelNs && ns != nfdv1alpha1.ProfileLabelNs &&
!strings.HasSuffix(ns, nfdv1alpha1.FeatureLabelSubNsSuffix) && !strings.HasSuffix(ns, nfdv1alpha1.ProfileLabelSubNsSuffix) { !strings.HasSuffix(ns, nfdv1alpha1.FeatureLabelSubNsSuffix) && !strings.HasSuffix(ns, nfdv1alpha1.ProfileLabelSubNsSuffix) {
// If the namespace is denied, and not present in the extraLabelNs, label will be ignored // If the namespace is denied, and not present in the extraLabelNs, label will be ignored
@ -764,8 +763,11 @@ func (m *nfdMaster) nfdAPIUpdateOneNode(nodeName string) error {
// NOTE: changing the rule api to support handle multiple objects instead // NOTE: changing the rule api to support handle multiple objects instead
// of merging would probably perform better with lot less data to copy. // of merging would probably perform better with lot less data to copy.
features = objs[0].Spec.DeepCopy() features = objs[0].Spec.DeepCopy()
features.Labels = addNsToMapKeys(features.Labels, nfdv1alpha1.FeatureLabelNs)
for _, o := range objs[1:] { for _, o := range objs[1:] {
o.Spec.MergeInto(features) s := o.Spec.DeepCopy()
s.Labels = addNsToMapKeys(s.Labels, nfdv1alpha1.FeatureLabelNs)
s.MergeInto(features)
} }
klog.V(4).InfoS("merged nodeFeatureSpecs", "newNodeFeatureSpec", utils.DelayedDumper(features)) klog.V(4).InfoS("merged nodeFeatureSpecs", "newNodeFeatureSpec", utils.DelayedDumper(features))
@ -790,9 +792,6 @@ func (m *nfdMaster) nfdAPIUpdateOneNode(nodeName string) error {
func filterExtendedResources(features *nfdv1alpha1.Features, extendedResources ExtendedResources) ExtendedResources { func filterExtendedResources(features *nfdv1alpha1.Features, extendedResources ExtendedResources) ExtendedResources {
outExtendedResources := ExtendedResources{} outExtendedResources := ExtendedResources{}
for name, value := range extendedResources { for name, value := range extendedResources {
// Add possibly missing default ns
name = addNs(name, nfdv1alpha1.ExtendedResourceNs)
capacity, err := filterExtendedResource(name, value, features) capacity, err := filterExtendedResource(name, value, features)
if err != nil { if err != nil {
klog.ErrorS(err, "failed to create extended resources", "extendedResourceName", name, "extendedResourceValue", value) klog.ErrorS(err, "failed to create extended resources", "extendedResourceName", name, "extendedResourceValue", value)
@ -807,6 +806,9 @@ func filterExtendedResources(features *nfdv1alpha1.Features, extendedResources E
func filterExtendedResource(name, value string, features *nfdv1alpha1.Features) (string, error) { func filterExtendedResource(name, value string, features *nfdv1alpha1.Features) (string, error) {
// Check if given NS is allowed // Check if given NS is allowed
ns, _ := splitNs(name) ns, _ := splitNs(name)
if ns == "" {
return "", fmt.Errorf("extended resource without namespace (prefix/) not allowed")
}
if ns != nfdv1alpha1.ExtendedResourceNs && !strings.HasSuffix(ns, nfdv1alpha1.ExtendedResourceSubNsSuffix) { if ns != nfdv1alpha1.ExtendedResourceNs && !strings.HasSuffix(ns, nfdv1alpha1.ExtendedResourceSubNsSuffix) {
if ns == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io") { if ns == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io") {
return "", fmt.Errorf("namespace %q is not allowed", ns) return "", fmt.Errorf("namespace %q is not allowed", ns)
@ -834,9 +836,7 @@ func filterExtendedResource(name, value string, features *nfdv1alpha1.Features)
} }
func (m *nfdMaster) refreshNodeFeatures(cli *kubernetes.Clientset, nodeName string, labels map[string]string, features *nfdv1alpha1.Features) error { func (m *nfdMaster) refreshNodeFeatures(cli *kubernetes.Clientset, nodeName string, labels map[string]string, features *nfdv1alpha1.Features) error {
if labels == nil { labels = addNsToMapKeys(labels, nfdv1alpha1.FeatureLabelNs)
labels = make(map[string]string)
}
crLabels, crAnnotations, crExtendedResources, crTaints := m.processNodeFeatureRule(nodeName, features) crLabels, crAnnotations, crExtendedResources, crTaints := m.processNodeFeatureRule(nodeName, features)
@ -1011,13 +1011,13 @@ func (m *nfdMaster) processNodeFeatureRule(nodeName string, features *nfdv1alpha
continue continue
} }
taints = append(taints, ruleOut.Taints...) taints = append(taints, ruleOut.Taints...)
for k, v := range ruleOut.Labels { for k, v := range addNsToMapKeys(ruleOut.Labels, nfdv1alpha1.FeatureLabelNs) {
labels[k] = v labels[k] = v
} }
for k, v := range ruleOut.ExtendedResources { for k, v := range addNsToMapKeys(ruleOut.ExtendedResources, nfdv1alpha1.ExtendedResourceNs) {
extendedResources[k] = v extendedResources[k] = v
} }
for k, v := range ruleOut.Annotations { for k, v := range addNsToMapKeys(ruleOut.Annotations, nfdv1alpha1.FeatureAnnotationNs) {
annotations[k] = v annotations[k] = v
} }
@ -1285,6 +1285,25 @@ func (m *nfdMaster) configure(filepath string, overrides string) error {
return nil return nil
} }
// addNsToMapKeys creates a copy of a map with the namespace (prefix) added to
// unprefixed keys. Prefixed keys in the input map will take presedence, i.e.
// if the input contains both prefixed (say "prefix/name") and unprefixed
// ("name") name the unprefixed key will be ignored.
func addNsToMapKeys(in map[string]string, nsToAdd string) map[string]string {
out := make(map[string]string, len(in))
for k, v := range in {
if strings.Contains(k, "/") {
out[k] = v
} else {
fqn := path.Join(nsToAdd, k)
if _, ok := in[fqn]; !ok {
out[fqn] = v
}
}
}
return out
}
// addNs adds a namespace if one isn't already found from src string // addNs adds a namespace if one isn't already found from src string
func addNs(src string, nsToAdd string) string { func addNs(src string, nsToAdd string) string {
if strings.Contains(src, "/") { if strings.Contains(src, "/") {
@ -1404,11 +1423,11 @@ func (m *nfdMaster) filterFeatureAnnotations(annotations map[string]string) map[
outAnnotations := make(map[string]string) outAnnotations := make(map[string]string)
for annotation, value := range annotations { for annotation, value := range annotations {
// Add possibly missing default ns
annotation := addNs(annotation, nfdv1alpha1.FeatureAnnotationNs)
ns, _ := splitNs(annotation) ns, _ := splitNs(annotation)
if ns == "" {
klog.ErrorS(fmt.Errorf("annotations without namespace (prefix/) not allowed"), fmt.Sprintf("Ignoring annotation %s", annotation))
continue
}
// Check annotation namespace, filter out if ns is not whitelisted // Check annotation namespace, filter out if ns is not whitelisted
if ns != nfdv1alpha1.FeatureAnnotationNs && !strings.HasSuffix(ns, nfdv1alpha1.FeatureAnnotationSubNsSuffix) { if ns != nfdv1alpha1.FeatureAnnotationNs && !strings.HasSuffix(ns, nfdv1alpha1.FeatureAnnotationSubNsSuffix) {
// If the namespace is denied, and not present in the extraLabelNs, label will be ignored // If the namespace is denied, and not present in the extraLabelNs, label will be ignored

View file

@ -25,7 +25,9 @@ spec:
attr_2: "9" attr_2: "9"
# Labels to be created # Labels to be created
labels: labels:
e2e-nodefeature-test-1: "obj-1" e2e-nodefeature-test-1: "foo"
# The prefixed name should take precedence over the non-prefixed name above
feature.node.kubernetes.io/e2e-nodefeature-test-1: "obj-1"
e2e-nodefeature-test-2: "obj-1" e2e-nodefeature-test-2: "obj-1"
# Override feature from nfd-worker # Override feature from nfd-worker
fake-fakefeature3: "overridden" fake-fakefeature3: "overridden"