diff --git a/pkg/apis/admissionregistration/validation/validation.go b/pkg/apis/admissionregistration/validation/validation.go index 4c478f457e0..39a5c4ab81f 100644 --- a/pkg/apis/admissionregistration/validation/validation.go +++ b/pkg/apis/admissionregistration/validation/validation.go @@ -22,7 +22,7 @@ import ( genericvalidation "k8s.io/apimachinery/pkg/api/validation" "k8s.io/apimachinery/pkg/util/sets" - validationutil "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/kubernetes/pkg/apis/admissionregistration" ) @@ -38,15 +38,7 @@ func ValidateInitializerConfiguration(ic *admissionregistration.InitializerConfi func validateInitializer(initializer *admissionregistration.Initializer, fldPath *field.Path) field.ErrorList { var allErrors field.ErrorList // initlializer.Name must be fully qualified - if len(initializer.Name) == 0 { - allErrors = append(allErrors, field.Required(fldPath.Child("name"), "")) - } - if errs := validationutil.IsDNS1123Subdomain(initializer.Name); len(errs) > 0 { - allErrors = append(allErrors, field.Invalid(fldPath.Child("name"), initializer.Name, strings.Join(errs, ","))) - } - if len(strings.Split(initializer.Name, ".")) < 3 { - allErrors = append(allErrors, field.Invalid(fldPath.Child("name"), initializer.Name, "should be a domain with at least two dots")) - } + allErrors = append(allErrors, validation.IsFullyQualifiedName(fldPath.Child("name"), initializer.Name)...) for i, rule := range initializer.Rules { notAllowSubresources := false @@ -186,15 +178,7 @@ func ValidateExternalAdmissionHookConfiguration(e *admissionregistration.Externa func validateExternalAdmissionHook(hook *admissionregistration.ExternalAdmissionHook, fldPath *field.Path) field.ErrorList { var allErrors field.ErrorList // hook.Name must be fully qualified - if len(hook.Name) == 0 { - allErrors = append(allErrors, field.Required(fldPath.Child("name"), "")) - } - if errs := validationutil.IsDNS1123Subdomain(hook.Name); len(errs) > 0 { - allErrors = append(allErrors, field.Invalid(fldPath.Child("name"), hook.Name, strings.Join(errs, ","))) - } - if len(strings.Split(hook.Name, ".")) < 3 { - allErrors = append(allErrors, field.Invalid(fldPath.Child("name"), hook.Name, "should be a domain with at least two dots")) - } + allErrors = append(allErrors, validation.IsFullyQualifiedName(fldPath.Child("name"), hook.Name)...) for i, rule := range hook.Rules { allErrors = append(allErrors, validateRuleWithOperations(&rule, fldPath.Child("rules").Index(i))...) diff --git a/pkg/apis/admissionregistration/validation/validation_test.go b/pkg/apis/admissionregistration/validation/validation_test.go index a864ac3a866..a8f74808006 100644 --- a/pkg/apis/admissionregistration/validation/validation_test.go +++ b/pkg/apis/admissionregistration/validation/validation_test.go @@ -62,7 +62,7 @@ func TestValidateInitializerConfiguration(t *testing.T) { Name: "", }, }), - expectedError: `initializers[1].name: Invalid value: "k8s.io": should be a domain with at least two dots, initializers[2].name: Required value`, + expectedError: `initializers[1].name: Invalid value: "k8s.io": should be a domain with at least three segments separated by dots, initializers[2].name: Required value`, }, { name: "APIGroups must not be empty or nil", @@ -274,7 +274,7 @@ func TestValidateExternalAdmissionHookConfiguration(t *testing.T) { Name: "", }, }), - expectedError: `externalAdmissionHooks[1].name: Invalid value: "k8s.io": should be a domain with at least two dots, externalAdmissionHooks[2].name: Required value`, + expectedError: `externalAdmissionHooks[1].name: Invalid value: "k8s.io": should be a domain with at least three segments separated by dots, externalAdmissionHooks[2].name: Required value`, }, { name: "Operations must not be empty or nil", diff --git a/staging/src/k8s.io/apimachinery/pkg/api/validation/objectmeta.go b/staging/src/k8s.io/apimachinery/pkg/api/validation/objectmeta.go index 5bef9495c60..3c32a937ac2 100644 --- a/staging/src/k8s.io/apimachinery/pkg/api/validation/objectmeta.go +++ b/staging/src/k8s.io/apimachinery/pkg/api/validation/objectmeta.go @@ -195,9 +195,7 @@ func ValidateInitializers(initializers *metav1.Initializers, fldPath *field.Path return allErrs } for i, initializer := range initializers.Pending { - for _, msg := range validation.IsQualifiedName(initializer.Name) { - allErrs = append(allErrs, field.Invalid(fldPath.Child("pending").Index(i), initializer.Name, msg)) - } + allErrs = append(allErrs, validation.IsFullyQualifiedName(fldPath.Child("pending").Index(i).Child("name"), initializer.Name)...) } allErrs = append(allErrs, validateInitializersResult(initializers.Result, fldPath.Child("result"))...) return allErrs diff --git a/staging/src/k8s.io/apimachinery/pkg/util/validation/BUILD b/staging/src/k8s.io/apimachinery/pkg/util/validation/BUILD index cd174f80082..252ee530862 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/validation/BUILD +++ b/staging/src/k8s.io/apimachinery/pkg/util/validation/BUILD @@ -10,11 +10,13 @@ go_test( name = "go_default_test", srcs = ["validation_test.go"], library = ":go_default_library", + deps = ["//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library"], ) go_library( name = "go_default_library", srcs = ["validation.go"], + deps = ["//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library"], ) filegroup( diff --git a/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go b/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go index 1159a02573c..13f3bc80788 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go @@ -22,6 +22,8 @@ import ( "net" "regexp" "strings" + + "k8s.io/apimachinery/pkg/util/validation/field" ) const qnameCharFmt string = "[A-Za-z0-9]" @@ -67,6 +69,21 @@ func IsQualifiedName(value string) []string { return errs } +// IsFullyQualifiedName checks if the name is fully qualified. +func IsFullyQualifiedName(fldPath *field.Path, name string) field.ErrorList { + var allErrors field.ErrorList + if len(name) == 0 { + return append(allErrors, field.Required(fldPath, "")) + } + if errs := IsDNS1123Subdomain(name); len(errs) > 0 { + return append(allErrors, field.Invalid(fldPath, name, strings.Join(errs, ","))) + } + if len(strings.Split(name, ".")) < 3 { + return append(allErrors, field.Invalid(fldPath, name, "should be a domain with at least three segments separated by dots")) + } + return allErrors +} + const labelValueFmt string = "(" + qualifiedNameFmt + ")?" const labelValueErrMsg string = "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character" const LabelValueMaxLength int = 63 diff --git a/staging/src/k8s.io/apimachinery/pkg/util/validation/validation_test.go b/staging/src/k8s.io/apimachinery/pkg/util/validation/validation_test.go index 061be1a6e65..2ce8437d400 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/validation/validation_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/validation/validation_test.go @@ -19,6 +19,8 @@ package validation import ( "strings" "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" ) func TestIsDNS1123Label(t *testing.T) { @@ -450,3 +452,38 @@ func TestIsWildcardDNS1123Subdomain(t *testing.T) { } } } + +func TestIsFullyQualifiedName(t *testing.T) { + tests := []struct { + name string + targetName string + err string + }{ + { + name: "name needs to be fully qualified, i.e., contains at least 2 dots", + targetName: "k8s.io", + err: "should be a domain with at least three segments separated by dots", + }, + { + name: "name cannot be empty", + targetName: "", + err: "Required value", + }, + { + name: "name must conform to RFC 1123", + targetName: "A.B.C", + err: "a DNS-1123 subdomain must consist of lower case alphanumeric characters", + }, + } + for _, tc := range tests { + err := IsFullyQualifiedName(field.NewPath(""), tc.targetName).ToAggregate() + switch { + case tc.err == "" && err != nil: + t.Errorf("%q: unexpected error: %v", tc.name, err) + case tc.err != "" && err == nil: + t.Errorf("%q: unexpected no error, expected %s", tc.name, tc.err) + case tc.err != "" && err != nil && !strings.Contains(err.Error(), tc.err): + t.Errorf("%q: expected %s, got %v", tc.name, tc.err, err) + } + } +}