unify the validation rules on initializer name

This commit is contained in:
Chao Xu 2017-08-24 10:27:46 -07:00
parent a64eeb47f6
commit c33de9f204
6 changed files with 62 additions and 24 deletions

View File

@ -22,7 +22,7 @@ import (
genericvalidation "k8s.io/apimachinery/pkg/api/validation" genericvalidation "k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/util/sets" "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/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/apis/admissionregistration" "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 { func validateInitializer(initializer *admissionregistration.Initializer, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList var allErrors field.ErrorList
// initlializer.Name must be fully qualified // initlializer.Name must be fully qualified
if len(initializer.Name) == 0 { allErrors = append(allErrors, validation.IsFullyQualifiedName(fldPath.Child("name"), initializer.Name)...)
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"))
}
for i, rule := range initializer.Rules { for i, rule := range initializer.Rules {
notAllowSubresources := false notAllowSubresources := false
@ -186,15 +178,7 @@ func ValidateExternalAdmissionHookConfiguration(e *admissionregistration.Externa
func validateExternalAdmissionHook(hook *admissionregistration.ExternalAdmissionHook, fldPath *field.Path) field.ErrorList { func validateExternalAdmissionHook(hook *admissionregistration.ExternalAdmissionHook, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList var allErrors field.ErrorList
// hook.Name must be fully qualified // hook.Name must be fully qualified
if len(hook.Name) == 0 { allErrors = append(allErrors, validation.IsFullyQualifiedName(fldPath.Child("name"), hook.Name)...)
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"))
}
for i, rule := range hook.Rules { for i, rule := range hook.Rules {
allErrors = append(allErrors, validateRuleWithOperations(&rule, fldPath.Child("rules").Index(i))...) allErrors = append(allErrors, validateRuleWithOperations(&rule, fldPath.Child("rules").Index(i))...)

View File

@ -62,7 +62,7 @@ func TestValidateInitializerConfiguration(t *testing.T) {
Name: "", 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", name: "APIGroups must not be empty or nil",
@ -274,7 +274,7 @@ func TestValidateExternalAdmissionHookConfiguration(t *testing.T) {
Name: "", 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", name: "Operations must not be empty or nil",

View File

@ -195,9 +195,7 @@ func ValidateInitializers(initializers *metav1.Initializers, fldPath *field.Path
return allErrs return allErrs
} }
for i, initializer := range initializers.Pending { for i, initializer := range initializers.Pending {
for _, msg := range validation.IsQualifiedName(initializer.Name) { allErrs = append(allErrs, validation.IsFullyQualifiedName(fldPath.Child("pending").Index(i).Child("name"), initializer.Name)...)
allErrs = append(allErrs, field.Invalid(fldPath.Child("pending").Index(i), initializer.Name, msg))
}
} }
allErrs = append(allErrs, validateInitializersResult(initializers.Result, fldPath.Child("result"))...) allErrs = append(allErrs, validateInitializersResult(initializers.Result, fldPath.Child("result"))...)
return allErrs return allErrs

View File

@ -10,11 +10,13 @@ go_test(
name = "go_default_test", name = "go_default_test",
srcs = ["validation_test.go"], srcs = ["validation_test.go"],
library = ":go_default_library", library = ":go_default_library",
deps = ["//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library"],
) )
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = ["validation.go"], srcs = ["validation.go"],
deps = ["//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library"],
) )
filegroup( filegroup(

View File

@ -22,6 +22,8 @@ import (
"net" "net"
"regexp" "regexp"
"strings" "strings"
"k8s.io/apimachinery/pkg/util/validation/field"
) )
const qnameCharFmt string = "[A-Za-z0-9]" const qnameCharFmt string = "[A-Za-z0-9]"
@ -67,6 +69,21 @@ func IsQualifiedName(value string) []string {
return errs 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 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 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 const LabelValueMaxLength int = 63

View File

@ -19,6 +19,8 @@ package validation
import ( import (
"strings" "strings"
"testing" "testing"
"k8s.io/apimachinery/pkg/util/validation/field"
) )
func TestIsDNS1123Label(t *testing.T) { 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)
}
}
}