1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2024-12-14 11:57:51 +00:00

Create a Validate pkg

Signed-off-by: Carlos Eduardo Arango Gutierrez <eduardoa@nvidia.com>
This commit is contained in:
Carlos Eduardo Arango Gutierrez 2023-11-01 15:57:31 +01:00
parent bdfef6df18
commit affb93ea50
No known key found for this signature in database
GPG key ID: 42D9CB42F300A852
7 changed files with 505 additions and 96 deletions

View file

@ -59,8 +59,6 @@ namespaces, excluding `kubernetes.io` namespace and its sub-namespaces
`kubernetes.io` and its sub-namespaces are always denied.
This option can be used to exclude some vendors or application specific
namespaces.
Note that the namespaces `feature.node.kubernetes.io` and `profile.node.kubernetes.io`
and their sub-namespaces are always allowed and cannot be denied.
Default: *empty*

View file

@ -475,9 +475,6 @@ The namespace part (i.e. prefix) of the labels is controlled by nfd:
[`-extra-label-ns`](../reference/master-commandline-reference.md#-extra-label-ns)
command line flag of nfd-master.
e.g: `nfd-master -deny-label-ns="*" -extra-label-ns=example.com`
- Built-in default namespaces `feature.node.kubernetes.io` and
`profile.node.kubernetes.io` (and their sub-namespaces) are always allowed
and cannot be denied.
## Feature rule format

View file

@ -0,0 +1,166 @@
/*
Copyright 2023 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 validate
import (
"fmt"
"strings"
corev1 "k8s.io/api/core/v1"
k8sQuantity "k8s.io/apimachinery/pkg/api/resource"
k8svalidation "k8s.io/apimachinery/pkg/util/validation"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
)
var (
// Default error message for invalid label/annotation keys
ErrNSNotAllowed = fmt.Errorf("namespace is not allowed")
// Default error message for invalid label/annotation keys
ErrUnprefixedKeysNotAllowed = fmt.Errorf("unprefixed keys are not allowed")
// Default error for invalid taint effect
ErrInvalidTaintEffect = fmt.Errorf("invalid taint effect")
// Default error for empty taint effect
ErrEmptyTaintEffect = fmt.Errorf("empty taint effect")
)
// Label validates a label key and value and returns an error if the key or
// value is invalid.
func Label(key, value string) error {
//Validate label key and value
if err := k8svalidation.IsQualifiedName(key); len(err) > 0 {
return fmt.Errorf("invalid label key %q: %s", key, strings.Join(err, "; "))
}
// Check label namespace, filter out if ns is not whitelisted
ns, _ := splitNs(key)
// And is not empty
if ns == "" {
return ErrUnprefixedKeysNotAllowed
}
// And is not a denied namespace
if ns == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io") {
// And is not a default namespace
if ns != nfdv1alpha1.FeatureLabelNs && ns != nfdv1alpha1.ProfileLabelNs &&
!strings.HasSuffix(ns, nfdv1alpha1.FeatureLabelSubNsSuffix) && !strings.HasSuffix(ns, nfdv1alpha1.ProfileLabelSubNsSuffix) {
return ErrNSNotAllowed
}
}
// Validate label value
if err := k8svalidation.IsValidLabelValue(value); len(err) > 0 {
return fmt.Errorf("invalid labelvalue %q: %s", value, strings.Join(err, "; "))
}
return nil
}
// Annotation validates an annotation key and value and returns an error if the
// key or value is invalid.
func Annotation(key, value string) error {
// Validate the annotation key
if err := k8svalidation.IsQualifiedName(key); len(err) > 0 {
return fmt.Errorf("invalid annotation key %q: %s", key, strings.Join(err, "; "))
}
ns, _ := splitNs(key)
// And is not empty
if ns == "" {
return ErrUnprefixedKeysNotAllowed
}
// And is not a denied namespace
if ns == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io") {
// And is not a default namespace
if ns != nfdv1alpha1.FeatureAnnotationNs && !strings.HasSuffix(ns, nfdv1alpha1.FeatureAnnotationSubNsSuffix) {
return ErrNSNotAllowed
}
}
// Validate annotation value
if errs := k8svalidation.IsValidLabelValue(value); len(errs) > 0 {
return fmt.Errorf("invalid annotation value %q: %s", value, strings.Join(errs, "; "))
}
return nil
}
// Taint validates a taint key and value and returns an error if the key or
// value is invalid.
func Taint(taint *corev1.Taint) error {
ns, _ := splitNs(taint.Key)
// And is not empty
if ns == "" {
return ErrUnprefixedKeysNotAllowed
}
// And is not a denied namespace
if ns == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io") {
// And is not a default namespace
if ns != nfdv1alpha1.TaintNs && !strings.HasSuffix(ns, nfdv1alpha1.TaintSubNsSuffix) {
return ErrNSNotAllowed
}
}
// Validate taint effect is not empty
if taint.Effect == "" {
return ErrEmptyTaintEffect
}
// Validate effect to be only one of NoSchedule, PreferNoSchedule or NoExecute
if taint.Effect != corev1.TaintEffectNoSchedule &&
taint.Effect != corev1.TaintEffectPreferNoSchedule &&
taint.Effect != corev1.TaintEffectNoExecute {
return ErrInvalidTaintEffect
}
return nil
}
// ExtendedResource validates an extended resource key and value and returns an
// error if the key or value is invalid.
func ExtendedResource(key, value string) error {
//Validate extendedResource name
if errs := k8svalidation.IsQualifiedName(key); len(errs) > 0 {
return fmt.Errorf("invalid name %q: %s", key, strings.Join(errs, "; "))
}
ns, _ := splitNs(key)
// And is not empty
if ns == "" {
return ErrUnprefixedKeysNotAllowed
}
// And is not a denied namespace
if ns == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io") {
// And is not a default namespace
if ns != nfdv1alpha1.ExtendedResourceNs && !strings.HasSuffix(ns, nfdv1alpha1.ExtendedResourceSubNsSuffix) {
return ErrNSNotAllowed
}
}
// Static Value (Pre-Defined at the NodeFeatureRule)
_, err := k8sQuantity.ParseQuantity(value)
if err != nil {
return fmt.Errorf("invalid value %s (from %s): %w", value, value, err)
}
return nil
}
// splitNs splits a name into its namespace and name parts
func splitNs(fullname string) (string, string) {
split := strings.SplitN(fullname, "/", 2)
if len(split) == 2 {
return split[0], split[1]
}
return "", fullname
}

View file

@ -0,0 +1,236 @@
package validate
import (
"fmt"
"testing"
corev1 "k8s.io/api/core/v1"
)
func TestAnnotation(t *testing.T) {
tests := []struct {
name string
key string
value string
want error
fail bool
}{
{
name: "Valid annotation",
key: "feature.node.kubernetes.io/feature",
value: "true",
want: nil,
},
{
name: "Invalid annotation key",
key: "invalid-key",
value: "true",
want: ErrUnprefixedKeysNotAllowed,
},
{
name: "Invalid annotation value",
key: "feature.node.kubernetes.io/feature",
value: "invalid value",
want: fmt.Errorf("invalid value \"invalid value\": value must be a valid label value"),
fail: true,
},
{
name: "Denied annotation key",
key: "kubernetes.io/denied",
value: "true",
want: ErrNSNotAllowed,
fail: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Annotation(tt.key, tt.value)
if got != tt.want {
if tt.fail {
return
}
t.Errorf("Annotation() = %v, want %v", got, tt.want)
}
})
}
}
func TestTaint(t *testing.T) {
tests := []struct {
name string
taint *corev1.Taint
want error
}{
{
name: "Valid taint",
taint: &corev1.Taint{
Key: "feature.node.kubernetes.io/taint",
Value: "true",
Effect: corev1.TaintEffectNoSchedule,
},
want: nil,
},
{
name: "UNPREFIXED taint key",
taint: &corev1.Taint{
Key: "invalid-key",
Value: "true",
Effect: corev1.TaintEffectNoSchedule,
},
want: ErrUnprefixedKeysNotAllowed,
},
{
name: "Invalid taint key",
taint: &corev1.Taint{
Key: "invalid.kubernetes.io/invalid-key",
Value: "true",
Effect: corev1.TaintEffectNoSchedule,
},
want: ErrNSNotAllowed,
},
{
name: "Empty taint effect",
taint: &corev1.Taint{
Key: "feature.node.kubernetes.io/taint",
Value: "true",
Effect: "",
},
want: ErrEmptyTaintEffect,
},
{
name: "Invalid taint effect",
taint: &corev1.Taint{
Key: "feature.node.kubernetes.io/taint",
Value: "true",
Effect: "invalid-effect",
},
want: ErrInvalidTaintEffect,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Taint(tt.taint)
if got != tt.want {
t.Errorf("Taint() = %v, want %v", got, tt.want)
}
})
}
}
func TestLabel(t *testing.T) {
tests := []struct {
name string
key string
value string
want error
fail bool
}{
{
name: "Valid label",
key: "feature.node.kubernetes.io/label",
value: "true",
want: nil,
fail: false,
},
{
name: "Valid vendor label",
key: "vendor.io/label",
value: "true",
want: nil,
fail: false,
},
{
name: "Denied label with prefix",
key: "kubernetes.io/label",
value: "true",
want: ErrNSNotAllowed,
fail: true,
},
{
name: "Invalid label key",
key: "invalid-key",
value: "true",
want: ErrNSNotAllowed,
fail: true,
},
{
name: "Invalid label value",
key: "feature.node.kubernetes.io/label",
value: "invalid value",
want: fmt.Errorf("invalid value \"invalid value\": value must be a valid label value"),
fail: true,
},
{
name: "Valid value label",
key: "feature.node.kubernetes.io/label",
value: "true",
want: nil,
fail: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := Label(tt.key, tt.value)
if err != tt.want {
if tt.fail {
return
}
t.Errorf("Label() = %v, want %v", err, tt.want)
}
})
}
}
func TestExtendedResource(t *testing.T) {
tests := []struct {
name string
key string
value string
want error
fail bool
}{
{
name: "Valid extended resource",
key: "feature.node.kubernetes.io/extended-resource",
value: "123",
want: nil,
fail: false,
},
{
name: "Invalid extended resource key",
key: "invalid-key",
value: "123",
want: ErrNSNotAllowed,
fail: true,
},
{
name: "Invalid extended resource value",
key: "feature.node.kubernetes.io/extended-resource",
value: "invalid value",
want: fmt.Errorf("invalid value \"invalid value\": value must be a valid label value"),
fail: true,
},
{
name: "Denied extended resource key",
key: "kubernetes.io/extended-resource",
value: "123",
want: ErrNSNotAllowed,
fail: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ExtendedResource(tt.key, tt.value)
if err != tt.want {
if tt.fail {
return
}
t.Errorf("ExtendedResource() = %v, want %v", err, tt.want)
}
})
}
}

View file

@ -382,6 +382,7 @@ func TestSetLabels(t *testing.T) {
expectedStatusPatches := []apihelper.JsonPatch{}
Convey("When node update succeeds", func() {
mockMaster.config.ExtraLabelNs = map[string]struct{}{"example.io": {}}
expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.FeatureLabelsAnnotation, strings.Join(mockLabelNames, ",")),
}
@ -400,6 +401,7 @@ func TestSetLabels(t *testing.T) {
})
Convey("When -label-whitelist is specified", func() {
mockMaster.config.ExtraLabelNs = map[string]struct{}{"example.io": {}}
expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.FeatureLabelsAnnotation, "example.io/feature-2"),
apihelper.NewJsonPatch("add", "/metadata/labels", "example.io/feature-2", mockLabels["example.io/feature-2"]),
@ -443,7 +445,6 @@ func TestSetLabels(t *testing.T) {
}
mockMaster.deniedNs.normal = map[string]struct{}{"random.denied.ns": {}}
mockMaster.deniedNs.wildcard = map[string]struct{}{"kubernetes.io": {}}
mockMaster.config.ExtraLabelNs = map[string]struct{}{"valid.ns": {}}
mockMaster.args.Instance = instance
mockHelper.On("GetClient").Return(mockClient, nil)
@ -459,10 +460,11 @@ func TestSetLabels(t *testing.T) {
})
Convey("When -resource-labels is specified", func() {
mockMaster.config.ExtraLabelNs = map[string]struct{}{"example.io": {}}
expectedPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.FeatureLabelsAnnotation, "example.io/feature-2"),
apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.ExtendedResourceAnnotation, "feature-1,feature-3"),
apihelper.NewJsonPatch("add", "/metadata/labels", "example.io/feature-2", mockLabels["example.io/feature-2"]),
apihelper.NewJsonPatch("add", "/metadata/annotations", nfdv1alpha1.ExtendedResourceAnnotation, "feature-1,feature-3"),
}
expectedStatusPatches := []apihelper.JsonPatch{
apihelper.NewJsonPatch("add", "/status/capacity", "feature.node.kubernetes.io/feature-1", mockLabels["feature.node.kubernetes.io/feature-1"]),
@ -502,6 +504,7 @@ func TestSetLabels(t *testing.T) {
func TestFilterLabels(t *testing.T) {
mockHelper := &apihelper.MockAPIHelpers{}
mockMaster := newMockMaster(mockHelper)
mockMaster.config.ExtraLabelNs = map[string]struct{}{"example.io": {}}
mockMaster.deniedNs = deniedNs{
normal: map[string]struct{}{"": struct{}{}, "kubernetes.io": struct{}{}, "denied.ns": struct{}{}},
wildcard: map[string]struct{}{".kubernetes.io": struct{}{}, ".denied.subns": struct{}{}},
@ -940,3 +943,62 @@ func removeLabelsWithPrefix(n *corev1.Node, search string) []apihelper.JsonPatch
return p
}
func TestGetDynamicValue(t *testing.T) {
tests := []struct {
name string
value string
features *nfdv1alpha1.Features
want string
fail bool
}{
{
name: "Valid dynamic value",
value: "@test.feature.LSM",
features: &nfdv1alpha1.Features{
Attributes: map[string]nfdv1alpha1.AttributeFeatureSet{
"test.feature": nfdv1alpha1.AttributeFeatureSet{
Elements: map[string]string{
"LSM": "123",
},
},
},
},
want: "123",
fail: false,
},
{
name: "Invalid feature name",
value: "@invalid",
features: &nfdv1alpha1.Features{},
want: "",
fail: true,
},
{
name: "Element not found",
value: "@test.feature.LSM",
features: &nfdv1alpha1.Features{},
want: "",
fail: true,
},
{
name: "Invalid dynamic value",
value: "@test.feature.LSM",
features: &nfdv1alpha1.Features{},
want: "",
fail: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := getDynamicValue(tt.value, tt.features)
if err != nil && !tt.fail {
t.Errorf("getDynamicValue() = %v, want %v", err, tt.want)
}
if got != tt.want {
t.Errorf("getDynamicValue() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -38,10 +38,8 @@ import (
"google.golang.org/grpc/health/grpc_health_v1"
"google.golang.org/grpc/peer"
corev1 "k8s.io/api/core/v1"
k8sQuantity "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sLabels "k8s.io/apimachinery/pkg/labels"
k8svalidation "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/leaderelection"
@ -55,6 +53,7 @@ import (
"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/apis/nfd/validate"
pb "sigs.k8s.io/node-feature-discovery/pkg/labeler"
"sigs.k8s.io/node-feature-discovery/pkg/utils"
"sigs.k8s.io/node-feature-discovery/pkg/version"
@ -553,24 +552,27 @@ func (m *nfdMaster) filterFeatureLabels(labels Labels, features *nfdv1alpha1.Fea
}
func (m *nfdMaster) filterFeatureLabel(name, value string, features *nfdv1alpha1.Features) (string, error) {
//Validate label name
if errs := k8svalidation.IsQualifiedName(name); len(errs) > 0 {
return "", fmt.Errorf("invalid name %q: %s", name, strings.Join(errs, "; "))
// Check if Value is dynamic
var filteredValue string
if strings.HasPrefix(value, "@") {
dynamicValue, err := getDynamicValue(value, features)
if err != nil {
return "", err
}
filteredValue = dynamicValue
} else {
filteredValue = value
}
// Check label namespace, filter out if ns is not whitelisted
// Validate
ns, base := splitNs(name)
if ns == "" {
return "", fmt.Errorf("labels without namespace (prefix/) not allowed")
}
if ns != nfdv1alpha1.FeatureLabelNs && ns != nfdv1alpha1.ProfileLabelNs &&
!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 isNamespaceDenied(ns, m.deniedNs.wildcard, m.deniedNs.normal) {
if _, ok := m.config.ExtraLabelNs[ns]; !ok {
return "", fmt.Errorf("namespace %q is not allowed", ns)
}
err := validate.Label(name, filteredValue)
if err == validate.ErrNSNotAllowed || isNamespaceDenied(ns, m.deniedNs.wildcard, m.deniedNs.normal) {
if _, ok := m.config.ExtraLabelNs[ns]; !ok {
return "", fmt.Errorf("namespace %q is not allowed", ns)
}
} else if err != nil {
return "", err
}
// Skip if label doesn't match labelWhiteList
@ -578,24 +580,7 @@ func (m *nfdMaster) filterFeatureLabel(name, value string, features *nfdv1alpha1
return "", fmt.Errorf("%s (%s) does not match the whitelist (%s)", base, name, m.config.LabelWhiteList.Regexp.String())
}
var filteredLabel string
// Dynamic Value
if strings.HasPrefix(value, "@") {
dynamicValue, err := getDynamicValue(value, features)
if err != nil {
return "", err
}
filteredLabel = dynamicValue
} else {
filteredLabel = value
}
// Validate the label value
if errs := k8svalidation.IsValidLabelValue(filteredLabel); len(errs) > 0 {
return "", fmt.Errorf("invalid value %q: %s", filteredLabel, strings.Join(errs, "; "))
}
return filteredLabel, nil
return filteredValue, nil
}
func getDynamicValue(value string, features *nfdv1alpha1.Features) (string, error) {
@ -621,7 +606,7 @@ func filterTaints(taints []corev1.Taint) []corev1.Taint {
outTaints := []corev1.Taint{}
for _, taint := range taints {
if err := filterTaint(&taint); err != nil {
if err := validate.Taint(&taint); err != nil {
klog.ErrorS(err, "ignoring taint", "taint", taint)
nodeTaintsRejected.Inc()
} else {
@ -631,19 +616,6 @@ func filterTaints(taints []corev1.Taint) []corev1.Taint {
return outTaints
}
func filterTaint(taint *corev1.Taint) error {
// Check prefix of the key, filter out disallowed ones
ns, _ := splitNs(taint.Key)
if ns == "" {
return fmt.Errorf("taint keys without namespace (prefix/) are not allowed")
}
if ns != nfdv1alpha1.TaintNs && !strings.HasSuffix(ns, nfdv1alpha1.TaintSubNsSuffix) &&
(ns == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io")) {
return fmt.Errorf("prefix %q is not allowed for taint key", ns)
}
return nil
}
func verifyNodeName(cert *x509.Certificate, nodeName string) error {
if cert.Subject.CommonName == nodeName {
return nil
@ -809,35 +781,25 @@ func (m *nfdMaster) filterExtendedResources(features *nfdv1alpha1.Features, exte
}
func filterExtendedResource(name, value string, features *nfdv1alpha1.Features) (string, error) {
// Check if given NS is allowed
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 == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io") {
return "", fmt.Errorf("namespace %q is not allowed", ns)
// Dynamic Value
var filteredValue string
if strings.HasPrefix(value, "@") {
dynamicValue, err := getDynamicValue(value, features)
if err != nil {
return "", err
}
filteredValue = dynamicValue
} else {
filteredValue = value
}
// Dynamic Value
if strings.HasPrefix(value, "@") {
if element, err := getDynamicValue(value, features); err != nil {
return "", err
} else {
q, err := k8sQuantity.ParseQuantity(element)
if err != nil {
return "", fmt.Errorf("invalid value %s (from %s): %w", element, value, err)
}
return q.String(), nil
}
}
// Static Value (Pre-Defined at the NodeFeatureRule)
q, err := k8sQuantity.ParseQuantity(value)
// Validate
err := validate.ExtendedResource(name, filteredValue)
if err != nil {
return "", fmt.Errorf("invalid value %s: %w", value, err)
return "", err
}
return q.String(), nil
return filteredValue, nil
}
func (m *nfdMaster) refreshNodeFeatures(cli *kubernetes.Clientset, nodeName string, labels map[string]string, features *nfdv1alpha1.Features) error {
@ -1331,6 +1293,7 @@ func addNs(src string, nsToAdd string) string {
}
// splitNs splits a name into its namespace and name parts
// Ported to Validate
func splitNs(fullname string) (string, string) {
split := strings.SplitN(fullname, "/", 2)
if len(split) == 2 {
@ -1441,22 +1404,11 @@ func (m *nfdMaster) filterFeatureAnnotations(annotations map[string]string) map[
outAnnotations := make(map[string]string)
for annotation, value := range annotations {
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
if ns != nfdv1alpha1.FeatureAnnotationNs && !strings.HasSuffix(ns, nfdv1alpha1.FeatureAnnotationSubNsSuffix) {
// If the namespace is denied the annotation will be ignored
if ns == "" {
klog.ErrorS(fmt.Errorf("labels without namespace (prefix/) not allowed"), fmt.Sprintf("Ignoring annotation %s", annotation))
continue
}
if ns == "kubernetes.io" || strings.HasSuffix(ns, ".kubernetes.io") || ns == nfdv1alpha1.AnnotationNs {
klog.ErrorS(fmt.Errorf("namespace %q is not allowed", ns), fmt.Sprintf("Ignoring annotation %s", annotation))
continue
}
err := validate.Annotation(annotation, value)
if err != nil {
klog.ErrorS(err, "ignoring annotation", "annotationKey", annotation, "annotationValue", value)
continue
}
outAnnotations[annotation] = value

View file

@ -30,7 +30,5 @@ while true; do
i=$(( $i + 1 ))
done
# Configure environment and run tests
make e2e-test