diff --git a/pkg/api/validation/events.go b/pkg/api/validation/events.go index d1a89c45c6f..1182429582e 100644 --- a/pkg/api/validation/events.go +++ b/pkg/api/validation/events.go @@ -37,8 +37,8 @@ func ValidateEvent(event *api.Event) field.ErrorList { event.Namespace != event.InvolvedObject.Namespace { allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match involvedObject")) } - if !validation.IsDNS1123Subdomain(event.Namespace) { - allErrs = append(allErrs, field.Invalid(field.NewPath("namespace"), event.Namespace, "")) + for _, msg := range validation.IsDNS1123Subdomain(event.Namespace) { + allErrs = append(allErrs, field.Invalid(field.NewPath("namespace"), event.Namespace, msg)) } return allErrs } diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 8e9a401ba34..2e1d30814b0 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -58,7 +58,6 @@ func InclusiveRangeErrorMsg(lo, hi int) string { return fmt.Sprintf(`must be between %d and %d, inclusive`, lo, hi) } -var DNSSubdomainErrorMsg string = fmt.Sprintf(`must be a DNS subdomain (at most %d characters, matching regex %s): e.g. "example.com"`, validation.DNS1123SubdomainMaxLength, validation.DNS1123SubdomainFmt) var DNS952LabelErrorMsg string = fmt.Sprintf(`must be a DNS 952 label (at most %d characters, matching regex %s): e.g. "my-name"`, validation.DNS952LabelMaxLength, validation.DNS952LabelFmt) var pdPartitionErrorMsg string = InclusiveRangeErrorMsg(1, 255) var PortRangeErrorMsg string = InclusiveRangeErrorMsg(1, 65535) @@ -241,10 +240,7 @@ func NameIsDNSSubdomain(name string, prefix bool) []string { if prefix { name = maskTrailingDash(name) } - if validation.IsDNS1123Subdomain(name) { - return nil - } - return []string{DNSSubdomainErrorMsg} + return validation.IsDNS1123Subdomain(name) } // NameIsDNSLabel is a ValidateNameFunc for names that must be a DNS 1123 label. @@ -3014,7 +3010,7 @@ func ValidateLoadBalancerStatus(status *api.LoadBalancerStatus, fldPath *field.P } } if len(ingress.Hostname) > 0 { - for _, msg := range NameIsDNSSubdomain(ingress.Hostname, false) { + for _, msg := range validation.IsDNS1123Subdomain(ingress.Hostname) { allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, msg)) } if isIP := (net.ParseIP(ingress.Hostname) != nil); isIP { diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 001ee1f30f6..4451364e8f6 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -4691,7 +4691,7 @@ func TestValidateLimitRange(t *testing.T) { }, "invalid-name": { api.LimitRange{ObjectMeta: api.ObjectMeta{Name: "^Invalid", Namespace: "foo"}, Spec: api.LimitRangeSpec{}}, - DNSSubdomainErrorMsg, + "must match the regex", }, "invalid-namespace": { api.LimitRange{ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "^Invalid"}, Spec: api.LimitRangeSpec{}}, @@ -5015,7 +5015,7 @@ func TestValidateResourceQuota(t *testing.T) { }, "invalid Name": { api.ResourceQuota{ObjectMeta: api.ObjectMeta{Name: "^Invalid", Namespace: "foo"}, Spec: spec}, - DNSSubdomainErrorMsg, + "must match the regex", }, "invalid Namespace": { api.ResourceQuota{ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: "^Invalid"}, Spec: spec}, @@ -5618,7 +5618,7 @@ func TestValidateEndpoints(t *testing.T) { "invalid name": { endpoints: api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "-_Invliad^&Characters", Namespace: "namespace"}}, errorType: "FieldValueInvalid", - errorDetail: DNSSubdomainErrorMsg, + errorDetail: "must match the regex", }, "empty addresses": { endpoints: api.Endpoints{ diff --git a/pkg/apis/extensions/validation/validation.go b/pkg/apis/extensions/validation/validation.go index a9017780d22..12114ef7a58 100644 --- a/pkg/apis/extensions/validation/validation.go +++ b/pkg/apis/extensions/validation/validation.go @@ -353,7 +353,7 @@ func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *field. if len(ih.Host) > 0 { // TODO: Ports and ips are allowed in the host part of a url // according to RFC 3986, consider allowing them. - for _, msg := range apivalidation.NameIsDNSSubdomain(ih.Host, false) { + for _, msg := range validation.IsDNS1123Subdomain(ih.Host) { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, msg)) } if isIP := (net.ParseIP(ih.Host) != nil); isIP { diff --git a/pkg/util/validation/validation.go b/pkg/util/validation/validation.go index 144ed4c4077..53a6ab2434e 100644 --- a/pkg/util/validation/validation.go +++ b/pkg/util/validation/validation.go @@ -47,8 +47,8 @@ func IsQualifiedName(value string) []string { prefix, name = parts[0], parts[1] if len(prefix) == 0 { errs = append(errs, "prefix part "+EmptyError()) - } else if !IsDNS1123Subdomain(prefix) { - errs = append(errs, fmt.Sprintf("prefix part must be a DNS subdomain (e.g. 'example.com')")) + } else if msgs := IsDNS1123Subdomain(prefix); len(msgs) != 0 { + errs = append(errs, prefixEach(msgs, "prefix part ")...) } default: return append(errs, RegexError(qualifiedNameFmt, "MyName", "my.name", "123-abc")+ @@ -110,8 +110,15 @@ var dns1123SubdomainRegexp = regexp.MustCompile("^" + DNS1123SubdomainFmt + "$") // IsDNS1123Subdomain tests for a string that conforms to the definition of a // subdomain in DNS (RFC 1123). -func IsDNS1123Subdomain(value string) bool { - return len(value) <= DNS1123SubdomainMaxLength && dns1123SubdomainRegexp.MatchString(value) +func IsDNS1123Subdomain(value string) []string { + var errs []string + if len(value) > DNS1123SubdomainMaxLength { + errs = append(errs, MaxLenError(DNS1123SubdomainMaxLength)) + } + if !dns1123SubdomainRegexp.MatchString(value) { + errs = append(errs, RegexError(DNS1123SubdomainFmt, "example.com")) + } + return errs } const DNS952LabelFmt string = "[a-z]([-a-z0-9]*[a-z0-9])?" @@ -239,3 +246,10 @@ func RegexError(fmt string, examples ...string) string { func EmptyError() string { return "must be non-empty" } + +func prefixEach(msgs []string, prefix string) []string { + for i := range msgs { + msgs[i] = prefix + msgs[i] + } + return msgs +} diff --git a/pkg/util/validation/validation_test.go b/pkg/util/validation/validation_test.go index f38ca7531fc..df4e661a496 100644 --- a/pkg/util/validation/validation_test.go +++ b/pkg/util/validation/validation_test.go @@ -60,8 +60,8 @@ func TestIsDNS1123Subdomain(t *testing.T) { strings.Repeat("a", 253), } for _, val := range goodValues { - if !IsDNS1123Subdomain(val) { - t.Errorf("expected true for '%s'", val) + if msgs := IsDNS1123Subdomain(val); len(msgs) != 0 { + t.Errorf("expected true for '%s': %v", val, msgs) } } @@ -80,7 +80,7 @@ func TestIsDNS1123Subdomain(t *testing.T) { strings.Repeat("a", 254), } for _, val := range badValues { - if IsDNS1123Subdomain(val) { + if msgs := IsDNS1123Subdomain(val); len(msgs) == 0 { t.Errorf("expected false for '%s'", val) } }