diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index 8a61d65ddd1..3f35be6e07d 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -133,7 +133,7 @@ func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) fie func ValidateDNS1123Label(value string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for _, msg := range validation.IsDNS1123Label(value) { - allErrs = append(allErrs, field.Invalid(fldPath, value, msg)) + allErrs = append(allErrs, field.Invalid(fldPath, value, msg).WithOrigin("format=dns-label")) } return allErrs } @@ -142,7 +142,7 @@ func ValidateDNS1123Label(value string, fldPath *field.Path) field.ErrorList { func ValidateQualifiedName(value string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for _, msg := range validation.IsQualifiedName(value) { - allErrs = append(allErrs, field.Invalid(fldPath, value, msg)) + allErrs = append(allErrs, field.Invalid(fldPath, value, msg).WithOrigin("format=qualified-name")) } return allErrs } @@ -7466,7 +7466,7 @@ func validateEndpointAddress(address *core.EndpointAddress, fldPath *field.Path) // During endpoint update, verify that NodeName is a DNS subdomain and transition rules allow the update if address.NodeName != nil { for _, msg := range ValidateNodeName(*address.NodeName, false) { - allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), *address.NodeName, msg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), *address.NodeName, msg).WithOrigin("format=dns-label")) } } allErrs = append(allErrs, ValidateNonSpecialIP(address.IP, fldPath.Child("ip"))...) @@ -7485,20 +7485,20 @@ func ValidateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList allErrs := field.ErrorList{} ip := netutils.ParseIPSloppy(ipAddress) if ip == nil { - allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "must be a valid IP address")) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "must be a valid IP address").WithOrigin("format=ip-sloppy")) return allErrs } if ip.IsUnspecified() { - allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, fmt.Sprintf("may not be unspecified (%v)", ipAddress))) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, fmt.Sprintf("may not be unspecified (%v)", ipAddress)).WithOrigin("format=non-special-ip")) } if ip.IsLoopback() { - allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the loopback range (127.0.0.0/8, ::1/128)")) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the loopback range (127.0.0.0/8, ::1/128)").WithOrigin("format=non-special-ip")) } if ip.IsLinkLocalUnicast() { - allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local range (169.254.0.0/16, fe80::/10)")) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local range (169.254.0.0/16, fe80::/10)").WithOrigin("format=non-special-ip")) } if ip.IsLinkLocalMulticast() { - allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local multicast range (224.0.0.0/24, ff02::/10)")) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local multicast range (224.0.0.0/24, ff02::/10)").WithOrigin("format=non-special-ip")) } return allErrs } @@ -7511,7 +7511,7 @@ func validateEndpointPort(port *core.EndpointPort, requireName bool, fldPath *fi allErrs = append(allErrs, ValidateDNS1123Label(port.Name, fldPath.Child("name"))...) } for _, msg := range validation.IsValidPortNum(int(port.Port)) { - allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), port.Port, msg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), port.Port, msg).WithOrigin("portNum")) } if len(port.Protocol) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), "")) diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 992ab9de564..4c6e0f64425 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -9183,7 +9183,7 @@ func TestValidateContainers(t *testing.T) { t.Fatal("expected error but received none") } - if diff := cmp.Diff(tc.expectedErrors, errs, cmpopts.IgnoreFields(field.Error{}, "BadValue", "Detail")); diff != "" { + if diff := cmp.Diff(tc.expectedErrors, errs, cmpopts.IgnoreFields(field.Error{}, "BadValue", "Detail", "Origin")); diff != "" { t.Errorf("unexpected diff in errors (-want, +got):\n%s", diff) t.Errorf("INFO: all errors:\n%s", prettyErrorList(errs)) } @@ -20674,7 +20674,7 @@ func TestValidateEndpointsCreate(t *testing.T) { errorCases := map[string]struct { endpoints core.Endpoints errorType field.ErrorType - errorDetail string + errorOrigin string }{ "missing namespace": { endpoints: core.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "mysvc"}}, @@ -20685,14 +20685,12 @@ func TestValidateEndpointsCreate(t *testing.T) { errorType: "FieldValueRequired", }, "invalid namespace": { - endpoints: core.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "mysvc", Namespace: "no@#invalid.;chars\"allowed"}}, - errorType: "FieldValueInvalid", - errorDetail: dnsLabelErrMsg, + endpoints: core.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "mysvc", Namespace: "no@#invalid.;chars\"allowed"}}, + errorType: "FieldValueInvalid", }, "invalid name": { - endpoints: core.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "-_Invliad^&Characters", Namespace: "namespace"}}, - errorType: "FieldValueInvalid", - errorDetail: dnsSubdomainLabelErrMsg, + endpoints: core.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "-_Invliad^&Characters", Namespace: "namespace"}}, + errorType: "FieldValueInvalid", }, "empty addresses": { endpoints: core.Endpoints{ @@ -20712,7 +20710,7 @@ func TestValidateEndpointsCreate(t *testing.T) { }}, }, errorType: "FieldValueInvalid", - errorDetail: "must be a valid IP address", + errorOrigin: "format=ip-sloppy", }, "Multiple ports, one without name": { endpoints: core.Endpoints{ @@ -20733,7 +20731,7 @@ func TestValidateEndpointsCreate(t *testing.T) { }}, }, errorType: "FieldValueInvalid", - errorDetail: "between", + errorOrigin: "portNum", }, "Invalid protocol": { endpoints: core.Endpoints{ @@ -20754,7 +20752,7 @@ func TestValidateEndpointsCreate(t *testing.T) { }}, }, errorType: "FieldValueInvalid", - errorDetail: "must be a valid IP address", + errorOrigin: "format=ip-sloppy", }, "Port missing number": { endpoints: core.Endpoints{ @@ -20765,7 +20763,7 @@ func TestValidateEndpointsCreate(t *testing.T) { }}, }, errorType: "FieldValueInvalid", - errorDetail: "between", + errorOrigin: "portNum", }, "Port missing protocol": { endpoints: core.Endpoints{ @@ -20786,7 +20784,7 @@ func TestValidateEndpointsCreate(t *testing.T) { }}, }, errorType: "FieldValueInvalid", - errorDetail: "loopback", + errorOrigin: "format=non-special-ip", }, "Address is link-local": { endpoints: core.Endpoints{ @@ -20797,7 +20795,7 @@ func TestValidateEndpointsCreate(t *testing.T) { }}, }, errorType: "FieldValueInvalid", - errorDetail: "link-local", + errorOrigin: "format=non-special-ip", }, "Address is link-local multicast": { endpoints: core.Endpoints{ @@ -20808,7 +20806,7 @@ func TestValidateEndpointsCreate(t *testing.T) { }}, }, errorType: "FieldValueInvalid", - errorDetail: "link-local multicast", + errorOrigin: "format=non-special-ip", }, "Invalid AppProtocol": { endpoints: core.Endpoints{ @@ -20819,14 +20817,14 @@ func TestValidateEndpointsCreate(t *testing.T) { }}, }, errorType: "FieldValueInvalid", - errorDetail: "name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character", + errorOrigin: "format=qualified-name", }, } for k, v := range errorCases { t.Run(k, func(t *testing.T) { - if errs := ValidateEndpointsCreate(&v.endpoints); len(errs) == 0 || errs[0].Type != v.errorType || !strings.Contains(errs[0].Detail, v.errorDetail) { - t.Errorf("Expected error type %s with detail %q, got %v", v.errorType, v.errorDetail, errs) + if errs := ValidateEndpointsCreate(&v.endpoints); len(errs) == 0 || errs[0].Type != v.errorType || errs[0].Origin != v.errorOrigin { + t.Errorf("Expected error type %s with origin %q, got %#v", v.errorType, v.errorOrigin, errs[0]) } }) } @@ -21190,7 +21188,7 @@ func TestValidateSchedulingGates(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { errs := validateSchedulingGates(tt.schedulingGates, fieldPath) - if diff := cmp.Diff(tt.wantFieldErrors, errs); diff != "" { + if diff := cmp.Diff(tt.wantFieldErrors, errs, cmpopts.IgnoreFields(field.Error{}, "Detail", "Origin")); diff != "" { t.Errorf("unexpected field errors (-want, +got):\n%s", diff) } }) 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 9bc393cf586..feb3d259b8a 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go @@ -373,7 +373,7 @@ func IsValidPortName(port string) []string { func IsValidIP(fldPath *field.Path, value string) field.ErrorList { var allErrors field.ErrorList if netutils.ParseIPSloppy(value) == nil { - allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IP address, (e.g. 10.9.8.7 or 2001:db8::ffff)")) + allErrors = append(allErrors, field.Invalid(fldPath, value, "must be a valid IP address, (e.g. 10.9.8.7 or 2001:db8::ffff)").WithOrigin("format=ip-sloppy")) } return allErrors }