diff --git a/pkg/api/errors/errors_test.go b/pkg/api/errors/errors_test.go index 3eaee41f7d4..b950e329ec4 100644 --- a/pkg/api/errors/errors_test.go +++ b/pkg/api/errors/errors_test.go @@ -125,7 +125,7 @@ func TestNewInvalid(t *testing.T) { }, }, { - fielderrors.NewFieldNotSupported("field[0].name", "bar"), + fielderrors.NewFieldValueNotSupported("field[0].name", "bar", nil), &api.StatusDetails{ Kind: "kind", Name: "name", diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index a32dee4bd33..a736416ddef 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -613,7 +613,7 @@ func validatePorts(ports []api.ContainerPort) errs.ValidationErrorList { if len(port.Protocol) == 0 { pErrs = append(pErrs, errs.NewFieldRequired("protocol")) } else if !supportedPortProtocols.Has(string(port.Protocol)) { - pErrs = append(pErrs, errs.NewFieldNotSupported("protocol", port.Protocol)) + pErrs = append(pErrs, errs.NewFieldValueNotSupported("protocol", port.Protocol, supportedPortProtocols.List())) } allErrs = append(allErrs, pErrs.PrefixIndex(i)...) } @@ -672,7 +672,7 @@ func validateObjectFieldSelector(fs *api.ObjectFieldSelector) errs.ValidationErr if err != nil { allErrs = append(allErrs, errs.NewFieldInvalid("fieldPath", fs.FieldPath, "error converting fieldPath")) } else if !validFieldPathExpressions.Has(internalFieldPath) { - allErrs = append(allErrs, errs.NewFieldNotSupported("fieldPath", internalFieldPath)) + allErrs = append(allErrs, errs.NewFieldValueNotSupported("fieldPath", internalFieldPath, validFieldPathExpressions.List())) } } @@ -816,7 +816,8 @@ func validatePullPolicy(ctr *api.Container) errs.ValidationErrorList { case "": allErrors = append(allErrors, errs.NewFieldRequired("")) default: - allErrors = append(allErrors, errs.NewFieldNotSupported("", ctr.ImagePullPolicy)) + validValues := []string{string(api.PullAlways), string(api.PullIfNotPresent), string(api.PullNever)} + allErrors = append(allErrors, errs.NewFieldValueNotSupported("", ctr.ImagePullPolicy, validValues)) } return allErrors @@ -871,7 +872,8 @@ func validateRestartPolicy(restartPolicy *api.RestartPolicy) errs.ValidationErro case "": allErrors = append(allErrors, errs.NewFieldRequired("")) default: - allErrors = append(allErrors, errs.NewFieldNotSupported("", restartPolicy)) + validValues := []string{string(api.RestartPolicyAlways), string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)} + allErrors = append(allErrors, errs.NewFieldValueNotSupported("", *restartPolicy, validValues)) } return allErrors @@ -885,7 +887,8 @@ func validateDNSPolicy(dnsPolicy *api.DNSPolicy) errs.ValidationErrorList { case "": allErrors = append(allErrors, errs.NewFieldRequired("")) default: - allErrors = append(allErrors, errs.NewFieldNotSupported("", dnsPolicy)) + validValues := []string{string(api.DNSClusterFirst), string(api.DNSDefault)} + allErrors = append(allErrors, errs.NewFieldValueNotSupported("", dnsPolicy, validValues)) } return allErrors } @@ -1043,7 +1046,7 @@ func ValidateService(service *api.Service) errs.ValidationErrorList { if service.Spec.SessionAffinity == "" { allErrs = append(allErrs, errs.NewFieldRequired("spec.sessionAffinity")) } else if !supportedSessionAffinityType.Has(string(service.Spec.SessionAffinity)) { - allErrs = append(allErrs, errs.NewFieldNotSupported("spec.sessionAffinity", service.Spec.SessionAffinity)) + allErrs = append(allErrs, errs.NewFieldValueNotSupported("spec.sessionAffinity", service.Spec.SessionAffinity, supportedSessionAffinityType.List())) } if api.IsServiceIPSet(service) { @@ -1063,7 +1066,7 @@ func ValidateService(service *api.Service) errs.ValidationErrorList { if service.Spec.Type == "" { allErrs = append(allErrs, errs.NewFieldRequired("spec.type")) } else if !supportedServiceType.Has(string(service.Spec.Type)) { - allErrs = append(allErrs, errs.NewFieldNotSupported("spec.type", service.Spec.Type)) + allErrs = append(allErrs, errs.NewFieldValueNotSupported("spec.type", service.Spec.Type, supportedServiceType.List())) } if service.Spec.Type == api.ServiceTypeLoadBalancer { @@ -1124,7 +1127,7 @@ func validateServicePort(sp *api.ServicePort, requireName bool, allNames *util.S if len(sp.Protocol) == 0 { allErrs = append(allErrs, errs.NewFieldRequired("protocol")) } else if !supportedPortProtocols.Has(string(sp.Protocol)) { - allErrs = append(allErrs, errs.NewFieldNotSupported("protocol", sp.Protocol)) + allErrs = append(allErrs, errs.NewFieldValueNotSupported("protocol", sp.Protocol, supportedPortProtocols.List())) } if sp.TargetPort != util.NewIntOrStringFromInt(0) && sp.TargetPort != util.NewIntOrStringFromString("") { @@ -1188,7 +1191,7 @@ func ValidateReplicationControllerSpec(spec *api.ReplicationControllerSpec) errs allErrs = append(allErrs, ValidatePodTemplateSpec(spec.Template, spec.Replicas).Prefix("template")...) // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec(). if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways { - allErrs = append(allErrs, errs.NewFieldNotSupported("template.restartPolicy", spec.Template.Spec.RestartPolicy)) + allErrs = append(allErrs, errs.NewFieldValueNotSupported("template.spec.restartPolicy", spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) } } return allErrs @@ -1660,7 +1663,7 @@ func validateEndpointPort(port *api.EndpointPort, requireName bool) errs.Validat if len(port.Protocol) == 0 { allErrs = append(allErrs, errs.NewFieldRequired("protocol")) } else if !supportedPortProtocols.Has(string(port.Protocol)) { - allErrs = append(allErrs, errs.NewFieldNotSupported("protocol", port.Protocol)) + allErrs = append(allErrs, errs.NewFieldValueNotSupported("protocol", port.Protocol, supportedPortProtocols.List())) } return allErrs } diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 9ba9a0f14f1..f7fe1ad87fe 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -521,8 +521,8 @@ func TestValidatePorts(t *testing.T) { "zero container port": {[]api.ContainerPort{{ContainerPort: 0, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].containerPort", portRangeErrorMsg}, "invalid container port": {[]api.ContainerPort{{ContainerPort: 65536, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].containerPort", portRangeErrorMsg}, "invalid host port": {[]api.ContainerPort{{ContainerPort: 80, HostPort: 65536, Protocol: "TCP"}}, errors.ValidationErrorTypeInvalid, "[0].hostPort", portRangeErrorMsg}, - "invalid protocol case": {[]api.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}}, errors.ValidationErrorTypeNotSupported, "[0].protocol", ""}, - "invalid protocol": {[]api.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}}, errors.ValidationErrorTypeNotSupported, "[0].protocol", ""}, + "invalid protocol case": {[]api.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}}, errors.ValidationErrorTypeNotSupported, "[0].protocol", "supported values: TCP, UDP"}, + "invalid protocol": {[]api.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}}, errors.ValidationErrorTypeNotSupported, "[0].protocol", "supported values: TCP, UDP"}, "protocol required": {[]api.ContainerPort{{Name: "abc", ContainerPort: 80}}, errors.ValidationErrorTypeRequired, "[0].protocol", ""}, } for k, v := range errorCases { @@ -642,7 +642,7 @@ func TestValidateEnv(t *testing.T) { }, }, }}, - expectedError: "[0].valueFrom.fieldRef.fieldPath: unsupported value 'status.phase'", + expectedError: "[0].valueFrom.fieldRef.fieldPath: unsupported value 'status.phase': supported values: metadata.name, metadata.namespace", }, } for _, tc := range errorCases { diff --git a/pkg/util/fielderrors/fielderrors.go b/pkg/util/fielderrors/fielderrors.go index 525f4123f60..e126f8c033b 100644 --- a/pkg/util/fielderrors/fielderrors.go +++ b/pkg/util/fielderrors/fielderrors.go @@ -113,9 +113,13 @@ func NewFieldInvalid(field string, value interface{}, detail string) *Validation return &ValidationError{ValidationErrorTypeInvalid, field, value, detail} } -// NewFieldNotSupported returns a *ValidationError indicating "unsupported value" -func NewFieldNotSupported(field string, value interface{}) *ValidationError { - return &ValidationError{ValidationErrorTypeNotSupported, field, value, ""} +// NewFieldValueNotSupported returns a *ValidationError indicating "unsupported value" +func NewFieldValueNotSupported(field string, value interface{}, validValues []string) *ValidationError { + detail := "" + if validValues != nil && len(validValues) > 0 { + detail = "supported values: " + strings.Join(validValues, ", ") + } + return &ValidationError{ValidationErrorTypeNotSupported, field, value, detail} } // NewFieldForbidden returns a *ValidationError indicating "forbidden" diff --git a/pkg/util/fielderrors/fielderrors_test.go b/pkg/util/fielderrors/fielderrors_test.go index 7e9a125dd7e..b77c641c29f 100644 --- a/pkg/util/fielderrors/fielderrors_test.go +++ b/pkg/util/fielderrors/fielderrors_test.go @@ -31,7 +31,7 @@ func TestMakeFuncs(t *testing.T) { ValidationErrorTypeInvalid, }, { - func() *ValidationError { return NewFieldNotSupported("f", "v") }, + func() *ValidationError { return NewFieldValueNotSupported("f", "v", nil) }, ValidationErrorTypeNotSupported, }, {