diff --git a/Gopkg.lock b/Gopkg.lock index 85d4b687cf6..45c5d907f51 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -867,7 +867,9 @@ "k8s.io/apimachinery/pkg/api/errors", "k8s.io/apimachinery/pkg/apis/meta/v1", "k8s.io/apimachinery/pkg/runtime", + "k8s.io/apimachinery/pkg/util/errors", "k8s.io/apimachinery/pkg/util/sets", + "k8s.io/apimachinery/pkg/util/validation", "k8s.io/apimachinery/pkg/util/wait", "k8s.io/apimachinery/pkg/watch", "k8s.io/client-go/kubernetes", diff --git a/pkg/validate/validate.go b/pkg/validate/validate.go index 73bdeb29522..d385e00678f 100644 --- a/pkg/validate/validate.go +++ b/pkg/validate/validate.go @@ -10,25 +10,28 @@ import ( "strconv" "strings" "unicode/utf8" + + k8serrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/validation" ) -// DomainName checks if the given string is a valid domain name and returns an error if not. -func DomainName(v string) error { - if err := nonEmpty(v); err != nil { - return err +func validateSubdomain(v string) error { + validationMessages := validation.IsDNS1123Subdomain(v) + if len(validationMessages) == 0 { + return nil } - split := strings.Split(v, ".") - for i, segment := range split { - // Trailing dot is OK - if len(segment) == 0 && i == len(split)-1 { - continue - } - if !isMatch("^[a-zA-Z0-9-]{1,63}$", segment) { - return errors.New("invalid domain name") - } + errs := make([]error, len(validationMessages)) + for i, m := range validationMessages { + errs[i] = errors.New(m) } - return nil + return k8serrors.NewAggregate(errs) +} + +// DomainName checks if the given string is a valid domain name and returns an error if not. +func DomainName(v string) error { + // Trailing dot is OK + return validateSubdomain(strings.TrimSuffix(v, ".")) } // Email checks if the given string is a valid email address and returns an error if not. diff --git a/pkg/validate/validate_test.go b/pkg/validate/validate_test.go index d64949a497c..e311b479fbc 100644 --- a/pkg/validate/validate_test.go +++ b/pkg/validate/validate_test.go @@ -171,32 +171,44 @@ func TestSubnetCIDR(t *testing.T) { } func TestDomainName(t *testing.T) { - tests := []test{ - {"", emptyMsg}, - {" ", emptyMsg}, - {"a", ""}, - {".", invalidDomainMsg}, - {"日本語", invalidDomainMsg}, - {"日本語.com", invalidDomainMsg}, - {"abc.日本語.com", invalidDomainMsg}, - {"a日本語a.com", invalidDomainMsg}, - {"abc", ""}, - {"ABC", ""}, - {"ABC123", ""}, - {"ABC123.COM123", ""}, - {"1", ""}, - {"0.0", ""}, - {"1.2.3.4", ""}, - {"1.2.3.4.", ""}, - {"abc.", ""}, - {"abc.com", ""}, - {"abc.com.", ""}, - {"a.b.c.d.e.f", ""}, - {".abc", invalidDomainMsg}, - {".abc.com", invalidDomainMsg}, - {".abc.com", invalidDomainMsg}, + cases := []struct { + domain string + valid bool + }{ + {"", false}, + {" ", false}, + {"a", true}, + {".", false}, + {"日本語", false}, + {"日本語.com", false}, + {"abc.日本語.com", false}, + {"a日本語a.com", false}, + {"abc", true}, + {"ABC", false}, + {"ABC123", false}, + {"ABC123.COM123", false}, + {"1", true}, + {"0.0", true}, + {"1.2.3.4", true}, + {"1.2.3.4.", true}, + {"abc.", true}, + {"abc.com", true}, + {"abc.com.", true}, + {"a.b.c.d.e.f", true}, + {".abc", false}, + {".abc.com", false}, + {".abc.com", false}, + } + for _, tc := range cases { + t.Run(tc.domain, func(t *testing.T) { + err := DomainName(tc.domain) + if tc.valid { + assert.NoError(t, err) + } else { + assert.Error(t, err) + } + }) } - runTests(t, "DomainName", DomainName, tests) } func TestEmail(t *testing.T) { @@ -214,10 +226,7 @@ func TestEmail(t *testing.T) { {"ア@abc.com", ""}, {"中文@abc.com", ""}, {"a@abc.com", ""}, - {"a@ABC.com", ""}, {"a@123.com", ""}, - {"a@日本語.com", invalidDomainMsg}, - {"a@.com", invalidDomainMsg}, {"@abc.com", invalidMsg}, } runTests(t, "Email", Email, tests)