diff --git a/examples/examples_test.go b/examples/examples_test.go index 336db7dd29298..ed6b7b93d8818 100644 --- a/examples/examples_test.go +++ b/examples/examples_test.go @@ -33,13 +33,13 @@ import ( expvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" "k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/util/yaml" schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api" schedulerapilatest "k8s.io/kubernetes/plugin/pkg/scheduler/api/latest" ) -func validateObject(obj runtime.Object) (errors utilvalidation.ErrorList) { +func validateObject(obj runtime.Object) (errors field.ErrorList) { switch t := obj.(type) { case *api.ReplicationController: if t.Namespace == "" { @@ -123,7 +123,7 @@ func validateObject(obj runtime.Object) (errors utilvalidation.ErrorList) { } errors = expvalidation.ValidateDaemonSet(t) default: - return utilvalidation.ErrorList{utilvalidation.NewInternalError(utilvalidation.NewFieldPath(""), fmt.Errorf("no validation defined for %#v", obj))} + return field.ErrorList{field.InternalError(field.NewPath(""), fmt.Errorf("no validation defined for %#v", obj))} } return errors } diff --git a/pkg/api/errors/errors.go b/pkg/api/errors/errors.go index 4eb4a72a1668e..43bfdd88a561d 100644 --- a/pkg/api/errors/errors.go +++ b/pkg/api/errors/errors.go @@ -24,7 +24,7 @@ import ( "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // HTTP Status codes not in the golang http package. @@ -168,7 +168,7 @@ func NewGone(message string) error { } // NewInvalid returns an error indicating the item is invalid and cannot be processed. -func NewInvalid(kind, name string, errs validation.ErrorList) error { +func NewInvalid(kind, name string, errs field.ErrorList) error { causes := make([]unversioned.StatusCause, 0, len(errs)) for i := range errs { err := errs[i] diff --git a/pkg/api/errors/errors_test.go b/pkg/api/errors/errors_test.go index 5c428b3b73ab2..dc6b138b87a6e 100644 --- a/pkg/api/errors/errors_test.go +++ b/pkg/api/errors/errors_test.go @@ -24,7 +24,7 @@ import ( "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) func TestErrorNew(t *testing.T) { @@ -88,11 +88,11 @@ func TestErrorNew(t *testing.T) { func TestNewInvalid(t *testing.T) { testCases := []struct { - Err *validation.Error + Err *field.Error Details *unversioned.StatusDetails }{ { - validation.NewDuplicateError(validation.NewFieldPath("field[0].name"), "bar"), + field.Duplicate(field.NewPath("field[0].name"), "bar"), &unversioned.StatusDetails{ Kind: "kind", Name: "name", @@ -103,7 +103,7 @@ func TestNewInvalid(t *testing.T) { }, }, { - validation.NewInvalidError(validation.NewFieldPath("field[0].name"), "bar", "detail"), + field.Invalid(field.NewPath("field[0].name"), "bar", "detail"), &unversioned.StatusDetails{ Kind: "kind", Name: "name", @@ -114,7 +114,7 @@ func TestNewInvalid(t *testing.T) { }, }, { - validation.NewNotFoundError(validation.NewFieldPath("field[0].name"), "bar"), + field.NotFound(field.NewPath("field[0].name"), "bar"), &unversioned.StatusDetails{ Kind: "kind", Name: "name", @@ -125,7 +125,7 @@ func TestNewInvalid(t *testing.T) { }, }, { - validation.NewNotSupportedError(validation.NewFieldPath("field[0].name"), "bar", nil), + field.NotSupported(field.NewPath("field[0].name"), "bar", nil), &unversioned.StatusDetails{ Kind: "kind", Name: "name", @@ -136,7 +136,7 @@ func TestNewInvalid(t *testing.T) { }, }, { - validation.NewRequiredError(validation.NewFieldPath("field[0].name")), + field.Required(field.NewPath("field[0].name")), &unversioned.StatusDetails{ Kind: "kind", Name: "name", @@ -150,7 +150,7 @@ func TestNewInvalid(t *testing.T) { for i, testCase := range testCases { vErr, expected := testCase.Err, testCase.Details expected.Causes[0].Message = vErr.ErrorBody() - err := NewInvalid("kind", "name", validation.ErrorList{vErr}) + err := NewInvalid("kind", "name", field.ErrorList{vErr}) status := err.(*StatusError).ErrStatus if status.Code != 422 || status.Reason != unversioned.StatusReasonInvalid { t.Errorf("%d: unexpected status: %#v", i, status) diff --git a/pkg/api/rest/create.go b/pkg/api/rest/create.go index 321a343711902..d20c122056d53 100644 --- a/pkg/api/rest/create.go +++ b/pkg/api/rest/create.go @@ -21,7 +21,7 @@ import ( "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // RESTCreateStrategy defines the minimum validation, accepted input, and @@ -42,7 +42,7 @@ type RESTCreateStrategy interface { PrepareForCreate(obj runtime.Object) // Validate is invoked after default fields in the object have been filled in before // the object is persisted. This method should not mutate the object. - Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList + Validate(ctx api.Context, obj runtime.Object) field.ErrorList // Canonicalize is invoked after validation has succeeded but before the // object has been persisted. This method may mutate the object. Canonicalize(obj runtime.Object) @@ -77,7 +77,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx api.Context, obj runtime.Obje // Custom validation (including name validation) passed // Now run common validation on object meta // Do this *after* custom validation so that specific error messages are shown whenever possible - if errs := validation.ValidateObjectMeta(objectMeta, strategy.NamespaceScoped(), validation.ValidatePathSegmentName, utilvalidation.NewFieldPath("metadata")); len(errs) > 0 { + if errs := validation.ValidateObjectMeta(objectMeta, strategy.NamespaceScoped(), validation.ValidatePathSegmentName, field.NewPath("metadata")); len(errs) > 0 { return errors.NewInvalid(kind, objectMeta.Name, errs) } diff --git a/pkg/api/rest/update.go b/pkg/api/rest/update.go index fb168e688d0c6..8f08d49b23cdb 100644 --- a/pkg/api/rest/update.go +++ b/pkg/api/rest/update.go @@ -17,11 +17,13 @@ limitations under the License. package rest import ( + "fmt" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // RESTUpdateStrategy defines the minimum validation, accepted input, and @@ -42,7 +44,7 @@ type RESTUpdateStrategy interface { // ValidateUpdate is invoked after default fields in the object have been // filled in before the object is persisted. This method should not mutate // the object. - ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList + ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList // Canonicalize is invoked after validation has succeeded but before the // object has been persisted. This method may mutate the object. Canonicalize(obj runtime.Object) @@ -53,19 +55,19 @@ type RESTUpdateStrategy interface { } // TODO: add other common fields that require global validation. -func validateCommonFields(obj, old runtime.Object) utilvalidation.ErrorList { - allErrs := utilvalidation.ErrorList{} +func validateCommonFields(obj, old runtime.Object) (field.ErrorList, error) { + allErrs := field.ErrorList{} objectMeta, err := api.ObjectMetaFor(obj) if err != nil { - return append(allErrs, utilvalidation.NewInternalError(utilvalidation.NewFieldPath("metadata"), err)) + return nil, fmt.Errorf("failed to get new object metadata: %v", err) } oldObjectMeta, err := api.ObjectMetaFor(old) if err != nil { - return append(allErrs, utilvalidation.NewInternalError(utilvalidation.NewFieldPath("metadata"), err)) + return nil, fmt.Errorf("failed to get old object metadata: %v", err) } - allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(objectMeta, oldObjectMeta, utilvalidation.NewFieldPath("metadata"))...) + allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(objectMeta, oldObjectMeta, field.NewPath("metadata"))...) - return allErrs + return allErrs, nil } // BeforeUpdate ensures that common operations for all resources are performed on update. It only returns @@ -87,7 +89,10 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx api.Context, obj, old runtime strategy.PrepareForUpdate(obj, old) // Ensure some common fields, like UID, are validated for all resources. - errs := validateCommonFields(obj, old) + errs, err := validateCommonFields(obj, old) + if err != nil { + return errors.NewInternalError(err) + } errs = append(errs, strategy.ValidateUpdate(ctx, obj, old)...) if len(errs) > 0 { diff --git a/pkg/api/testing/compat/compatibility_tester.go b/pkg/api/testing/compat/compatibility_tester.go index acf96dde669c3..7044fab1643a7 100644 --- a/pkg/api/testing/compat/compatibility_tester.go +++ b/pkg/api/testing/compat/compatibility_tester.go @@ -27,10 +27,9 @@ import ( "testing" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util/validation" - "k8s.io/kubernetes/pkg/kubectl" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/util/validation/field" ) // Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go @@ -42,7 +41,7 @@ func TestCompatibility( t *testing.T, version string, input []byte, - validator func(obj runtime.Object) validation.ErrorList, + validator func(obj runtime.Object) field.ErrorList, expectedKeys map[string]string, absentKeys []string, ) { diff --git a/pkg/api/v1/backward_compatibility_test.go b/pkg/api/v1/backward_compatibility_test.go index d919ed2b9917c..6700f4f2ef42b 100644 --- a/pkg/api/v1/backward_compatibility_test.go +++ b/pkg/api/v1/backward_compatibility_test.go @@ -23,7 +23,7 @@ import ( "k8s.io/kubernetes/pkg/api/testing/compat" "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) func TestCompatibility_v1_PodSecurityContext(t *testing.T) { @@ -217,8 +217,8 @@ func TestCompatibility_v1_PodSecurityContext(t *testing.T) { }, } - validator := func(obj runtime.Object) utilvalidation.ErrorList { - return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec), utilvalidation.NewFieldPath("spec")) + validator := func(obj runtime.Object) field.ErrorList { + return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec), field.NewPath("spec")) } for _, tc := range cases { diff --git a/pkg/api/validation/events.go b/pkg/api/validation/events.go index 6eba8904726e1..05409714a132f 100644 --- a/pkg/api/validation/events.go +++ b/pkg/api/validation/events.go @@ -19,22 +19,23 @@ package validation import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // ValidateEvent makes sure that the event makes sense. -func ValidateEvent(event *api.Event) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateEvent(event *api.Event) field.ErrorList { + allErrs := field.ErrorList{} // There is no namespace required for node. if event.InvolvedObject.Kind == "Node" && event.Namespace != "" { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "namespace is not required for node")) + allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "not required for node")) } if event.InvolvedObject.Kind != "Node" && event.Namespace != event.InvolvedObject.Namespace { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match involvedObject")) + allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match involvedObject")) } if !validation.IsDNS1123Subdomain(event.Namespace) { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("namespace"), event.Namespace, "")) + allErrs = append(allErrs, field.Invalid(field.NewPath("namespace"), event.Namespace, "")) } return allErrs } diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index a16a2c8f2f5b7..1d6905523ffa5 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -33,6 +33,7 @@ import ( "k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" "github.com/golang/glog" ) @@ -61,38 +62,38 @@ var PortNameErrorMsg string = fmt.Sprintf(`must be an IANA_SVC_NAME (at most 15 const totalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB -func ValidateLabelName(labelName string, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateLabelName(labelName string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if !validation.IsQualifiedName(labelName) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, labelName, qualifiedNameErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath, labelName, qualifiedNameErrorMsg)) } return allErrs } // ValidateLabels validates that a set of labels are correctly defined. -func ValidateLabels(labels map[string]string, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateLabels(labels map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} for k, v := range labels { allErrs = append(allErrs, ValidateLabelName(k, fldPath)...) if !validation.IsValidLabelValue(v) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, v, labelValueErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath, v, labelValueErrorMsg)) } } return allErrs } // ValidateAnnotations validates that a set of annotations are correctly defined. -func ValidateAnnotations(annotations map[string]string, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} var totalSize int64 for k, v := range annotations { if !validation.IsQualifiedName(strings.ToLower(k)) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, k, qualifiedNameErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath, k, qualifiedNameErrorMsg)) } totalSize += (int64)(len(k)) + (int64)(len(v)) } if totalSize > (int64)(totalAnnotationSizeLimitB) { - allErrs = append(allErrs, validation.NewTooLongError(fldPath, "", totalAnnotationSizeLimitB)) + allErrs = append(allErrs, field.TooLong(fldPath, "", totalAnnotationSizeLimitB)) } return allErrs } @@ -217,27 +218,27 @@ func NameIsDNS952Label(name string, prefix bool) (bool, string) { } // Validates that given value is not negative. -func ValidatePositiveField(value int64, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePositiveField(value int64, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if value < 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, value, isNegativeErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath, value, isNegativeErrorMsg)) } return allErrs } // Validates that a Quantity is not negative -func ValidatePositiveQuantity(value resource.Quantity, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePositiveQuantity(value resource.Quantity, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if value.Cmp(resource.Quantity{}) < 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, value.String(), isNegativeErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath, value.String(), isNegativeErrorMsg)) } return allErrs } -func ValidateImmutableField(newVal, oldVal interface{}, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateImmutableField(newVal, oldVal interface{}, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if !api.Semantic.DeepEqual(oldVal, newVal) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, newVal, fieldImmutableErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath, newVal, fieldImmutableErrorMsg)) } return allErrs } @@ -246,36 +247,36 @@ func ValidateImmutableField(newVal, oldVal interface{}, fldPath *validation.Fiel // been performed. // It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before. // TODO: Remove calls to this method scattered in validations of specific resources, e.g., ValidatePodUpdate. -func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(meta.GenerateName) != 0 { if ok, qualifier := nameFn(meta.GenerateName, true); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("generateName"), meta.GenerateName, qualifier)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("generateName"), meta.GenerateName, qualifier)) } } // If the generated name validates, but the calculated value does not, it's a problem with generation, and we // report it here. This may confuse users, but indicates a programming bug and still must be validated. // If there are multiple fields out of which one is required then add a or as a separator if len(meta.Name) == 0 { - requiredErr := validation.NewRequiredError(fldPath.Child("name")) + requiredErr := field.Required(fldPath.Child("name")) requiredErr.Detail = "name or generateName is required" allErrs = append(allErrs, requiredErr) } else { if ok, qualifier := nameFn(meta.Name, false); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("name"), meta.Name, qualifier)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), meta.Name, qualifier)) } } allErrs = append(allErrs, ValidatePositiveField(meta.Generation, fldPath.Child("generation"))...) if requiresNamespace { if len(meta.Namespace) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("namespace"))) + allErrs = append(allErrs, field.Required(fldPath.Child("namespace"))) } else if ok, _ := ValidateNamespaceName(meta.Namespace, false); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("namespace"), meta.Namespace, DNS1123LabelErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), meta.Namespace, DNS1123LabelErrorMsg)) } } else { if len(meta.Namespace) != 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("namespace"), meta.Namespace, "namespace is not allowed on this type")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), meta.Namespace, "namespace is not allowed on this type")) } } allErrs = append(allErrs, ValidateLabels(meta.Labels, fldPath.Child("labels"))...) @@ -285,11 +286,11 @@ func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn Val } // ValidateObjectMetaUpdate validates an object's metadata when updated -func ValidateObjectMetaUpdate(newMeta, oldMeta *api.ObjectMeta, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateObjectMetaUpdate(newMeta, oldMeta *api.ObjectMeta, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if !RepairMalformedUpdates && newMeta.UID != oldMeta.UID { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("uid"), newMeta.UID, "field is immutable")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), newMeta.UID, "field is immutable")) } // in the event it is left empty, set it, to allow clients more flexibility // TODO: remove the following code that repairs the update request when we retire the clients that modify the immutable fields. @@ -315,12 +316,12 @@ func ValidateObjectMetaUpdate(newMeta, oldMeta *api.ObjectMeta, fldPath *validat // TODO: needs to check if newMeta==nil && oldMeta !=nil after the repair logic is removed. if newMeta.DeletionGracePeriodSeconds != nil && oldMeta.DeletionGracePeriodSeconds != nil && *newMeta.DeletionGracePeriodSeconds != *oldMeta.DeletionGracePeriodSeconds { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("deletionGracePeriodSeconds"), newMeta.DeletionGracePeriodSeconds, "field is immutable; may only be changed via deletion")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("deletionGracePeriodSeconds"), newMeta.DeletionGracePeriodSeconds, "field is immutable; may only be changed via deletion")) } // Reject updates that don't specify a resource version if newMeta.ResourceVersion == "" { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("resourceVersion"), newMeta.ResourceVersion, "resourceVersion must be specified for an update")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceVersion"), newMeta.ResourceVersion, "resourceVersion must be specified for an update")) } allErrs = append(allErrs, ValidateImmutableField(newMeta.Name, oldMeta.Name, fldPath.Child("name"))...) @@ -334,19 +335,19 @@ func ValidateObjectMetaUpdate(newMeta, oldMeta *api.ObjectMeta, fldPath *validat return allErrs } -func validateVolumes(volumes []api.Volume, fldPath *validation.FieldPath) (sets.String, validation.ErrorList) { - allErrs := validation.ErrorList{} +func validateVolumes(volumes []api.Volume, fldPath *field.Path) (sets.String, field.ErrorList) { + allErrs := field.ErrorList{} allNames := sets.String{} for i, vol := range volumes { idxPath := fldPath.Index(i) el := validateVolumeSource(&vol.VolumeSource, idxPath) if len(vol.Name) == 0 { - el = append(el, validation.NewRequiredError(idxPath.Child("name"))) + el = append(el, field.Required(idxPath.Child("name"))) } else if !validation.IsDNS1123Label(vol.Name) { - el = append(el, validation.NewInvalidError(idxPath.Child("name"), vol.Name, DNS1123LabelErrorMsg)) + el = append(el, field.Invalid(idxPath.Child("name"), vol.Name, DNS1123LabelErrorMsg)) } else if allNames.Has(vol.Name) { - el = append(el, validation.NewDuplicateError(idxPath.Child("name"), vol.Name)) + el = append(el, field.Duplicate(idxPath.Child("name"), vol.Name)) } if len(el) == 0 { allNames.Insert(vol.Name) @@ -358,9 +359,9 @@ func validateVolumes(volumes []api.Volume, fldPath *validation.FieldPath) (sets. return allNames, allErrs } -func validateVolumeSource(source *api.VolumeSource, fldPath *validation.FieldPath) validation.ErrorList { +func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.ErrorList { numVolumes := 0 - allErrs := validation.ErrorList{} + allErrs := field.ErrorList{} if source.HostPath != nil { numVolumes++ allErrs = append(allErrs, validateHostPathVolumeSource(source.HostPath, fldPath.Child("hostPath"))...) @@ -426,24 +427,24 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *validation.FieldPat allErrs = append(allErrs, validateFCVolumeSource(source.FC, fldPath.Child("fc"))...) } if numVolumes != 1 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, source, "exactly 1 volume type is required")) + allErrs = append(allErrs, field.Invalid(fldPath, source, "exactly 1 volume type is required")) } return allErrs } -func validateHostPathVolumeSource(hostPath *api.HostPathVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateHostPathVolumeSource(hostPath *api.HostPathVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if hostPath.Path == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("path"))) + allErrs = append(allErrs, field.Required(fldPath.Child("path"))) } return allErrs } -func validateGitRepoVolumeSource(gitRepo *api.GitRepoVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateGitRepoVolumeSource(gitRepo *api.GitRepoVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(gitRepo.Repository) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("repository"))) + allErrs = append(allErrs, field.Required(fldPath.Child("repository"))) } pathErrs := validateVolumeSourcePath(gitRepo.Directory, fldPath.Child("directory")) @@ -451,129 +452,129 @@ func validateGitRepoVolumeSource(gitRepo *api.GitRepoVolumeSource, fldPath *vali return allErrs } -func validateISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if iscsi.TargetPortal == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("targetPortal"))) + allErrs = append(allErrs, field.Required(fldPath.Child("targetPortal"))) } if iscsi.IQN == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("iqn"))) + allErrs = append(allErrs, field.Required(fldPath.Child("iqn"))) } if iscsi.FSType == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("fsType"))) + allErrs = append(allErrs, field.Required(fldPath.Child("fsType"))) } if iscsi.Lun < 0 || iscsi.Lun > 255 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("lun"), iscsi.Lun, "")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, "")) } return allErrs } -func validateFCVolumeSource(fc *api.FCVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateFCVolumeSource(fc *api.FCVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(fc.TargetWWNs) < 1 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("targetWWNs"))) + allErrs = append(allErrs, field.Required(fldPath.Child("targetWWNs"))) } if fc.FSType == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("fsType"))) + allErrs = append(allErrs, field.Required(fldPath.Child("fsType"))) } if fc.Lun == nil { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("lun"))) + allErrs = append(allErrs, field.Required(fldPath.Child("lun"))) } else { if *fc.Lun < 0 || *fc.Lun > 255 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("lun"), fc.Lun, "")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), fc.Lun, "")) } } return allErrs } -func validateGCEPersistentDiskVolumeSource(pd *api.GCEPersistentDiskVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateGCEPersistentDiskVolumeSource(pd *api.GCEPersistentDiskVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if pd.PDName == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("pdName"))) + allErrs = append(allErrs, field.Required(fldPath.Child("pdName"))) } if pd.FSType == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("fsType"))) + allErrs = append(allErrs, field.Required(fldPath.Child("fsType"))) } if pd.Partition < 0 || pd.Partition > 255 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("partition"), pd.Partition, pdPartitionErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("partition"), pd.Partition, pdPartitionErrorMsg)) } return allErrs } -func validateAWSElasticBlockStoreVolumeSource(PD *api.AWSElasticBlockStoreVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateAWSElasticBlockStoreVolumeSource(PD *api.AWSElasticBlockStoreVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if PD.VolumeID == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("volumeID"))) + allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"))) } if PD.FSType == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("fsType"))) + allErrs = append(allErrs, field.Required(fldPath.Child("fsType"))) } if PD.Partition < 0 || PD.Partition > 255 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("partition"), PD.Partition, pdPartitionErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("partition"), PD.Partition, pdPartitionErrorMsg)) } return allErrs } -func validateSecretVolumeSource(secretSource *api.SecretVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateSecretVolumeSource(secretSource *api.SecretVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if secretSource.SecretName == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("secretName"))) + allErrs = append(allErrs, field.Required(fldPath.Child("secretName"))) } return allErrs } -func validatePersistentClaimVolumeSource(claim *api.PersistentVolumeClaimVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validatePersistentClaimVolumeSource(claim *api.PersistentVolumeClaimVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if claim.ClaimName == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("claimName"))) + allErrs = append(allErrs, field.Required(fldPath.Child("claimName"))) } return allErrs } -func validateNFSVolumeSource(nfs *api.NFSVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateNFSVolumeSource(nfs *api.NFSVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if nfs.Server == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("server"))) + allErrs = append(allErrs, field.Required(fldPath.Child("server"))) } if nfs.Path == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("path"))) + allErrs = append(allErrs, field.Required(fldPath.Child("path"))) } if !path.IsAbs(nfs.Path) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("path"), nfs.Path, "must be an absolute path")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("path"), nfs.Path, "must be an absolute path")) } return allErrs } -func validateGlusterfs(glusterfs *api.GlusterfsVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateGlusterfs(glusterfs *api.GlusterfsVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if glusterfs.EndpointsName == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("endpoints"))) + allErrs = append(allErrs, field.Required(fldPath.Child("endpoints"))) } if glusterfs.Path == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("path"))) + allErrs = append(allErrs, field.Required(fldPath.Child("path"))) } return allErrs } -func validateFlockerVolumeSource(flocker *api.FlockerVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateFlockerVolumeSource(flocker *api.FlockerVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if flocker.DatasetName == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("datasetName"))) + allErrs = append(allErrs, field.Required(fldPath.Child("datasetName"))) } if strings.Contains(flocker.DatasetName, "/") { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("datasetName"), flocker.DatasetName, "must not contain '/'")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("datasetName"), flocker.DatasetName, "must not contain '/'")) } return allErrs } var validDownwardAPIFieldPathExpressions = sets.NewString("metadata.name", "metadata.namespace", "metadata.labels", "metadata.annotations") -func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} for _, downwardAPIVolumeFile := range downwardAPIVolume.Items { if len(downwardAPIVolumeFile.Path) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("path"))) + allErrs = append(allErrs, field.Required(fldPath.Child("path"))) } allErrs = append(allErrs, validateVolumeSourcePath(downwardAPIVolumeFile.Path, fldPath.Child("path"))...) allErrs = append(allErrs, validateObjectFieldSelector(&downwardAPIVolumeFile.FieldRef, &validDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...) @@ -585,54 +586,54 @@ func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSou // 1. is not abs path // 2. does not contain '..' // 3. does not start with '..' -func validateVolumeSourcePath(targetPath string, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateVolumeSourcePath(targetPath string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if path.IsAbs(targetPath) { - allErrs = append(allErrs, validation.NewForbiddenError(fldPath, "must not be an absolute path")) + allErrs = append(allErrs, field.Forbidden(fldPath, "must not be an absolute path")) } // TODO assume OS of api server & nodes are the same for now items := strings.Split(targetPath, string(os.PathSeparator)) for _, item := range items { if item == ".." { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, targetPath, "must not contain \"..\"")) + allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not contain \"..\"")) } } if strings.HasPrefix(items[0], "..") && len(items[0]) > 2 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, targetPath, "must not start with \"..\"")) + allErrs = append(allErrs, field.Invalid(fldPath, targetPath, "must not start with \"..\"")) } return allErrs } -func validateRBDVolumeSource(rbd *api.RBDVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateRBDVolumeSource(rbd *api.RBDVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(rbd.CephMonitors) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("monitors"))) + allErrs = append(allErrs, field.Required(fldPath.Child("monitors"))) } if rbd.RBDImage == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("image"))) + allErrs = append(allErrs, field.Required(fldPath.Child("image"))) } if rbd.FSType == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("fsType"))) + allErrs = append(allErrs, field.Required(fldPath.Child("fsType"))) } return allErrs } -func validateCinderVolumeSource(cd *api.CinderVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateCinderVolumeSource(cd *api.CinderVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if cd.VolumeID == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("volumeID"))) + allErrs = append(allErrs, field.Required(fldPath.Child("volumeID"))) } if cd.FSType == "" || (cd.FSType != "ext3" && cd.FSType != "ext4") { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("fsType"))) + allErrs = append(allErrs, field.Required(fldPath.Child("fsType"))) } return allErrs } -func validateCephFSVolumeSource(cephfs *api.CephFSVolumeSource, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateCephFSVolumeSource(cephfs *api.CephFSVolumeSource, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(cephfs.Monitors) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("monitors"))) + allErrs = append(allErrs, field.Required(fldPath.Child("monitors"))) } return allErrs } @@ -643,25 +644,25 @@ func ValidatePersistentVolumeName(name string, prefix bool) (bool, string) { var supportedAccessModes = sets.NewString(string(api.ReadWriteOnce), string(api.ReadOnlyMany), string(api.ReadWriteMany)) -func ValidatePersistentVolume(pv *api.PersistentVolume) validation.ErrorList { - allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName, validation.NewFieldPath("metadata")) +func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList { + allErrs := ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName, field.NewPath("metadata")) - specPath := validation.NewFieldPath("spec") + specPath := field.NewPath("spec") if len(pv.Spec.AccessModes) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(specPath.Child("accessModes"))) + allErrs = append(allErrs, field.Required(specPath.Child("accessModes"))) } for _, mode := range pv.Spec.AccessModes { if !supportedAccessModes.Has(string(mode)) { - allErrs = append(allErrs, validation.NewNotSupportedError(specPath.Child("accessModes"), mode, supportedAccessModes.List())) + allErrs = append(allErrs, field.NotSupported(specPath.Child("accessModes"), mode, supportedAccessModes.List())) } } if len(pv.Spec.Capacity) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(specPath.Child("capacity"))) + allErrs = append(allErrs, field.Required(specPath.Child("capacity"))) } if _, ok := pv.Spec.Capacity[api.ResourceStorage]; !ok || len(pv.Spec.Capacity) > 1 { - allErrs = append(allErrs, validation.NewNotSupportedError(specPath.Child("capacity"), pv.Spec.Capacity, []string{string(api.ResourceStorage)})) + allErrs = append(allErrs, field.NotSupported(specPath.Child("capacity"), pv.Spec.Capacity, []string{string(api.ResourceStorage)})) } capPath := specPath.Child("capacity") for r, qty := range pv.Spec.Capacity { @@ -714,15 +715,15 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) validation.ErrorList { allErrs = append(allErrs, validateFCVolumeSource(pv.Spec.FC, specPath.Child("fc"))...) } if numVolumes != 1 { - allErrs = append(allErrs, validation.NewInvalidError(specPath, pv.Spec.PersistentVolumeSource, "exactly 1 volume type is required")) + allErrs = append(allErrs, field.Invalid(specPath, pv.Spec.PersistentVolumeSource, "exactly 1 volume type is required")) } return allErrs } // ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make. // newPv is updated with fields that cannot be changed. -func ValidatePersistentVolumeUpdate(newPv, oldPv *api.PersistentVolume) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePersistentVolumeUpdate(newPv, oldPv *api.PersistentVolume) field.ErrorList { + allErrs := field.ErrorList{} allErrs = ValidatePersistentVolume(newPv) newPv.Status = oldPv.Status return allErrs @@ -730,50 +731,48 @@ func ValidatePersistentVolumeUpdate(newPv, oldPv *api.PersistentVolume) validati // ValidatePersistentVolumeStatusUpdate tests to see if the status update is legal for an end user to make. // newPv is updated with fields that cannot be changed. -func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *api.PersistentVolume) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newPv.ObjectMeta, &oldPv.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *api.PersistentVolume) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newPv.ObjectMeta, &oldPv.ObjectMeta, field.NewPath("metadata")) if newPv.ResourceVersion == "" { - allErrs = append(allErrs, validation.NewRequiredError(validation.NewFieldPath("resourceVersion"))) + allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"))) } newPv.Spec = oldPv.Spec return allErrs } -func ValidatePersistentVolumeClaim(pvc *api.PersistentVolumeClaim) validation.ErrorList { - allErrs := ValidateObjectMeta(&pvc.ObjectMeta, true, ValidatePersistentVolumeName, validation.NewFieldPath("metadata")) - specPath := validation.NewFieldPath("spec") +func ValidatePersistentVolumeClaim(pvc *api.PersistentVolumeClaim) field.ErrorList { + allErrs := ValidateObjectMeta(&pvc.ObjectMeta, true, ValidatePersistentVolumeName, field.NewPath("metadata")) + specPath := field.NewPath("spec") if len(pvc.Spec.AccessModes) == 0 { - allErrs = append(allErrs, validation.NewInvalidError(specPath.Child("accessModes"), pvc.Spec.AccessModes, "at least 1 accessMode is required")) + allErrs = append(allErrs, field.Invalid(specPath.Child("accessModes"), pvc.Spec.AccessModes, "at least 1 accessMode is required")) } for _, mode := range pvc.Spec.AccessModes { if mode != api.ReadWriteOnce && mode != api.ReadOnlyMany && mode != api.ReadWriteMany { - allErrs = append(allErrs, validation.NewNotSupportedError(specPath.Child("accessModes"), mode, supportedAccessModes.List())) + allErrs = append(allErrs, field.NotSupported(specPath.Child("accessModes"), mode, supportedAccessModes.List())) } } if _, ok := pvc.Spec.Resources.Requests[api.ResourceStorage]; !ok { - allErrs = append(allErrs, validation.NewRequiredError(specPath.Child("resources").Key(string(api.ResourceStorage)))) + allErrs = append(allErrs, field.Required(specPath.Child("resources").Key(string(api.ResourceStorage)))) } return allErrs } -func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) field.ErrorList { + allErrs := field.ErrorList{} allErrs = ValidatePersistentVolumeClaim(newPvc) newPvc.Status = oldPvc.Status return allErrs } -func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata")) if newPvc.ResourceVersion == "" { - allErrs = append(allErrs, validation.NewRequiredError(validation.NewFieldPath("resourceVersion"))) + allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"))) } if len(newPvc.Spec.AccessModes) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(validation.NewFieldPath("Spec", "accessModes"))) + allErrs = append(allErrs, field.Required(field.NewPath("Spec", "accessModes"))) } - capPath := validation.NewFieldPath("status", "capacity") + capPath := field.NewPath("status", "capacity") for r, qty := range newPvc.Status.Capacity { allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...) } @@ -783,47 +782,47 @@ func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *api.PersistentVol var supportedPortProtocols = sets.NewString(string(api.ProtocolTCP), string(api.ProtocolUDP)) -func validateContainerPorts(ports []api.ContainerPort, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateContainerPorts(ports []api.ContainerPort, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allNames := sets.String{} for i, port := range ports { idxPath := fldPath.Index(i) if len(port.Name) > 0 { if !validation.IsValidPortName(port.Name) { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("name"), port.Name, PortNameErrorMsg)) + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), port.Name, PortNameErrorMsg)) } else if allNames.Has(port.Name) { - allErrs = append(allErrs, validation.NewDuplicateError(idxPath.Child("name"), port.Name)) + allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), port.Name)) } else { allNames.Insert(port.Name) } } if port.ContainerPort == 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("containerPort"), port.ContainerPort, PortRangeErrorMsg)) + allErrs = append(allErrs, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, PortRangeErrorMsg)) } else if !validation.IsValidPortNum(port.ContainerPort) { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("containerPort"), port.ContainerPort, PortRangeErrorMsg)) + allErrs = append(allErrs, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, PortRangeErrorMsg)) } if port.HostPort != 0 && !validation.IsValidPortNum(port.HostPort) { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("hostPort"), port.HostPort, PortRangeErrorMsg)) + allErrs = append(allErrs, field.Invalid(idxPath.Child("hostPort"), port.HostPort, PortRangeErrorMsg)) } if len(port.Protocol) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(idxPath.Child("protocol"))) + allErrs = append(allErrs, field.Required(idxPath.Child("protocol"))) } else if !supportedPortProtocols.Has(string(port.Protocol)) { - allErrs = append(allErrs, validation.NewNotSupportedError(idxPath.Child("protocol"), port.Protocol, supportedPortProtocols.List())) + allErrs = append(allErrs, field.NotSupported(idxPath.Child("protocol"), port.Protocol, supportedPortProtocols.List())) } } return allErrs } -func validateEnv(vars []api.EnvVar, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateEnv(vars []api.EnvVar, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} for i, ev := range vars { idxPath := fldPath.Index(i) if len(ev.Name) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(idxPath.Child("name"))) + allErrs = append(allErrs, field.Required(idxPath.Child("name"))) } else if !validation.IsCIdentifier(ev.Name) { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("name"), ev.Name, cIdentifierErrorMsg)) + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, cIdentifierErrorMsg)) } allErrs = append(allErrs, validateEnvVarValueFrom(ev, idxPath.Child("valueFrom"))...) } @@ -832,8 +831,8 @@ func validateEnv(vars []api.EnvVar, fldPath *validation.FieldPath) validation.Er var validFieldPathExpressionsEnv = sets.NewString("metadata.name", "metadata.namespace", "status.podIP") -func validateEnvVarValueFrom(ev api.EnvVar, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateEnvVarValueFrom(ev api.EnvVar, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if ev.ValueFrom == nil { return allErrs @@ -848,50 +847,50 @@ func validateEnvVarValueFrom(ev api.EnvVar, fldPath *validation.FieldPath) valid } if ev.Value != "" && numSources != 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, "", "sources cannot be specified when value is not empty")) + allErrs = append(allErrs, field.Invalid(fldPath, "", "sources cannot be specified when value is not empty")) } return allErrs } -func validateObjectFieldSelector(fs *api.ObjectFieldSelector, expressions *sets.String, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateObjectFieldSelector(fs *api.ObjectFieldSelector, expressions *sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if fs.APIVersion == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("apiVersion"))) + allErrs = append(allErrs, field.Required(fldPath.Child("apiVersion"))) } else if fs.FieldPath == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("fieldPath"))) + allErrs = append(allErrs, field.Required(fldPath.Child("fieldPath"))) } else { internalFieldPath, _, err := api.Scheme.ConvertFieldLabel(fs.APIVersion, "Pod", fs.FieldPath, "") if err != nil { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("fieldPath"), fs.FieldPath, "error converting fieldPath")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("fieldPath"), fs.FieldPath, "error converting fieldPath")) } else if !expressions.Has(internalFieldPath) { - allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("fieldPath"), internalFieldPath, expressions.List())) + allErrs = append(allErrs, field.NotSupported(fldPath.Child("fieldPath"), internalFieldPath, expressions.List())) } } return allErrs } -func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} for i, mnt := range mounts { idxPath := fldPath.Index(i) if len(mnt.Name) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(idxPath.Child("name"))) + allErrs = append(allErrs, field.Required(idxPath.Child("name"))) } else if !volumes.Has(mnt.Name) { - allErrs = append(allErrs, validation.NewNotFoundError(idxPath.Child("name"), mnt.Name)) + allErrs = append(allErrs, field.NotFound(idxPath.Child("name"), mnt.Name)) } if len(mnt.MountPath) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(idxPath.Child("mountPath"))) + allErrs = append(allErrs, field.Required(idxPath.Child("mountPath"))) } } return allErrs } -func validateProbe(probe *api.Probe, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateProbe(probe *api.Probe, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if probe == nil { return allErrs @@ -908,8 +907,8 @@ func validateProbe(probe *api.Probe, fldPath *validation.FieldPath) validation.E // AccumulateUniqueHostPorts extracts each HostPort of each Container, // accumulating the results and returning an error if any ports conflict. -func AccumulateUniqueHostPorts(containers []api.Container, accumulator *sets.String, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func AccumulateUniqueHostPorts(containers []api.Container, accumulator *sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} for ci, ctr := range containers { idxPath := fldPath.Index(ci) @@ -922,7 +921,7 @@ func AccumulateUniqueHostPorts(containers []api.Container, accumulator *sets.Str } str := fmt.Sprintf("%d/%s", port, ctr.Ports[pi].Protocol) if accumulator.Has(str) { - allErrs = append(allErrs, validation.NewDuplicateError(idxPath.Child("hostPort"), str)) + allErrs = append(allErrs, field.Duplicate(idxPath.Child("hostPort"), str)) } else { accumulator.Insert(str) } @@ -933,49 +932,49 @@ func AccumulateUniqueHostPorts(containers []api.Container, accumulator *sets.Str // checkHostPortConflicts checks for colliding Port.HostPort values across // a slice of containers. -func checkHostPortConflicts(containers []api.Container, fldPath *validation.FieldPath) validation.ErrorList { +func checkHostPortConflicts(containers []api.Container, fldPath *field.Path) field.ErrorList { allPorts := sets.String{} return AccumulateUniqueHostPorts(containers, &allPorts, fldPath) } -func validateExecAction(exec *api.ExecAction, fldPath *validation.FieldPath) validation.ErrorList { - allErrors := validation.ErrorList{} +func validateExecAction(exec *api.ExecAction, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} if len(exec.Command) == 0 { - allErrors = append(allErrors, validation.NewRequiredError(fldPath.Child("command"))) + allErrors = append(allErrors, field.Required(fldPath.Child("command"))) } return allErrors } -func validateHTTPGetAction(http *api.HTTPGetAction, fldPath *validation.FieldPath) validation.ErrorList { - allErrors := validation.ErrorList{} +func validateHTTPGetAction(http *api.HTTPGetAction, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} if len(http.Path) == 0 { - allErrors = append(allErrors, validation.NewRequiredError(fldPath.Child("path"))) + allErrors = append(allErrors, field.Required(fldPath.Child("path"))) } if http.Port.Type == intstr.Int && !validation.IsValidPortNum(http.Port.IntValue()) { - allErrors = append(allErrors, validation.NewInvalidError(fldPath.Child("port"), http.Port, PortRangeErrorMsg)) + allErrors = append(allErrors, field.Invalid(fldPath.Child("port"), http.Port, PortRangeErrorMsg)) } else if http.Port.Type == intstr.String && !validation.IsValidPortName(http.Port.StrVal) { - allErrors = append(allErrors, validation.NewInvalidError(fldPath.Child("port"), http.Port.StrVal, PortNameErrorMsg)) + allErrors = append(allErrors, field.Invalid(fldPath.Child("port"), http.Port.StrVal, PortNameErrorMsg)) } supportedSchemes := sets.NewString(string(api.URISchemeHTTP), string(api.URISchemeHTTPS)) if !supportedSchemes.Has(string(http.Scheme)) { - allErrors = append(allErrors, validation.NewInvalidError(fldPath.Child("scheme"), http.Scheme, fmt.Sprintf("must be one of %v", supportedSchemes.List()))) + allErrors = append(allErrors, field.Invalid(fldPath.Child("scheme"), http.Scheme, fmt.Sprintf("must be one of %v", supportedSchemes.List()))) } return allErrors } -func validateTCPSocketAction(tcp *api.TCPSocketAction, fldPath *validation.FieldPath) validation.ErrorList { - allErrors := validation.ErrorList{} +func validateTCPSocketAction(tcp *api.TCPSocketAction, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} if tcp.Port.Type == intstr.Int && !validation.IsValidPortNum(tcp.Port.IntValue()) { - allErrors = append(allErrors, validation.NewInvalidError(fldPath.Child("port"), tcp.Port, PortRangeErrorMsg)) + allErrors = append(allErrors, field.Invalid(fldPath.Child("port"), tcp.Port, PortRangeErrorMsg)) } else if tcp.Port.Type == intstr.String && !validation.IsValidPortName(tcp.Port.StrVal) { - allErrors = append(allErrors, validation.NewInvalidError(fldPath.Child("port"), tcp.Port.StrVal, PortNameErrorMsg)) + allErrors = append(allErrors, field.Invalid(fldPath.Child("port"), tcp.Port.StrVal, PortNameErrorMsg)) } return allErrors } -func validateHandler(handler *api.Handler, fldPath *validation.FieldPath) validation.ErrorList { +func validateHandler(handler *api.Handler, fldPath *field.Path) field.ErrorList { numHandlers := 0 - allErrors := validation.ErrorList{} + allErrors := field.ErrorList{} if handler.Exec != nil { numHandlers++ allErrors = append(allErrors, validateExecAction(handler.Exec, fldPath.Child("exec"))...) @@ -989,13 +988,13 @@ func validateHandler(handler *api.Handler, fldPath *validation.FieldPath) valida allErrors = append(allErrors, validateTCPSocketAction(handler.TCPSocket, fldPath.Child("tcpSocket"))...) } if numHandlers != 1 { - allErrors = append(allErrors, validation.NewInvalidError(fldPath, handler, "exactly 1 handler type is required")) + allErrors = append(allErrors, field.Invalid(fldPath, handler, "exactly 1 handler type is required")) } return allErrors } -func validateLifecycle(lifecycle *api.Lifecycle, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateLifecycle(lifecycle *api.Lifecycle, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if lifecycle.PostStart != nil { allErrs = append(allErrs, validateHandler(lifecycle.PostStart, fldPath.Child("postStart"))...) } @@ -1007,42 +1006,42 @@ func validateLifecycle(lifecycle *api.Lifecycle, fldPath *validation.FieldPath) var supportedPullPolicies = sets.NewString(string(api.PullAlways), string(api.PullIfNotPresent), string(api.PullNever)) -func validatePullPolicy(policy api.PullPolicy, fldPath *validation.FieldPath) validation.ErrorList { - allErrors := validation.ErrorList{} +func validatePullPolicy(policy api.PullPolicy, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} switch policy { case api.PullAlways, api.PullIfNotPresent, api.PullNever: break case "": - allErrors = append(allErrors, validation.NewRequiredError(fldPath)) + allErrors = append(allErrors, field.Required(fldPath)) default: - allErrors = append(allErrors, validation.NewNotSupportedError(fldPath, policy, supportedPullPolicies.List())) + allErrors = append(allErrors, field.NotSupported(fldPath, policy, supportedPullPolicies.List())) } return allErrors } -func validateContainers(containers []api.Container, volumes sets.String, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateContainers(containers []api.Container, volumes sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(containers) == 0 { - return append(allErrs, validation.NewRequiredError(fldPath)) + return append(allErrs, field.Required(fldPath)) } allNames := sets.String{} for i, ctr := range containers { idxPath := fldPath.Index(i) if len(ctr.Name) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(idxPath.Child("name"))) + allErrs = append(allErrs, field.Required(idxPath.Child("name"))) } else if !validation.IsDNS1123Label(ctr.Name) { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("name"), ctr.Name, DNS1123LabelErrorMsg)) + allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ctr.Name, DNS1123LabelErrorMsg)) } else if allNames.Has(ctr.Name) { - allErrs = append(allErrs, validation.NewDuplicateError(idxPath.Child("name"), ctr.Name)) + allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name)) } else { allNames.Insert(ctr.Name) } if len(ctr.Image) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(idxPath.Child("image"))) + allErrs = append(allErrs, field.Required(idxPath.Child("image"))) } if ctr.Lifecycle != nil { allErrs = append(allErrs, validateLifecycle(ctr.Lifecycle, idxPath.Child("lifecycle"))...) @@ -1050,7 +1049,7 @@ func validateContainers(containers []api.Container, volumes sets.String, fldPath allErrs = append(allErrs, validateProbe(ctr.LivenessProbe, idxPath.Child("livenessProbe"))...) // Liveness-specific validation if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 { - allErrs = append(allErrs, validation.NewForbiddenError(idxPath.Child("livenessProbe", "successThreshold"), "must be 1")) + allErrs = append(allErrs, field.Forbidden(idxPath.Child("livenessProbe", "successThreshold"), "must be 1")) } allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...) @@ -1067,44 +1066,44 @@ func validateContainers(containers []api.Container, volumes sets.String, fldPath return allErrs } -func validateRestartPolicy(restartPolicy *api.RestartPolicy, fldPath *validation.FieldPath) validation.ErrorList { - allErrors := validation.ErrorList{} +func validateRestartPolicy(restartPolicy *api.RestartPolicy, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} switch *restartPolicy { case api.RestartPolicyAlways, api.RestartPolicyOnFailure, api.RestartPolicyNever: break case "": - allErrors = append(allErrors, validation.NewRequiredError(fldPath)) + allErrors = append(allErrors, field.Required(fldPath)) default: validValues := []string{string(api.RestartPolicyAlways), string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)} - allErrors = append(allErrors, validation.NewNotSupportedError(fldPath, *restartPolicy, validValues)) + allErrors = append(allErrors, field.NotSupported(fldPath, *restartPolicy, validValues)) } return allErrors } -func validateDNSPolicy(dnsPolicy *api.DNSPolicy, fldPath *validation.FieldPath) validation.ErrorList { - allErrors := validation.ErrorList{} +func validateDNSPolicy(dnsPolicy *api.DNSPolicy, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} switch *dnsPolicy { case api.DNSClusterFirst, api.DNSDefault: break case "": - allErrors = append(allErrors, validation.NewRequiredError(fldPath)) + allErrors = append(allErrors, field.Required(fldPath)) default: validValues := []string{string(api.DNSClusterFirst), string(api.DNSDefault)} - allErrors = append(allErrors, validation.NewNotSupportedError(fldPath, dnsPolicy, validValues)) + allErrors = append(allErrors, field.NotSupported(fldPath, dnsPolicy, validValues)) } return allErrors } -func validateHostNetwork(hostNetwork bool, containers []api.Container, fldPath *validation.FieldPath) validation.ErrorList { - allErrors := validation.ErrorList{} +func validateHostNetwork(hostNetwork bool, containers []api.Container, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} if hostNetwork { for i, container := range containers { portsPath := fldPath.Index(i).Child("ports") for i, port := range container.Ports { idxPath := portsPath.Index(i) if port.HostPort != port.ContainerPort { - allErrors = append(allErrors, validation.NewInvalidError(idxPath.Child("containerPort"), port.ContainerPort, "must match hostPort when hostNetwork is set to true")) + allErrors = append(allErrors, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, "must match hostPort when hostNetwork is set to true")) } } } @@ -1116,22 +1115,22 @@ func validateHostNetwork(hostNetwork bool, containers []api.Container, fldPath * // formed. Right now, we only expect name to be set (it's the only field). If // this ever changes and someone decides to set those fields, we'd like to // know. -func validateImagePullSecrets(imagePullSecrets []api.LocalObjectReference, fldPath *validation.FieldPath) validation.ErrorList { - allErrors := validation.ErrorList{} +func validateImagePullSecrets(imagePullSecrets []api.LocalObjectReference, fldPath *field.Path) field.ErrorList { + allErrors := field.ErrorList{} for i, currPullSecret := range imagePullSecrets { idxPath := fldPath.Index(i) strippedRef := api.LocalObjectReference{Name: currPullSecret.Name} if !reflect.DeepEqual(strippedRef, currPullSecret) { - allErrors = append(allErrors, validation.NewInvalidError(idxPath, currPullSecret, "only name may be set")) + allErrors = append(allErrors, field.Invalid(idxPath, currPullSecret, "only name may be set")) } } return allErrors } // ValidatePod tests if required fields in the pod are set. -func ValidatePod(pod *api.Pod) validation.ErrorList { - allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, validation.NewFieldPath("metadata")) - allErrs = append(allErrs, ValidatePodSpec(&pod.Spec, validation.NewFieldPath("spec"))...) +func ValidatePod(pod *api.Pod) field.ErrorList { + allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidatePodSpec(&pod.Spec, field.NewPath("spec"))...) return allErrs } @@ -1139,8 +1138,8 @@ func ValidatePod(pod *api.Pod) validation.ErrorList { // This includes checking formatting and uniqueness. It also canonicalizes the // structure by setting default values and implementing any backwards-compatibility // tricks. -func ValidatePodSpec(spec *api.PodSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePodSpec(spec *api.PodSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allVolumes, vErrs := validateVolumes(spec.Volumes, fldPath.Child("volumes")) allErrs = append(allErrs, vErrs...) @@ -1152,27 +1151,27 @@ func ValidatePodSpec(spec *api.PodSpec, fldPath *validation.FieldPath) validatio allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets, fldPath.Child("imagePullSecrets"))...) if len(spec.ServiceAccountName) > 0 { if ok, msg := ValidateServiceAccountName(spec.ServiceAccountName, false); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("serviceAccountName"), spec.ServiceAccountName, msg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceAccountName"), spec.ServiceAccountName, msg)) } } if len(spec.NodeName) > 0 { if ok, msg := ValidateNodeName(spec.NodeName, false); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("nodeName"), spec.NodeName, msg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("nodeName"), spec.NodeName, msg)) } } if spec.ActiveDeadlineSeconds != nil { if *spec.ActiveDeadlineSeconds <= 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("activeDeadlineSeconds"), spec.ActiveDeadlineSeconds, "must be greater than 0")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("activeDeadlineSeconds"), spec.ActiveDeadlineSeconds, "must be greater than 0")) } } return allErrs } // ValidatePodSecurityContext test that the specified PodSecurityContext has valid data. -func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *api.PodSpec, specPath, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *api.PodSpec, specPath, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if securityContext != nil { allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers, specPath.Child("containers"))...) @@ -1183,15 +1182,13 @@ func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *a // ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields // that cannot be changed. -func ValidatePodUpdate(newPod, oldPod *api.Pod) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePodUpdate(newPod, oldPod *api.Pod) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, field.NewPath("metadata")) - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, validation.NewFieldPath("metadata"))...) - - specPath := validation.NewFieldPath("spec") + specPath := field.NewPath("spec") if len(newPod.Spec.Containers) != len(oldPod.Spec.Containers) { //TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff - allErrs = append(allErrs, validation.NewInvalidError(specPath.Child("containers"), "contents not printed here, please refer to the \"details\"", "may not add or remove containers")) + allErrs = append(allErrs, field.Invalid(specPath.Child("containers"), "contents not printed here, please refer to the \"details\"", "may not add or remove containers")) return allErrs } pod := *newPod @@ -1204,7 +1201,7 @@ func ValidatePodUpdate(newPod, oldPod *api.Pod) validation.ErrorList { pod.Spec.Containers = newContainers if !api.Semantic.DeepEqual(pod.Spec, oldPod.Spec) { //TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff - allErrs = append(allErrs, validation.NewInvalidError(specPath, "contents not printed here, please refer to the \"details\"", "may not update fields other than container.image")) + allErrs = append(allErrs, field.Invalid(specPath, "contents not printed here, please refer to the \"details\"", "may not update fields other than container.image")) } newPod.Status = oldPod.Status @@ -1213,14 +1210,12 @@ func ValidatePodUpdate(newPod, oldPod *api.Pod) validation.ErrorList { // ValidatePodStatusUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields // that cannot be changed. -func ValidatePodStatusUpdate(newPod, oldPod *api.Pod) validation.ErrorList { - allErrs := validation.ErrorList{} - - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidatePodStatusUpdate(newPod, oldPod *api.Pod) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta, field.NewPath("metadata")) // TODO: allow change when bindings are properly decoupled from pods if newPod.Spec.NodeName != oldPod.Spec.NodeName { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("status", "nodeName"), newPod.Spec.NodeName, "cannot be changed directly")) + allErrs = append(allErrs, field.Invalid(field.NewPath("status", "nodeName"), newPod.Spec.NodeName, "cannot be changed directly")) } // For status update we ignore changes to pod spec. @@ -1230,18 +1225,17 @@ func ValidatePodStatusUpdate(newPod, oldPod *api.Pod) validation.ErrorList { } // ValidatePodTemplate tests if required fields in the pod template are set. -func ValidatePodTemplate(pod *api.PodTemplate) validation.ErrorList { - allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, validation.NewFieldPath("metadata")) - allErrs = append(allErrs, ValidatePodTemplateSpec(&pod.Template, validation.NewFieldPath("template"))...) +func ValidatePodTemplate(pod *api.PodTemplate) field.ErrorList { + allErrs := ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidatePodTemplateSpec(&pod.Template, field.NewPath("template"))...) return allErrs } // ValidatePodTemplateUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields // that cannot be changed. -func ValidatePodTemplateUpdate(newPod, oldPod *api.PodTemplate) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&oldPod.ObjectMeta, &newPod.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidatePodTemplateSpec(&newPod.Template, validation.NewFieldPath("template"))...) +func ValidatePodTemplateUpdate(newPod, oldPod *api.PodTemplate) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&oldPod.ObjectMeta, &newPod.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidatePodTemplateSpec(&newPod.Template, field.NewPath("template"))...) return allErrs } @@ -1250,19 +1244,19 @@ var supportedServiceType = sets.NewString(string(api.ServiceTypeClusterIP), stri string(api.ServiceTypeLoadBalancer)) // ValidateService tests if required fields in the service are set. -func ValidateService(service *api.Service) validation.ErrorList { - allErrs := ValidateObjectMeta(&service.ObjectMeta, true, ValidateServiceName, validation.NewFieldPath("metadata")) +func ValidateService(service *api.Service) field.ErrorList { + allErrs := ValidateObjectMeta(&service.ObjectMeta, true, ValidateServiceName, field.NewPath("metadata")) - specPath := validation.NewFieldPath("spec") + specPath := field.NewPath("spec") if len(service.Spec.Ports) == 0 && service.Spec.ClusterIP != api.ClusterIPNone { - allErrs = append(allErrs, validation.NewRequiredError(specPath.Child("ports"))) + allErrs = append(allErrs, field.Required(specPath.Child("ports"))) } if service.Spec.Type == api.ServiceTypeLoadBalancer { for ix := range service.Spec.Ports { port := &service.Spec.Ports[ix] if port.Port == 10250 { portPath := specPath.Child("ports").Index(ix) - allErrs = append(allErrs, validation.NewInvalidError(portPath, port.Port, "can not expose port 10250 externally since it is used by kubelet")) + allErrs = append(allErrs, field.Invalid(portPath, port.Port, "can not expose port 10250 externally since it is used by kubelet")) } } } @@ -1280,14 +1274,14 @@ func ValidateService(service *api.Service) validation.ErrorList { } if service.Spec.SessionAffinity == "" { - allErrs = append(allErrs, validation.NewRequiredError(specPath.Child("sessionAffinity"))) + allErrs = append(allErrs, field.Required(specPath.Child("sessionAffinity"))) } else if !supportedSessionAffinityType.Has(string(service.Spec.SessionAffinity)) { - allErrs = append(allErrs, validation.NewNotSupportedError(specPath.Child("sessionAffinity"), service.Spec.SessionAffinity, supportedSessionAffinityType.List())) + allErrs = append(allErrs, field.NotSupported(specPath.Child("sessionAffinity"), service.Spec.SessionAffinity, supportedSessionAffinityType.List())) } if api.IsServiceIPSet(service) { if ip := net.ParseIP(service.Spec.ClusterIP); ip == nil { - allErrs = append(allErrs, validation.NewInvalidError(specPath.Child("clusterIP"), service.Spec.ClusterIP, "must be empty, 'None', or a valid IP address")) + allErrs = append(allErrs, field.Invalid(specPath.Child("clusterIP"), service.Spec.ClusterIP, "must be empty, 'None', or a valid IP address")) } } @@ -1295,15 +1289,15 @@ func ValidateService(service *api.Service) validation.ErrorList { for i, ip := range service.Spec.ExternalIPs { idxPath := ipPath.Index(i) if ip == "0.0.0.0" { - allErrs = append(allErrs, validation.NewInvalidError(idxPath, ip, "is not an IP address")) + allErrs = append(allErrs, field.Invalid(idxPath, ip, "is not an IP address")) } allErrs = append(allErrs, validateIpIsNotLinkLocalOrLoopback(ip, idxPath)...) } if service.Spec.Type == "" { - allErrs = append(allErrs, validation.NewRequiredError(specPath.Child("type"))) + allErrs = append(allErrs, field.Required(specPath.Child("type"))) } else if !supportedServiceType.Has(string(service.Spec.Type)) { - allErrs = append(allErrs, validation.NewNotSupportedError(specPath.Child("type"), service.Spec.Type, supportedServiceType.List())) + allErrs = append(allErrs, field.NotSupported(specPath.Child("type"), service.Spec.Type, supportedServiceType.List())) } if service.Spec.Type == api.ServiceTypeLoadBalancer { @@ -1311,7 +1305,7 @@ func ValidateService(service *api.Service) validation.ErrorList { for i := range service.Spec.Ports { portPath := portsPath.Index(i) if service.Spec.Ports[i].Protocol != api.ProtocolTCP { - allErrs = append(allErrs, validation.NewInvalidError(portPath.Child("protocol"), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP ports")) + allErrs = append(allErrs, field.Invalid(portPath.Child("protocol"), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP ports")) } } } @@ -1321,7 +1315,7 @@ func ValidateService(service *api.Service) validation.ErrorList { for i := range service.Spec.Ports { portPath := portsPath.Index(i) if service.Spec.Ports[i].NodePort != 0 { - allErrs = append(allErrs, validation.NewInvalidError(portPath.Child("nodePort"), service.Spec.Ports[i].NodePort, "cannot specify a node port with services of type ClusterIP")) + allErrs = append(allErrs, field.Invalid(portPath.Child("nodePort"), service.Spec.Ports[i].NodePort, "cannot specify a node port with services of type ClusterIP")) } } } @@ -1340,7 +1334,7 @@ func ValidateService(service *api.Service) validation.ErrorList { key.NodePort = port.NodePort _, found := nodePorts[key] if found { - allErrs = append(allErrs, validation.NewInvalidError(portPath.Child("nodePort"), port.NodePort, "duplicate nodePort specified")) + allErrs = append(allErrs, field.Invalid(portPath.Child("nodePort"), port.NodePort, "duplicate nodePort specified")) } nodePorts[key] = true } @@ -1348,41 +1342,41 @@ func ValidateService(service *api.Service) validation.ErrorList { return allErrs } -func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService bool, allNames *sets.String, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService bool, allNames *sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if requireName && sp.Name == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("name"))) + allErrs = append(allErrs, field.Required(fldPath.Child("name"))) } else if sp.Name != "" { if !validation.IsDNS1123Label(sp.Name) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("name"), sp.Name, DNS1123LabelErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), sp.Name, DNS1123LabelErrorMsg)) } else if allNames.Has(sp.Name) { - allErrs = append(allErrs, validation.NewDuplicateError(fldPath.Child("name"), sp.Name)) + allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), sp.Name)) } else { allNames.Insert(sp.Name) } } if !validation.IsValidPortNum(sp.Port) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("port"), sp.Port, PortRangeErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), sp.Port, PortRangeErrorMsg)) } if len(sp.Protocol) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("protocol"))) + allErrs = append(allErrs, field.Required(fldPath.Child("protocol"))) } else if !supportedPortProtocols.Has(string(sp.Protocol)) { - allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("protocol"), sp.Protocol, supportedPortProtocols.List())) + allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), sp.Protocol, supportedPortProtocols.List())) } if sp.TargetPort.Type == intstr.Int && !validation.IsValidPortNum(sp.TargetPort.IntValue()) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("targetPort"), sp.TargetPort, PortRangeErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, PortRangeErrorMsg)) } if sp.TargetPort.Type == intstr.String && !validation.IsValidPortName(sp.TargetPort.StrVal) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("targetPort"), sp.TargetPort, PortNameErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, PortNameErrorMsg)) } if isHeadlessService { if sp.TargetPort.Type == intstr.String || (sp.TargetPort.Type == intstr.Int && sp.Port != sp.TargetPort.IntValue()) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("port"), sp.Port, "must be equal to targetPort when clusterIP = None")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), sp.Port, "must be equal to targetPort when clusterIP = None")) } } @@ -1390,12 +1384,11 @@ func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService boo } // ValidateServiceUpdate tests if required fields in the service are set during an update -func ValidateServiceUpdate(service, oldService *api.Service) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateServiceUpdate(service, oldService *api.Service) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta, field.NewPath("metadata")) if api.IsServiceIPSet(oldService) { - allErrs = append(allErrs, ValidateImmutableField(service.Spec.ClusterIP, oldService.Spec.ClusterIP, validation.NewFieldPath("spec", "clusterIP"))...) + allErrs = append(allErrs, ValidateImmutableField(service.Spec.ClusterIP, oldService.Spec.ClusterIP, field.NewPath("spec", "clusterIP"))...) } allErrs = append(allErrs, ValidateService(service)...) @@ -1403,52 +1396,50 @@ func ValidateServiceUpdate(service, oldService *api.Service) validation.ErrorLis } // ValidateReplicationController tests if required fields in the replication controller are set. -func ValidateReplicationController(controller *api.ReplicationController) validation.ErrorList { - allErrs := ValidateObjectMeta(&controller.ObjectMeta, true, ValidateReplicationControllerName, validation.NewFieldPath("metadata")) - allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, validation.NewFieldPath("spec"))...) +func ValidateReplicationController(controller *api.ReplicationController) field.ErrorList { + allErrs := ValidateObjectMeta(&controller.ObjectMeta, true, ValidateReplicationControllerName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"))...) return allErrs } // ValidateReplicationControllerUpdate tests if required fields in the replication controller are set. -func ValidateReplicationControllerUpdate(controller, oldController *api.ReplicationController) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, validation.NewFieldPath("spec"))...) +func ValidateReplicationControllerUpdate(controller, oldController *api.ReplicationController) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec, field.NewPath("spec"))...) return allErrs } // ValidateReplicationControllerStatusUpdate tests if required fields in the replication controller are set. -func ValidateReplicationControllerStatusUpdate(controller, oldController *api.ReplicationController) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, validation.NewFieldPath("metadata"))...) - statusPath := validation.NewFieldPath("status") +func ValidateReplicationControllerStatusUpdate(controller, oldController *api.ReplicationController) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) + statusPath := field.NewPath("status") allErrs = append(allErrs, ValidatePositiveField(int64(controller.Status.Replicas), statusPath.Child("replicas"))...) allErrs = append(allErrs, ValidatePositiveField(int64(controller.Status.ObservedGeneration), statusPath.Child("observedGeneration"))...) return allErrs } // Validates that the given selector is non-empty. -func ValidateNonEmptySelector(selectorMap map[string]string, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateNonEmptySelector(selectorMap map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} selector := labels.Set(selectorMap).AsSelector() if selector.Empty() { - allErrs = append(allErrs, validation.NewRequiredError(fldPath)) + allErrs = append(allErrs, field.Required(fldPath)) } return allErrs } // Validates the given template and ensures that it is in accordance with the desrired selector and replicas. -func ValidatePodTemplateSpecForRC(template *api.PodTemplateSpec, selectorMap map[string]string, replicas int, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePodTemplateSpecForRC(template *api.PodTemplateSpec, selectorMap map[string]string, replicas int, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if template == nil { - allErrs = append(allErrs, validation.NewRequiredError(fldPath)) + allErrs = append(allErrs, field.Required(fldPath)) } else { selector := labels.Set(selectorMap).AsSelector() if !selector.Empty() { // Verify that the RC selector matches the labels in template. labels := labels.Set(template.Labels) if !selector.Matches(labels) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("metadata", "labels"), template.Labels, "selector does not match labels in "+fldPath.String())) + allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "selector does not match labels in "+fldPath.String())) } } allErrs = append(allErrs, ValidatePodTemplateSpec(template, fldPath)...) @@ -1457,16 +1448,15 @@ func ValidatePodTemplateSpecForRC(template *api.PodTemplateSpec, selectorMap map } // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec(). if template.Spec.RestartPolicy != api.RestartPolicyAlways { - allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("spec", "restartPolicy"), template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) + allErrs = append(allErrs, field.NotSupported(fldPath.Child("spec", "restartPolicy"), template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) } } return allErrs } // ValidateReplicationControllerSpec tests if required fields in the replication controller spec are set. -func ValidateReplicationControllerSpec(spec *api.ReplicationControllerSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} - +func ValidateReplicationControllerSpec(spec *api.ReplicationControllerSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, ValidateNonEmptySelector(spec.Selector, fldPath.Child("selector"))...) allErrs = append(allErrs, ValidatePositiveField(int64(spec.Replicas), fldPath.Child("replicas"))...) allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"))...) @@ -1474,22 +1464,22 @@ func ValidateReplicationControllerSpec(spec *api.ReplicationControllerSpec, fldP } // ValidatePodTemplateSpec validates the spec of a pod template -func ValidatePodTemplateSpec(spec *api.PodTemplateSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePodTemplateSpec(spec *api.PodTemplateSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, ValidateLabels(spec.Labels, fldPath.Child("labels"))...) allErrs = append(allErrs, ValidateAnnotations(spec.Annotations, fldPath.Child("annotations"))...) allErrs = append(allErrs, ValidatePodSpec(&spec.Spec, fldPath.Child("spec"))...) return allErrs } -func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} for i := range volumes { vol := &volumes[i] idxPath := fldPath.Index(i) if vol.GCEPersistentDisk != nil { if vol.GCEPersistentDisk.ReadOnly == false { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("gcePersistentDisk", ".readOnly"), false, "readOnly must be true for replicated pods > 1, as GCE PD can only be mounted on multiple machines if it is read-only.")) + allErrs = append(allErrs, field.Invalid(idxPath.Child("gcePersistentDisk", ".readOnly"), false, "readOnly must be true for replicated pods > 1, as GCE PD can only be mounted on multiple machines if it is read-only.")) } } // TODO: What to do for AWS? It doesn't support replicas @@ -1498,14 +1488,14 @@ func ValidateReadOnlyPersistentDisks(volumes []api.Volume, fldPath *validation.F } // ValidateNode tests if required fields in the node are set. -func ValidateNode(node *api.Node) validation.ErrorList { - allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, validation.NewFieldPath("metadata")) +func ValidateNode(node *api.Node) field.ErrorList { + allErrs := ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName, field.NewPath("metadata")) // Only validate spec. All status fields are optional and can be updated later. // external ID is required. if len(node.Spec.ExternalID) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(validation.NewFieldPath("spec", "externalID"))) + allErrs = append(allErrs, field.Required(field.NewPath("spec", "externalID"))) } // TODO(rjnagal): Ignore PodCIDR till its completely implemented. @@ -1513,21 +1503,20 @@ func ValidateNode(node *api.Node) validation.ErrorList { } // ValidateNodeUpdate tests to make sure a node update can be applied. Modifies oldNode. -func ValidateNodeUpdate(node, oldNode *api.Node) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&node.ObjectMeta, &oldNode.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateNodeUpdate(node, oldNode *api.Node) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&node.ObjectMeta, &oldNode.ObjectMeta, field.NewPath("metadata")) // TODO: Enable the code once we have better api object.status update model. Currently, // anyone can update node status. // if !api.Semantic.DeepEqual(node.Status, api.NodeStatus{}) { - // allErrs = append(allErrs, validation.NewInvalidError("status", node.Status, "status must be empty")) + // allErrs = append(allErrs, field.Invalid("status", node.Status, "status must be empty")) // } // Validte no duplicate addresses in node status. addresses := make(map[api.NodeAddress]bool) for i, address := range node.Status.Addresses { if _, ok := addresses[address]; ok { - allErrs = append(allErrs, validation.NewDuplicateError(validation.NewFieldPath("status", "addresses").Index(i), address)) + allErrs = append(allErrs, field.Duplicate(field.NewPath("status", "addresses").Index(i), address)) } addresses[address] = true } @@ -1547,7 +1536,7 @@ func ValidateNodeUpdate(node, oldNode *api.Node) validation.ErrorList { // TODO: Add a 'real' error type for this error and provide print actual diffs. if !api.Semantic.DeepEqual(oldNode, node) { glog.V(4).Infof("Update failed validation %#v vs %#v", oldNode, node) - allErrs = append(allErrs, validation.NewForbiddenError(validation.NewFieldPath(""), "update contains more than labels or capacity changes")) + allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "update contains more than labels or capacity changes")) } return allErrs @@ -1555,34 +1544,34 @@ func ValidateNodeUpdate(node, oldNode *api.Node) validation.ErrorList { // Validate compute resource typename. // Refer to docs/design/resources.md for more details. -func validateResourceName(value string, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateResourceName(value string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if !validation.IsQualifiedName(value) { - return append(allErrs, validation.NewInvalidError(fldPath, value, "resource typename: "+qualifiedNameErrorMsg)) + return append(allErrs, field.Invalid(fldPath, value, "resource typename: "+qualifiedNameErrorMsg)) } if len(strings.Split(value, "/")) == 1 { if !api.IsStandardResourceName(value) { - return append(allErrs, validation.NewInvalidError(fldPath, value, "is neither a standard resource type nor is fully qualified")) + return append(allErrs, field.Invalid(fldPath, value, "is neither a standard resource type nor is fully qualified")) } } - return validation.ErrorList{} + return field.ErrorList{} } // ValidateLimitRange tests if required fields in the LimitRange are set. -func ValidateLimitRange(limitRange *api.LimitRange) validation.ErrorList { - allErrs := ValidateObjectMeta(&limitRange.ObjectMeta, true, ValidateLimitRangeName, validation.NewFieldPath("metadata")) +func ValidateLimitRange(limitRange *api.LimitRange) field.ErrorList { + allErrs := ValidateObjectMeta(&limitRange.ObjectMeta, true, ValidateLimitRangeName, field.NewPath("metadata")) // ensure resource names are properly qualified per docs/design/resources.md limitTypeSet := map[api.LimitType]bool{} - fldPath := validation.NewFieldPath("spec", "limits") + fldPath := field.NewPath("spec", "limits") for i := range limitRange.Spec.Limits { idxPath := fldPath.Index(i) limit := &limitRange.Spec.Limits[i] _, found := limitTypeSet[limit.Type] if found { - allErrs = append(allErrs, validation.NewDuplicateError(idxPath.Child("type"), limit.Type)) + allErrs = append(allErrs, field.Duplicate(idxPath.Child("type"), limit.Type)) } limitTypeSet[limit.Type] = true @@ -1606,10 +1595,10 @@ func ValidateLimitRange(limitRange *api.LimitRange) validation.ErrorList { if limit.Type == api.LimitTypePod { if len(limit.Default) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("default"), limit.Default, "not supported when limit type is Pod")) + allErrs = append(allErrs, field.Invalid(idxPath.Child("default"), limit.Default, "not supported when limit type is Pod")) } if len(limit.DefaultRequest) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("defaultRequest"), limit.DefaultRequest, "not supported when limit type is Pod")) + allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest"), limit.DefaultRequest, "not supported when limit type is Pod")) } } else { for k, q := range limit.Default { @@ -1638,30 +1627,30 @@ func ValidateLimitRange(limitRange *api.LimitRange) validation.ErrorList { maxRatio, maxRatioFound := maxLimitRequestRatios[k] if minQuantityFound && maxQuantityFound && minQuantity.Cmp(maxQuantity) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("min").Key(string(k)), minQuantity, fmt.Sprintf("min value %s is greater than max value %s", minQuantity.String(), maxQuantity.String()))) + allErrs = append(allErrs, field.Invalid(idxPath.Child("min").Key(string(k)), minQuantity, fmt.Sprintf("min value %s is greater than max value %s", minQuantity.String(), maxQuantity.String()))) } if defaultRequestQuantityFound && minQuantityFound && minQuantity.Cmp(defaultRequestQuantity) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("min value %s is greater than default request value %s", minQuantity.String(), defaultRequestQuantity.String()))) + allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("min value %s is greater than default request value %s", minQuantity.String(), defaultRequestQuantity.String()))) } if defaultRequestQuantityFound && maxQuantityFound && defaultRequestQuantity.Cmp(maxQuantity) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than max value %s", defaultRequestQuantity.String(), maxQuantity.String()))) + allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than max value %s", defaultRequestQuantity.String(), maxQuantity.String()))) } if defaultRequestQuantityFound && defaultQuantityFound && defaultRequestQuantity.Cmp(defaultQuantity) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than default limit value %s", defaultRequestQuantity.String(), defaultQuantity.String()))) + allErrs = append(allErrs, field.Invalid(idxPath.Child("defaultRequest").Key(string(k)), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than default limit value %s", defaultRequestQuantity.String(), defaultQuantity.String()))) } if defaultQuantityFound && minQuantityFound && minQuantity.Cmp(defaultQuantity) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("default").Key(string(k)), minQuantity, fmt.Sprintf("min value %s is greater than default value %s", minQuantity.String(), defaultQuantity.String()))) + allErrs = append(allErrs, field.Invalid(idxPath.Child("default").Key(string(k)), minQuantity, fmt.Sprintf("min value %s is greater than default value %s", minQuantity.String(), defaultQuantity.String()))) } if defaultQuantityFound && maxQuantityFound && defaultQuantity.Cmp(maxQuantity) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("default").Key(string(k)), maxQuantity, fmt.Sprintf("default value %s is greater than max value %s", defaultQuantity.String(), maxQuantity.String()))) + allErrs = append(allErrs, field.Invalid(idxPath.Child("default").Key(string(k)), maxQuantity, fmt.Sprintf("default value %s is greater than max value %s", defaultQuantity.String(), maxQuantity.String()))) } if maxRatioFound && maxRatio.Cmp(*resource.NewQuantity(1, resource.DecimalSI)) < 0 { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is less than 1", maxRatio.String()))) + allErrs = append(allErrs, field.Invalid(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is less than 1", maxRatio.String()))) } if maxRatioFound && minQuantityFound && maxQuantityFound { maxRatioValue := float64(maxRatio.Value()) @@ -1674,7 +1663,7 @@ func ValidateLimitRange(limitRange *api.LimitRange) validation.ErrorList { } maxRatioLimit := float64(maxQuantityValue) / float64(minQuantityValue) if maxRatioValue > maxRatioLimit { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is greater than max/min = %f", maxRatio.String(), maxRatioLimit))) + allErrs = append(allErrs, field.Invalid(idxPath.Child("maxLimitRequestRatio").Key(string(k)), maxRatio, fmt.Sprintf("ratio %s is greater than max/min = %f", maxRatio.String(), maxRatioLimit))) } } } @@ -1684,15 +1673,14 @@ func ValidateLimitRange(limitRange *api.LimitRange) validation.ErrorList { } // ValidateServiceAccount tests if required fields in the ServiceAccount are set. -func ValidateServiceAccount(serviceAccount *api.ServiceAccount) validation.ErrorList { - allErrs := ValidateObjectMeta(&serviceAccount.ObjectMeta, true, ValidateServiceAccountName, validation.NewFieldPath("metadata")) +func ValidateServiceAccount(serviceAccount *api.ServiceAccount) field.ErrorList { + allErrs := ValidateObjectMeta(&serviceAccount.ObjectMeta, true, ValidateServiceAccountName, field.NewPath("metadata")) return allErrs } // ValidateServiceAccountUpdate tests if required fields in the ServiceAccount are set. -func ValidateServiceAccountUpdate(newServiceAccount, oldServiceAccount *api.ServiceAccount) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newServiceAccount.ObjectMeta, &oldServiceAccount.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateServiceAccountUpdate(newServiceAccount, oldServiceAccount *api.ServiceAccount) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newServiceAccount.ObjectMeta, &oldServiceAccount.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, ValidateServiceAccount(newServiceAccount)...) return allErrs } @@ -1708,19 +1696,19 @@ func IsSecretKey(value string) bool { } // ValidateSecret tests if required fields in the Secret are set. -func ValidateSecret(secret *api.Secret) validation.ErrorList { - allErrs := ValidateObjectMeta(&secret.ObjectMeta, true, ValidateSecretName, validation.NewFieldPath("metadata")) +func ValidateSecret(secret *api.Secret) field.ErrorList { + allErrs := ValidateObjectMeta(&secret.ObjectMeta, true, ValidateSecretName, field.NewPath("metadata")) - dataPath := validation.NewFieldPath("data") + dataPath := field.NewPath("data") totalSize := 0 for key, value := range secret.Data { if !IsSecretKey(key) { - allErrs = append(allErrs, validation.NewInvalidError(dataPath.Key(key), key, fmt.Sprintf("must have at most %d characters and match regex %s", validation.DNS1123SubdomainMaxLength, SecretKeyFmt))) + allErrs = append(allErrs, field.Invalid(dataPath.Key(key), key, fmt.Sprintf("must have at most %d characters and match regex %s", validation.DNS1123SubdomainMaxLength, SecretKeyFmt))) } totalSize += len(value) } if totalSize > api.MaxSecretSize { - allErrs = append(allErrs, validation.NewTooLongError(dataPath, "", api.MaxSecretSize)) + allErrs = append(allErrs, field.TooLong(dataPath, "", api.MaxSecretSize)) } switch secret.Type { @@ -1728,20 +1716,20 @@ func ValidateSecret(secret *api.Secret) validation.ErrorList { // Only require Annotations[kubernetes.io/service-account.name] // Additional fields (like Annotations[kubernetes.io/service-account.uid] and Data[token]) might be contributed later by a controller loop if value := secret.Annotations[api.ServiceAccountNameKey]; len(value) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(validation.NewFieldPath("metadata", "annotations").Key(api.ServiceAccountNameKey))) + allErrs = append(allErrs, field.Required(field.NewPath("metadata", "annotations").Key(api.ServiceAccountNameKey))) } case api.SecretTypeOpaque, "": // no-op case api.SecretTypeDockercfg: dockercfgBytes, exists := secret.Data[api.DockerConfigKey] if !exists { - allErrs = append(allErrs, validation.NewRequiredError(dataPath.Key(api.DockerConfigKey))) + allErrs = append(allErrs, field.Required(dataPath.Key(api.DockerConfigKey))) break } // make sure that the content is well-formed json. if err := json.Unmarshal(dockercfgBytes, &map[string]interface{}{}); err != nil { - allErrs = append(allErrs, validation.NewInvalidError(dataPath.Key(api.DockerConfigKey), "", err.Error())) + allErrs = append(allErrs, field.Invalid(dataPath.Key(api.DockerConfigKey), "", err.Error())) } default: @@ -1752,30 +1740,29 @@ func ValidateSecret(secret *api.Secret) validation.ErrorList { } // ValidateSecretUpdate tests if required fields in the Secret are set. -func ValidateSecretUpdate(newSecret, oldSecret *api.Secret) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newSecret.ObjectMeta, &oldSecret.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateSecretUpdate(newSecret, oldSecret *api.Secret) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newSecret.ObjectMeta, &oldSecret.ObjectMeta, field.NewPath("metadata")) if len(newSecret.Type) == 0 { newSecret.Type = oldSecret.Type } - allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, oldSecret.Type, validation.NewFieldPath("type"))...) + allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, oldSecret.Type, field.NewPath("type"))...) allErrs = append(allErrs, ValidateSecret(newSecret)...) return allErrs } -func validateBasicResource(quantity resource.Quantity, fldPath *validation.FieldPath) validation.ErrorList { +func validateBasicResource(quantity resource.Quantity, fldPath *field.Path) field.ErrorList { if quantity.Value() < 0 { - return validation.ErrorList{validation.NewInvalidError(fldPath, quantity.Value(), "must be a valid resource quantity")} + return field.ErrorList{field.Invalid(fldPath, quantity.Value(), "must be a valid resource quantity")} } - return validation.ErrorList{} + return field.ErrorList{} } // Validates resource requirement spec. -func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} limPath := fldPath.Child("limits") for resourceName, quantity := range requirements.Limits { fldPath := limPath.Key(string(resourceName)) @@ -1796,7 +1783,7 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat limitValue = quantity.MilliValue() } if limitValue < requestValue { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, quantity.String(), "limit cannot be smaller than request")) + allErrs = append(allErrs, field.Invalid(fldPath, quantity.String(), "limit cannot be smaller than request")) } } } @@ -1813,22 +1800,22 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat } // ValidateResourceQuota tests if required fields in the ResourceQuota are set. -func ValidateResourceQuota(resourceQuota *api.ResourceQuota) validation.ErrorList { - allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, validation.NewFieldPath("metadata")) +func ValidateResourceQuota(resourceQuota *api.ResourceQuota) field.ErrorList { + allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata")) - fldPath := validation.NewFieldPath("spec", "hard") + fldPath := field.NewPath("spec", "hard") for k, v := range resourceQuota.Spec.Hard { resPath := fldPath.Key(string(k)) allErrs = append(allErrs, validateResourceName(string(k), resPath)...) allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...) } - fldPath = validation.NewFieldPath("status", "hard") + fldPath = field.NewPath("status", "hard") for k, v := range resourceQuota.Status.Hard { resPath := fldPath.Key(string(k)) allErrs = append(allErrs, validateResourceName(string(k), resPath)...) allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...) } - fldPath = validation.NewFieldPath("status", "used") + fldPath = field.NewPath("status", "used") for k, v := range resourceQuota.Status.Used { resPath := fldPath.Key(string(k)) allErrs = append(allErrs, validateResourceName(string(k), resPath)...) @@ -1838,12 +1825,12 @@ func ValidateResourceQuota(resourceQuota *api.ResourceQuota) validation.ErrorLis } // validateResourceQuantityValue enforces that specified quantity is valid for specified resource -func validateResourceQuantityValue(resource string, value resource.Quantity, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, ValidatePositiveQuantity(value, fldPath)...) if api.IsIntegerResourceName(resource) { if value.MilliValue()%int64(1000) != int64(0) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, value, isNotIntegerErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath, value, isNotIntegerErrorMsg)) } } return allErrs @@ -1851,10 +1838,9 @@ func validateResourceQuantityValue(resource string, value resource.Quantity, fld // ValidateResourceQuotaUpdate tests to see if the update is legal for an end user to make. // newResourceQuota is updated with fields that cannot be changed. -func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, validation.NewFieldPath("metadata"))...) - fldPath := validation.NewFieldPath("spec", "hard") +func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata")) + fldPath := field.NewPath("spec", "hard") for k, v := range newResourceQuota.Spec.Hard { resPath := fldPath.Key(string(k)) allErrs = append(allErrs, validateResourceName(string(k), resPath)...) @@ -1866,19 +1852,18 @@ func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *api.Resourc // ValidateResourceQuotaStatusUpdate tests to see if the status update is legal for an end user to make. // newResourceQuota is updated with fields that cannot be changed. -func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata")) if newResourceQuota.ResourceVersion == "" { - allErrs = append(allErrs, validation.NewRequiredError(validation.NewFieldPath("resourceVersion"))) + allErrs = append(allErrs, field.Required(field.NewPath("resourceVersion"))) } - fldPath := validation.NewFieldPath("status", "hard") + fldPath := field.NewPath("status", "hard") for k, v := range newResourceQuota.Status.Hard { resPath := fldPath.Key(string(k)) allErrs = append(allErrs, validateResourceName(string(k), resPath)...) allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...) } - fldPath = validation.NewFieldPath("status", "used") + fldPath = field.NewPath("status", "used") for k, v := range newResourceQuota.Status.Used { resPath := fldPath.Key(string(k)) allErrs = append(allErrs, validateResourceName(string(k), resPath)...) @@ -1889,35 +1874,34 @@ func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *api.R } // ValidateNamespace tests if required fields are set. -func ValidateNamespace(namespace *api.Namespace) validation.ErrorList { - allErrs := ValidateObjectMeta(&namespace.ObjectMeta, false, ValidateNamespaceName, validation.NewFieldPath("metadata")) +func ValidateNamespace(namespace *api.Namespace) field.ErrorList { + allErrs := ValidateObjectMeta(&namespace.ObjectMeta, false, ValidateNamespaceName, field.NewPath("metadata")) for i := range namespace.Spec.Finalizers { - allErrs = append(allErrs, validateFinalizerName(string(namespace.Spec.Finalizers[i]), validation.NewFieldPath("spec", "finalizers"))...) + allErrs = append(allErrs, validateFinalizerName(string(namespace.Spec.Finalizers[i]), field.NewPath("spec", "finalizers"))...) } return allErrs } // Validate finalizer names -func validateFinalizerName(stringValue string, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateFinalizerName(stringValue string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if !validation.IsQualifiedName(stringValue) { - return append(allErrs, validation.NewInvalidError(fldPath, stringValue, qualifiedNameErrorMsg)) + return append(allErrs, field.Invalid(fldPath, stringValue, qualifiedNameErrorMsg)) } if len(strings.Split(stringValue, "/")) == 1 { if !api.IsStandardFinalizerName(stringValue) { - return append(allErrs, validation.NewInvalidError(fldPath, stringValue, fmt.Sprintf("name is neither a standard finalizer name nor is it fully qualified"))) + return append(allErrs, field.Invalid(fldPath, stringValue, fmt.Sprintf("name is neither a standard finalizer name nor is it fully qualified"))) } } - return validation.ErrorList{} + return field.ErrorList{} } // ValidateNamespaceUpdate tests to make sure a namespace update can be applied. // newNamespace is updated with fields that cannot be changed -func ValidateNamespaceUpdate(newNamespace *api.Namespace, oldNamespace *api.Namespace) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateNamespaceUpdate(newNamespace *api.Namespace, oldNamespace *api.Namespace) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata")) newNamespace.Spec.Finalizers = oldNamespace.Spec.Finalizers newNamespace.Status = oldNamespace.Status return allErrs @@ -1925,17 +1909,16 @@ func ValidateNamespaceUpdate(newNamespace *api.Namespace, oldNamespace *api.Name // ValidateNamespaceStatusUpdate tests to see if the update is legal for an end user to make. newNamespace is updated with fields // that cannot be changed. -func ValidateNamespaceStatusUpdate(newNamespace, oldNamespace *api.Namespace) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateNamespaceStatusUpdate(newNamespace, oldNamespace *api.Namespace) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata")) newNamespace.Spec = oldNamespace.Spec if newNamespace.DeletionTimestamp.IsZero() { if newNamespace.Status.Phase != api.NamespaceActive { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("status", "Phase"), newNamespace.Status.Phase, "may only be in active status if it does not have a deletion timestamp.")) + allErrs = append(allErrs, field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may only be in active status if it does not have a deletion timestamp.")) } } else { if newNamespace.Status.Phase != api.NamespaceTerminating { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("status", "Phase"), newNamespace.Status.Phase, "may only be in terminating status if it has a deletion timestamp.")) + allErrs = append(allErrs, field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may only be in terminating status if it has a deletion timestamp.")) } } return allErrs @@ -1943,11 +1926,10 @@ func ValidateNamespaceStatusUpdate(newNamespace, oldNamespace *api.Namespace) va // ValidateNamespaceFinalizeUpdate tests to see if the update is legal for an end user to make. // newNamespace is updated with fields that cannot be changed. -func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *api.Namespace) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *api.Namespace) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta, field.NewPath("metadata")) - fldPath := validation.NewFieldPath("spec", "finalizers") + fldPath := field.NewPath("spec", "finalizers") for i := range newNamespace.Spec.Finalizers { idxPath := fldPath.Index(i) allErrs = append(allErrs, validateFinalizerName(string(newNamespace.Spec.Finalizers[i]), idxPath)...) @@ -1957,14 +1939,14 @@ func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *api.Namespace) } // ValidateEndpoints tests if required fields are set. -func ValidateEndpoints(endpoints *api.Endpoints) validation.ErrorList { - allErrs := ValidateObjectMeta(&endpoints.ObjectMeta, true, ValidateEndpointsName, validation.NewFieldPath("metadata")) - allErrs = append(allErrs, validateEndpointSubsets(endpoints.Subsets, validation.NewFieldPath("subsets"))...) +func ValidateEndpoints(endpoints *api.Endpoints) field.ErrorList { + allErrs := ValidateObjectMeta(&endpoints.ObjectMeta, true, ValidateEndpointsName, field.NewPath("metadata")) + allErrs = append(allErrs, validateEndpointSubsets(endpoints.Subsets, field.NewPath("subsets"))...) return allErrs } -func validateEndpointSubsets(subsets []api.EndpointSubset, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateEndpointSubsets(subsets []api.EndpointSubset, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} for i := range subsets { ss := &subsets[i] @@ -1972,10 +1954,10 @@ func validateEndpointSubsets(subsets []api.EndpointSubset, fldPath *validation.F if len(ss.Addresses) == 0 && len(ss.NotReadyAddresses) == 0 { //TODO: consider adding a RequiredOneOf() error for this and similar cases - allErrs = append(allErrs, validation.NewRequiredError(idxPath.Child("addresses or notReadyAddresses"))) + allErrs = append(allErrs, field.Required(idxPath.Child("addresses or notReadyAddresses"))) } if len(ss.Ports) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(idxPath.Child("ports"))) + allErrs = append(allErrs, field.Required(idxPath.Child("ports"))) } for addr := range ss.Addresses { allErrs = append(allErrs, validateEndpointAddress(&ss.Addresses[addr], idxPath.Child("addresses").Index(addr))...) @@ -1988,67 +1970,66 @@ func validateEndpointSubsets(subsets []api.EndpointSubset, fldPath *validation.F return allErrs } -func validateEndpointAddress(address *api.EndpointAddress, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateEndpointAddress(address *api.EndpointAddress, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if !validation.IsValidIPv4(address.IP) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("ip"), address.IP, "invalid IPv4 address")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, "invalid IPv4 address")) return allErrs } return validateIpIsNotLinkLocalOrLoopback(address.IP, fldPath.Child("ip")) } -func validateIpIsNotLinkLocalOrLoopback(ipAddress string, fldPath *validation.FieldPath) validation.ErrorList { +func validateIpIsNotLinkLocalOrLoopback(ipAddress string, fldPath *field.Path) field.ErrorList { // We disallow some IPs as endpoints or external-ips. Specifically, loopback addresses are // nonsensical and link-local addresses tend to be used for node-centric purposes (e.g. metadata service). - allErrs := validation.ErrorList{} + allErrs := field.ErrorList{} ip := net.ParseIP(ipAddress) if ip == nil { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, ipAddress, "not a valid IP address")) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "not a valid IP address")) return allErrs } if ip.IsLoopback() { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, ipAddress, "may not be in the loopback range (127.0.0.0/8)")) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the loopback range (127.0.0.0/8)")) } if ip.IsLinkLocalUnicast() { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, ipAddress, "may not be in the link-local range (169.254.0.0/16)")) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local range (169.254.0.0/16)")) } if ip.IsLinkLocalMulticast() { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, ipAddress, "may not be in the link-local multicast range (224.0.0.0/24)")) + allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the link-local multicast range (224.0.0.0/24)")) } return allErrs } -func validateEndpointPort(port *api.EndpointPort, requireName bool, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateEndpointPort(port *api.EndpointPort, requireName bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if requireName && port.Name == "" { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("name"))) + allErrs = append(allErrs, field.Required(fldPath.Child("name"))) } else if port.Name != "" { if !validation.IsDNS1123Label(port.Name) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("name"), port.Name, DNS1123LabelErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), port.Name, DNS1123LabelErrorMsg)) } } if !validation.IsValidPortNum(port.Port) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("port"), port.Port, PortRangeErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), port.Port, PortRangeErrorMsg)) } if len(port.Protocol) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("protocol"))) + allErrs = append(allErrs, field.Required(fldPath.Child("protocol"))) } else if !supportedPortProtocols.Has(string(port.Protocol)) { - allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("protocol"), port.Protocol, supportedPortProtocols.List())) + allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), port.Protocol, supportedPortProtocols.List())) } return allErrs } // ValidateEndpointsUpdate tests to make sure an endpoints update can be applied. -func ValidateEndpointsUpdate(newEndpoints, oldEndpoints *api.Endpoints) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateObjectMetaUpdate(&newEndpoints.ObjectMeta, &oldEndpoints.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, validateEndpointSubsets(newEndpoints.Subsets, validation.NewFieldPath("subsets"))...) +func ValidateEndpointsUpdate(newEndpoints, oldEndpoints *api.Endpoints) field.ErrorList { + allErrs := ValidateObjectMetaUpdate(&newEndpoints.ObjectMeta, &oldEndpoints.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, validateEndpointSubsets(newEndpoints.Subsets, field.NewPath("subsets"))...) return allErrs } // ValidateSecurityContext ensure the security context contains valid settings -func ValidateSecurityContext(sc *api.SecurityContext, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateSecurityContext(sc *api.SecurityContext, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} //this should only be true for testing since SecurityContext is defaulted by the api if sc == nil { return allErrs @@ -2056,54 +2037,54 @@ func ValidateSecurityContext(sc *api.SecurityContext, fldPath *validation.FieldP if sc.Privileged != nil { if *sc.Privileged && !capabilities.Get().AllowPrivileged { - allErrs = append(allErrs, validation.NewForbiddenError(fldPath.Child("privileged"), sc.Privileged)) + allErrs = append(allErrs, field.Forbidden(fldPath.Child("privileged"), sc.Privileged)) } } if sc.RunAsUser != nil { if *sc.RunAsUser < 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("runAsUser"), *sc.RunAsUser, "runAsUser cannot be negative")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *sc.RunAsUser, "runAsUser cannot be negative")) } } return allErrs } -func ValidatePodLogOptions(opts *api.PodLogOptions) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePodLogOptions(opts *api.PodLogOptions) field.ErrorList { + allErrs := field.ErrorList{} if opts.TailLines != nil && *opts.TailLines < 0 { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("tailLines"), *opts.TailLines, "tailLines must be a non-negative integer or nil")) + allErrs = append(allErrs, field.Invalid(field.NewPath("tailLines"), *opts.TailLines, "tailLines must be a non-negative integer or nil")) } if opts.LimitBytes != nil && *opts.LimitBytes < 1 { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("limitBytes"), *opts.LimitBytes, "limitBytes must be a positive integer or nil")) + allErrs = append(allErrs, field.Invalid(field.NewPath("limitBytes"), *opts.LimitBytes, "limitBytes must be a positive integer or nil")) } switch { case opts.SinceSeconds != nil && opts.SinceTime != nil: - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("sinceSeconds"), *opts.SinceSeconds, "only one of sinceTime or sinceSeconds can be provided")) - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("sinceTime"), *opts.SinceTime, "only one of sinceTime or sinceSeconds can be provided")) + allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "only one of sinceTime or sinceSeconds can be provided")) + allErrs = append(allErrs, field.Invalid(field.NewPath("sinceTime"), *opts.SinceTime, "only one of sinceTime or sinceSeconds can be provided")) case opts.SinceSeconds != nil: if *opts.SinceSeconds < 1 { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("sinceSeconds"), *opts.SinceSeconds, "sinceSeconds must be a positive integer")) + allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "sinceSeconds must be a positive integer")) } } return allErrs } // ValidateLoadBalancerStatus validates required fields on a LoadBalancerStatus -func ValidateLoadBalancerStatus(status *api.LoadBalancerStatus, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateLoadBalancerStatus(status *api.LoadBalancerStatus, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} for i, ingress := range status.Ingress { idxPath := fldPath.Child("ingress").Index(i) if len(ingress.IP) > 0 { if isIP := (net.ParseIP(ingress.IP) != nil); !isIP { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("ip"), ingress.IP, "must be an IP address")) + allErrs = append(allErrs, field.Invalid(idxPath.Child("ip"), ingress.IP, "must be an IP address")) } } if len(ingress.Hostname) > 0 { if valid, errMsg := NameIsDNSSubdomain(ingress.Hostname, false); !valid { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("hostname"), ingress.Hostname, errMsg)) + allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, errMsg)) } if isIP := (net.ParseIP(ingress.Hostname) != nil); isIP { - allErrs = append(allErrs, validation.NewInvalidError(idxPath.Child("hostname"), ingress.Hostname, "must be a DNS name, not an IP address")) + allErrs = append(allErrs, field.Invalid(idxPath.Child("hostname"), ingress.Hostname, "must be a DNS name, not an IP address")) } } } diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 246f26f0a7fe9..03d5f8fb8bc16 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -30,10 +30,10 @@ import ( "k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/sets" - "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) -func expectPrefix(t *testing.T, prefix string, errs validation.ErrorList) { +func expectPrefix(t *testing.T, prefix string, errs field.ErrorList) { for i := range errs { if f, p := errs[i].Field, prefix; !strings.HasPrefix(f, p) { t.Errorf("expected prefix '%s' for field '%s' (%v)", p, f, errs[i]) @@ -52,7 +52,7 @@ func TestValidateObjectMetaCustomName(t *testing.T) { } return false, "name-gen" }, - validation.NewFieldPath("field")) + field.NewPath("field")) if len(errs) != 1 { t.Fatalf("unexpected errors: %v", errs) } @@ -69,7 +69,7 @@ func TestValidateObjectMetaNamespaces(t *testing.T) { func(s string, prefix bool) (bool, string) { return true, "" }, - validation.NewFieldPath("field")) + field.NewPath("field")) if len(errs) != 1 { t.Fatalf("unexpected errors: %v", errs) } @@ -88,7 +88,7 @@ func TestValidateObjectMetaNamespaces(t *testing.T) { func(s string, prefix bool) (bool, string) { return true, "" }, - validation.NewFieldPath("field")) + field.NewPath("field")) if len(errs) != 1 { t.Fatalf("unexpected errors: %v", errs) } @@ -101,21 +101,21 @@ func TestValidateObjectMetaUpdateIgnoresCreationTimestamp(t *testing.T) { if errs := ValidateObjectMetaUpdate( &api.ObjectMeta{Name: "test", ResourceVersion: "1"}, &api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: unversioned.NewTime(time.Unix(10, 0))}, - validation.NewFieldPath("field"), + field.NewPath("field"), ); len(errs) != 0 { t.Fatalf("unexpected errors: %v", errs) } if errs := ValidateObjectMetaUpdate( &api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: unversioned.NewTime(time.Unix(10, 0))}, &api.ObjectMeta{Name: "test", ResourceVersion: "1"}, - validation.NewFieldPath("field"), + field.NewPath("field"), ); len(errs) != 0 { t.Fatalf("unexpected errors: %v", errs) } if errs := ValidateObjectMetaUpdate( &api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: unversioned.NewTime(time.Unix(10, 0))}, &api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: unversioned.NewTime(time.Unix(11, 0))}, - validation.NewFieldPath("field"), + field.NewPath("field"), ); len(errs) != 0 { t.Fatalf("unexpected errors: %v", errs) } @@ -127,7 +127,7 @@ func TestValidateObjectMetaTrimsTrailingSlash(t *testing.T) { &api.ObjectMeta{Name: "test", GenerateName: "foo-"}, false, NameIsDNSSubdomain, - validation.NewFieldPath("field")) + field.NewPath("field")) if len(errs) != 0 { t.Fatalf("unexpected errors: %v", errs) } @@ -151,7 +151,7 @@ func TestValidateLabels(t *testing.T) { {"goodvalue": "123_-.BaR"}, } for i := range successCases { - errs := ValidateLabels(successCases[i], validation.NewFieldPath("field")) + errs := ValidateLabels(successCases[i], field.NewPath("field")) if len(errs) != 0 { t.Errorf("case[%d] expected success, got %#v", i, errs) } @@ -164,7 +164,7 @@ func TestValidateLabels(t *testing.T) { {strings.Repeat("a", 254): "bar"}, } for i := range labelNameErrorCases { - errs := ValidateLabels(labelNameErrorCases[i], validation.NewFieldPath("field")) + errs := ValidateLabels(labelNameErrorCases[i], field.NewPath("field")) if len(errs) != 1 { t.Errorf("case[%d] expected failure", i) } else { @@ -182,7 +182,7 @@ func TestValidateLabels(t *testing.T) { {"strangecharsinvalue": "?#$notsogood"}, } for i := range labelValueErrorCases { - errs := ValidateLabels(labelValueErrorCases[i], validation.NewFieldPath("field")) + errs := ValidateLabels(labelValueErrorCases[i], field.NewPath("field")) if len(errs) != 1 { t.Errorf("case[%d] expected failure", i) } else { @@ -216,7 +216,7 @@ func TestValidateAnnotations(t *testing.T) { }, } for i := range successCases { - errs := ValidateAnnotations(successCases[i], validation.NewFieldPath("field")) + errs := ValidateAnnotations(successCases[i], field.NewPath("field")) if len(errs) != 0 { t.Errorf("case[%d] expected success, got %#v", i, errs) } @@ -229,7 +229,7 @@ func TestValidateAnnotations(t *testing.T) { {strings.Repeat("a", 254): "bar"}, } for i := range nameErrorCases { - errs := ValidateAnnotations(nameErrorCases[i], validation.NewFieldPath("field")) + errs := ValidateAnnotations(nameErrorCases[i], field.NewPath("field")) if len(errs) != 1 { t.Errorf("case[%d] expected failure", i) } @@ -246,7 +246,7 @@ func TestValidateAnnotations(t *testing.T) { }, } for i := range totalSizeErrorCases { - errs := ValidateAnnotations(totalSizeErrorCases[i], validation.NewFieldPath("field")) + errs := ValidateAnnotations(totalSizeErrorCases[i], field.NewPath("field")) if len(errs) != 1 { t.Errorf("case[%d] expected failure", i) } @@ -509,7 +509,7 @@ func TestValidateVolumes(t *testing.T) { }}}}, {Name: "fc", VolumeSource: api.VolumeSource{FC: &api.FCVolumeSource{[]string{"some_wwn"}, &lun, "ext4", false}}}, } - names, errs := validateVolumes(successCase, validation.NewFieldPath("field")) + names, errs := validateVolumes(successCase, field.NewPath("field")) if len(errs) != 0 { t.Errorf("expected success: %v", errs) } @@ -558,128 +558,128 @@ func TestValidateVolumes(t *testing.T) { slashInName := api.VolumeSource{Flocker: &api.FlockerVolumeSource{DatasetName: "foo/bar"}} errorCases := map[string]struct { V []api.Volume - T validation.ErrorType + T field.ErrorType F string D string }{ "zero-length name": { []api.Volume{{Name: "", VolumeSource: emptyVS}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "name", "", }, "name > 63 characters": { []api.Volume{{Name: strings.Repeat("a", 64), VolumeSource: emptyVS}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "name", "must be a DNS label", }, "name not a DNS label": { []api.Volume{{Name: "a.b.c", VolumeSource: emptyVS}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "name", "must be a DNS label", }, "name not unique": { []api.Volume{{Name: "abc", VolumeSource: emptyVS}, {Name: "abc", VolumeSource: emptyVS}}, - validation.ErrorTypeDuplicate, + field.ErrorTypeDuplicate, "[1].name", "", }, "empty portal": { []api.Volume{{Name: "badportal", VolumeSource: emptyPortal}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "iscsi.targetPortal", "", }, "empty iqn": { []api.Volume{{Name: "badiqn", VolumeSource: emptyIQN}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "iscsi.iqn", "", }, "empty hosts": { []api.Volume{{Name: "badhost", VolumeSource: emptyHosts}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "glusterfs.endpoints", "", }, "empty path": { []api.Volume{{Name: "badpath", VolumeSource: emptyPath}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "glusterfs.path", "", }, "empty datasetName": { []api.Volume{{Name: "badname", VolumeSource: emptyName}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "flocker.datasetName", "", }, "empty mon": { []api.Volume{{Name: "badmon", VolumeSource: emptyMon}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "rbd.monitors", "", }, "empty image": { []api.Volume{{Name: "badimage", VolumeSource: emptyImage}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "rbd.image", "", }, "empty cephfs mon": { []api.Volume{{Name: "badmon", VolumeSource: emptyCephFSMon}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "cephfs.monitors", "", }, "empty metatada path": { []api.Volume{{Name: "emptyname", VolumeSource: emptyPathName}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "downwardAPI.path", "", }, "absolute path": { []api.Volume{{Name: "absolutepath", VolumeSource: absolutePathName}}, - validation.ErrorTypeForbidden, + field.ErrorTypeForbidden, "downwardAPI.path", "", }, "dot dot path": { []api.Volume{{Name: "dotdotpath", VolumeSource: dotDotInPath}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "downwardAPI.path", `must not contain ".."`, }, "dot dot file name": { []api.Volume{{Name: "dotdotfilename", VolumeSource: dotDotPathName}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "downwardAPI.path", `must not start with ".."`, }, "dot dot first level dirent": { []api.Volume{{Name: "dotdotdirfilename", VolumeSource: dotDotFirstLevelDirent}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "downwardAPI.path", `must not start with ".."`, }, "empty wwn": { []api.Volume{{Name: "badimage", VolumeSource: zeroWWN}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "fc.targetWWNs", "", }, "empty lun": { []api.Volume{{Name: "badimage", VolumeSource: emptyLun}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "fc.lun", "", }, "slash in datasetName": { []api.Volume{{Name: "slashinname", VolumeSource: slashInName}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "flocker.datasetName", "must not contain '/'", }, "starts with '..'": { []api.Volume{{Name: "badprefix", VolumeSource: startsWithDots}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "gitRepo.directory", `must not start with ".."`, }, "contains '..'": { []api.Volume{{Name: "containsdots", VolumeSource: containsDots}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "gitRepo.directory", `must not contain ".."`, }, "absolute target": { []api.Volume{{Name: "absolutetarget", VolumeSource: absPath}}, - validation.ErrorTypeForbidden, + field.ErrorTypeForbidden, "gitRepo.directory", "", }, } for k, v := range errorCases { - _, errs := validateVolumes(v.V, validation.NewFieldPath("field")) + _, errs := validateVolumes(v.V, field.NewPath("field")) if len(errs) == 0 { t.Errorf("expected failure %s for %v", k, v.V) continue @@ -706,36 +706,36 @@ func TestValidatePorts(t *testing.T) { {Name: "do-re-me", ContainerPort: 84, Protocol: "UDP"}, {ContainerPort: 85, Protocol: "TCP"}, } - if errs := validateContainerPorts(successCase, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateContainerPorts(successCase, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } nonCanonicalCase := []api.ContainerPort{ {ContainerPort: 80, Protocol: "TCP"}, } - if errs := validateContainerPorts(nonCanonicalCase, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateContainerPorts(nonCanonicalCase, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } errorCases := map[string]struct { P []api.ContainerPort - T validation.ErrorType + T field.ErrorType F string D string }{ "name > 15 characters": { []api.ContainerPort{{Name: strings.Repeat("a", 16), ContainerPort: 80, Protocol: "TCP"}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "name", PortNameErrorMsg, }, "name not a IANA svc name ": { []api.ContainerPort{{Name: "a.b.c", ContainerPort: 80, Protocol: "TCP"}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "name", PortNameErrorMsg, }, "name not a IANA svc name (i.e. a number)": { []api.ContainerPort{{Name: "80", ContainerPort: 80, Protocol: "TCP"}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "name", PortNameErrorMsg, }, "name not unique": { @@ -743,42 +743,42 @@ func TestValidatePorts(t *testing.T) { {Name: "abc", ContainerPort: 80, Protocol: "TCP"}, {Name: "abc", ContainerPort: 81, Protocol: "TCP"}, }, - validation.ErrorTypeDuplicate, + field.ErrorTypeDuplicate, "[1].name", "", }, "zero container port": { []api.ContainerPort{{ContainerPort: 0, Protocol: "TCP"}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "containerPort", PortRangeErrorMsg, }, "invalid container port": { []api.ContainerPort{{ContainerPort: 65536, Protocol: "TCP"}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "containerPort", PortRangeErrorMsg, }, "invalid host port": { []api.ContainerPort{{ContainerPort: 80, HostPort: 65536, Protocol: "TCP"}}, - validation.ErrorTypeInvalid, + field.ErrorTypeInvalid, "hostPort", PortRangeErrorMsg, }, "invalid protocol case": { []api.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}}, - validation.ErrorTypeNotSupported, + field.ErrorTypeNotSupported, "protocol", "supported values: TCP, UDP", }, "invalid protocol": { []api.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}}, - validation.ErrorTypeNotSupported, + field.ErrorTypeNotSupported, "protocol", "supported values: TCP, UDP", }, "protocol required": { []api.ContainerPort{{Name: "abc", ContainerPort: 80}}, - validation.ErrorTypeRequired, + field.ErrorTypeRequired, "protocol", "", }, } for k, v := range errorCases { - errs := validateContainerPorts(v.P, validation.NewFieldPath("field")) + errs := validateContainerPorts(v.P, field.NewPath("field")) if len(errs) == 0 { t.Errorf("expected failure for %s", k) } @@ -812,7 +812,7 @@ func TestValidateEnv(t *testing.T) { }, }, } - if errs := validateEnv(successCase, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateEnv(successCase, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } @@ -923,7 +923,7 @@ func TestValidateEnv(t *testing.T) { }, } for _, tc := range errorCases { - if errs := validateEnv(tc.envs, validation.NewFieldPath("field")); len(errs) == 0 { + if errs := validateEnv(tc.envs, field.NewPath("field")); len(errs) == 0 { t.Errorf("expected failure for %s", tc.name) } else { for i := range errs { @@ -944,7 +944,7 @@ func TestValidateVolumeMounts(t *testing.T) { {Name: "123", MountPath: "/foo"}, {Name: "abc-123", MountPath: "/bar"}, } - if errs := validateVolumeMounts(successCase, volumes, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateVolumeMounts(successCase, volumes, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } @@ -954,7 +954,7 @@ func TestValidateVolumeMounts(t *testing.T) { "empty mountpath": {{Name: "abc", MountPath: ""}}, } for k, v := range errorCases { - if errs := validateVolumeMounts(v, volumes, validation.NewFieldPath("field")); len(errs) == 0 { + if errs := validateVolumeMounts(v, volumes, field.NewPath("field")); len(errs) == 0 { t.Errorf("expected failure for %s", k) } } @@ -972,7 +972,7 @@ func TestValidateProbe(t *testing.T) { } for _, p := range successCases { - if errs := validateProbe(p, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateProbe(p, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } @@ -984,7 +984,7 @@ func TestValidateProbe(t *testing.T) { errorCases = append(errorCases, probe) } for _, p := range errorCases { - if errs := validateProbe(p, validation.NewFieldPath("field")); len(errs) == 0 { + if errs := validateProbe(p, field.NewPath("field")); len(errs) == 0 { t.Errorf("expected failure for %v", p) } } @@ -998,7 +998,7 @@ func TestValidateHandler(t *testing.T) { {HTTPGet: &api.HTTPGetAction{Path: "/", Port: intstr.FromString("port"), Host: "", Scheme: "HTTP"}}, } for _, h := range successCases { - if errs := validateHandler(&h, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateHandler(&h, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } @@ -1011,7 +1011,7 @@ func TestValidateHandler(t *testing.T) { {HTTPGet: &api.HTTPGetAction{Path: "", Port: intstr.FromString(""), Host: ""}}, } for _, h := range errorCases { - if errs := validateHandler(&h, validation.NewFieldPath("field")); len(errs) == 0 { + if errs := validateHandler(&h, field.NewPath("field")); len(errs) == 0 { t.Errorf("expected failure for %#v", h) } } @@ -1050,7 +1050,7 @@ func TestValidatePullPolicy(t *testing.T) { } for k, v := range testCases { ctr := &v.Container - errs := validatePullPolicy(ctr.ImagePullPolicy, validation.NewFieldPath("field")) + errs := validatePullPolicy(ctr.ImagePullPolicy, field.NewPath("field")) if len(errs) != 0 { t.Errorf("case[%s] expected success, got %#v", k, errs) } @@ -1166,7 +1166,7 @@ func TestValidateContainers(t *testing.T) { }, {Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", SecurityContext: fakeValidSecurityContext(true)}, } - if errs := validateContainers(successCase, volumes, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateContainers(successCase, volumes, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } @@ -1346,7 +1346,7 @@ func TestValidateContainers(t *testing.T) { }, } for k, v := range errorCases { - if errs := validateContainers(v, volumes, validation.NewFieldPath("field")); len(errs) == 0 { + if errs := validateContainers(v, volumes, field.NewPath("field")); len(errs) == 0 { t.Errorf("expected failure for %s", k) } } @@ -1359,7 +1359,7 @@ func TestValidateRestartPolicy(t *testing.T) { api.RestartPolicyNever, } for _, policy := range successCases { - if errs := validateRestartPolicy(&policy, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateRestartPolicy(&policy, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } @@ -1367,7 +1367,7 @@ func TestValidateRestartPolicy(t *testing.T) { errorCases := []api.RestartPolicy{"", "newpolicy"} for k, policy := range errorCases { - if errs := validateRestartPolicy(&policy, validation.NewFieldPath("field")); len(errs) == 0 { + if errs := validateRestartPolicy(&policy, field.NewPath("field")); len(errs) == 0 { t.Errorf("expected failure for %d", k) } } @@ -1376,14 +1376,14 @@ func TestValidateRestartPolicy(t *testing.T) { func TestValidateDNSPolicy(t *testing.T) { successCases := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault, api.DNSPolicy(api.DNSClusterFirst)} for _, policy := range successCases { - if errs := validateDNSPolicy(&policy, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := validateDNSPolicy(&policy, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } errorCases := []api.DNSPolicy{api.DNSPolicy("invalid")} for _, policy := range errorCases { - if errs := validateDNSPolicy(&policy, validation.NewFieldPath("field")); len(errs) == 0 { + if errs := validateDNSPolicy(&policy, field.NewPath("field")); len(errs) == 0 { t.Errorf("expected failure for %v", policy) } } @@ -1444,7 +1444,7 @@ func TestValidatePodSpec(t *testing.T) { }, } for i := range successCases { - if errs := ValidatePodSpec(&successCases[i], validation.NewFieldPath("field")); len(errs) != 0 { + if errs := ValidatePodSpec(&successCases[i], field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } @@ -1516,7 +1516,7 @@ func TestValidatePodSpec(t *testing.T) { }, } for k, v := range failureCases { - if errs := ValidatePodSpec(&v, validation.NewFieldPath("field")); len(errs) == 0 { + if errs := ValidatePodSpec(&v, field.NewPath("field")); len(errs) == 0 { t.Errorf("expected failure for %q", k) } } @@ -3191,7 +3191,7 @@ func TestValidateResourceNames(t *testing.T) { {"kubernetes.io/will/not/work/", false}, } for k, item := range table { - err := validateResourceName(item.input, validation.NewFieldPath("field")) + err := validateResourceName(item.input, field.NewPath("field")) if len(err) != 0 && item.success { t.Errorf("expected no failure for input %q", item.input) } else if len(err) == 0 && !item.success { @@ -3948,7 +3948,7 @@ func TestValidateEndpoints(t *testing.T) { errorCases := map[string]struct { endpoints api.Endpoints - errorType validation.ErrorType + errorType field.ErrorType errorDetail string }{ "missing namespace": { @@ -4171,7 +4171,7 @@ func TestValidateSecurityContext(t *testing.T) { "no run as user": {noRunAsUser}, } for k, v := range successCases { - if errs := ValidateSecurityContext(v.sc, validation.NewFieldPath("field")); len(errs) != 0 { + if errs := ValidateSecurityContext(v.sc, field.NewPath("field")); len(errs) != 0 { t.Errorf("Expected success for %s, got %v", k, errs) } } @@ -4186,7 +4186,7 @@ func TestValidateSecurityContext(t *testing.T) { errorCases := map[string]struct { sc *api.SecurityContext - errorType validation.ErrorType + errorType field.ErrorType errorDetail string }{ "request privileged when capabilities forbids": { @@ -4201,7 +4201,7 @@ func TestValidateSecurityContext(t *testing.T) { }, } for k, v := range errorCases { - if errs := ValidateSecurityContext(v.sc, validation.NewFieldPath("field")); len(errs) == 0 || errs[0].Type != v.errorType || errs[0].Detail != v.errorDetail { + if errs := ValidateSecurityContext(v.sc, field.NewPath("field")); len(errs) == 0 || errs[0].Type != v.errorType || errs[0].Detail != v.errorDetail { t.Errorf("Expected error type %s with detail %s for %s, got %v", v.errorType, v.errorDetail, k, errs) } } diff --git a/pkg/apis/extensions/validation/validation.go b/pkg/apis/extensions/validation/validation.go index 0d393216cd88b..ac347500549dd 100644 --- a/pkg/apis/extensions/validation/validation.go +++ b/pkg/apis/extensions/validation/validation.go @@ -29,6 +29,7 @@ import ( "k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // ValidateHorizontalPodAutoscaler can be used to check whether the given autoscaler name is valid. @@ -38,77 +39,73 @@ func ValidateHorizontalPodAutoscalerName(name string, prefix bool) (bool, string return apivalidation.ValidateReplicationControllerName(name, prefix) } -func validateHorizontalPodAutoscalerSpec(autoscaler extensions.HorizontalPodAutoscalerSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateHorizontalPodAutoscalerSpec(autoscaler extensions.HorizontalPodAutoscalerSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if autoscaler.MinReplicas != nil && *autoscaler.MinReplicas < 1 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("minReplicas"), autoscaler.MinReplicas, `must be greater than or equal to 1`)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("minReplicas"), autoscaler.MinReplicas, `must be greater than or equal to 1`)) } if autoscaler.MaxReplicas < 1 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, `must be greater than or equal to 1`)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, `must be greater than or equal to 1`)) } if autoscaler.MinReplicas != nil && autoscaler.MaxReplicas < *autoscaler.MinReplicas { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, `must be greater than or equal to minReplicas`)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, `must be greater than or equal to minReplicas`)) } if autoscaler.CPUUtilization != nil && autoscaler.CPUUtilization.TargetPercentage < 1 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("cpuUtilization", "targetPercentage"), autoscaler.CPUUtilization.TargetPercentage, `must be greater than or equal to 1`)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("cpuUtilization", "targetPercentage"), autoscaler.CPUUtilization.TargetPercentage, `must be greater than or equal to 1`)) } if refErrs := ValidateSubresourceReference(autoscaler.ScaleRef, fldPath.Child("scaleRef")); len(refErrs) > 0 { allErrs = append(allErrs, refErrs...) } else if autoscaler.ScaleRef.Subresource != "scale" { - allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("scaleRef", "subresource"), autoscaler.ScaleRef.Subresource, []string{"scale"})) + allErrs = append(allErrs, field.NotSupported(fldPath.Child("scaleRef", "subresource"), autoscaler.ScaleRef.Subresource, []string{"scale"})) } return allErrs } -func ValidateSubresourceReference(ref extensions.SubresourceReference, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateSubresourceReference(ref extensions.SubresourceReference, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(ref.Kind) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("kind"))) + allErrs = append(allErrs, field.Required(fldPath.Child("kind"))) } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Kind); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("kind"), ref.Kind, msg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ref.Kind, msg)) } if len(ref.Name) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("name"))) + allErrs = append(allErrs, field.Required(fldPath.Child("name"))) } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Name); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("name"), ref.Name, msg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ref.Name, msg)) } if len(ref.Subresource) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("subresource"))) + allErrs = append(allErrs, field.Required(fldPath.Child("subresource"))) } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Subresource); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("subresource"), ref.Subresource, msg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("subresource"), ref.Subresource, msg)) } return allErrs } -func ValidateHorizontalPodAutoscaler(autoscaler *extensions.HorizontalPodAutoscaler) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, validation.NewFieldPath("spec"))...) +func ValidateHorizontalPodAutoscaler(autoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList { + allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata")) + allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...) return allErrs } -func ValidateHorizontalPodAutoscalerUpdate(newAutoscaler, oldAutoscaler *extensions.HorizontalPodAutoscaler) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(newAutoscaler.Spec, validation.NewFieldPath("spec"))...) +func ValidateHorizontalPodAutoscalerUpdate(newAutoscaler, oldAutoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(newAutoscaler.Spec, field.NewPath("spec"))...) return allErrs } -func ValidateHorizontalPodAutoscalerStatusUpdate(controller, oldController *extensions.HorizontalPodAutoscaler) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, validation.NewFieldPath("metadata"))...) - +func ValidateHorizontalPodAutoscalerStatusUpdate(controller, oldController *extensions.HorizontalPodAutoscaler) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) status := controller.Status - allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.CurrentReplicas), validation.NewFieldPath("status", "currentReplicas"))...) - allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.DesiredReplicas), validation.NewFieldPath("status", "desiredReplicasa"))...) + allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.CurrentReplicas), field.NewPath("status", "currentReplicas"))...) + allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.DesiredReplicas), field.NewPath("status", "desiredReplicasa"))...) return allErrs } -func ValidateThirdPartyResourceUpdate(update, old *extensions.ThirdPartyResource) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateThirdPartyResourceUpdate(update, old *extensions.ThirdPartyResource) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))...) allErrs = append(allErrs, ValidateThirdPartyResource(update)...) return allErrs } @@ -117,18 +114,18 @@ func ValidateThirdPartyResourceName(name string, prefix bool) (bool, string) { return apivalidation.NameIsDNSSubdomain(name, prefix) } -func ValidateThirdPartyResource(obj *extensions.ThirdPartyResource) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateThirdPartyResourceName, validation.NewFieldPath("metadata"))...) +func ValidateThirdPartyResource(obj *extensions.ThirdPartyResource) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateThirdPartyResourceName, field.NewPath("metadata"))...) versions := sets.String{} for ix := range obj.Versions { version := &obj.Versions[ix] if len(version.Name) == 0 { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("versions").Index(ix).Child("name"), version, "can not be empty")) + allErrs = append(allErrs, field.Invalid(field.NewPath("versions").Index(ix).Child("name"), version, "can not be empty")) } if versions.Has(version.Name) { - allErrs = append(allErrs, validation.NewDuplicateError(validation.NewFieldPath("versions").Index(ix).Child("name"), version)) + allErrs = append(allErrs, field.Duplicate(field.NewPath("versions").Index(ix).Child("name"), version)) } versions.Insert(version.Name) } @@ -136,25 +133,23 @@ func ValidateThirdPartyResource(obj *extensions.ThirdPartyResource) validation.E } // ValidateDaemonSet tests if required fields in the DaemonSet are set. -func ValidateDaemonSet(controller *extensions.DaemonSet) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&controller.ObjectMeta, true, ValidateDaemonSetName, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, validation.NewFieldPath("spec"))...) +func ValidateDaemonSet(controller *extensions.DaemonSet) field.ErrorList { + allErrs := apivalidation.ValidateObjectMeta(&controller.ObjectMeta, true, ValidateDaemonSetName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, field.NewPath("spec"))...) return allErrs } // ValidateDaemonSetUpdate tests if required fields in the DaemonSet are set. -func ValidateDaemonSetUpdate(controller, oldController *extensions.DaemonSet) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, validation.NewFieldPath("spec"))...) - allErrs = append(allErrs, ValidateDaemonSetTemplateUpdate(controller.Spec.Template, oldController.Spec.Template, validation.NewFieldPath("spec", "template"))...) +func ValidateDaemonSetUpdate(controller, oldController *extensions.DaemonSet) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, field.NewPath("spec"))...) + allErrs = append(allErrs, ValidateDaemonSetTemplateUpdate(controller.Spec.Template, oldController.Spec.Template, field.NewPath("spec", "template"))...) return allErrs } // validateDaemonSetStatus validates a DaemonSetStatus -func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.CurrentNumberScheduled), fldPath.Child("currentNumberScheduled"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.NumberMisscheduled), fldPath.Child("numberMisscheduled"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.DesiredNumberScheduled), fldPath.Child("desiredNumberScheduled"))...) @@ -162,16 +157,15 @@ func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *valida } // ValidateDaemonSetStatus validates tests if required fields in the DaemonSet Status section -func ValidateDaemonSetStatusUpdate(controller, oldController *extensions.DaemonSet) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, validateDaemonSetStatus(&controller.Status, validation.NewFieldPath("status"))...) +func ValidateDaemonSetStatusUpdate(controller, oldController *extensions.DaemonSet) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, validateDaemonSetStatus(&controller.Status, field.NewPath("status"))...) return allErrs } // ValidateDaemonSetTemplateUpdate tests that certain fields in the daemon set's pod template are not updated. -func ValidateDaemonSetTemplateUpdate(podTemplate, oldPodTemplate *api.PodTemplateSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateDaemonSetTemplateUpdate(podTemplate, oldPodTemplate *api.PodTemplateSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} podSpec := podTemplate.Spec // podTemplate.Spec is not a pointer, so we can modify NodeSelector and NodeName directly. podSpec.NodeSelector = oldPodTemplate.Spec.NodeSelector @@ -179,25 +173,25 @@ func ValidateDaemonSetTemplateUpdate(podTemplate, oldPodTemplate *api.PodTemplat // In particular, we do not allow updates to container images at this point. if !api.Semantic.DeepEqual(oldPodTemplate.Spec, podSpec) { // TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("spec"), "content of spec is not printed out, please refer to the \"details\"", "may not update fields other than spec.nodeSelector")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("spec"), "content of spec is not printed out, please refer to the \"details\"", "may not update fields other than spec.nodeSelector")) } return allErrs } // ValidateDaemonSetSpec tests if required fields in the DaemonSetSpec are set. -func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) if spec.Template == nil { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("template"))) + allErrs = append(allErrs, field.Required(fldPath.Child("template"))) return allErrs } selector, err := extensions.LabelSelectorAsSelector(spec.Selector) if err == nil && !selector.Matches(labels.Set(spec.Template.Labels)) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "selector does not match template")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "selector does not match template")) } allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(spec.Template, fldPath.Child("template"))...) @@ -205,7 +199,7 @@ func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec, fldPath *validation.F allErrs = append(allErrs, apivalidation.ValidateReadOnlyPersistentDisks(spec.Template.Spec.Volumes, fldPath.Child("template", "spec", "volumes"))...) // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec(). if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways { - allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) + allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) } return allErrs @@ -223,11 +217,11 @@ func ValidateDeploymentName(name string, prefix bool) (bool, string) { return apivalidation.NameIsDNSSubdomain(name, prefix) } -func ValidatePositiveIntOrPercent(intOrPercent intstr.IntOrString, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidatePositiveIntOrPercent(intOrPercent intstr.IntOrString, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if intOrPercent.Type == intstr.String { if !validation.IsValidPercent(intOrPercent.StrVal) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath, intOrPercent, "value should be int(5) or percentage(5%)")) + allErrs = append(allErrs, field.Invalid(fldPath, intOrPercent, "value should be int(5) or percentage(5%)")) } } else if intOrPercent.Type == intstr.Int { allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(intOrPercent.IntValue()), fldPath)...) @@ -251,23 +245,23 @@ func getIntOrPercentValue(intOrStringValue intstr.IntOrString) int { return intOrStringValue.IntValue() } -func IsNotMoreThan100Percent(intOrStringValue intstr.IntOrString, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func IsNotMoreThan100Percent(intOrStringValue intstr.IntOrString, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} value, isPercent := getPercentValue(intOrStringValue) if !isPercent || value <= 100 { return nil } - allErrs = append(allErrs, validation.NewInvalidError(fldPath, intOrStringValue, "should not be more than 100%")) + allErrs = append(allErrs, field.Invalid(fldPath, intOrStringValue, "should not be more than 100%")) return allErrs } -func ValidateRollingUpdateDeployment(rollingUpdate *extensions.RollingUpdateDeployment, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateRollingUpdateDeployment(rollingUpdate *extensions.RollingUpdateDeployment, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, ValidatePositiveIntOrPercent(rollingUpdate.MaxUnavailable, fldPath.Child("maxUnavailable"))...) allErrs = append(allErrs, ValidatePositiveIntOrPercent(rollingUpdate.MaxSurge, fldPath.Child("maxSurge"))...) if getIntOrPercentValue(rollingUpdate.MaxUnavailable) == 0 && getIntOrPercentValue(rollingUpdate.MaxSurge) == 0 { // Both MaxSurge and MaxUnavailable cannot be zero. - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("maxUnavailable"), rollingUpdate.MaxUnavailable, "cannot be 0 when maxSurge is 0 as well")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("maxUnavailable"), rollingUpdate.MaxUnavailable, "cannot be 0 when maxSurge is 0 as well")) } // Validate that MaxUnavailable is not more than 100%. allErrs = append(allErrs, IsNotMoreThan100Percent(rollingUpdate.MaxUnavailable, fldPath.Child("maxUnavailable"))...) @@ -275,14 +269,14 @@ func ValidateRollingUpdateDeployment(rollingUpdate *extensions.RollingUpdateDepl return allErrs } -func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if strategy.RollingUpdate == nil { return allErrs } switch strategy.Type { case extensions.RecreateDeploymentStrategyType: - allErrs = append(allErrs, validation.NewForbiddenError(fldPath.Child("rollingUpdate"), "should be nil when strategy type is "+extensions.RecreateDeploymentStrategyType)) + allErrs = append(allErrs, field.Forbidden(fldPath.Child("rollingUpdate"), "should be nil when strategy type is "+extensions.RecreateDeploymentStrategyType)) case extensions.RollingUpdateDeploymentStrategyType: allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...) } @@ -290,8 +284,8 @@ func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath } // Validates given deployment spec. -func ValidateDeploymentSpec(spec *extensions.DeploymentSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateDeploymentSpec(spec *extensions.DeploymentSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateNonEmptySelector(spec.Selector, fldPath.Child("selector"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(spec.Replicas), fldPath.Child("replicas"))...) allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpecForRC(&spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"))...) @@ -303,42 +297,39 @@ func ValidateDeploymentSpec(spec *extensions.DeploymentSpec, fldPath *validation return allErrs } -func ValidateDeploymentUpdate(update, old *extensions.Deployment) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateDeploymentSpec(&update.Spec, validation.NewFieldPath("spec"))...) +func ValidateDeploymentUpdate(update, old *extensions.Deployment) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateDeploymentSpec(&update.Spec, field.NewPath("spec"))...) return allErrs } -func ValidateDeployment(obj *extensions.Deployment) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateDeploymentName, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateDeploymentSpec(&obj.Spec, validation.NewFieldPath("spec"))...) +func ValidateDeployment(obj *extensions.Deployment) field.ErrorList { + allErrs := apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateDeploymentName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateDeploymentSpec(&obj.Spec, field.NewPath("spec"))...) return allErrs } -func ValidateThirdPartyResourceDataUpdate(update, old *extensions.ThirdPartyResourceData) validation.ErrorList { +func ValidateThirdPartyResourceDataUpdate(update, old *extensions.ThirdPartyResourceData) field.ErrorList { return ValidateThirdPartyResourceData(update) } -func ValidateThirdPartyResourceData(obj *extensions.ThirdPartyResourceData) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateThirdPartyResourceData(obj *extensions.ThirdPartyResourceData) field.ErrorList { + allErrs := field.ErrorList{} if len(obj.Name) == 0 { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("name"), obj.Name, "must be non-empty")) + allErrs = append(allErrs, field.Invalid(field.NewPath("name"), obj.Name, "must be non-empty")) } return allErrs } -func ValidateJob(job *extensions.Job) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateJob(job *extensions.Job) field.ErrorList { // Jobs and rcs have the same name validation - allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&job.ObjectMeta, true, apivalidation.ValidateReplicationControllerName, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateJobSpec(&job.Spec, validation.NewFieldPath("spec"))...) + allErrs := apivalidation.ValidateObjectMeta(&job.ObjectMeta, true, apivalidation.ValidateReplicationControllerName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateJobSpec(&job.Spec, field.NewPath("spec"))...) return allErrs } -func ValidateJobSpec(spec *extensions.JobSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateJobSpec(spec *extensions.JobSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if spec.Parallelism != nil { allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(*spec.Parallelism), fldPath.Child("parallelism"))...) @@ -347,7 +338,7 @@ func ValidateJobSpec(spec *extensions.JobSpec, fldPath *validation.FieldPath) va allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(*spec.Completions), fldPath.Child("completions"))...) } if spec.Selector == nil { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("selector"))) + allErrs = append(allErrs, field.Required(fldPath.Child("selector"))) } else { allErrs = append(allErrs, ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) } @@ -355,43 +346,41 @@ func ValidateJobSpec(spec *extensions.JobSpec, fldPath *validation.FieldPath) va if selector, err := extensions.LabelSelectorAsSelector(spec.Selector); err == nil { labels := labels.Set(spec.Template.Labels) if !selector.Matches(labels) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "selector does not match template")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "selector does not match template")) } } allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(&spec.Template, fldPath.Child("template"))...) if spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure && spec.Template.Spec.RestartPolicy != api.RestartPolicyNever { - allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("template", "spec", "restartPolicy"), + allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)})) } return allErrs } -func ValidateJobStatus(status *extensions.JobStatus, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateJobStatus(status *extensions.JobStatus, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.Active), fldPath.Child("active"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.Succeeded), fldPath.Child("succeeded"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.Failed), fldPath.Child("failed"))...) return allErrs } -func ValidateJobUpdate(job, oldJob *extensions.Job) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateJobSpecUpdate(job.Spec, oldJob.Spec, validation.NewFieldPath("spec"))...) +func ValidateJobUpdate(job, oldJob *extensions.Job) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateJobSpecUpdate(job.Spec, oldJob.Spec, field.NewPath("spec"))...) return allErrs } -func ValidateJobUpdateStatus(job, oldJob *extensions.Job) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, validation.NewFieldPath("metadata"))...) +func ValidateJobUpdateStatus(job, oldJob *extensions.Job) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, ValidateJobStatusUpdate(job.Status, oldJob.Status)...) return allErrs } -func ValidateJobSpecUpdate(spec, oldSpec extensions.JobSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateJobSpecUpdate(spec, oldSpec extensions.JobSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} allErrs = append(allErrs, ValidateJobSpec(&spec, fldPath)...) allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Completions, oldSpec.Completions, fldPath.Child("completions"))...) allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Selector, oldSpec.Selector, fldPath.Child("selector"))...) @@ -399,17 +388,16 @@ func ValidateJobSpecUpdate(spec, oldSpec extensions.JobSpec, fldPath *validation return allErrs } -func ValidateJobStatusUpdate(status, oldStatus extensions.JobStatus) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, ValidateJobStatus(&status, validation.NewFieldPath("status"))...) +func ValidateJobStatusUpdate(status, oldStatus extensions.JobStatus) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, ValidateJobStatus(&status, field.NewPath("status"))...) return allErrs } // ValidateIngress tests if required fields in the Ingress are set. -func ValidateIngress(ingress *extensions.Ingress) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&ingress.ObjectMeta, true, ValidateIngressName, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, validation.NewFieldPath("spec"))...) +func ValidateIngress(ingress *extensions.Ingress) field.ErrorList { + allErrs := apivalidation.ValidateObjectMeta(&ingress.ObjectMeta, true, ValidateIngressName, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, field.NewPath("spec"))...) return allErrs } @@ -419,13 +407,13 @@ func ValidateIngressName(name string, prefix bool) (bool, string) { } // ValidateIngressSpec tests if required fields in the IngressSpec are set. -func ValidateIngressSpec(spec *extensions.IngressSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateIngressSpec(spec *extensions.IngressSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} // TODO: Is a default backend mandatory? if spec.Backend != nil { allErrs = append(allErrs, validateIngressBackend(spec.Backend, fldPath.Child("backend"))...) } else if len(spec.Rules) == 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("rules"), spec.Rules, "Either a default backend or a set of host rules are required for ingress.")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("rules"), spec.Rules, "Either a default backend or a set of host rules are required for ingress.")) } if len(spec.Rules) > 0 { allErrs = append(allErrs, validateIngressRules(spec.Rules, fldPath.Child("rules"))...) @@ -434,35 +422,33 @@ func ValidateIngressSpec(spec *extensions.IngressSpec, fldPath *validation.Field } // ValidateIngressUpdate tests if required fields in the Ingress are set. -func ValidateIngressUpdate(ingress, oldIngress *extensions.Ingress) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, validation.NewFieldPath("spec"))...) +func ValidateIngressUpdate(ingress, oldIngress *extensions.Ingress) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, field.NewPath("spec"))...) return allErrs } // ValidateIngressStatusUpdate tests if required fields in the Ingress are set when updating status. -func ValidateIngressStatusUpdate(ingress, oldIngress *extensions.Ingress) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, validation.NewFieldPath("metadata"))...) - allErrs = append(allErrs, apivalidation.ValidateLoadBalancerStatus(&ingress.Status.LoadBalancer, validation.NewFieldPath("status", "loadBalancer"))...) +func ValidateIngressStatusUpdate(ingress, oldIngress *extensions.Ingress) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, apivalidation.ValidateLoadBalancerStatus(&ingress.Status.LoadBalancer, field.NewPath("status", "loadBalancer"))...) return allErrs } -func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(IngressRules) == 0 { - return append(allErrs, validation.NewRequiredError(fldPath)) + return append(allErrs, field.Required(fldPath)) } for i, ih := range IngressRules { 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. if valid, errMsg := apivalidation.NameIsDNSSubdomain(ih.Host, false); !valid { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Index(i).Child("host"), ih.Host, errMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, errMsg)) } if isIP := (net.ParseIP(ih.Host) != nil); isIP { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Index(i).Child("host"), ih.Host, "Host must be a DNS name, not ip address")) + allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, "Host must be a DNS name, not ip address")) } } allErrs = append(allErrs, validateIngressRuleValue(&ih.IngressRuleValue, fldPath.Index(0))...) @@ -470,23 +456,23 @@ func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *valida return allErrs } -func validateIngressRuleValue(ingressRule *extensions.IngressRuleValue, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateIngressRuleValue(ingressRule *extensions.IngressRuleValue, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if ingressRule.HTTP != nil { allErrs = append(allErrs, validateHTTPIngressRuleValue(ingressRule.HTTP, fldPath.Child("http"))...) } return allErrs } -func validateHTTPIngressRuleValue(httpIngressRuleValue *extensions.HTTPIngressRuleValue, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateHTTPIngressRuleValue(httpIngressRuleValue *extensions.HTTPIngressRuleValue, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if len(httpIngressRuleValue.Paths) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("paths"))) + allErrs = append(allErrs, field.Required(fldPath.Child("paths"))) } for i, rule := range httpIngressRuleValue.Paths { if len(rule.Path) > 0 { if !strings.HasPrefix(rule.Path, "/") { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("paths").Index(i).Child("path"), rule.Path, "must begin with /")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("paths").Index(i).Child("path"), rule.Path, "must begin with /")) } // TODO: More draconian path regex validation. // Path must be a valid regex. This is the basic requirement. @@ -499,7 +485,7 @@ func validateHTTPIngressRuleValue(httpIngressRuleValue *extensions.HTTPIngressRu // the user is confusing url regexes with path regexes. _, err := regexp.CompilePOSIX(rule.Path) if err != nil { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("paths").Index(i).Child("path"), rule.Path, "must be a valid regex.")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("paths").Index(i).Child("path"), rule.Path, "must be a valid regex.")) } } allErrs = append(allErrs, validateIngressBackend(&rule.Backend, fldPath.Child("backend"))...) @@ -508,67 +494,67 @@ func validateHTTPIngressRuleValue(httpIngressRuleValue *extensions.HTTPIngressRu } // validateIngressBackend tests if a given backend is valid. -func validateIngressBackend(backend *extensions.IngressBackend, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateIngressBackend(backend *extensions.IngressBackend, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} // All backends must reference a single local service by name, and a single service port by name or number. if len(backend.ServiceName) == 0 { - return append(allErrs, validation.NewRequiredError(fldPath.Child("serviceName"))) + return append(allErrs, field.Required(fldPath.Child("serviceName"))) } else if ok, errMsg := apivalidation.ValidateServiceName(backend.ServiceName, false); !ok { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("serviceName"), backend.ServiceName, errMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("serviceName"), backend.ServiceName, errMsg)) } if backend.ServicePort.Type == intstr.String { if !validation.IsDNS1123Label(backend.ServicePort.StrVal) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort.StrVal, apivalidation.DNS1123LabelErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("servicePort"), backend.ServicePort.StrVal, apivalidation.DNS1123LabelErrorMsg)) } if !validation.IsValidPortName(backend.ServicePort.StrVal) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort.StrVal, apivalidation.PortNameErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("servicePort"), backend.ServicePort.StrVal, apivalidation.PortNameErrorMsg)) } } else if !validation.IsValidPortNum(backend.ServicePort.IntValue()) { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort, apivalidation.PortRangeErrorMsg)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("servicePort"), backend.ServicePort, apivalidation.PortRangeErrorMsg)) } return allErrs } -func validateClusterAutoscalerSpec(spec extensions.ClusterAutoscalerSpec, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func validateClusterAutoscalerSpec(spec extensions.ClusterAutoscalerSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if spec.MinNodes < 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("minNodes"), spec.MinNodes, `must be non-negative`)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("minNodes"), spec.MinNodes, `must be non-negative`)) } if spec.MaxNodes < spec.MinNodes { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("maxNodes"), spec.MaxNodes, `must be greater than or equal to minNodes`)) + allErrs = append(allErrs, field.Invalid(fldPath.Child("maxNodes"), spec.MaxNodes, `must be greater than or equal to minNodes`)) } if len(spec.TargetUtilization) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("targetUtilization"))) + allErrs = append(allErrs, field.Required(fldPath.Child("targetUtilization"))) } for _, target := range spec.TargetUtilization { if len(target.Resource) == 0 { - allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("targetUtilization", "resource"))) + allErrs = append(allErrs, field.Required(fldPath.Child("targetUtilization", "resource"))) } if target.Value <= 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("targetUtilization", "value"), target.Value, "must be greater than 0")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("targetUtilization", "value"), target.Value, "must be greater than 0")) } if target.Value > 1 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("targetUtilization", "value"), target.Value, "must be less or equal 1")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("targetUtilization", "value"), target.Value, "must be less or equal 1")) } } return allErrs } -func ValidateClusterAutoscaler(autoscaler *extensions.ClusterAutoscaler) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateClusterAutoscaler(autoscaler *extensions.ClusterAutoscaler) field.ErrorList { + allErrs := field.ErrorList{} if autoscaler.Name != "ClusterAutoscaler" { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("metadata", "name"), autoscaler.Name, `name must be ClusterAutoscaler`)) + allErrs = append(allErrs, field.Invalid(field.NewPath("metadata", "name"), autoscaler.Name, `name must be ClusterAutoscaler`)) } if autoscaler.Namespace != api.NamespaceDefault { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("metadata", "namespace"), autoscaler.Namespace, `namespace must be default`)) + allErrs = append(allErrs, field.Invalid(field.NewPath("metadata", "namespace"), autoscaler.Namespace, `namespace must be default`)) } - allErrs = append(allErrs, validateClusterAutoscalerSpec(autoscaler.Spec, validation.NewFieldPath("spec"))...) + allErrs = append(allErrs, validateClusterAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...) return allErrs } -func ValidateLabelSelector(ps *extensions.LabelSelector, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateLabelSelector(ps *extensions.LabelSelector, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} if ps == nil { return allErrs } @@ -579,30 +565,30 @@ func ValidateLabelSelector(ps *extensions.LabelSelector, fldPath *validation.Fie return allErrs } -func ValidateLabelSelectorRequirement(sr extensions.LabelSelectorRequirement, fldPath *validation.FieldPath) validation.ErrorList { - allErrs := validation.ErrorList{} +func ValidateLabelSelectorRequirement(sr extensions.LabelSelectorRequirement, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} switch sr.Operator { case extensions.LabelSelectorOpIn, extensions.LabelSelectorOpNotIn: if len(sr.Values) == 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("values"), sr.Values, "must be non-empty when operator is In or NotIn")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("values"), sr.Values, "must be non-empty when operator is In or NotIn")) } case extensions.LabelSelectorOpExists, extensions.LabelSelectorOpDoesNotExist: if len(sr.Values) > 0 { - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("values"), sr.Values, "must be empty when operator is Exists or DoesNotExist")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("values"), sr.Values, "must be empty when operator is Exists or DoesNotExist")) } default: - allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("operator"), sr.Operator, "not a valid pod selector operator")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), sr.Operator, "not a valid pod selector operator")) } allErrs = append(allErrs, apivalidation.ValidateLabelName(sr.Key, fldPath.Child("key"))...) return allErrs } -func ValidateScale(scale *extensions.Scale) validation.ErrorList { - allErrs := validation.ErrorList{} - allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&scale.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, validation.NewFieldPath("metadata"))...) +func ValidateScale(scale *extensions.Scale) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&scale.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...) if scale.Spec.Replicas < 0 { - allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("spec", "replicas"), scale.Spec.Replicas, "must be non-negative")) + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "replicas"), scale.Spec.Replicas, "must be non-negative")) } return allErrs diff --git a/pkg/kubectl/cmd/util/helpers_test.go b/pkg/kubectl/cmd/util/helpers_test.go index 84536b615b2ef..ef641d98d0eeb 100644 --- a/pkg/kubectl/cmd/util/helpers_test.go +++ b/pkg/kubectl/cmd/util/helpers_test.go @@ -31,7 +31,7 @@ import ( "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/runtime" - "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) func TestMerge(t *testing.T) { @@ -274,15 +274,15 @@ func TestCheckInvalidErr(t *testing.T) { expected string }{ { - errors.NewInvalid("Invalid1", "invalidation", validation.ErrorList{validation.NewInvalidError(validation.NewFieldPath("field"), "single", "details")}), + errors.NewInvalid("Invalid1", "invalidation", field.ErrorList{field.Invalid(field.NewPath("field"), "single", "details")}), `Error from server: Invalid1 "invalidation" is invalid: field: invalid value 'single', Details: details`, }, { - errors.NewInvalid("Invalid2", "invalidation", validation.ErrorList{validation.NewInvalidError(validation.NewFieldPath("field1"), "multi1", "details"), validation.NewInvalidError(validation.NewFieldPath("field2"), "multi2", "details")}), + errors.NewInvalid("Invalid2", "invalidation", field.ErrorList{field.Invalid(field.NewPath("field1"), "multi1", "details"), field.Invalid(field.NewPath("field2"), "multi2", "details")}), `Error from server: Invalid2 "invalidation" is invalid: [field1: invalid value 'multi1', Details: details, field2: invalid value 'multi2', Details: details]`, }, { - errors.NewInvalid("Invalid3", "invalidation", validation.ErrorList{}), + errors.NewInvalid("Invalid3", "invalidation", field.ErrorList{}), `Error from server: Invalid3 "invalidation" is invalid: `, }, } diff --git a/pkg/kubelet/config/config.go b/pkg/kubelet/config/config.go index 8f481dbd8bc0b..6caea27986a43 100644 --- a/pkg/kubelet/config/config.go +++ b/pkg/kubelet/config/config.go @@ -30,7 +30,7 @@ import ( "k8s.io/kubernetes/pkg/kubelet/util/format" "k8s.io/kubernetes/pkg/util/config" "k8s.io/kubernetes/pkg/util/sets" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // PodConfigNotificationMode describes how changes are sent to the update channel. @@ -309,7 +309,7 @@ func (s *podStorage) seenSources(sources ...string) bool { func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventRecorder) (filtered []*api.Pod) { names := sets.String{} for i, pod := range pods { - var errlist utilvalidation.ErrorList + var errlist field.ErrorList if errs := validation.ValidatePod(pod); len(errs) != 0 { errlist = append(errlist, errs...) // If validation fails, don't trust it any further - @@ -317,8 +317,9 @@ func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventReco } else { name := kubecontainer.GetPodFullName(pod) if names.Has(name) { - //FIXME: this implies an API version - errlist = append(errlist, utilvalidation.NewDuplicateError(utilvalidation.NewFieldPath("metadata", "name"), pod.Name)) + // TODO: when validation becomes versioned, this gets a bit + // more complicated. + errlist = append(errlist, field.Duplicate(field.NewPath("metadata", "name"), pod.Name)) } else { names.Insert(name) } diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 75bffa8f5bd74..80d150ce5062d 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -77,7 +77,7 @@ import ( "k8s.io/kubernetes/pkg/util/procfs" "k8s.io/kubernetes/pkg/util/selinux" "k8s.io/kubernetes/pkg/util/sets" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/util/yaml" "k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/pkg/volume" @@ -2178,7 +2178,7 @@ func (s podsByCreationTime) Less(i, j int) bool { func hasHostPortConflicts(pods []*api.Pod) bool { ports := sets.String{} for _, pod := range pods { - if errs := validation.AccumulateUniqueHostPorts(pod.Spec.Containers, &ports, utilvalidation.NewFieldPath("spec", "containers")); len(errs) > 0 { + if errs := validation.AccumulateUniqueHostPorts(pod.Spec.Containers, &ports, field.NewPath("spec", "containers")); len(errs) > 0 { glog.Errorf("Pod %q: HostPort is already allocated, ignoring: %v", kubecontainer.GetPodFullName(pod), errs) return true } diff --git a/pkg/registry/controller/strategy.go b/pkg/registry/controller/strategy.go index a27bd2ca5fe6b..0ef9fba00b5a5 100644 --- a/pkg/registry/controller/strategy.go +++ b/pkg/registry/controller/strategy.go @@ -27,7 +27,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // rcStrategy implements verification logic for Replication Controllers. @@ -76,7 +76,7 @@ func (rcStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new replication controller. -func (rcStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (rcStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { controller := obj.(*api.ReplicationController) return validation.ValidateReplicationController(controller) } @@ -92,7 +92,7 @@ func (rcStrategy) AllowCreateOnUpdate() bool { } // ValidateUpdate is the default update validation for an end user. -func (rcStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (rcStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { validationErrorList := validation.ValidateReplicationController(obj.(*api.ReplicationController)) updateErrorList := validation.ValidateReplicationControllerUpdate(obj.(*api.ReplicationController), old.(*api.ReplicationController)) return append(validationErrorList, updateErrorList...) @@ -141,6 +141,6 @@ func (rcStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { newRc.Spec = oldRc.Spec } -func (rcStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (rcStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateReplicationControllerStatusUpdate(obj.(*api.ReplicationController), old.(*api.ReplicationController)) } diff --git a/pkg/registry/daemonset/strategy.go b/pkg/registry/daemonset/strategy.go index 1dccd1f02317b..044d779b43e4c 100644 --- a/pkg/registry/daemonset/strategy.go +++ b/pkg/registry/daemonset/strategy.go @@ -27,7 +27,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // daemonSetStrategy implements verification logic for daemon sets. @@ -77,7 +77,7 @@ func (daemonSetStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new daemon set. -func (daemonSetStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (daemonSetStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { daemonSet := obj.(*extensions.DaemonSet) return validation.ValidateDaemonSet(daemonSet) } @@ -93,7 +93,7 @@ func (daemonSetStrategy) AllowCreateOnUpdate() bool { } // ValidateUpdate is the default update validation for an end user. -func (daemonSetStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (daemonSetStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { validationErrorList := validation.ValidateDaemonSet(obj.(*extensions.DaemonSet)) updateErrorList := validation.ValidateDaemonSetUpdate(obj.(*extensions.DaemonSet), old.(*extensions.DaemonSet)) return append(validationErrorList, updateErrorList...) @@ -138,6 +138,6 @@ func (daemonSetStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { newDaemonSet.Spec = oldDaemonSet.Spec } -func (daemonSetStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (daemonSetStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateDaemonSetStatusUpdate(obj.(*extensions.DaemonSet), old.(*extensions.DaemonSet)) } diff --git a/pkg/registry/deployment/strategy.go b/pkg/registry/deployment/strategy.go index e3c8236b3fa43..87f283158136b 100644 --- a/pkg/registry/deployment/strategy.go +++ b/pkg/registry/deployment/strategy.go @@ -26,7 +26,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // deploymentStrategy implements behavior for Deployments. @@ -51,7 +51,7 @@ func (deploymentStrategy) PrepareForCreate(obj runtime.Object) { } // Validate validates a new deployment. -func (deploymentStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (deploymentStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { deployment := obj.(*extensions.Deployment) return validation.ValidateDeployment(deployment) } @@ -73,7 +73,7 @@ func (deploymentStrategy) PrepareForUpdate(obj, old runtime.Object) { } // ValidateUpdate is the default update validation for an end user. -func (deploymentStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (deploymentStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateDeploymentUpdate(obj.(*extensions.Deployment), old.(*extensions.Deployment)) } @@ -95,7 +95,7 @@ func (deploymentStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { } // ValidateUpdate is the default update validation for an end user updating status -func (deploymentStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (deploymentStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateDeploymentUpdate(obj.(*extensions.Deployment), old.(*extensions.Deployment)) } diff --git a/pkg/registry/endpoint/strategy.go b/pkg/registry/endpoint/strategy.go index fcd0c08b7205e..f6f6634a32236 100644 --- a/pkg/registry/endpoint/strategy.go +++ b/pkg/registry/endpoint/strategy.go @@ -26,7 +26,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // endpointsStrategy implements behavior for Endpoints @@ -53,7 +53,7 @@ func (endpointsStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new endpoints. -func (endpointsStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (endpointsStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { return validation.ValidateEndpoints(obj.(*api.Endpoints)) } @@ -69,7 +69,7 @@ func (endpointsStrategy) AllowCreateOnUpdate() bool { } // ValidateUpdate is the default update validation for an end user. -func (endpointsStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (endpointsStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { errorList := validation.ValidateEndpoints(obj.(*api.Endpoints)) return append(errorList, validation.ValidateEndpointsUpdate(obj.(*api.Endpoints), old.(*api.Endpoints))...) } diff --git a/pkg/registry/event/strategy.go b/pkg/registry/event/strategy.go index 3617206064e35..d9f628e76837a 100644 --- a/pkg/registry/event/strategy.go +++ b/pkg/registry/event/strategy.go @@ -26,7 +26,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) type eventStrategy struct { @@ -48,7 +48,7 @@ func (eventStrategy) PrepareForCreate(obj runtime.Object) { func (eventStrategy) PrepareForUpdate(obj, old runtime.Object) { } -func (eventStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (eventStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { event := obj.(*api.Event) return validation.ValidateEvent(event) } @@ -61,7 +61,7 @@ func (eventStrategy) AllowCreateOnUpdate() bool { return true } -func (eventStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (eventStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { event := obj.(*api.Event) return validation.ValidateEvent(event) } diff --git a/pkg/registry/generic/etcd/etcd_test.go b/pkg/registry/generic/etcd/etcd_test.go index e86262712ce3d..1ce4589d4d13d 100644 --- a/pkg/registry/generic/etcd/etcd_test.go +++ b/pkg/registry/generic/etcd/etcd_test.go @@ -32,7 +32,7 @@ import ( etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" storagetesting "k8s.io/kubernetes/pkg/storage/testing" "k8s.io/kubernetes/pkg/util/sets" - "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) type testRESTStrategy struct { @@ -49,10 +49,10 @@ func (t *testRESTStrategy) AllowUnconditionalUpdate() bool { return t.allowUncon func (t *testRESTStrategy) PrepareForCreate(obj runtime.Object) {} func (t *testRESTStrategy) PrepareForUpdate(obj, old runtime.Object) {} -func (t *testRESTStrategy) Validate(ctx api.Context, obj runtime.Object) validation.ErrorList { +func (t *testRESTStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { return nil } -func (t *testRESTStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) validation.ErrorList { +func (t *testRESTStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return nil } func (t *testRESTStrategy) Canonicalize(obj runtime.Object) {} diff --git a/pkg/registry/horizontalpodautoscaler/strategy.go b/pkg/registry/horizontalpodautoscaler/strategy.go index 6bc4c24914f93..623cf222441c5 100644 --- a/pkg/registry/horizontalpodautoscaler/strategy.go +++ b/pkg/registry/horizontalpodautoscaler/strategy.go @@ -26,7 +26,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // autoscalerStrategy implements behavior for HorizontalPodAutoscalers @@ -53,7 +53,7 @@ func (autoscalerStrategy) PrepareForCreate(obj runtime.Object) { } // Validate validates a new autoscaler. -func (autoscalerStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (autoscalerStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { autoscaler := obj.(*extensions.HorizontalPodAutoscaler) return validation.ValidateHorizontalPodAutoscaler(autoscaler) } @@ -76,7 +76,7 @@ func (autoscalerStrategy) PrepareForUpdate(obj, old runtime.Object) { } // ValidateUpdate is the default update validation for an end user. -func (autoscalerStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (autoscalerStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateHorizontalPodAutoscalerUpdate(obj.(*extensions.HorizontalPodAutoscaler), old.(*extensions.HorizontalPodAutoscaler)) } @@ -115,6 +115,6 @@ func (autoscalerStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { newAutoscaler.Spec = oldAutoscaler.Spec } -func (autoscalerStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (autoscalerStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateHorizontalPodAutoscalerStatusUpdate(obj.(*extensions.HorizontalPodAutoscaler), old.(*extensions.HorizontalPodAutoscaler)) } diff --git a/pkg/registry/ingress/strategy.go b/pkg/registry/ingress/strategy.go index bb94faa4cd645..92a596a5e574b 100644 --- a/pkg/registry/ingress/strategy.go +++ b/pkg/registry/ingress/strategy.go @@ -27,7 +27,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // ingressStrategy implements verification logic for Replication Ingresss. @@ -70,7 +70,7 @@ func (ingressStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new Ingress. -func (ingressStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (ingressStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { ingress := obj.(*extensions.Ingress) err := validation.ValidateIngress(ingress) return err @@ -86,7 +86,7 @@ func (ingressStrategy) AllowCreateOnUpdate() bool { } // ValidateUpdate is the default update validation for an end user. -func (ingressStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (ingressStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { validationErrorList := validation.ValidateIngress(obj.(*extensions.Ingress)) updateErrorList := validation.ValidateIngressUpdate(obj.(*extensions.Ingress), old.(*extensions.Ingress)) return append(validationErrorList, updateErrorList...) @@ -134,6 +134,6 @@ func (ingressStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { } // ValidateUpdate is the default update validation for an end user updating status -func (ingressStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (ingressStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateIngressStatusUpdate(obj.(*extensions.Ingress), old.(*extensions.Ingress)) } diff --git a/pkg/registry/job/strategy.go b/pkg/registry/job/strategy.go index 5f340f89d5485..807dc078a42e5 100644 --- a/pkg/registry/job/strategy.go +++ b/pkg/registry/job/strategy.go @@ -27,7 +27,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // jobStrategy implements verification logic for Replication Controllers. @@ -58,7 +58,7 @@ func (jobStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new job. -func (jobStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (jobStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { job := obj.(*extensions.Job) return validation.ValidateJob(job) } @@ -77,7 +77,7 @@ func (jobStrategy) AllowCreateOnUpdate() bool { } // ValidateUpdate is the default update validation for an end user. -func (jobStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (jobStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { validationErrorList := validation.ValidateJob(obj.(*extensions.Job)) updateErrorList := validation.ValidateJobUpdate(obj.(*extensions.Job), old.(*extensions.Job)) return append(validationErrorList, updateErrorList...) @@ -95,7 +95,7 @@ func (jobStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { newJob.Spec = oldJob.Spec } -func (jobStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (jobStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateJobUpdateStatus(obj.(*extensions.Job), old.(*extensions.Job)) } diff --git a/pkg/registry/limitrange/strategy.go b/pkg/registry/limitrange/strategy.go index b384ace6ff8e7..f9fd568225e49 100644 --- a/pkg/registry/limitrange/strategy.go +++ b/pkg/registry/limitrange/strategy.go @@ -26,7 +26,7 @@ import ( "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) type limitrangeStrategy struct { @@ -52,7 +52,7 @@ func (limitrangeStrategy) PrepareForCreate(obj runtime.Object) { func (limitrangeStrategy) PrepareForUpdate(obj, old runtime.Object) { } -func (limitrangeStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (limitrangeStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { limitRange := obj.(*api.LimitRange) return validation.ValidateLimitRange(limitRange) } @@ -65,7 +65,7 @@ func (limitrangeStrategy) AllowCreateOnUpdate() bool { return true } -func (limitrangeStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (limitrangeStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { limitRange := obj.(*api.LimitRange) return validation.ValidateLimitRange(limitRange) } diff --git a/pkg/registry/namespace/strategy.go b/pkg/registry/namespace/strategy.go index 9d571e3fa5541..3b069847c3628 100644 --- a/pkg/registry/namespace/strategy.go +++ b/pkg/registry/namespace/strategy.go @@ -25,7 +25,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // namespaceStrategy implements behavior for Namespaces @@ -77,7 +77,7 @@ func (namespaceStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new namespace. -func (namespaceStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (namespaceStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { namespace := obj.(*api.Namespace) return validation.ValidateNamespace(namespace) } @@ -92,7 +92,7 @@ func (namespaceStrategy) AllowCreateOnUpdate() bool { } // ValidateUpdate is the default update validation for an end user. -func (namespaceStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (namespaceStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { errorList := validation.ValidateNamespace(obj.(*api.Namespace)) return append(errorList, validation.ValidateNamespaceUpdate(obj.(*api.Namespace), old.(*api.Namespace))...) } @@ -113,7 +113,7 @@ func (namespaceStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { newNamespace.Spec = oldNamespace.Spec } -func (namespaceStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (namespaceStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateNamespaceStatusUpdate(obj.(*api.Namespace), old.(*api.Namespace)) } @@ -123,7 +123,7 @@ type namespaceFinalizeStrategy struct { var FinalizeStrategy = namespaceFinalizeStrategy{Strategy} -func (namespaceFinalizeStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (namespaceFinalizeStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateNamespaceFinalizeUpdate(obj.(*api.Namespace), old.(*api.Namespace)) } diff --git a/pkg/registry/node/strategy.go b/pkg/registry/node/strategy.go index 3aab4e2639702..ab9b3632a750d 100644 --- a/pkg/registry/node/strategy.go +++ b/pkg/registry/node/strategy.go @@ -34,7 +34,7 @@ import ( "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util" nodeutil "k8s.io/kubernetes/pkg/util/node" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // nodeStrategy implements behavior for nodes @@ -71,7 +71,7 @@ func (nodeStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new node. -func (nodeStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (nodeStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { node := obj.(*api.Node) return validation.ValidateNode(node) } @@ -81,7 +81,7 @@ func (nodeStrategy) Canonicalize(obj runtime.Object) { } // ValidateUpdate is the default update validation for an end user. -func (nodeStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (nodeStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { errorList := validation.ValidateNode(obj.(*api.Node)) return append(errorList, validation.ValidateNodeUpdate(obj.(*api.Node), old.(*api.Node))...) } @@ -107,7 +107,7 @@ func (nodeStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { newNode.Spec = oldNode.Spec } -func (nodeStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (nodeStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateNodeUpdate(obj.(*api.Node), old.(*api.Node)) } diff --git a/pkg/registry/persistentvolume/strategy.go b/pkg/registry/persistentvolume/strategy.go index 49ee2abf72938..12eb72ce95589 100644 --- a/pkg/registry/persistentvolume/strategy.go +++ b/pkg/registry/persistentvolume/strategy.go @@ -25,7 +25,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // persistentvolumeStrategy implements behavior for PersistentVolume objects @@ -48,7 +48,7 @@ func (persistentvolumeStrategy) PrepareForCreate(obj runtime.Object) { pv.Status = api.PersistentVolumeStatus{} } -func (persistentvolumeStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (persistentvolumeStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { persistentvolume := obj.(*api.PersistentVolume) return validation.ValidatePersistentVolume(persistentvolume) } @@ -68,7 +68,7 @@ func (persistentvolumeStrategy) PrepareForUpdate(obj, old runtime.Object) { newPv.Status = oldPv.Status } -func (persistentvolumeStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (persistentvolumeStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { errorList := validation.ValidatePersistentVolume(obj.(*api.PersistentVolume)) return append(errorList, validation.ValidatePersistentVolumeUpdate(obj.(*api.PersistentVolume), old.(*api.PersistentVolume))...) } @@ -90,7 +90,7 @@ func (persistentvolumeStatusStrategy) PrepareForUpdate(obj, old runtime.Object) newPv.Spec = oldPv.Spec } -func (persistentvolumeStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (persistentvolumeStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidatePersistentVolumeStatusUpdate(obj.(*api.PersistentVolume), old.(*api.PersistentVolume)) } diff --git a/pkg/registry/persistentvolumeclaim/strategy.go b/pkg/registry/persistentvolumeclaim/strategy.go index 7c145db5aef05..8580c53b112ac 100644 --- a/pkg/registry/persistentvolumeclaim/strategy.go +++ b/pkg/registry/persistentvolumeclaim/strategy.go @@ -25,7 +25,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // persistentvolumeclaimStrategy implements behavior for PersistentVolumeClaim objects @@ -48,7 +48,7 @@ func (persistentvolumeclaimStrategy) PrepareForCreate(obj runtime.Object) { pv.Status = api.PersistentVolumeClaimStatus{} } -func (persistentvolumeclaimStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (persistentvolumeclaimStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { pvc := obj.(*api.PersistentVolumeClaim) return validation.ValidatePersistentVolumeClaim(pvc) } @@ -68,7 +68,7 @@ func (persistentvolumeclaimStrategy) PrepareForUpdate(obj, old runtime.Object) { newPvc.Status = oldPvc.Status } -func (persistentvolumeclaimStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (persistentvolumeclaimStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { errorList := validation.ValidatePersistentVolumeClaim(obj.(*api.PersistentVolumeClaim)) return append(errorList, validation.ValidatePersistentVolumeClaimUpdate(obj.(*api.PersistentVolumeClaim), old.(*api.PersistentVolumeClaim))...) } @@ -90,7 +90,7 @@ func (persistentvolumeclaimStatusStrategy) PrepareForUpdate(obj, old runtime.Obj newPv.Spec = oldPv.Spec } -func (persistentvolumeclaimStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (persistentvolumeclaimStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidatePersistentVolumeClaimStatusUpdate(obj.(*api.PersistentVolumeClaim), old.(*api.PersistentVolumeClaim)) } diff --git a/pkg/registry/pod/etcd/etcd.go b/pkg/registry/pod/etcd/etcd.go index 3584a5b866f64..90e799f870e3c 100644 --- a/pkg/registry/pod/etcd/etcd.go +++ b/pkg/registry/pod/etcd/etcd.go @@ -35,7 +35,7 @@ import ( podrest "k8s.io/kubernetes/pkg/registry/pod/rest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/storage" - "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // PodStorage includes storage for pods and all sub resources @@ -134,10 +134,12 @@ func (r *BindingREST) Create(ctx api.Context, obj runtime.Object) (out runtime.O binding := obj.(*api.Binding) // TODO: move me to a binding strategy if len(binding.Target.Kind) != 0 && binding.Target.Kind != "Node" { - return nil, errors.NewInvalid("binding", binding.Name, validation.ErrorList{validation.NewInvalidError(validation.NewFieldPath("target", "kind"), binding.Target.Kind, "must be empty or 'Node'")}) + // TODO: When validation becomes versioned, this gets more complicated. + return nil, errors.NewInvalid("binding", binding.Name, field.ErrorList{field.NotSupported(field.NewPath("target", "kind"), binding.Target.Kind, []string{"Node", ""})}) } if len(binding.Target.Name) == 0 { - return nil, errors.NewInvalid("binding", binding.Name, validation.ErrorList{validation.NewRequiredError(validation.NewFieldPath("target", "name"))}) + // TODO: When validation becomes versioned, this gets more complicated. + return nil, errors.NewInvalid("binding", binding.Name, field.ErrorList{field.Required(field.NewPath("target", "name"))}) } err = r.assignPod(ctx, binding.Name, binding.Target.Name, binding.Annotations) out = &unversioned.Status{Status: unversioned.StatusSuccess} diff --git a/pkg/registry/pod/strategy.go b/pkg/registry/pod/strategy.go index 75ccdb6c0970c..f486100da2325 100644 --- a/pkg/registry/pod/strategy.go +++ b/pkg/registry/pod/strategy.go @@ -33,7 +33,7 @@ import ( "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // podStrategy implements behavior for Pods @@ -67,7 +67,7 @@ func (podStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new pod. -func (podStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (podStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { pod := obj.(*api.Pod) return validation.ValidatePod(pod) } @@ -82,7 +82,7 @@ func (podStrategy) AllowCreateOnUpdate() bool { } // ValidateUpdate is the default update validation for an end user. -func (podStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (podStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { errorList := validation.ValidatePod(obj.(*api.Pod)) return append(errorList, validation.ValidatePodUpdate(obj.(*api.Pod), old.(*api.Pod))...) } @@ -147,7 +147,7 @@ func (podStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { newPod.DeletionTimestamp = nil } -func (podStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (podStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { // TODO: merge valid fields after update return validation.ValidatePodStatusUpdate(obj.(*api.Pod), old.(*api.Pod)) } diff --git a/pkg/registry/podtemplate/strategy.go b/pkg/registry/podtemplate/strategy.go index a5b07a2337330..e4c451aca0515 100644 --- a/pkg/registry/podtemplate/strategy.go +++ b/pkg/registry/podtemplate/strategy.go @@ -25,7 +25,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // podTemplateStrategy implements behavior for PodTemplates @@ -49,7 +49,7 @@ func (podTemplateStrategy) PrepareForCreate(obj runtime.Object) { } // Validate validates a new pod template. -func (podTemplateStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (podTemplateStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { pod := obj.(*api.PodTemplate) return validation.ValidatePodTemplate(pod) } @@ -69,7 +69,7 @@ func (podTemplateStrategy) PrepareForUpdate(obj, old runtime.Object) { } // ValidateUpdate is the default update validation for an end user. -func (podTemplateStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (podTemplateStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidatePodTemplateUpdate(obj.(*api.PodTemplate), old.(*api.PodTemplate)) } diff --git a/pkg/registry/resourcequota/strategy.go b/pkg/registry/resourcequota/strategy.go index 70173e83cd345..656d5cecbac92 100644 --- a/pkg/registry/resourcequota/strategy.go +++ b/pkg/registry/resourcequota/strategy.go @@ -25,7 +25,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // resourcequotaStrategy implements behavior for ResourceQuota objects @@ -57,7 +57,7 @@ func (resourcequotaStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new resourcequota. -func (resourcequotaStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (resourcequotaStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { resourcequota := obj.(*api.ResourceQuota) return validation.ValidateResourceQuota(resourcequota) } @@ -72,7 +72,7 @@ func (resourcequotaStrategy) AllowCreateOnUpdate() bool { } // ValidateUpdate is the default update validation for an end user. -func (resourcequotaStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (resourcequotaStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { errorList := validation.ValidateResourceQuota(obj.(*api.ResourceQuota)) return append(errorList, validation.ValidateResourceQuotaUpdate(obj.(*api.ResourceQuota), old.(*api.ResourceQuota))...) } @@ -93,7 +93,7 @@ func (resourcequotaStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { newResourcequota.Spec = oldResourcequota.Spec } -func (resourcequotaStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (resourcequotaStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateResourceQuotaStatusUpdate(obj.(*api.ResourceQuota), old.(*api.ResourceQuota)) } diff --git a/pkg/registry/secret/strategy.go b/pkg/registry/secret/strategy.go index 692c3094c9429..71c525eb134ff 100644 --- a/pkg/registry/secret/strategy.go +++ b/pkg/registry/secret/strategy.go @@ -26,7 +26,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // strategy implements behavior for Secret objects @@ -50,7 +50,7 @@ func (strategy) NamespaceScoped() bool { func (strategy) PrepareForCreate(obj runtime.Object) { } -func (strategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (strategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { return validation.ValidateSecret(obj.(*api.Secret)) } @@ -64,7 +64,7 @@ func (strategy) AllowCreateOnUpdate() bool { func (strategy) PrepareForUpdate(obj, old runtime.Object) { } -func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateSecretUpdate(obj.(*api.Secret), old.(*api.Secret)) } diff --git a/pkg/registry/service/rest.go b/pkg/registry/service/rest.go index 079240d253186..26a455b06c111 100644 --- a/pkg/registry/service/rest.go +++ b/pkg/registry/service/rest.go @@ -35,7 +35,7 @@ import ( "k8s.io/kubernetes/pkg/registry/service/portallocator" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/util" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/watch" ) @@ -84,15 +84,18 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, err // Allocate next available. ip, err := rs.serviceIPs.AllocateNext() if err != nil { - el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "clusterIP"), service.Spec.ClusterIP, err.Error())} - return nil, errors.NewInvalid("Service", service.Name, el) + // TODO: what error should be returned here? It's not a + // field-level validation failure (the field is valid), and it's + // not really an internal error. + return nil, errors.NewInternalError(fmt.Errorf("failed to allocate a serviceIP: %v", err)) } service.Spec.ClusterIP = ip.String() releaseServiceIP = true } else if api.IsServiceIPSet(service) { // Try to respect the requested IP. if err := rs.serviceIPs.Allocate(net.ParseIP(service.Spec.ClusterIP)); err != nil { - el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "clusterIP"), service.Spec.ClusterIP, err.Error())} + // TODO: when validation becomes versioned, this gets more complicated. + el := field.ErrorList{field.Invalid(field.NewPath("spec", "clusterIP"), service.Spec.ClusterIP, err.Error())} return nil, errors.NewInvalid("Service", service.Name, el) } releaseServiceIP = true @@ -104,14 +107,17 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, err if servicePort.NodePort != 0 { err := nodePortOp.Allocate(servicePort.NodePort) if err != nil { - el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "ports").Index(i).Child("nodePort"), servicePort.NodePort, err.Error())} + // TODO: when validation becomes versioned, this gets more complicated. + el := field.ErrorList{field.Invalid(field.NewPath("spec", "ports").Index(i).Child("nodePort"), servicePort.NodePort, err.Error())} return nil, errors.NewInvalid("Service", service.Name, el) } } else if assignNodePorts { nodePort, err := nodePortOp.AllocateNext() if err != nil { - el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "ports").Index(i).Child("nodePort"), servicePort.NodePort, err.Error())} - return nil, errors.NewInvalid("Service", service.Name, el) + // TODO: what error should be returned here? It's not a + // field-level validation failure (the field is valid), and it's + // not really an internal error. + return nil, errors.NewInternalError(fmt.Errorf("failed to allocate a nodePort: %v", err)) } servicePort.NodePort = nodePort } @@ -223,15 +229,17 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo if !contains(oldNodePorts, nodePort) { err := nodePortOp.Allocate(nodePort) if err != nil { - el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "ports").Index(i).Child("nodePort"), nodePort, err.Error())} + el := field.ErrorList{field.Invalid(field.NewPath("spec", "ports").Index(i).Child("nodePort"), nodePort, err.Error())} return nil, false, errors.NewInvalid("Service", service.Name, el) } } } else { nodePort, err = nodePortOp.AllocateNext() if err != nil { - el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "ports").Index(i).Child("nodePort"), nodePort, err.Error())} - return nil, false, errors.NewInvalid("Service", service.Name, el) + // TODO: what error should be returned here? It's not a + // field-level validation failure (the field is valid), and it's + // not really an internal error. + return nil, false, errors.NewInternalError(fmt.Errorf("failed to allocate a nodePort: %v", err)) } servicePort.NodePort = nodePort } diff --git a/pkg/registry/service/strategy.go b/pkg/registry/service/strategy.go index 44bf2ad8ed63e..a927d8dc4ff5f 100644 --- a/pkg/registry/service/strategy.go +++ b/pkg/registry/service/strategy.go @@ -25,7 +25,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // svcStrategy implements behavior for Services @@ -58,7 +58,7 @@ func (svcStrategy) PrepareForUpdate(obj, old runtime.Object) { } // Validate validates a new service. -func (svcStrategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (svcStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { service := obj.(*api.Service) return validation.ValidateService(service) } @@ -71,7 +71,7 @@ func (svcStrategy) AllowCreateOnUpdate() bool { return true } -func (svcStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (svcStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateServiceUpdate(obj.(*api.Service), old.(*api.Service)) } diff --git a/pkg/registry/serviceaccount/strategy.go b/pkg/registry/serviceaccount/strategy.go index 760628b6e4f55..1d1f208f8c735 100644 --- a/pkg/registry/serviceaccount/strategy.go +++ b/pkg/registry/serviceaccount/strategy.go @@ -25,7 +25,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // strategy implements behavior for ServiceAccount objects @@ -46,7 +46,7 @@ func (strategy) PrepareForCreate(obj runtime.Object) { cleanSecretReferences(obj.(*api.ServiceAccount)) } -func (strategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (strategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { return validation.ValidateServiceAccount(obj.(*api.ServiceAccount)) } @@ -68,7 +68,7 @@ func cleanSecretReferences(serviceAccount *api.ServiceAccount) { } } -func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateServiceAccountUpdate(obj.(*api.ServiceAccount), old.(*api.ServiceAccount)) } diff --git a/pkg/registry/thirdpartyresource/strategy.go b/pkg/registry/thirdpartyresource/strategy.go index 053bef334b824..0f466d29751c8 100644 --- a/pkg/registry/thirdpartyresource/strategy.go +++ b/pkg/registry/thirdpartyresource/strategy.go @@ -27,7 +27,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // strategy implements behavior for ThirdPartyResource objects @@ -51,7 +51,7 @@ func (strategy) NamespaceScoped() bool { func (strategy) PrepareForCreate(obj runtime.Object) { } -func (strategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (strategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { return validation.ValidateThirdPartyResource(obj.(*extensions.ThirdPartyResource)) } @@ -66,7 +66,7 @@ func (strategy) AllowCreateOnUpdate() bool { func (strategy) PrepareForUpdate(obj, old runtime.Object) { } -func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateThirdPartyResourceUpdate(obj.(*extensions.ThirdPartyResource), old.(*extensions.ThirdPartyResource)) } diff --git a/pkg/registry/thirdpartyresourcedata/strategy.go b/pkg/registry/thirdpartyresourcedata/strategy.go index e5becb4a58094..9f7673d7c06e2 100644 --- a/pkg/registry/thirdpartyresourcedata/strategy.go +++ b/pkg/registry/thirdpartyresourcedata/strategy.go @@ -27,7 +27,7 @@ import ( "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) // strategy implements behavior for ThirdPartyResource objects @@ -51,7 +51,7 @@ func (strategy) NamespaceScoped() bool { func (strategy) PrepareForCreate(obj runtime.Object) { } -func (strategy) Validate(ctx api.Context, obj runtime.Object) utilvalidation.ErrorList { +func (strategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { return validation.ValidateThirdPartyResourceData(obj.(*extensions.ThirdPartyResourceData)) } @@ -66,7 +66,7 @@ func (strategy) AllowCreateOnUpdate() bool { func (strategy) PrepareForUpdate(obj, old runtime.Object) { } -func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) utilvalidation.ErrorList { +func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return validation.ValidateThirdPartyResourceDataUpdate(obj.(*extensions.ThirdPartyResourceData), old.(*extensions.ThirdPartyResourceData)) } diff --git a/pkg/storage/util.go b/pkg/storage/util.go index 2f24cf276ae68..deb89d6001fd2 100644 --- a/pkg/storage/util.go +++ b/pkg/storage/util.go @@ -24,7 +24,7 @@ import ( "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/runtime" - utilvalidation "k8s.io/kubernetes/pkg/util/validation" + "k8s.io/kubernetes/pkg/util/validation/field" ) type SimpleUpdateFunc func(runtime.Object) (runtime.Object, error) @@ -47,10 +47,10 @@ func ParseWatchResourceVersion(resourceVersion string) (uint64, error) { } version, err := strconv.ParseUint(resourceVersion, 10, 64) if err != nil { - return 0, errors.NewInvalid("", "", utilvalidation.ErrorList{ + return 0, errors.NewInvalid("", "", field.ErrorList{ // Validation errors are supposed to return version-specific field // paths, but this is probably close enough. - utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("resourceVersion"), resourceVersion, err.Error()), + field.Invalid(field.NewPath("resourceVersion"), resourceVersion, err.Error()), }) } return version + 1, nil diff --git a/pkg/util/validation/errors.go b/pkg/util/validation/field/errors.go similarity index 88% rename from pkg/util/validation/errors.go rename to pkg/util/validation/field/errors.go index 0efe4a9fa199d..862cbc3f976b0 100644 --- a/pkg/util/validation/errors.go +++ b/pkg/util/validation/field/errors.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package validation +package field import ( "fmt" @@ -26,7 +26,7 @@ import ( ) // Error is an implementation of the 'error' interface, which represents a -// validation error. +// field-level validation error. type Error struct { Type ErrorType Field string @@ -72,22 +72,22 @@ const ( // NewRequiredError. ErrorTypeRequired ErrorType = "FieldValueRequired" // ErrorTypeDuplicate is used to report collisions of values that must be - // unique (e.g. unique IDs). See NewDuplicateError. + // unique (e.g. unique IDs). See Duplicate(). ErrorTypeDuplicate ErrorType = "FieldValueDuplicate" // ErrorTypeInvalid is used to report malformed values (e.g. failed regex - // match, too long, out of bounds). See NewInvalidError. + // match, too long, out of bounds). See Invalid(). ErrorTypeInvalid ErrorType = "FieldValueInvalid" // ErrorTypeNotSupported is used to report unknown values for enumerated - // fields (e.g. a list of valid values). See NewNotSupportedError. + // fields (e.g. a list of valid values). See NotSupported(). ErrorTypeNotSupported ErrorType = "FieldValueNotSupported" // ErrorTypeForbidden is used to report valid (as per formatting rules) // values which would be accepted under some conditions, but which are not // permitted by the current conditions (such as security policy). See - // NewForbiddenError. + // Forbidden(). ErrorTypeForbidden ErrorType = "FieldValueForbidden" // ErrorTypeTooLong is used to report that the given value is too long. // This is similar to ErrorTypeInvalid, but the error will not include the - // too-long value. See NewTooLongError. + // too-long value. See TooLong(). ErrorTypeTooLong ErrorType = "FieldValueTooLong" // ErrorTypeInternal is used to report other errors that are not related // to user input. @@ -121,33 +121,33 @@ func (t ErrorType) String() string { // NewNotFoundError returns a *Error indicating "value not found". This is // used to report failure to find a requested value (e.g. looking up an ID). -func NewNotFoundError(field *FieldPath, value interface{}) *Error { +func NotFound(field *Path, value interface{}) *Error { return &Error{ErrorTypeNotFound, field.String(), value, ""} } // NewRequiredError returns a *Error indicating "value required". This is used // to report required values that are not provided (e.g. empty strings, null // values, or empty arrays). -func NewRequiredError(field *FieldPath) *Error { +func Required(field *Path) *Error { return &Error{ErrorTypeRequired, field.String(), "", ""} } // NewDuplicateError returns a *Error indicating "duplicate value". This is // used to report collisions of values that must be unique (e.g. names or IDs). -func NewDuplicateError(field *FieldPath, value interface{}) *Error { +func Duplicate(field *Path, value interface{}) *Error { return &Error{ErrorTypeDuplicate, field.String(), value, ""} } // NewInvalidError returns a *Error indicating "invalid value". This is used // to report malformed values (e.g. failed regex match, too long, out of bounds). -func NewInvalidError(field *FieldPath, value interface{}, detail string) *Error { +func Invalid(field *Path, value interface{}, detail string) *Error { return &Error{ErrorTypeInvalid, field.String(), value, detail} } // NewNotSupportedError returns a *Error indicating "unsupported value". // This is used to report unknown values for enumerated fields (e.g. a list of // valid values). -func NewNotSupportedError(field *FieldPath, value interface{}, validValues []string) *Error { +func NotSupported(field *Path, value interface{}, validValues []string) *Error { detail := "" if validValues != nil && len(validValues) > 0 { detail = "supported values: " + strings.Join(validValues, ", ") @@ -159,7 +159,7 @@ func NewNotSupportedError(field *FieldPath, value interface{}, validValues []str // report valid (as per formatting rules) values which would be accepted under // some conditions, but which are not permitted by current conditions (e.g. // security policy). -func NewForbiddenError(field *FieldPath, value interface{}) *Error { +func Forbidden(field *Path, value interface{}) *Error { return &Error{ErrorTypeForbidden, field.String(), value, ""} } @@ -167,18 +167,20 @@ func NewForbiddenError(field *FieldPath, value interface{}) *Error { // report that the given value is too long. This is similar to // NewInvalidError, but the returned error will not include the too-long // value. -func NewTooLongError(field *FieldPath, value interface{}, maxLength int) *Error { +func TooLong(field *Path, value interface{}, maxLength int) *Error { return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d characters", maxLength)} } // NewInternalError returns a *Error indicating "internal error". This is used // to signal that an error was found that was not directly related to user // input. The err argument must be non-nil. -func NewInternalError(field *FieldPath, err error) *Error { +func InternalError(field *Path, err error) *Error { return &Error{ErrorTypeInternal, field.String(), nil, err.Error()} } -// ErrorList holds a set of errors. +// ErrorList holds a set of Errors. It is plausible that we might one day have +// non-field errors in this same umbrella package, but for now we don't, so +// we can keep it simple and leave ErrorList here. type ErrorList []*Error // NewErrorTypeMatcher returns an errors.Matcher that returns true diff --git a/pkg/util/validation/errors_test.go b/pkg/util/validation/field/errors_test.go similarity index 74% rename from pkg/util/validation/errors_test.go rename to pkg/util/validation/field/errors_test.go index 504d0f1853cc5..50ad653f960ba 100644 --- a/pkg/util/validation/errors_test.go +++ b/pkg/util/validation/field/errors_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package validation +package field import ( "fmt" @@ -28,27 +28,27 @@ func TestMakeFuncs(t *testing.T) { expected ErrorType }{ { - func() *Error { return NewInvalidError(NewFieldPath("f"), "v", "d") }, + func() *Error { return Invalid(NewPath("f"), "v", "d") }, ErrorTypeInvalid, }, { - func() *Error { return NewNotSupportedError(NewFieldPath("f"), "v", nil) }, + func() *Error { return NotSupported(NewPath("f"), "v", nil) }, ErrorTypeNotSupported, }, { - func() *Error { return NewDuplicateError(NewFieldPath("f"), "v") }, + func() *Error { return Duplicate(NewPath("f"), "v") }, ErrorTypeDuplicate, }, { - func() *Error { return NewNotFoundError(NewFieldPath("f"), "v") }, + func() *Error { return NotFound(NewPath("f"), "v") }, ErrorTypeNotFound, }, { - func() *Error { return NewRequiredError(NewFieldPath("f")) }, + func() *Error { return Required(NewPath("f")) }, ErrorTypeRequired, }, { - func() *Error { return NewInternalError(NewFieldPath("f"), fmt.Errorf("e")) }, + func() *Error { return InternalError(NewPath("f"), fmt.Errorf("e")) }, ErrorTypeInternal, }, } @@ -62,7 +62,7 @@ func TestMakeFuncs(t *testing.T) { } func TestErrorUsefulMessage(t *testing.T) { - s := NewInvalidError(NewFieldPath("foo"), "bar", "deet").Error() + s := Invalid(NewPath("foo"), "bar", "deet").Error() t.Logf("message: %v", s) for _, part := range []string{"foo", "bar", "deet", ErrorTypeInvalid.String()} { if !strings.Contains(s, part) { @@ -76,8 +76,8 @@ func TestErrorUsefulMessage(t *testing.T) { Inner interface{} KV map[string]int } - s = NewInvalidError( - NewFieldPath("foo"), + s = Invalid( + NewPath("foo"), &complicated{ Baz: 1, Qux: "aoeu", @@ -102,8 +102,8 @@ func TestToAggregate(t *testing.T) { testCases := []ErrorList{ nil, {}, - {NewInvalidError(NewFieldPath("f"), "v", "d")}, - {NewInvalidError(NewFieldPath("f"), "v", "d"), NewInternalError(NewFieldPath(""), fmt.Errorf("e"))}, + {Invalid(NewPath("f"), "v", "d")}, + {Invalid(NewPath("f"), "v", "d"), InternalError(NewPath(""), fmt.Errorf("e"))}, } for i, tc := range testCases { agg := tc.ToAggregate() @@ -121,9 +121,9 @@ func TestToAggregate(t *testing.T) { func TestErrListFilter(t *testing.T) { list := ErrorList{ - NewInvalidError(NewFieldPath("test.field"), "", ""), - NewInvalidError(NewFieldPath("field.test"), "", ""), - NewDuplicateError(NewFieldPath("test"), "value"), + Invalid(NewPath("test.field"), "", ""), + Invalid(NewPath("field.test"), "", ""), + Duplicate(NewPath("test"), "value"), } if len(list.Filter(NewErrorTypeMatcher(ErrorTypeDuplicate))) != 2 { t.Errorf("should not filter") diff --git a/pkg/util/validation/field/path.go b/pkg/util/validation/field/path.go new file mode 100644 index 0000000000000..30ff5a8f788a4 --- /dev/null +++ b/pkg/util/validation/field/path.go @@ -0,0 +1,91 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package field + +import ( + "bytes" + "fmt" + "strconv" +) + +// Path represents the path from some root to a particular field. +type Path struct { + name string // the name of this field or "" if this is an index + index string // if name == "", this is a subscript (index or map key) of the previous element + parent *Path // nil if this is the root element +} + +// NewPath creates a root Path object. +func NewPath(name string, moreNames ...string) *Path { + r := &Path{name: name, parent: nil} + for _, anotherName := range moreNames { + r = &Path{name: anotherName, parent: r} + } + return r +} + +// Root returns the root element of this Path. +func (p *Path) Root() *Path { + for ; p.parent != nil; p = p.parent { + // Do nothing. + } + return p +} + +// Child creates a new Path that is a child of the method receiver. +func (p *Path) Child(name string, moreNames ...string) *Path { + r := NewPath(name, moreNames...) + r.Root().parent = p + return r +} + +// Index indicates that the previous Path is to be subscripted by an int. +// This sets the same underlying value as Key. +func (p *Path) Index(index int) *Path { + return &Path{index: strconv.Itoa(index), parent: p} +} + +// Key indicates that the previous Path is to be subscripted by a string. +// This sets the same underlying value as Index. +func (p *Path) Key(key string) *Path { + return &Path{index: key, parent: p} +} + +// String produces a string representation of the Path. +func (p *Path) String() string { + // make a slice to iterate + elems := []*Path{} + for ; p != nil; p = p.parent { + elems = append(elems, p) + } + + // iterate, but it has to be backwards + buf := bytes.NewBuffer(nil) + for i := range elems { + p := elems[len(elems)-1-i] + if p.parent != nil && len(p.name) > 0 { + // This is either the root or it is a subscript. + buf.WriteString(".") + } + if len(p.name) > 0 { + buf.WriteString(p.name) + } else { + fmt.Fprintf(buf, "[%s]", p.index) + } + } + return buf.String() +} diff --git a/pkg/util/validation/field/path_test.go b/pkg/util/validation/field/path_test.go new file mode 100644 index 0000000000000..42a16e4bdc7cc --- /dev/null +++ b/pkg/util/validation/field/path_test.go @@ -0,0 +1,123 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package field + +import "testing" + +func TestPath(t *testing.T) { + testCases := []struct { + op func(*Path) *Path + expected string + }{ + { + func(p *Path) *Path { return p }, + "root", + }, + { + func(p *Path) *Path { return p.Child("first") }, + "root.first", + }, + { + func(p *Path) *Path { return p.Child("second") }, + "root.first.second", + }, + { + func(p *Path) *Path { return p.Index(0) }, + "root.first.second[0]", + }, + { + func(p *Path) *Path { return p.Child("third") }, + "root.first.second[0].third", + }, + { + func(p *Path) *Path { return p.Index(93) }, + "root.first.second[0].third[93]", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first.second[0].third", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first.second[0]", + }, + { + func(p *Path) *Path { return p.Key("key") }, + "root.first.second[0][key]", + }, + } + + root := NewPath("root") + p := root + for i, tc := range testCases { + p = tc.op(p) + if p.String() != tc.expected { + t.Errorf("[%d] Expected %q, got %q", i, tc.expected, p.String()) + } + if p.Root() != root { + t.Errorf("[%d] Wrong root: %#v", i, p.Root()) + } + } +} + +func TestPathMultiArg(t *testing.T) { + testCases := []struct { + op func(*Path) *Path + expected string + }{ + { + func(p *Path) *Path { return p }, + "root.first", + }, + { + func(p *Path) *Path { return p.Child("second", "third") }, + "root.first.second.third", + }, + { + func(p *Path) *Path { return p.Index(0) }, + "root.first.second.third[0]", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first.second.third", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first.second", + }, + { + func(p *Path) *Path { return p.parent }, + "root.first", + }, + { + func(p *Path) *Path { return p.parent }, + "root", + }, + } + + root := NewPath("root", "first") + p := root + for i, tc := range testCases { + p = tc.op(p) + if p.String() != tc.expected { + t.Errorf("[%d] Expected %q, got %q", i, tc.expected, p.String()) + } + if p.Root() != root.Root() { + t.Errorf("[%d] Wrong root: %#v", i, p.Root()) + } + } +} diff --git a/pkg/util/validation/fieldpath.go b/pkg/util/validation/fieldpath.go deleted file mode 100644 index e6a411cf55f3f..0000000000000 --- a/pkg/util/validation/fieldpath.go +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package validation - -import ( - "bytes" - "fmt" - "strconv" -) - -// FieldPath represents the path from some root to a particular field. -type FieldPath struct { - name string // the name of this field or "" if this is an index - index string // if name == "", this is a subscript (index or map key) of the previous element - parent *FieldPath // nil if this is the root element -} - -// NewFieldPath creates a root FieldPath object. -func NewFieldPath(name string, moreNames ...string) *FieldPath { - r := &FieldPath{name: name, parent: nil} - for _, anotherName := range moreNames { - r = &FieldPath{name: anotherName, parent: r} - } - return r -} - -// Root returns the root element of this FieldPath. -func (fp *FieldPath) Root() *FieldPath { - for ; fp.parent != nil; fp = fp.parent { - // Do nothing. - } - return fp -} - -// Child creates a new FieldPath that is a child of the method receiver. -func (fp *FieldPath) Child(name string, moreNames ...string) *FieldPath { - r := NewFieldPath(name, moreNames...) - r.Root().parent = fp - return r -} - -// Index indicates that the previous FieldPath is to be subscripted by an int. -// This sets the same underlying value as Key. -func (fp *FieldPath) Index(index int) *FieldPath { - return &FieldPath{index: strconv.Itoa(index), parent: fp} -} - -// Key indicates that the previous FieldPath is to be subscripted by a string. -// This sets the same underlying value as Index. -func (fp *FieldPath) Key(key string) *FieldPath { - return &FieldPath{index: key, parent: fp} -} - -// String produces a string representation of the FieldPath. -func (fp *FieldPath) String() string { - // make a slice to iterate - elems := []*FieldPath{} - for p := fp; p != nil; p = p.parent { - elems = append(elems, p) - } - - // iterate, but it has to be backwards - buf := bytes.NewBuffer(nil) - for i := range elems { - p := elems[len(elems)-1-i] - if p.parent != nil && len(p.name) > 0 { - // This is either the root or it is a subscript. - buf.WriteString(".") - } - if len(p.name) > 0 { - buf.WriteString(p.name) - } else { - fmt.Fprintf(buf, "[%s]", p.index) - } - } - return buf.String() -} diff --git a/pkg/util/validation/fieldpath_test.go b/pkg/util/validation/fieldpath_test.go deleted file mode 100644 index ad95e7bfea983..0000000000000 --- a/pkg/util/validation/fieldpath_test.go +++ /dev/null @@ -1,123 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package validation - -import "testing" - -func TestFieldPath(t *testing.T) { - testCases := []struct { - op func(*FieldPath) *FieldPath - expected string - }{ - { - func(fp *FieldPath) *FieldPath { return fp }, - "root", - }, - { - func(fp *FieldPath) *FieldPath { return fp.Child("first") }, - "root.first", - }, - { - func(fp *FieldPath) *FieldPath { return fp.Child("second") }, - "root.first.second", - }, - { - func(fp *FieldPath) *FieldPath { return fp.Index(0) }, - "root.first.second[0]", - }, - { - func(fp *FieldPath) *FieldPath { return fp.Child("third") }, - "root.first.second[0].third", - }, - { - func(fp *FieldPath) *FieldPath { return fp.Index(93) }, - "root.first.second[0].third[93]", - }, - { - func(fp *FieldPath) *FieldPath { return fp.parent }, - "root.first.second[0].third", - }, - { - func(fp *FieldPath) *FieldPath { return fp.parent }, - "root.first.second[0]", - }, - { - func(fp *FieldPath) *FieldPath { return fp.Key("key") }, - "root.first.second[0][key]", - }, - } - - root := NewFieldPath("root") - fp := root - for i, tc := range testCases { - fp = tc.op(fp) - if fp.String() != tc.expected { - t.Errorf("[%d] Expected %q, got %q", i, tc.expected, fp.String()) - } - if fp.Root() != root { - t.Errorf("[%d] Wrong root: %#v", i, fp.Root()) - } - } -} - -func TestFieldPathMultiArg(t *testing.T) { - testCases := []struct { - op func(*FieldPath) *FieldPath - expected string - }{ - { - func(fp *FieldPath) *FieldPath { return fp }, - "root.first", - }, - { - func(fp *FieldPath) *FieldPath { return fp.Child("second", "third") }, - "root.first.second.third", - }, - { - func(fp *FieldPath) *FieldPath { return fp.Index(0) }, - "root.first.second.third[0]", - }, - { - func(fp *FieldPath) *FieldPath { return fp.parent }, - "root.first.second.third", - }, - { - func(fp *FieldPath) *FieldPath { return fp.parent }, - "root.first.second", - }, - { - func(fp *FieldPath) *FieldPath { return fp.parent }, - "root.first", - }, - { - func(fp *FieldPath) *FieldPath { return fp.parent }, - "root", - }, - } - - root := NewFieldPath("root", "first") - fp := root - for i, tc := range testCases { - fp = tc.op(fp) - if fp.String() != tc.expected { - t.Errorf("[%d] Expected %q, got %q", i, tc.expected, fp.String()) - } - if fp.Root() != root.Root() { - t.Errorf("[%d] Wrong root: %#v", i, fp.Root()) - } - } -}