Move FieldPath and errors to a sub-package

This makes the naming and reading a lot simpler.
pull/6/head
Tim Hockin 2015-11-06 15:30:52 -08:00
parent b9aa71089e
commit 87a35047dd
45 changed files with 1032 additions and 1052 deletions

View File

@ -33,13 +33,13 @@ import (
expvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" expvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation"
"k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/runtime" "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" "k8s.io/kubernetes/pkg/util/yaml"
schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api" schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
schedulerapilatest "k8s.io/kubernetes/plugin/pkg/scheduler/api/latest" 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) { switch t := obj.(type) {
case *api.ReplicationController: case *api.ReplicationController:
if t.Namespace == "" { if t.Namespace == "" {
@ -123,7 +123,7 @@ func validateObject(obj runtime.Object) (errors utilvalidation.ErrorList) {
} }
errors = expvalidation.ValidateDaemonSet(t) errors = expvalidation.ValidateDaemonSet(t)
default: default:
return utilvalidation.ErrorList{utilvalidation.NewInternalError(utilvalidation.NewFieldPath(""), fmt.Errorf("no validation defined for %#v", obj))} return field.ErrorList{field.NewInternalError(field.NewPath(""), fmt.Errorf("no validation defined for %#v", obj))}
} }
return errors return errors
} }

View File

@ -24,7 +24,7 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime" "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. // 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. // 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)) causes := make([]unversioned.StatusCause, 0, len(errs))
for i := range errs { for i := range errs {
err := errs[i] err := errs[i]

View File

@ -24,7 +24,7 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
func TestErrorNew(t *testing.T) { func TestErrorNew(t *testing.T) {
@ -88,11 +88,11 @@ func TestErrorNew(t *testing.T) {
func TestNewInvalid(t *testing.T) { func TestNewInvalid(t *testing.T) {
testCases := []struct { testCases := []struct {
Err *validation.Error Err *field.Error
Details *unversioned.StatusDetails Details *unversioned.StatusDetails
}{ }{
{ {
validation.NewDuplicateError(validation.NewFieldPath("field[0].name"), "bar"), field.NewDuplicateError(field.NewPath("field[0].name"), "bar"),
&unversioned.StatusDetails{ &unversioned.StatusDetails{
Kind: "kind", Kind: "kind",
Name: "name", Name: "name",
@ -103,7 +103,7 @@ func TestNewInvalid(t *testing.T) {
}, },
}, },
{ {
validation.NewInvalidError(validation.NewFieldPath("field[0].name"), "bar", "detail"), field.NewInvalidError(field.NewPath("field[0].name"), "bar", "detail"),
&unversioned.StatusDetails{ &unversioned.StatusDetails{
Kind: "kind", Kind: "kind",
Name: "name", Name: "name",
@ -114,7 +114,7 @@ func TestNewInvalid(t *testing.T) {
}, },
}, },
{ {
validation.NewNotFoundError(validation.NewFieldPath("field[0].name"), "bar"), field.NewNotFoundError(field.NewPath("field[0].name"), "bar"),
&unversioned.StatusDetails{ &unversioned.StatusDetails{
Kind: "kind", Kind: "kind",
Name: "name", Name: "name",
@ -125,7 +125,7 @@ func TestNewInvalid(t *testing.T) {
}, },
}, },
{ {
validation.NewNotSupportedError(validation.NewFieldPath("field[0].name"), "bar", nil), field.NewNotSupportedError(field.NewPath("field[0].name"), "bar", nil),
&unversioned.StatusDetails{ &unversioned.StatusDetails{
Kind: "kind", Kind: "kind",
Name: "name", Name: "name",
@ -136,7 +136,7 @@ func TestNewInvalid(t *testing.T) {
}, },
}, },
{ {
validation.NewRequiredError(validation.NewFieldPath("field[0].name")), field.NewRequiredError(field.NewPath("field[0].name")),
&unversioned.StatusDetails{ &unversioned.StatusDetails{
Kind: "kind", Kind: "kind",
Name: "name", Name: "name",
@ -150,7 +150,7 @@ func TestNewInvalid(t *testing.T) {
for i, testCase := range testCases { for i, testCase := range testCases {
vErr, expected := testCase.Err, testCase.Details vErr, expected := testCase.Err, testCase.Details
expected.Causes[0].Message = vErr.ErrorBody() expected.Causes[0].Message = vErr.ErrorBody()
err := NewInvalid("kind", "name", validation.ErrorList{vErr}) err := NewInvalid("kind", "name", field.ErrorList{vErr})
status := err.(*StatusError).ErrStatus status := err.(*StatusError).ErrStatus
if status.Code != 422 || status.Reason != unversioned.StatusReasonInvalid { if status.Code != 422 || status.Reason != unversioned.StatusReasonInvalid {
t.Errorf("%d: unexpected status: %#v", i, status) t.Errorf("%d: unexpected status: %#v", i, status)

View File

@ -21,7 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime" "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 // RESTCreateStrategy defines the minimum validation, accepted input, and
@ -42,7 +42,7 @@ type RESTCreateStrategy interface {
PrepareForCreate(obj runtime.Object) PrepareForCreate(obj runtime.Object)
// Validate is invoked after default fields in the object have been filled in before // 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. // 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 // Canonicalize is invoked after validation has succeeded but before the
// object has been persisted. This method may mutate the object. // object has been persisted. This method may mutate the object.
Canonicalize(obj runtime.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 // Custom validation (including name validation) passed
// Now run common validation on object meta // Now run common validation on object meta
// Do this *after* custom validation so that specific error messages are shown whenever possible // 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) return errors.NewInvalid(kind, objectMeta.Name, errs)
} }

View File

@ -21,7 +21,7 @@ import (
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime" "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 // RESTUpdateStrategy defines the minimum validation, accepted input, and
@ -42,7 +42,7 @@ type RESTUpdateStrategy interface {
// ValidateUpdate is invoked after default fields in the object have been // ValidateUpdate is invoked after default fields in the object have been
// filled in before the object is persisted. This method should not mutate // filled in before the object is persisted. This method should not mutate
// the object. // 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 // Canonicalize is invoked after validation has succeeded but before the
// object has been persisted. This method may mutate the object. // object has been persisted. This method may mutate the object.
Canonicalize(obj runtime.Object) Canonicalize(obj runtime.Object)
@ -53,17 +53,17 @@ type RESTUpdateStrategy interface {
} }
// TODO: add other common fields that require global validation. // TODO: add other common fields that require global validation.
func validateCommonFields(obj, old runtime.Object) utilvalidation.ErrorList { func validateCommonFields(obj, old runtime.Object) field.ErrorList {
allErrs := utilvalidation.ErrorList{} allErrs := field.ErrorList{}
objectMeta, err := api.ObjectMetaFor(obj) objectMeta, err := api.ObjectMetaFor(obj)
if err != nil { if err != nil {
return append(allErrs, utilvalidation.NewInternalError(utilvalidation.NewFieldPath("metadata"), err)) return append(allErrs, field.NewInternalError(field.NewPath("metadata"), err))
} }
oldObjectMeta, err := api.ObjectMetaFor(old) oldObjectMeta, err := api.ObjectMetaFor(old)
if err != nil { if err != nil {
return append(allErrs, utilvalidation.NewInternalError(utilvalidation.NewFieldPath("metadata"), err)) return append(allErrs, field.NewInternalError(field.NewPath("metadata"), 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
} }

View File

@ -27,10 +27,9 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "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/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 // Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
@ -42,7 +41,7 @@ func TestCompatibility(
t *testing.T, t *testing.T,
version string, version string,
input []byte, input []byte,
validator func(obj runtime.Object) validation.ErrorList, validator func(obj runtime.Object) field.ErrorList,
expectedKeys map[string]string, expectedKeys map[string]string,
absentKeys []string, absentKeys []string,
) { ) {

View File

@ -23,7 +23,7 @@ import (
"k8s.io/kubernetes/pkg/api/testing/compat" "k8s.io/kubernetes/pkg/api/testing/compat"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime" "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) { 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 { validator := func(obj runtime.Object) field.ErrorList {
return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec), utilvalidation.NewFieldPath("spec")) return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec), field.NewPath("spec"))
} }
for _, tc := range cases { for _, tc := range cases {

View File

@ -19,22 +19,23 @@ package validation
import ( import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation"
"k8s.io/kubernetes/pkg/util/validation/field"
) )
// ValidateEvent makes sure that the event makes sense. // ValidateEvent makes sure that the event makes sense.
func ValidateEvent(event *api.Event) validation.ErrorList { func ValidateEvent(event *api.Event) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
// There is no namespace required for node. // There is no namespace required for node.
if event.InvolvedObject.Kind == "Node" && if event.InvolvedObject.Kind == "Node" &&
event.Namespace != "" { event.Namespace != "" {
allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "namespace is not required for node")) allErrs = append(allErrs, field.NewInvalidError(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "not required for node"))
} }
if event.InvolvedObject.Kind != "Node" && if event.InvolvedObject.Kind != "Node" &&
event.Namespace != event.InvolvedObject.Namespace { 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.NewInvalidError(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match involvedObject"))
} }
if !validation.IsDNS1123Subdomain(event.Namespace) { if !validation.IsDNS1123Subdomain(event.Namespace) {
allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("namespace"), event.Namespace, "")) allErrs = append(allErrs, field.NewInvalidError(field.NewPath("namespace"), event.Namespace, ""))
} }
return allErrs return allErrs
} }

File diff suppressed because it is too large Load Diff

View File

@ -30,10 +30,10 @@ import (
"k8s.io/kubernetes/pkg/capabilities" "k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
"k8s.io/kubernetes/pkg/util/sets" "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 { for i := range errs {
if f, p := errs[i].Field, prefix; !strings.HasPrefix(f, p) { if f, p := errs[i].Field, prefix; !strings.HasPrefix(f, p) {
t.Errorf("expected prefix '%s' for field '%s' (%v)", p, f, errs[i]) 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" return false, "name-gen"
}, },
validation.NewFieldPath("field")) field.NewPath("field"))
if len(errs) != 1 { if len(errs) != 1 {
t.Fatalf("unexpected errors: %v", errs) t.Fatalf("unexpected errors: %v", errs)
} }
@ -69,7 +69,7 @@ func TestValidateObjectMetaNamespaces(t *testing.T) {
func(s string, prefix bool) (bool, string) { func(s string, prefix bool) (bool, string) {
return true, "" return true, ""
}, },
validation.NewFieldPath("field")) field.NewPath("field"))
if len(errs) != 1 { if len(errs) != 1 {
t.Fatalf("unexpected errors: %v", errs) t.Fatalf("unexpected errors: %v", errs)
} }
@ -88,7 +88,7 @@ func TestValidateObjectMetaNamespaces(t *testing.T) {
func(s string, prefix bool) (bool, string) { func(s string, prefix bool) (bool, string) {
return true, "" return true, ""
}, },
validation.NewFieldPath("field")) field.NewPath("field"))
if len(errs) != 1 { if len(errs) != 1 {
t.Fatalf("unexpected errors: %v", errs) t.Fatalf("unexpected errors: %v", errs)
} }
@ -101,21 +101,21 @@ func TestValidateObjectMetaUpdateIgnoresCreationTimestamp(t *testing.T) {
if errs := ValidateObjectMetaUpdate( if errs := ValidateObjectMetaUpdate(
&api.ObjectMeta{Name: "test", ResourceVersion: "1"}, &api.ObjectMeta{Name: "test", ResourceVersion: "1"},
&api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: unversioned.NewTime(time.Unix(10, 0))}, &api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: unversioned.NewTime(time.Unix(10, 0))},
validation.NewFieldPath("field"), field.NewPath("field"),
); len(errs) != 0 { ); len(errs) != 0 {
t.Fatalf("unexpected errors: %v", errs) t.Fatalf("unexpected errors: %v", errs)
} }
if errs := ValidateObjectMetaUpdate( 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(10, 0))},
&api.ObjectMeta{Name: "test", ResourceVersion: "1"}, &api.ObjectMeta{Name: "test", ResourceVersion: "1"},
validation.NewFieldPath("field"), field.NewPath("field"),
); len(errs) != 0 { ); len(errs) != 0 {
t.Fatalf("unexpected errors: %v", errs) t.Fatalf("unexpected errors: %v", errs)
} }
if errs := ValidateObjectMetaUpdate( 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(10, 0))},
&api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: unversioned.NewTime(time.Unix(11, 0))}, &api.ObjectMeta{Name: "test", ResourceVersion: "1", CreationTimestamp: unversioned.NewTime(time.Unix(11, 0))},
validation.NewFieldPath("field"), field.NewPath("field"),
); len(errs) != 0 { ); len(errs) != 0 {
t.Fatalf("unexpected errors: %v", errs) t.Fatalf("unexpected errors: %v", errs)
} }
@ -127,7 +127,7 @@ func TestValidateObjectMetaTrimsTrailingSlash(t *testing.T) {
&api.ObjectMeta{Name: "test", GenerateName: "foo-"}, &api.ObjectMeta{Name: "test", GenerateName: "foo-"},
false, false,
NameIsDNSSubdomain, NameIsDNSSubdomain,
validation.NewFieldPath("field")) field.NewPath("field"))
if len(errs) != 0 { if len(errs) != 0 {
t.Fatalf("unexpected errors: %v", errs) t.Fatalf("unexpected errors: %v", errs)
} }
@ -151,7 +151,7 @@ func TestValidateLabels(t *testing.T) {
{"goodvalue": "123_-.BaR"}, {"goodvalue": "123_-.BaR"},
} }
for i := range successCases { for i := range successCases {
errs := ValidateLabels(successCases[i], validation.NewFieldPath("field")) errs := ValidateLabels(successCases[i], field.NewPath("field"))
if len(errs) != 0 { if len(errs) != 0 {
t.Errorf("case[%d] expected success, got %#v", i, errs) t.Errorf("case[%d] expected success, got %#v", i, errs)
} }
@ -164,7 +164,7 @@ func TestValidateLabels(t *testing.T) {
{strings.Repeat("a", 254): "bar"}, {strings.Repeat("a", 254): "bar"},
} }
for i := range labelNameErrorCases { for i := range labelNameErrorCases {
errs := ValidateLabels(labelNameErrorCases[i], validation.NewFieldPath("field")) errs := ValidateLabels(labelNameErrorCases[i], field.NewPath("field"))
if len(errs) != 1 { if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i) t.Errorf("case[%d] expected failure", i)
} else { } else {
@ -182,7 +182,7 @@ func TestValidateLabels(t *testing.T) {
{"strangecharsinvalue": "?#$notsogood"}, {"strangecharsinvalue": "?#$notsogood"},
} }
for i := range labelValueErrorCases { for i := range labelValueErrorCases {
errs := ValidateLabels(labelValueErrorCases[i], validation.NewFieldPath("field")) errs := ValidateLabels(labelValueErrorCases[i], field.NewPath("field"))
if len(errs) != 1 { if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i) t.Errorf("case[%d] expected failure", i)
} else { } else {
@ -216,7 +216,7 @@ func TestValidateAnnotations(t *testing.T) {
}, },
} }
for i := range successCases { for i := range successCases {
errs := ValidateAnnotations(successCases[i], validation.NewFieldPath("field")) errs := ValidateAnnotations(successCases[i], field.NewPath("field"))
if len(errs) != 0 { if len(errs) != 0 {
t.Errorf("case[%d] expected success, got %#v", i, errs) t.Errorf("case[%d] expected success, got %#v", i, errs)
} }
@ -229,7 +229,7 @@ func TestValidateAnnotations(t *testing.T) {
{strings.Repeat("a", 254): "bar"}, {strings.Repeat("a", 254): "bar"},
} }
for i := range nameErrorCases { for i := range nameErrorCases {
errs := ValidateAnnotations(nameErrorCases[i], validation.NewFieldPath("field")) errs := ValidateAnnotations(nameErrorCases[i], field.NewPath("field"))
if len(errs) != 1 { if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i) t.Errorf("case[%d] expected failure", i)
} }
@ -246,7 +246,7 @@ func TestValidateAnnotations(t *testing.T) {
}, },
} }
for i := range totalSizeErrorCases { for i := range totalSizeErrorCases {
errs := ValidateAnnotations(totalSizeErrorCases[i], validation.NewFieldPath("field")) errs := ValidateAnnotations(totalSizeErrorCases[i], field.NewPath("field"))
if len(errs) != 1 { if len(errs) != 1 {
t.Errorf("case[%d] expected failure", i) 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}}}, {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 { if len(errs) != 0 {
t.Errorf("expected success: %v", errs) t.Errorf("expected success: %v", errs)
} }
@ -558,128 +558,128 @@ func TestValidateVolumes(t *testing.T) {
slashInName := api.VolumeSource{Flocker: &api.FlockerVolumeSource{DatasetName: "foo/bar"}} slashInName := api.VolumeSource{Flocker: &api.FlockerVolumeSource{DatasetName: "foo/bar"}}
errorCases := map[string]struct { errorCases := map[string]struct {
V []api.Volume V []api.Volume
T validation.ErrorType T field.ErrorType
F string F string
D string D string
}{ }{
"zero-length name": { "zero-length name": {
[]api.Volume{{Name: "", VolumeSource: emptyVS}}, []api.Volume{{Name: "", VolumeSource: emptyVS}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"name", "", "name", "",
}, },
"name > 63 characters": { "name > 63 characters": {
[]api.Volume{{Name: strings.Repeat("a", 64), VolumeSource: emptyVS}}, []api.Volume{{Name: strings.Repeat("a", 64), VolumeSource: emptyVS}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"name", "must be a DNS label", "name", "must be a DNS label",
}, },
"name not a DNS label": { "name not a DNS label": {
[]api.Volume{{Name: "a.b.c", VolumeSource: emptyVS}}, []api.Volume{{Name: "a.b.c", VolumeSource: emptyVS}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"name", "must be a DNS label", "name", "must be a DNS label",
}, },
"name not unique": { "name not unique": {
[]api.Volume{{Name: "abc", VolumeSource: emptyVS}, {Name: "abc", VolumeSource: emptyVS}}, []api.Volume{{Name: "abc", VolumeSource: emptyVS}, {Name: "abc", VolumeSource: emptyVS}},
validation.ErrorTypeDuplicate, field.ErrorTypeDuplicate,
"[1].name", "", "[1].name", "",
}, },
"empty portal": { "empty portal": {
[]api.Volume{{Name: "badportal", VolumeSource: emptyPortal}}, []api.Volume{{Name: "badportal", VolumeSource: emptyPortal}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"iscsi.targetPortal", "", "iscsi.targetPortal", "",
}, },
"empty iqn": { "empty iqn": {
[]api.Volume{{Name: "badiqn", VolumeSource: emptyIQN}}, []api.Volume{{Name: "badiqn", VolumeSource: emptyIQN}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"iscsi.iqn", "", "iscsi.iqn", "",
}, },
"empty hosts": { "empty hosts": {
[]api.Volume{{Name: "badhost", VolumeSource: emptyHosts}}, []api.Volume{{Name: "badhost", VolumeSource: emptyHosts}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"glusterfs.endpoints", "", "glusterfs.endpoints", "",
}, },
"empty path": { "empty path": {
[]api.Volume{{Name: "badpath", VolumeSource: emptyPath}}, []api.Volume{{Name: "badpath", VolumeSource: emptyPath}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"glusterfs.path", "", "glusterfs.path", "",
}, },
"empty datasetName": { "empty datasetName": {
[]api.Volume{{Name: "badname", VolumeSource: emptyName}}, []api.Volume{{Name: "badname", VolumeSource: emptyName}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"flocker.datasetName", "", "flocker.datasetName", "",
}, },
"empty mon": { "empty mon": {
[]api.Volume{{Name: "badmon", VolumeSource: emptyMon}}, []api.Volume{{Name: "badmon", VolumeSource: emptyMon}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"rbd.monitors", "", "rbd.monitors", "",
}, },
"empty image": { "empty image": {
[]api.Volume{{Name: "badimage", VolumeSource: emptyImage}}, []api.Volume{{Name: "badimage", VolumeSource: emptyImage}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"rbd.image", "", "rbd.image", "",
}, },
"empty cephfs mon": { "empty cephfs mon": {
[]api.Volume{{Name: "badmon", VolumeSource: emptyCephFSMon}}, []api.Volume{{Name: "badmon", VolumeSource: emptyCephFSMon}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"cephfs.monitors", "", "cephfs.monitors", "",
}, },
"empty metatada path": { "empty metatada path": {
[]api.Volume{{Name: "emptyname", VolumeSource: emptyPathName}}, []api.Volume{{Name: "emptyname", VolumeSource: emptyPathName}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"downwardAPI.path", "", "downwardAPI.path", "",
}, },
"absolute path": { "absolute path": {
[]api.Volume{{Name: "absolutepath", VolumeSource: absolutePathName}}, []api.Volume{{Name: "absolutepath", VolumeSource: absolutePathName}},
validation.ErrorTypeForbidden, field.ErrorTypeForbidden,
"downwardAPI.path", "", "downwardAPI.path", "",
}, },
"dot dot path": { "dot dot path": {
[]api.Volume{{Name: "dotdotpath", VolumeSource: dotDotInPath}}, []api.Volume{{Name: "dotdotpath", VolumeSource: dotDotInPath}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"downwardAPI.path", `must not contain ".."`, "downwardAPI.path", `must not contain ".."`,
}, },
"dot dot file name": { "dot dot file name": {
[]api.Volume{{Name: "dotdotfilename", VolumeSource: dotDotPathName}}, []api.Volume{{Name: "dotdotfilename", VolumeSource: dotDotPathName}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"downwardAPI.path", `must not start with ".."`, "downwardAPI.path", `must not start with ".."`,
}, },
"dot dot first level dirent": { "dot dot first level dirent": {
[]api.Volume{{Name: "dotdotdirfilename", VolumeSource: dotDotFirstLevelDirent}}, []api.Volume{{Name: "dotdotdirfilename", VolumeSource: dotDotFirstLevelDirent}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"downwardAPI.path", `must not start with ".."`, "downwardAPI.path", `must not start with ".."`,
}, },
"empty wwn": { "empty wwn": {
[]api.Volume{{Name: "badimage", VolumeSource: zeroWWN}}, []api.Volume{{Name: "badimage", VolumeSource: zeroWWN}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"fc.targetWWNs", "", "fc.targetWWNs", "",
}, },
"empty lun": { "empty lun": {
[]api.Volume{{Name: "badimage", VolumeSource: emptyLun}}, []api.Volume{{Name: "badimage", VolumeSource: emptyLun}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"fc.lun", "", "fc.lun", "",
}, },
"slash in datasetName": { "slash in datasetName": {
[]api.Volume{{Name: "slashinname", VolumeSource: slashInName}}, []api.Volume{{Name: "slashinname", VolumeSource: slashInName}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"flocker.datasetName", "must not contain '/'", "flocker.datasetName", "must not contain '/'",
}, },
"starts with '..'": { "starts with '..'": {
[]api.Volume{{Name: "badprefix", VolumeSource: startsWithDots}}, []api.Volume{{Name: "badprefix", VolumeSource: startsWithDots}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"gitRepo.directory", `must not start with ".."`, "gitRepo.directory", `must not start with ".."`,
}, },
"contains '..'": { "contains '..'": {
[]api.Volume{{Name: "containsdots", VolumeSource: containsDots}}, []api.Volume{{Name: "containsdots", VolumeSource: containsDots}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"gitRepo.directory", `must not contain ".."`, "gitRepo.directory", `must not contain ".."`,
}, },
"absolute target": { "absolute target": {
[]api.Volume{{Name: "absolutetarget", VolumeSource: absPath}}, []api.Volume{{Name: "absolutetarget", VolumeSource: absPath}},
validation.ErrorTypeForbidden, field.ErrorTypeForbidden,
"gitRepo.directory", "", "gitRepo.directory", "",
}, },
} }
for k, v := range errorCases { for k, v := range errorCases {
_, errs := validateVolumes(v.V, validation.NewFieldPath("field")) _, errs := validateVolumes(v.V, field.NewPath("field"))
if len(errs) == 0 { if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.V) t.Errorf("expected failure %s for %v", k, v.V)
continue continue
@ -706,36 +706,36 @@ func TestValidatePorts(t *testing.T) {
{Name: "do-re-me", ContainerPort: 84, Protocol: "UDP"}, {Name: "do-re-me", ContainerPort: 84, Protocol: "UDP"},
{ContainerPort: 85, Protocol: "TCP"}, {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) t.Errorf("expected success: %v", errs)
} }
nonCanonicalCase := []api.ContainerPort{ nonCanonicalCase := []api.ContainerPort{
{ContainerPort: 80, Protocol: "TCP"}, {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) t.Errorf("expected success: %v", errs)
} }
errorCases := map[string]struct { errorCases := map[string]struct {
P []api.ContainerPort P []api.ContainerPort
T validation.ErrorType T field.ErrorType
F string F string
D string D string
}{ }{
"name > 15 characters": { "name > 15 characters": {
[]api.ContainerPort{{Name: strings.Repeat("a", 16), ContainerPort: 80, Protocol: "TCP"}}, []api.ContainerPort{{Name: strings.Repeat("a", 16), ContainerPort: 80, Protocol: "TCP"}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"name", PortNameErrorMsg, "name", PortNameErrorMsg,
}, },
"name not a IANA svc name ": { "name not a IANA svc name ": {
[]api.ContainerPort{{Name: "a.b.c", ContainerPort: 80, Protocol: "TCP"}}, []api.ContainerPort{{Name: "a.b.c", ContainerPort: 80, Protocol: "TCP"}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"name", PortNameErrorMsg, "name", PortNameErrorMsg,
}, },
"name not a IANA svc name (i.e. a number)": { "name not a IANA svc name (i.e. a number)": {
[]api.ContainerPort{{Name: "80", ContainerPort: 80, Protocol: "TCP"}}, []api.ContainerPort{{Name: "80", ContainerPort: 80, Protocol: "TCP"}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"name", PortNameErrorMsg, "name", PortNameErrorMsg,
}, },
"name not unique": { "name not unique": {
@ -743,42 +743,42 @@ func TestValidatePorts(t *testing.T) {
{Name: "abc", ContainerPort: 80, Protocol: "TCP"}, {Name: "abc", ContainerPort: 80, Protocol: "TCP"},
{Name: "abc", ContainerPort: 81, Protocol: "TCP"}, {Name: "abc", ContainerPort: 81, Protocol: "TCP"},
}, },
validation.ErrorTypeDuplicate, field.ErrorTypeDuplicate,
"[1].name", "", "[1].name", "",
}, },
"zero container port": { "zero container port": {
[]api.ContainerPort{{ContainerPort: 0, Protocol: "TCP"}}, []api.ContainerPort{{ContainerPort: 0, Protocol: "TCP"}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"containerPort", PortRangeErrorMsg, "containerPort", PortRangeErrorMsg,
}, },
"invalid container port": { "invalid container port": {
[]api.ContainerPort{{ContainerPort: 65536, Protocol: "TCP"}}, []api.ContainerPort{{ContainerPort: 65536, Protocol: "TCP"}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"containerPort", PortRangeErrorMsg, "containerPort", PortRangeErrorMsg,
}, },
"invalid host port": { "invalid host port": {
[]api.ContainerPort{{ContainerPort: 80, HostPort: 65536, Protocol: "TCP"}}, []api.ContainerPort{{ContainerPort: 80, HostPort: 65536, Protocol: "TCP"}},
validation.ErrorTypeInvalid, field.ErrorTypeInvalid,
"hostPort", PortRangeErrorMsg, "hostPort", PortRangeErrorMsg,
}, },
"invalid protocol case": { "invalid protocol case": {
[]api.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}}, []api.ContainerPort{{ContainerPort: 80, Protocol: "tcp"}},
validation.ErrorTypeNotSupported, field.ErrorTypeNotSupported,
"protocol", "supported values: TCP, UDP", "protocol", "supported values: TCP, UDP",
}, },
"invalid protocol": { "invalid protocol": {
[]api.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}}, []api.ContainerPort{{ContainerPort: 80, Protocol: "ICMP"}},
validation.ErrorTypeNotSupported, field.ErrorTypeNotSupported,
"protocol", "supported values: TCP, UDP", "protocol", "supported values: TCP, UDP",
}, },
"protocol required": { "protocol required": {
[]api.ContainerPort{{Name: "abc", ContainerPort: 80}}, []api.ContainerPort{{Name: "abc", ContainerPort: 80}},
validation.ErrorTypeRequired, field.ErrorTypeRequired,
"protocol", "", "protocol", "",
}, },
} }
for k, v := range errorCases { for k, v := range errorCases {
errs := validateContainerPorts(v.P, validation.NewFieldPath("field")) errs := validateContainerPorts(v.P, field.NewPath("field"))
if len(errs) == 0 { if len(errs) == 0 {
t.Errorf("expected failure for %s", k) 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) t.Errorf("expected success: %v", errs)
} }
@ -923,7 +923,7 @@ func TestValidateEnv(t *testing.T) {
}, },
} }
for _, tc := range errorCases { 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) t.Errorf("expected failure for %s", tc.name)
} else { } else {
for i := range errs { for i := range errs {
@ -944,7 +944,7 @@ func TestValidateVolumeMounts(t *testing.T) {
{Name: "123", MountPath: "/foo"}, {Name: "123", MountPath: "/foo"},
{Name: "abc-123", MountPath: "/bar"}, {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) t.Errorf("expected success: %v", errs)
} }
@ -954,7 +954,7 @@ func TestValidateVolumeMounts(t *testing.T) {
"empty mountpath": {{Name: "abc", MountPath: ""}}, "empty mountpath": {{Name: "abc", MountPath: ""}},
} }
for k, v := range errorCases { 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) t.Errorf("expected failure for %s", k)
} }
} }
@ -972,7 +972,7 @@ func TestValidateProbe(t *testing.T) {
} }
for _, p := range successCases { 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) t.Errorf("expected success: %v", errs)
} }
} }
@ -984,7 +984,7 @@ func TestValidateProbe(t *testing.T) {
errorCases = append(errorCases, probe) errorCases = append(errorCases, probe)
} }
for _, p := range errorCases { 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) 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"}}, {HTTPGet: &api.HTTPGetAction{Path: "/", Port: intstr.FromString("port"), Host: "", Scheme: "HTTP"}},
} }
for _, h := range successCases { 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) t.Errorf("expected success: %v", errs)
} }
} }
@ -1011,7 +1011,7 @@ func TestValidateHandler(t *testing.T) {
{HTTPGet: &api.HTTPGetAction{Path: "", Port: intstr.FromString(""), Host: ""}}, {HTTPGet: &api.HTTPGetAction{Path: "", Port: intstr.FromString(""), Host: ""}},
} }
for _, h := range errorCases { 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) t.Errorf("expected failure for %#v", h)
} }
} }
@ -1050,7 +1050,7 @@ func TestValidatePullPolicy(t *testing.T) {
} }
for k, v := range testCases { for k, v := range testCases {
ctr := &v.Container ctr := &v.Container
errs := validatePullPolicy(ctr.ImagePullPolicy, validation.NewFieldPath("field")) errs := validatePullPolicy(ctr.ImagePullPolicy, field.NewPath("field"))
if len(errs) != 0 { if len(errs) != 0 {
t.Errorf("case[%s] expected success, got %#v", k, errs) 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)}, {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) t.Errorf("expected success: %v", errs)
} }
@ -1346,7 +1346,7 @@ func TestValidateContainers(t *testing.T) {
}, },
} }
for k, v := range errorCases { 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) t.Errorf("expected failure for %s", k)
} }
} }
@ -1359,7 +1359,7 @@ func TestValidateRestartPolicy(t *testing.T) {
api.RestartPolicyNever, api.RestartPolicyNever,
} }
for _, policy := range successCases { 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) t.Errorf("expected success: %v", errs)
} }
} }
@ -1367,7 +1367,7 @@ func TestValidateRestartPolicy(t *testing.T) {
errorCases := []api.RestartPolicy{"", "newpolicy"} errorCases := []api.RestartPolicy{"", "newpolicy"}
for k, policy := range errorCases { 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) t.Errorf("expected failure for %d", k)
} }
} }
@ -1376,14 +1376,14 @@ func TestValidateRestartPolicy(t *testing.T) {
func TestValidateDNSPolicy(t *testing.T) { func TestValidateDNSPolicy(t *testing.T) {
successCases := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault, api.DNSPolicy(api.DNSClusterFirst)} successCases := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault, api.DNSPolicy(api.DNSClusterFirst)}
for _, policy := range successCases { 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) t.Errorf("expected success: %v", errs)
} }
} }
errorCases := []api.DNSPolicy{api.DNSPolicy("invalid")} errorCases := []api.DNSPolicy{api.DNSPolicy("invalid")}
for _, policy := range errorCases { 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) t.Errorf("expected failure for %v", policy)
} }
} }
@ -1444,7 +1444,7 @@ func TestValidatePodSpec(t *testing.T) {
}, },
} }
for i := range successCases { 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) t.Errorf("expected success: %v", errs)
} }
} }
@ -1516,7 +1516,7 @@ func TestValidatePodSpec(t *testing.T) {
}, },
} }
for k, v := range failureCases { 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) t.Errorf("expected failure for %q", k)
} }
} }
@ -3191,7 +3191,7 @@ func TestValidateResourceNames(t *testing.T) {
{"kubernetes.io/will/not/work/", false}, {"kubernetes.io/will/not/work/", false},
} }
for k, item := range table { 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 { if len(err) != 0 && item.success {
t.Errorf("expected no failure for input %q", item.input) t.Errorf("expected no failure for input %q", item.input)
} else if len(err) == 0 && !item.success { } else if len(err) == 0 && !item.success {
@ -3948,7 +3948,7 @@ func TestValidateEndpoints(t *testing.T) {
errorCases := map[string]struct { errorCases := map[string]struct {
endpoints api.Endpoints endpoints api.Endpoints
errorType validation.ErrorType errorType field.ErrorType
errorDetail string errorDetail string
}{ }{
"missing namespace": { "missing namespace": {
@ -4171,7 +4171,7 @@ func TestValidateSecurityContext(t *testing.T) {
"no run as user": {noRunAsUser}, "no run as user": {noRunAsUser},
} }
for k, v := range successCases { 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) t.Errorf("Expected success for %s, got %v", k, errs)
} }
} }
@ -4186,7 +4186,7 @@ func TestValidateSecurityContext(t *testing.T) {
errorCases := map[string]struct { errorCases := map[string]struct {
sc *api.SecurityContext sc *api.SecurityContext
errorType validation.ErrorType errorType field.ErrorType
errorDetail string errorDetail string
}{ }{
"request privileged when capabilities forbids": { "request privileged when capabilities forbids": {
@ -4201,7 +4201,7 @@ func TestValidateSecurityContext(t *testing.T) {
}, },
} }
for k, v := range errorCases { 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) t.Errorf("Expected error type %s with detail %s for %s, got %v", v.errorType, v.errorDetail, k, errs)
} }
} }

View File

@ -29,6 +29,7 @@ import (
"k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/validation" "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. // 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) return apivalidation.ValidateReplicationControllerName(name, prefix)
} }
func validateHorizontalPodAutoscalerSpec(autoscaler extensions.HorizontalPodAutoscalerSpec, fldPath *validation.FieldPath) validation.ErrorList { func validateHorizontalPodAutoscalerSpec(autoscaler extensions.HorizontalPodAutoscalerSpec, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if autoscaler.MinReplicas != nil && *autoscaler.MinReplicas < 1 { 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.NewInvalidError(fldPath.Child("minReplicas"), autoscaler.MinReplicas, `must be greater than or equal to 1`))
} }
if autoscaler.MaxReplicas < 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.NewInvalidError(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, `must be greater than or equal to 1`))
} }
if autoscaler.MinReplicas != nil && autoscaler.MaxReplicas < *autoscaler.MinReplicas { 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.NewInvalidError(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, `must be greater than or equal to minReplicas`))
} }
if autoscaler.CPUUtilization != nil && autoscaler.CPUUtilization.TargetPercentage < 1 { 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.NewInvalidError(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 { if refErrs := ValidateSubresourceReference(autoscaler.ScaleRef, fldPath.Child("scaleRef")); len(refErrs) > 0 {
allErrs = append(allErrs, refErrs...) allErrs = append(allErrs, refErrs...)
} else if autoscaler.ScaleRef.Subresource != "scale" { } else if autoscaler.ScaleRef.Subresource != "scale" {
allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("scaleRef", "subresource"), autoscaler.ScaleRef.Subresource, []string{"scale"})) allErrs = append(allErrs, field.NewNotSupportedError(fldPath.Child("scaleRef", "subresource"), autoscaler.ScaleRef.Subresource, []string{"scale"}))
} }
return allErrs return allErrs
} }
func ValidateSubresourceReference(ref extensions.SubresourceReference, fldPath *validation.FieldPath) validation.ErrorList { func ValidateSubresourceReference(ref extensions.SubresourceReference, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if len(ref.Kind) == 0 { if len(ref.Kind) == 0 {
allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("kind"))) allErrs = append(allErrs, field.NewRequiredError(fldPath.Child("kind")))
} else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Kind); !ok { } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Kind); !ok {
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("kind"), ref.Kind, msg)) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("kind"), ref.Kind, msg))
} }
if len(ref.Name) == 0 { if len(ref.Name) == 0 {
allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("name"))) allErrs = append(allErrs, field.NewRequiredError(fldPath.Child("name")))
} else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Name); !ok { } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Name); !ok {
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("name"), ref.Name, msg)) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("name"), ref.Name, msg))
} }
if len(ref.Subresource) == 0 { if len(ref.Subresource) == 0 {
allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("subresource"))) allErrs = append(allErrs, field.NewRequiredError(fldPath.Child("subresource")))
} else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Subresource); !ok { } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Subresource); !ok {
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("subresource"), ref.Subresource, msg)) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("subresource"), ref.Subresource, msg))
} }
return allErrs return allErrs
} }
func ValidateHorizontalPodAutoscaler(autoscaler *extensions.HorizontalPodAutoscaler) validation.ErrorList { func ValidateHorizontalPodAutoscaler(autoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, validation.NewFieldPath("spec"))...)
return allErrs return allErrs
} }
func ValidateHorizontalPodAutoscalerUpdate(newAutoscaler, oldAutoscaler *extensions.HorizontalPodAutoscaler) validation.ErrorList { func ValidateHorizontalPodAutoscalerUpdate(newAutoscaler, oldAutoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(newAutoscaler.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(newAutoscaler.Spec, validation.NewFieldPath("spec"))...)
return allErrs return allErrs
} }
func ValidateHorizontalPodAutoscalerStatusUpdate(controller, oldController *extensions.HorizontalPodAutoscaler) validation.ErrorList { func ValidateHorizontalPodAutoscalerStatusUpdate(controller, oldController *extensions.HorizontalPodAutoscaler) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, validation.NewFieldPath("metadata"))...)
status := controller.Status status := controller.Status
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.CurrentReplicas), validation.NewFieldPath("status", "currentReplicas"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.CurrentReplicas), field.NewPath("status", "currentReplicas"))...)
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.DesiredReplicas), validation.NewFieldPath("status", "desiredReplicasa"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.DesiredReplicas), field.NewPath("status", "desiredReplicasa"))...)
return allErrs return allErrs
} }
func ValidateThirdPartyResourceUpdate(update, old *extensions.ThirdPartyResource) validation.ErrorList { func ValidateThirdPartyResourceUpdate(update, old *extensions.ThirdPartyResource) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))...)
allErrs = append(allErrs, ValidateThirdPartyResource(update)...) allErrs = append(allErrs, ValidateThirdPartyResource(update)...)
return allErrs return allErrs
} }
@ -117,18 +114,18 @@ func ValidateThirdPartyResourceName(name string, prefix bool) (bool, string) {
return apivalidation.NameIsDNSSubdomain(name, prefix) return apivalidation.NameIsDNSSubdomain(name, prefix)
} }
func ValidateThirdPartyResource(obj *extensions.ThirdPartyResource) validation.ErrorList { func ValidateThirdPartyResource(obj *extensions.ThirdPartyResource) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateThirdPartyResourceName, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateThirdPartyResourceName, field.NewPath("metadata"))...)
versions := sets.String{} versions := sets.String{}
for ix := range obj.Versions { for ix := range obj.Versions {
version := &obj.Versions[ix] version := &obj.Versions[ix]
if len(version.Name) == 0 { 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.NewInvalidError(field.NewPath("versions").Index(ix).Child("name"), version, "can not be empty"))
} }
if versions.Has(version.Name) { if versions.Has(version.Name) {
allErrs = append(allErrs, validation.NewDuplicateError(validation.NewFieldPath("versions").Index(ix).Child("name"), version)) allErrs = append(allErrs, field.NewDuplicateError(field.NewPath("versions").Index(ix).Child("name"), version))
} }
versions.Insert(version.Name) 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. // ValidateDaemonSet tests if required fields in the DaemonSet are set.
func ValidateDaemonSet(controller *extensions.DaemonSet) validation.ErrorList { func ValidateDaemonSet(controller *extensions.DaemonSet) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMeta(&controller.ObjectMeta, true, ValidateDaemonSetName, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&controller.ObjectMeta, true, ValidateDaemonSetName, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, validation.NewFieldPath("spec"))...)
return allErrs return allErrs
} }
// ValidateDaemonSetUpdate tests if required fields in the DaemonSet are set. // ValidateDaemonSetUpdate tests if required fields in the DaemonSet are set.
func ValidateDaemonSetUpdate(controller, oldController *extensions.DaemonSet) validation.ErrorList { func ValidateDaemonSetUpdate(controller, oldController *extensions.DaemonSet) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, validation.NewFieldPath("spec"))...) allErrs = append(allErrs, ValidateDaemonSetTemplateUpdate(controller.Spec.Template, oldController.Spec.Template, field.NewPath("spec", "template"))...)
allErrs = append(allErrs, ValidateDaemonSetTemplateUpdate(controller.Spec.Template, oldController.Spec.Template, validation.NewFieldPath("spec", "template"))...)
return allErrs return allErrs
} }
// validateDaemonSetStatus validates a DaemonSetStatus // validateDaemonSetStatus validates a DaemonSetStatus
func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *validation.FieldPath) validation.ErrorList { func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.CurrentNumberScheduled), fldPath.Child("currentNumberScheduled"))...) 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.NumberMisscheduled), fldPath.Child("numberMisscheduled"))...)
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.DesiredNumberScheduled), fldPath.Child("desiredNumberScheduled"))...) 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 // ValidateDaemonSetStatus validates tests if required fields in the DaemonSet Status section
func ValidateDaemonSetStatusUpdate(controller, oldController *extensions.DaemonSet) validation.ErrorList { func ValidateDaemonSetStatusUpdate(controller, oldController *extensions.DaemonSet) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, validateDaemonSetStatus(&controller.Status, field.NewPath("status"))...)
allErrs = append(allErrs, validateDaemonSetStatus(&controller.Status, validation.NewFieldPath("status"))...)
return allErrs return allErrs
} }
// ValidateDaemonSetTemplateUpdate tests that certain fields in the daemon set's pod template are not updated. // 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 { func ValidateDaemonSetTemplateUpdate(podTemplate, oldPodTemplate *api.PodTemplateSpec, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
podSpec := podTemplate.Spec podSpec := podTemplate.Spec
// podTemplate.Spec is not a pointer, so we can modify NodeSelector and NodeName directly. // podTemplate.Spec is not a pointer, so we can modify NodeSelector and NodeName directly.
podSpec.NodeSelector = oldPodTemplate.Spec.NodeSelector 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. // In particular, we do not allow updates to container images at this point.
if !api.Semantic.DeepEqual(oldPodTemplate.Spec, podSpec) { if !api.Semantic.DeepEqual(oldPodTemplate.Spec, podSpec) {
// TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff // 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.NewInvalidError(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 return allErrs
} }
// ValidateDaemonSetSpec tests if required fields in the DaemonSetSpec are set. // ValidateDaemonSetSpec tests if required fields in the DaemonSetSpec are set.
func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec, fldPath *validation.FieldPath) validation.ErrorList { func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) allErrs = append(allErrs, ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...)
if spec.Template == nil { if spec.Template == nil {
allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("template"))) allErrs = append(allErrs, field.NewRequiredError(fldPath.Child("template")))
return allErrs return allErrs
} }
selector, err := extensions.LabelSelectorAsSelector(spec.Selector) selector, err := extensions.LabelSelectorAsSelector(spec.Selector)
if err == nil && !selector.Matches(labels.Set(spec.Template.Labels)) { 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.NewInvalidError(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "selector does not match template"))
} }
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(spec.Template, fldPath.Child("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"))...) allErrs = append(allErrs, apivalidation.ValidateReadOnlyPersistentDisks(spec.Template.Spec.Volumes, fldPath.Child("template", "spec", "volumes"))...)
// RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec(). // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways { 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.NewNotSupportedError(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
} }
return allErrs return allErrs
@ -223,11 +217,11 @@ func ValidateDeploymentName(name string, prefix bool) (bool, string) {
return apivalidation.NameIsDNSSubdomain(name, prefix) return apivalidation.NameIsDNSSubdomain(name, prefix)
} }
func ValidatePositiveIntOrPercent(intOrPercent intstr.IntOrString, fldPath *validation.FieldPath) validation.ErrorList { func ValidatePositiveIntOrPercent(intOrPercent intstr.IntOrString, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if intOrPercent.Type == intstr.String { if intOrPercent.Type == intstr.String {
if !validation.IsValidPercent(intOrPercent.StrVal) { if !validation.IsValidPercent(intOrPercent.StrVal) {
allErrs = append(allErrs, validation.NewInvalidError(fldPath, intOrPercent, "value should be int(5) or percentage(5%)")) allErrs = append(allErrs, field.NewInvalidError(fldPath, intOrPercent, "value should be int(5) or percentage(5%)"))
} }
} else if intOrPercent.Type == intstr.Int { } else if intOrPercent.Type == intstr.Int {
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(intOrPercent.IntValue()), fldPath)...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(intOrPercent.IntValue()), fldPath)...)
@ -251,23 +245,23 @@ func getIntOrPercentValue(intOrStringValue intstr.IntOrString) int {
return intOrStringValue.IntValue() return intOrStringValue.IntValue()
} }
func IsNotMoreThan100Percent(intOrStringValue intstr.IntOrString, fldPath *validation.FieldPath) validation.ErrorList { func IsNotMoreThan100Percent(intOrStringValue intstr.IntOrString, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
value, isPercent := getPercentValue(intOrStringValue) value, isPercent := getPercentValue(intOrStringValue)
if !isPercent || value <= 100 { if !isPercent || value <= 100 {
return nil return nil
} }
allErrs = append(allErrs, validation.NewInvalidError(fldPath, intOrStringValue, "should not be more than 100%")) allErrs = append(allErrs, field.NewInvalidError(fldPath, intOrStringValue, "should not be more than 100%"))
return allErrs return allErrs
} }
func ValidateRollingUpdateDeployment(rollingUpdate *extensions.RollingUpdateDeployment, fldPath *validation.FieldPath) validation.ErrorList { func ValidateRollingUpdateDeployment(rollingUpdate *extensions.RollingUpdateDeployment, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidatePositiveIntOrPercent(rollingUpdate.MaxUnavailable, fldPath.Child("maxUnavailable"))...) allErrs = append(allErrs, ValidatePositiveIntOrPercent(rollingUpdate.MaxUnavailable, fldPath.Child("maxUnavailable"))...)
allErrs = append(allErrs, ValidatePositiveIntOrPercent(rollingUpdate.MaxSurge, fldPath.Child("maxSurge"))...) allErrs = append(allErrs, ValidatePositiveIntOrPercent(rollingUpdate.MaxSurge, fldPath.Child("maxSurge"))...)
if getIntOrPercentValue(rollingUpdate.MaxUnavailable) == 0 && getIntOrPercentValue(rollingUpdate.MaxSurge) == 0 { if getIntOrPercentValue(rollingUpdate.MaxUnavailable) == 0 && getIntOrPercentValue(rollingUpdate.MaxSurge) == 0 {
// Both MaxSurge and MaxUnavailable cannot be zero. // 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.NewInvalidError(fldPath.Child("maxUnavailable"), rollingUpdate.MaxUnavailable, "cannot be 0 when maxSurge is 0 as well"))
} }
// Validate that MaxUnavailable is not more than 100%. // Validate that MaxUnavailable is not more than 100%.
allErrs = append(allErrs, IsNotMoreThan100Percent(rollingUpdate.MaxUnavailable, fldPath.Child("maxUnavailable"))...) allErrs = append(allErrs, IsNotMoreThan100Percent(rollingUpdate.MaxUnavailable, fldPath.Child("maxUnavailable"))...)
@ -275,14 +269,14 @@ func ValidateRollingUpdateDeployment(rollingUpdate *extensions.RollingUpdateDepl
return allErrs return allErrs
} }
func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *validation.FieldPath) validation.ErrorList { func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if strategy.RollingUpdate == nil { if strategy.RollingUpdate == nil {
return allErrs return allErrs
} }
switch strategy.Type { switch strategy.Type {
case extensions.RecreateDeploymentStrategyType: case extensions.RecreateDeploymentStrategyType:
allErrs = append(allErrs, validation.NewForbiddenError(fldPath.Child("rollingUpdate"), "should be nil when strategy type is "+extensions.RecreateDeploymentStrategyType)) allErrs = append(allErrs, field.NewForbiddenError(fldPath.Child("rollingUpdate"), "should be nil when strategy type is "+extensions.RecreateDeploymentStrategyType))
case extensions.RollingUpdateDeploymentStrategyType: case extensions.RollingUpdateDeploymentStrategyType:
allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...) allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...)
} }
@ -290,8 +284,8 @@ func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath
} }
// Validates given deployment spec. // Validates given deployment spec.
func ValidateDeploymentSpec(spec *extensions.DeploymentSpec, fldPath *validation.FieldPath) validation.ErrorList { func ValidateDeploymentSpec(spec *extensions.DeploymentSpec, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateNonEmptySelector(spec.Selector, fldPath.Child("selector"))...) 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.ValidatePositiveField(int64(spec.Replicas), fldPath.Child("replicas"))...)
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpecForRC(&spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"))...) 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 return allErrs
} }
func ValidateDeploymentUpdate(update, old *extensions.Deployment) validation.ErrorList { func ValidateDeploymentUpdate(update, old *extensions.Deployment) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, ValidateDeploymentSpec(&update.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateDeploymentSpec(&update.Spec, validation.NewFieldPath("spec"))...)
return allErrs return allErrs
} }
func ValidateDeployment(obj *extensions.Deployment) validation.ErrorList { func ValidateDeployment(obj *extensions.Deployment) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateDeploymentName, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateDeploymentName, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, ValidateDeploymentSpec(&obj.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateDeploymentSpec(&obj.Spec, validation.NewFieldPath("spec"))...)
return allErrs return allErrs
} }
func ValidateThirdPartyResourceDataUpdate(update, old *extensions.ThirdPartyResourceData) validation.ErrorList { func ValidateThirdPartyResourceDataUpdate(update, old *extensions.ThirdPartyResourceData) field.ErrorList {
return ValidateThirdPartyResourceData(update) return ValidateThirdPartyResourceData(update)
} }
func ValidateThirdPartyResourceData(obj *extensions.ThirdPartyResourceData) validation.ErrorList { func ValidateThirdPartyResourceData(obj *extensions.ThirdPartyResourceData) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if len(obj.Name) == 0 { if len(obj.Name) == 0 {
allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("name"), obj.Name, "must be non-empty")) allErrs = append(allErrs, field.NewInvalidError(field.NewPath("name"), obj.Name, "must be non-empty"))
} }
return allErrs return allErrs
} }
func ValidateJob(job *extensions.Job) validation.ErrorList { func ValidateJob(job *extensions.Job) field.ErrorList {
allErrs := validation.ErrorList{}
// Jobs and rcs have the same name validation // Jobs and rcs have the same name validation
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&job.ObjectMeta, true, apivalidation.ValidateReplicationControllerName, validation.NewFieldPath("metadata"))...) allErrs := apivalidation.ValidateObjectMeta(&job.ObjectMeta, true, apivalidation.ValidateReplicationControllerName, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateJobSpec(&job.Spec, validation.NewFieldPath("spec"))...) allErrs = append(allErrs, ValidateJobSpec(&job.Spec, field.NewPath("spec"))...)
return allErrs return allErrs
} }
func ValidateJobSpec(spec *extensions.JobSpec, fldPath *validation.FieldPath) validation.ErrorList { func ValidateJobSpec(spec *extensions.JobSpec, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if spec.Parallelism != nil { if spec.Parallelism != nil {
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(*spec.Parallelism), fldPath.Child("parallelism"))...) 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"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(*spec.Completions), fldPath.Child("completions"))...)
} }
if spec.Selector == nil { if spec.Selector == nil {
allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("selector"))) allErrs = append(allErrs, field.NewRequiredError(fldPath.Child("selector")))
} else { } else {
allErrs = append(allErrs, ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) 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 { if selector, err := extensions.LabelSelectorAsSelector(spec.Selector); err == nil {
labels := labels.Set(spec.Template.Labels) labels := labels.Set(spec.Template.Labels)
if !selector.Matches(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.NewInvalidError(fldPath.Child("template", "metadata", "labels"), spec.Template.Labels, "selector does not match template"))
} }
} }
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(&spec.Template, fldPath.Child("template"))...) allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(&spec.Template, fldPath.Child("template"))...)
if spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure && if spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure &&
spec.Template.Spec.RestartPolicy != api.RestartPolicyNever { spec.Template.Spec.RestartPolicy != api.RestartPolicyNever {
allErrs = append(allErrs, validation.NewNotSupportedError(fldPath.Child("template", "spec", "restartPolicy"), allErrs = append(allErrs, field.NewNotSupportedError(fldPath.Child("template", "spec", "restartPolicy"),
spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)})) spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)}))
} }
return allErrs return allErrs
} }
func ValidateJobStatus(status *extensions.JobStatus, fldPath *validation.FieldPath) validation.ErrorList { func ValidateJobStatus(status *extensions.JobStatus, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.Active), fldPath.Child("active"))...) 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.Succeeded), fldPath.Child("succeeded"))...)
allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.Failed), fldPath.Child("failed"))...) allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(status.Failed), fldPath.Child("failed"))...)
return allErrs return allErrs
} }
func ValidateJobUpdate(job, oldJob *extensions.Job) validation.ErrorList { func ValidateJobUpdate(job, oldJob *extensions.Job) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, ValidateJobSpecUpdate(job.Spec, oldJob.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateJobSpecUpdate(job.Spec, oldJob.Spec, validation.NewFieldPath("spec"))...)
return allErrs return allErrs
} }
func ValidateJobUpdateStatus(job, oldJob *extensions.Job) validation.ErrorList { func ValidateJobUpdateStatus(job, oldJob *extensions.Job) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, validation.NewFieldPath("metadata"))...)
allErrs = append(allErrs, ValidateJobStatusUpdate(job.Status, oldJob.Status)...) allErrs = append(allErrs, ValidateJobStatusUpdate(job.Status, oldJob.Status)...)
return allErrs return allErrs
} }
func ValidateJobSpecUpdate(spec, oldSpec extensions.JobSpec, fldPath *validation.FieldPath) validation.ErrorList { func ValidateJobSpecUpdate(spec, oldSpec extensions.JobSpec, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateJobSpec(&spec, fldPath)...) allErrs = append(allErrs, ValidateJobSpec(&spec, fldPath)...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Completions, oldSpec.Completions, fldPath.Child("completions"))...) allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Completions, oldSpec.Completions, fldPath.Child("completions"))...)
allErrs = append(allErrs, apivalidation.ValidateImmutableField(spec.Selector, oldSpec.Selector, fldPath.Child("selector"))...) 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 return allErrs
} }
func ValidateJobStatusUpdate(status, oldStatus extensions.JobStatus) validation.ErrorList { func ValidateJobStatusUpdate(status, oldStatus extensions.JobStatus) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateJobStatus(&status, validation.NewFieldPath("status"))...) allErrs = append(allErrs, ValidateJobStatus(&status, field.NewPath("status"))...)
return allErrs return allErrs
} }
// ValidateIngress tests if required fields in the Ingress are set. // ValidateIngress tests if required fields in the Ingress are set.
func ValidateIngress(ingress *extensions.Ingress) validation.ErrorList { func ValidateIngress(ingress *extensions.Ingress) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMeta(&ingress.ObjectMeta, true, ValidateIngressName, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&ingress.ObjectMeta, true, ValidateIngressName, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, validation.NewFieldPath("spec"))...)
return allErrs return allErrs
} }
@ -419,13 +407,13 @@ func ValidateIngressName(name string, prefix bool) (bool, string) {
} }
// ValidateIngressSpec tests if required fields in the IngressSpec are set. // ValidateIngressSpec tests if required fields in the IngressSpec are set.
func ValidateIngressSpec(spec *extensions.IngressSpec, fldPath *validation.FieldPath) validation.ErrorList { func ValidateIngressSpec(spec *extensions.IngressSpec, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
// TODO: Is a default backend mandatory? // TODO: Is a default backend mandatory?
if spec.Backend != nil { if spec.Backend != nil {
allErrs = append(allErrs, validateIngressBackend(spec.Backend, fldPath.Child("backend"))...) allErrs = append(allErrs, validateIngressBackend(spec.Backend, fldPath.Child("backend"))...)
} else if len(spec.Rules) == 0 { } 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.NewInvalidError(fldPath.Child("rules"), spec.Rules, "Either a default backend or a set of host rules are required for ingress."))
} }
if len(spec.Rules) > 0 { if len(spec.Rules) > 0 {
allErrs = append(allErrs, validateIngressRules(spec.Rules, fldPath.Child("rules"))...) 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. // ValidateIngressUpdate tests if required fields in the Ingress are set.
func ValidateIngressUpdate(ingress, oldIngress *extensions.Ingress) validation.ErrorList { func ValidateIngressUpdate(ingress, oldIngress *extensions.Ingress) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, validation.NewFieldPath("spec"))...)
return allErrs return allErrs
} }
// ValidateIngressStatusUpdate tests if required fields in the Ingress are set when updating status. // ValidateIngressStatusUpdate tests if required fields in the Ingress are set when updating status.
func ValidateIngressStatusUpdate(ingress, oldIngress *extensions.Ingress) validation.ErrorList { func ValidateIngressStatusUpdate(ingress, oldIngress *extensions.Ingress) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, apivalidation.ValidateLoadBalancerStatus(&ingress.Status.LoadBalancer, field.NewPath("status", "loadBalancer"))...)
allErrs = append(allErrs, apivalidation.ValidateLoadBalancerStatus(&ingress.Status.LoadBalancer, validation.NewFieldPath("status", "loadBalancer"))...)
return allErrs return allErrs
} }
func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *validation.FieldPath) validation.ErrorList { func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if len(IngressRules) == 0 { if len(IngressRules) == 0 {
return append(allErrs, validation.NewRequiredError(fldPath)) return append(allErrs, field.NewRequiredError(fldPath))
} }
for i, ih := range IngressRules { for i, ih := range IngressRules {
if len(ih.Host) > 0 { if len(ih.Host) > 0 {
// TODO: Ports and ips are allowed in the host part of a url // TODO: Ports and ips are allowed in the host part of a url
// according to RFC 3986, consider allowing them. // according to RFC 3986, consider allowing them.
if valid, errMsg := apivalidation.NameIsDNSSubdomain(ih.Host, false); !valid { 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.NewInvalidError(fldPath.Index(i).Child("host"), ih.Host, errMsg))
} }
if isIP := (net.ParseIP(ih.Host) != nil); isIP { 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.NewInvalidError(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))...) allErrs = append(allErrs, validateIngressRuleValue(&ih.IngressRuleValue, fldPath.Index(0))...)
@ -470,23 +456,23 @@ func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *valida
return allErrs return allErrs
} }
func validateIngressRuleValue(ingressRule *extensions.IngressRuleValue, fldPath *validation.FieldPath) validation.ErrorList { func validateIngressRuleValue(ingressRule *extensions.IngressRuleValue, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if ingressRule.HTTP != nil { if ingressRule.HTTP != nil {
allErrs = append(allErrs, validateHTTPIngressRuleValue(ingressRule.HTTP, fldPath.Child("http"))...) allErrs = append(allErrs, validateHTTPIngressRuleValue(ingressRule.HTTP, fldPath.Child("http"))...)
} }
return allErrs return allErrs
} }
func validateHTTPIngressRuleValue(httpIngressRuleValue *extensions.HTTPIngressRuleValue, fldPath *validation.FieldPath) validation.ErrorList { func validateHTTPIngressRuleValue(httpIngressRuleValue *extensions.HTTPIngressRuleValue, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if len(httpIngressRuleValue.Paths) == 0 { if len(httpIngressRuleValue.Paths) == 0 {
allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("paths"))) allErrs = append(allErrs, field.NewRequiredError(fldPath.Child("paths")))
} }
for i, rule := range httpIngressRuleValue.Paths { for i, rule := range httpIngressRuleValue.Paths {
if len(rule.Path) > 0 { if len(rule.Path) > 0 {
if !strings.HasPrefix(rule.Path, "/") { 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.NewInvalidError(fldPath.Child("paths").Index(i).Child("path"), rule.Path, "must begin with /"))
} }
// TODO: More draconian path regex validation. // TODO: More draconian path regex validation.
// Path must be a valid regex. This is the basic requirement. // 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. // the user is confusing url regexes with path regexes.
_, err := regexp.CompilePOSIX(rule.Path) _, err := regexp.CompilePOSIX(rule.Path)
if err != nil { 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.NewInvalidError(fldPath.Child("paths").Index(i).Child("path"), rule.Path, "must be a valid regex."))
} }
} }
allErrs = append(allErrs, validateIngressBackend(&rule.Backend, fldPath.Child("backend"))...) 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. // validateIngressBackend tests if a given backend is valid.
func validateIngressBackend(backend *extensions.IngressBackend, fldPath *validation.FieldPath) validation.ErrorList { func validateIngressBackend(backend *extensions.IngressBackend, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
// All backends must reference a single local service by name, and a single service port by name or number. // All backends must reference a single local service by name, and a single service port by name or number.
if len(backend.ServiceName) == 0 { if len(backend.ServiceName) == 0 {
return append(allErrs, validation.NewRequiredError(fldPath.Child("serviceName"))) return append(allErrs, field.NewRequiredError(fldPath.Child("serviceName")))
} else if ok, errMsg := apivalidation.ValidateServiceName(backend.ServiceName, false); !ok { } 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.NewInvalidError(fldPath.Child("serviceName"), backend.ServiceName, errMsg))
} }
if backend.ServicePort.Type == intstr.String { if backend.ServicePort.Type == intstr.String {
if !validation.IsDNS1123Label(backend.ServicePort.StrVal) { if !validation.IsDNS1123Label(backend.ServicePort.StrVal) {
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort.StrVal, apivalidation.DNS1123LabelErrorMsg)) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort.StrVal, apivalidation.DNS1123LabelErrorMsg))
} }
if !validation.IsValidPortName(backend.ServicePort.StrVal) { if !validation.IsValidPortName(backend.ServicePort.StrVal) {
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort.StrVal, apivalidation.PortNameErrorMsg)) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort.StrVal, apivalidation.PortNameErrorMsg))
} }
} else if !validation.IsValidPortNum(backend.ServicePort.IntValue()) { } else if !validation.IsValidPortNum(backend.ServicePort.IntValue()) {
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort, apivalidation.PortRangeErrorMsg)) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("servicePort"), backend.ServicePort, apivalidation.PortRangeErrorMsg))
} }
return allErrs return allErrs
} }
func validateClusterAutoscalerSpec(spec extensions.ClusterAutoscalerSpec, fldPath *validation.FieldPath) validation.ErrorList { func validateClusterAutoscalerSpec(spec extensions.ClusterAutoscalerSpec, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if spec.MinNodes < 0 { if spec.MinNodes < 0 {
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("minNodes"), spec.MinNodes, `must be non-negative`)) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("minNodes"), spec.MinNodes, `must be non-negative`))
} }
if spec.MaxNodes < spec.MinNodes { 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.NewInvalidError(fldPath.Child("maxNodes"), spec.MaxNodes, `must be greater than or equal to minNodes`))
} }
if len(spec.TargetUtilization) == 0 { if len(spec.TargetUtilization) == 0 {
allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("targetUtilization"))) allErrs = append(allErrs, field.NewRequiredError(fldPath.Child("targetUtilization")))
} }
for _, target := range spec.TargetUtilization { for _, target := range spec.TargetUtilization {
if len(target.Resource) == 0 { if len(target.Resource) == 0 {
allErrs = append(allErrs, validation.NewRequiredError(fldPath.Child("targetUtilization", "resource"))) allErrs = append(allErrs, field.NewRequiredError(fldPath.Child("targetUtilization", "resource")))
} }
if target.Value <= 0 { if target.Value <= 0 {
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("targetUtilization", "value"), target.Value, "must be greater than 0")) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("targetUtilization", "value"), target.Value, "must be greater than 0"))
} }
if target.Value > 1 { 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.NewInvalidError(fldPath.Child("targetUtilization", "value"), target.Value, "must be less or equal 1"))
} }
} }
return allErrs return allErrs
} }
func ValidateClusterAutoscaler(autoscaler *extensions.ClusterAutoscaler) validation.ErrorList { func ValidateClusterAutoscaler(autoscaler *extensions.ClusterAutoscaler) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if autoscaler.Name != "ClusterAutoscaler" { if autoscaler.Name != "ClusterAutoscaler" {
allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("metadata", "name"), autoscaler.Name, `name must be ClusterAutoscaler`)) allErrs = append(allErrs, field.NewInvalidError(field.NewPath("metadata", "name"), autoscaler.Name, `name must be ClusterAutoscaler`))
} }
if autoscaler.Namespace != api.NamespaceDefault { if autoscaler.Namespace != api.NamespaceDefault {
allErrs = append(allErrs, validation.NewInvalidError(validation.NewFieldPath("metadata", "namespace"), autoscaler.Namespace, `namespace must be default`)) allErrs = append(allErrs, field.NewInvalidError(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 return allErrs
} }
func ValidateLabelSelector(ps *extensions.LabelSelector, fldPath *validation.FieldPath) validation.ErrorList { func ValidateLabelSelector(ps *extensions.LabelSelector, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
if ps == nil { if ps == nil {
return allErrs return allErrs
} }
@ -579,30 +565,30 @@ func ValidateLabelSelector(ps *extensions.LabelSelector, fldPath *validation.Fie
return allErrs return allErrs
} }
func ValidateLabelSelectorRequirement(sr extensions.LabelSelectorRequirement, fldPath *validation.FieldPath) validation.ErrorList { func ValidateLabelSelectorRequirement(sr extensions.LabelSelectorRequirement, fldPath *field.Path) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
switch sr.Operator { switch sr.Operator {
case extensions.LabelSelectorOpIn, extensions.LabelSelectorOpNotIn: case extensions.LabelSelectorOpIn, extensions.LabelSelectorOpNotIn:
if len(sr.Values) == 0 { 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.NewInvalidError(fldPath.Child("values"), sr.Values, "must be non-empty when operator is In or NotIn"))
} }
case extensions.LabelSelectorOpExists, extensions.LabelSelectorOpDoesNotExist: case extensions.LabelSelectorOpExists, extensions.LabelSelectorOpDoesNotExist:
if len(sr.Values) > 0 { 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.NewInvalidError(fldPath.Child("values"), sr.Values, "must be empty when operator is Exists or DoesNotExist"))
} }
default: default:
allErrs = append(allErrs, validation.NewInvalidError(fldPath.Child("operator"), sr.Operator, "not a valid pod selector operator")) allErrs = append(allErrs, field.NewInvalidError(fldPath.Child("operator"), sr.Operator, "not a valid pod selector operator"))
} }
allErrs = append(allErrs, apivalidation.ValidateLabelName(sr.Key, fldPath.Child("key"))...) allErrs = append(allErrs, apivalidation.ValidateLabelName(sr.Key, fldPath.Child("key"))...)
return allErrs return allErrs
} }
func ValidateScale(scale *extensions.Scale) validation.ErrorList { func ValidateScale(scale *extensions.Scale) field.ErrorList {
allErrs := validation.ErrorList{} allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&scale.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, validation.NewFieldPath("metadata"))...) allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&scale.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...)
if scale.Spec.Replicas < 0 { 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.NewInvalidError(field.NewPath("spec", "replicas"), scale.Spec.Replicas, "must be non-negative"))
} }
return allErrs return allErrs

View File

@ -31,7 +31,7 @@ import (
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing" apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
@ -274,15 +274,15 @@ func TestCheckInvalidErr(t *testing.T) {
expected string expected string
}{ }{
{ {
errors.NewInvalid("Invalid1", "invalidation", validation.ErrorList{validation.NewInvalidError(validation.NewFieldPath("field"), "single", "details")}), errors.NewInvalid("Invalid1", "invalidation", field.ErrorList{field.NewInvalidError(field.NewPath("field"), "single", "details")}),
`Error from server: Invalid1 "invalidation" is invalid: field: invalid value 'single', Details: 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.NewInvalidError(field.NewPath("field1"), "multi1", "details"), field.NewInvalidError(field.NewPath("field2"), "multi2", "details")}),
`Error from server: Invalid2 "invalidation" is invalid: [field1: invalid value 'multi1', Details: details, field2: invalid value 'multi2', Details: 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: <nil>`, `Error from server: Invalid3 "invalidation" is invalid: <nil>`,
}, },
} }

View File

@ -30,7 +30,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/util/format" "k8s.io/kubernetes/pkg/kubelet/util/format"
"k8s.io/kubernetes/pkg/util/config" "k8s.io/kubernetes/pkg/util/config"
"k8s.io/kubernetes/pkg/util/sets" "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. // 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) { func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventRecorder) (filtered []*api.Pod) {
names := sets.String{} names := sets.String{}
for i, pod := range pods { for i, pod := range pods {
var errlist utilvalidation.ErrorList var errlist field.ErrorList
if errs := validation.ValidatePod(pod); len(errs) != 0 { if errs := validation.ValidatePod(pod); len(errs) != 0 {
errlist = append(errlist, errs...) errlist = append(errlist, errs...)
// If validation fails, don't trust it any further - // If validation fails, don't trust it any further -
@ -317,8 +317,9 @@ func filterInvalidPods(pods []*api.Pod, source string, recorder record.EventReco
} else { } else {
name := kubecontainer.GetPodFullName(pod) name := kubecontainer.GetPodFullName(pod)
if names.Has(name) { if names.Has(name) {
//FIXME: this implies an API version // TODO: when validation becomes versioned, this gets a bit
errlist = append(errlist, utilvalidation.NewDuplicateError(utilvalidation.NewFieldPath("metadata", "name"), pod.Name)) // more complicated.
errlist = append(errlist, field.NewDuplicateError(field.NewPath("metadata", "name"), pod.Name))
} else { } else {
names.Insert(name) names.Insert(name)
} }

View File

@ -77,7 +77,7 @@ import (
"k8s.io/kubernetes/pkg/util/procfs" "k8s.io/kubernetes/pkg/util/procfs"
"k8s.io/kubernetes/pkg/util/selinux" "k8s.io/kubernetes/pkg/util/selinux"
"k8s.io/kubernetes/pkg/util/sets" "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/util/yaml"
"k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/pkg/version"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
@ -2178,7 +2178,7 @@ func (s podsByCreationTime) Less(i, j int) bool {
func hasHostPortConflicts(pods []*api.Pod) bool { func hasHostPortConflicts(pods []*api.Pod) bool {
ports := sets.String{} ports := sets.String{}
for _, pod := range pods { 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) glog.Errorf("Pod %q: HostPort is already allocated, ignoring: %v", kubecontainer.GetPodFullName(pod), errs)
return true return true
} }

View File

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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. // rcStrategy implements verification logic for Replication Controllers.
@ -76,7 +76,7 @@ func (rcStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new replication controller. // 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) controller := obj.(*api.ReplicationController)
return validation.ValidateReplicationController(controller) return validation.ValidateReplicationController(controller)
} }
@ -92,7 +92,7 @@ func (rcStrategy) AllowCreateOnUpdate() bool {
} }
// ValidateUpdate is the default update validation for an end user. // 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)) validationErrorList := validation.ValidateReplicationController(obj.(*api.ReplicationController))
updateErrorList := validation.ValidateReplicationControllerUpdate(obj.(*api.ReplicationController), old.(*api.ReplicationController)) updateErrorList := validation.ValidateReplicationControllerUpdate(obj.(*api.ReplicationController), old.(*api.ReplicationController))
return append(validationErrorList, updateErrorList...) return append(validationErrorList, updateErrorList...)
@ -141,6 +141,6 @@ func (rcStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
newRc.Spec = oldRc.Spec 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)) return validation.ValidateReplicationControllerStatusUpdate(obj.(*api.ReplicationController), old.(*api.ReplicationController))
} }

View File

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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. // daemonSetStrategy implements verification logic for daemon sets.
@ -77,7 +77,7 @@ func (daemonSetStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new daemon set. // 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) daemonSet := obj.(*extensions.DaemonSet)
return validation.ValidateDaemonSet(daemonSet) return validation.ValidateDaemonSet(daemonSet)
} }
@ -93,7 +93,7 @@ func (daemonSetStrategy) AllowCreateOnUpdate() bool {
} }
// ValidateUpdate is the default update validation for an end user. // 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)) validationErrorList := validation.ValidateDaemonSet(obj.(*extensions.DaemonSet))
updateErrorList := validation.ValidateDaemonSetUpdate(obj.(*extensions.DaemonSet), old.(*extensions.DaemonSet)) updateErrorList := validation.ValidateDaemonSetUpdate(obj.(*extensions.DaemonSet), old.(*extensions.DaemonSet))
return append(validationErrorList, updateErrorList...) return append(validationErrorList, updateErrorList...)
@ -138,6 +138,6 @@ func (daemonSetStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
newDaemonSet.Spec = oldDaemonSet.Spec 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)) return validation.ValidateDaemonSetStatusUpdate(obj.(*extensions.DaemonSet), old.(*extensions.DaemonSet))
} }

View File

@ -26,7 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
// deploymentStrategy implements behavior for Deployments. // deploymentStrategy implements behavior for Deployments.
@ -51,7 +51,7 @@ func (deploymentStrategy) PrepareForCreate(obj runtime.Object) {
} }
// Validate validates a new deployment. // 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) deployment := obj.(*extensions.Deployment)
return validation.ValidateDeployment(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. // 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)) 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 // 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)) return validation.ValidateDeploymentUpdate(obj.(*extensions.Deployment), old.(*extensions.Deployment))
} }

View File

@ -26,7 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
// endpointsStrategy implements behavior for Endpoints // endpointsStrategy implements behavior for Endpoints
@ -53,7 +53,7 @@ func (endpointsStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new endpoints. // 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)) return validation.ValidateEndpoints(obj.(*api.Endpoints))
} }
@ -69,7 +69,7 @@ func (endpointsStrategy) AllowCreateOnUpdate() bool {
} }
// ValidateUpdate is the default update validation for an end user. // 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)) errorList := validation.ValidateEndpoints(obj.(*api.Endpoints))
return append(errorList, validation.ValidateEndpointsUpdate(obj.(*api.Endpoints), old.(*api.Endpoints))...) return append(errorList, validation.ValidateEndpointsUpdate(obj.(*api.Endpoints), old.(*api.Endpoints))...)
} }

View File

@ -26,7 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
type eventStrategy struct { type eventStrategy struct {
@ -48,7 +48,7 @@ func (eventStrategy) PrepareForCreate(obj runtime.Object) {
func (eventStrategy) PrepareForUpdate(obj, old 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) event := obj.(*api.Event)
return validation.ValidateEvent(event) return validation.ValidateEvent(event)
} }
@ -61,7 +61,7 @@ func (eventStrategy) AllowCreateOnUpdate() bool {
return true 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) event := obj.(*api.Event)
return validation.ValidateEvent(event) return validation.ValidateEvent(event)
} }

View File

@ -32,7 +32,7 @@ import (
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
storagetesting "k8s.io/kubernetes/pkg/storage/testing" storagetesting "k8s.io/kubernetes/pkg/storage/testing"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
type testRESTStrategy struct { 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) PrepareForCreate(obj runtime.Object) {}
func (t *testRESTStrategy) PrepareForUpdate(obj, old 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 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 return nil
} }
func (t *testRESTStrategy) Canonicalize(obj runtime.Object) {} func (t *testRESTStrategy) Canonicalize(obj runtime.Object) {}

View File

@ -26,7 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
// autoscalerStrategy implements behavior for HorizontalPodAutoscalers // autoscalerStrategy implements behavior for HorizontalPodAutoscalers
@ -53,7 +53,7 @@ func (autoscalerStrategy) PrepareForCreate(obj runtime.Object) {
} }
// Validate validates a new autoscaler. // 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) autoscaler := obj.(*extensions.HorizontalPodAutoscaler)
return validation.ValidateHorizontalPodAutoscaler(autoscaler) 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. // 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)) return validation.ValidateHorizontalPodAutoscalerUpdate(obj.(*extensions.HorizontalPodAutoscaler), old.(*extensions.HorizontalPodAutoscaler))
} }
@ -115,6 +115,6 @@ func (autoscalerStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
newAutoscaler.Spec = oldAutoscaler.Spec 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)) return validation.ValidateHorizontalPodAutoscalerStatusUpdate(obj.(*extensions.HorizontalPodAutoscaler), old.(*extensions.HorizontalPodAutoscaler))
} }

View File

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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. // ingressStrategy implements verification logic for Replication Ingresss.
@ -70,7 +70,7 @@ func (ingressStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new Ingress. // 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) ingress := obj.(*extensions.Ingress)
err := validation.ValidateIngress(ingress) err := validation.ValidateIngress(ingress)
return err return err
@ -86,7 +86,7 @@ func (ingressStrategy) AllowCreateOnUpdate() bool {
} }
// ValidateUpdate is the default update validation for an end user. // 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)) validationErrorList := validation.ValidateIngress(obj.(*extensions.Ingress))
updateErrorList := validation.ValidateIngressUpdate(obj.(*extensions.Ingress), old.(*extensions.Ingress)) updateErrorList := validation.ValidateIngressUpdate(obj.(*extensions.Ingress), old.(*extensions.Ingress))
return append(validationErrorList, updateErrorList...) 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 // 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)) return validation.ValidateIngressStatusUpdate(obj.(*extensions.Ingress), old.(*extensions.Ingress))
} }

View File

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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. // jobStrategy implements verification logic for Replication Controllers.
@ -58,7 +58,7 @@ func (jobStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new job. // 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) job := obj.(*extensions.Job)
return validation.ValidateJob(job) return validation.ValidateJob(job)
} }
@ -77,7 +77,7 @@ func (jobStrategy) AllowCreateOnUpdate() bool {
} }
// ValidateUpdate is the default update validation for an end user. // 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)) validationErrorList := validation.ValidateJob(obj.(*extensions.Job))
updateErrorList := validation.ValidateJobUpdate(obj.(*extensions.Job), old.(*extensions.Job)) updateErrorList := validation.ValidateJobUpdate(obj.(*extensions.Job), old.(*extensions.Job))
return append(validationErrorList, updateErrorList...) return append(validationErrorList, updateErrorList...)
@ -95,7 +95,7 @@ func (jobStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
newJob.Spec = oldJob.Spec 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)) return validation.ValidateJobUpdateStatus(obj.(*extensions.Job), old.(*extensions.Job))
} }

View File

@ -26,7 +26,7 @@ import (
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
type limitrangeStrategy struct { type limitrangeStrategy struct {
@ -52,7 +52,7 @@ func (limitrangeStrategy) PrepareForCreate(obj runtime.Object) {
func (limitrangeStrategy) PrepareForUpdate(obj, old 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) limitRange := obj.(*api.LimitRange)
return validation.ValidateLimitRange(limitRange) return validation.ValidateLimitRange(limitRange)
} }
@ -65,7 +65,7 @@ func (limitrangeStrategy) AllowCreateOnUpdate() bool {
return true 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) limitRange := obj.(*api.LimitRange)
return validation.ValidateLimitRange(limitRange) return validation.ValidateLimitRange(limitRange)
} }

View File

@ -25,7 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
// namespaceStrategy implements behavior for Namespaces // namespaceStrategy implements behavior for Namespaces
@ -77,7 +77,7 @@ func (namespaceStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new namespace. // 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) namespace := obj.(*api.Namespace)
return validation.ValidateNamespace(namespace) return validation.ValidateNamespace(namespace)
} }
@ -92,7 +92,7 @@ func (namespaceStrategy) AllowCreateOnUpdate() bool {
} }
// ValidateUpdate is the default update validation for an end user. // 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)) errorList := validation.ValidateNamespace(obj.(*api.Namespace))
return append(errorList, validation.ValidateNamespaceUpdate(obj.(*api.Namespace), old.(*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 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)) return validation.ValidateNamespaceStatusUpdate(obj.(*api.Namespace), old.(*api.Namespace))
} }
@ -123,7 +123,7 @@ type namespaceFinalizeStrategy struct {
var FinalizeStrategy = namespaceFinalizeStrategy{Strategy} 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)) return validation.ValidateNamespaceFinalizeUpdate(obj.(*api.Namespace), old.(*api.Namespace))
} }

View File

@ -34,7 +34,7 @@ import (
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
nodeutil "k8s.io/kubernetes/pkg/util/node" 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 // nodeStrategy implements behavior for nodes
@ -71,7 +71,7 @@ func (nodeStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new node. // 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) node := obj.(*api.Node)
return validation.ValidateNode(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. // 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)) errorList := validation.ValidateNode(obj.(*api.Node))
return append(errorList, validation.ValidateNodeUpdate(obj.(*api.Node), old.(*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 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)) return validation.ValidateNodeUpdate(obj.(*api.Node), old.(*api.Node))
} }

View File

@ -25,7 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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 // persistentvolumeStrategy implements behavior for PersistentVolume objects
@ -48,7 +48,7 @@ func (persistentvolumeStrategy) PrepareForCreate(obj runtime.Object) {
pv.Status = api.PersistentVolumeStatus{} 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) persistentvolume := obj.(*api.PersistentVolume)
return validation.ValidatePersistentVolume(persistentvolume) return validation.ValidatePersistentVolume(persistentvolume)
} }
@ -68,7 +68,7 @@ func (persistentvolumeStrategy) PrepareForUpdate(obj, old runtime.Object) {
newPv.Status = oldPv.Status 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)) errorList := validation.ValidatePersistentVolume(obj.(*api.PersistentVolume))
return append(errorList, validation.ValidatePersistentVolumeUpdate(obj.(*api.PersistentVolume), old.(*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 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)) return validation.ValidatePersistentVolumeStatusUpdate(obj.(*api.PersistentVolume), old.(*api.PersistentVolume))
} }

View File

@ -25,7 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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 // persistentvolumeclaimStrategy implements behavior for PersistentVolumeClaim objects
@ -48,7 +48,7 @@ func (persistentvolumeclaimStrategy) PrepareForCreate(obj runtime.Object) {
pv.Status = api.PersistentVolumeClaimStatus{} 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) pvc := obj.(*api.PersistentVolumeClaim)
return validation.ValidatePersistentVolumeClaim(pvc) return validation.ValidatePersistentVolumeClaim(pvc)
} }
@ -68,7 +68,7 @@ func (persistentvolumeclaimStrategy) PrepareForUpdate(obj, old runtime.Object) {
newPvc.Status = oldPvc.Status 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)) errorList := validation.ValidatePersistentVolumeClaim(obj.(*api.PersistentVolumeClaim))
return append(errorList, validation.ValidatePersistentVolumeClaimUpdate(obj.(*api.PersistentVolumeClaim), old.(*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 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)) return validation.ValidatePersistentVolumeClaimStatusUpdate(obj.(*api.PersistentVolumeClaim), old.(*api.PersistentVolumeClaim))
} }

View File

@ -35,7 +35,7 @@ import (
podrest "k8s.io/kubernetes/pkg/registry/pod/rest" podrest "k8s.io/kubernetes/pkg/registry/pod/rest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage" "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 // 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) binding := obj.(*api.Binding)
// TODO: move me to a binding strategy // TODO: move me to a binding strategy
if len(binding.Target.Kind) != 0 && binding.Target.Kind != "Node" { 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.NewNotSupportedError(field.NewPath("target", "kind"), binding.Target.Kind, []string{"Node", ""})})
} }
if len(binding.Target.Name) == 0 { 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.NewRequiredError(field.NewPath("target", "name"))})
} }
err = r.assignPod(ctx, binding.Name, binding.Target.Name, binding.Annotations) err = r.assignPod(ctx, binding.Name, binding.Target.Name, binding.Annotations)
out = &unversioned.Status{Status: unversioned.StatusSuccess} out = &unversioned.Status{Status: unversioned.StatusSuccess}

View File

@ -33,7 +33,7 @@ import (
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
// podStrategy implements behavior for Pods // podStrategy implements behavior for Pods
@ -67,7 +67,7 @@ func (podStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new pod. // 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) pod := obj.(*api.Pod)
return validation.ValidatePod(pod) return validation.ValidatePod(pod)
} }
@ -82,7 +82,7 @@ func (podStrategy) AllowCreateOnUpdate() bool {
} }
// ValidateUpdate is the default update validation for an end user. // 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)) errorList := validation.ValidatePod(obj.(*api.Pod))
return append(errorList, validation.ValidatePodUpdate(obj.(*api.Pod), old.(*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 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 // TODO: merge valid fields after update
return validation.ValidatePodStatusUpdate(obj.(*api.Pod), old.(*api.Pod)) return validation.ValidatePodStatusUpdate(obj.(*api.Pod), old.(*api.Pod))
} }

View File

@ -25,7 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
// podTemplateStrategy implements behavior for PodTemplates // podTemplateStrategy implements behavior for PodTemplates
@ -49,7 +49,7 @@ func (podTemplateStrategy) PrepareForCreate(obj runtime.Object) {
} }
// Validate validates a new pod template. // 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) pod := obj.(*api.PodTemplate)
return validation.ValidatePodTemplate(pod) 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. // 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)) return validation.ValidatePodTemplateUpdate(obj.(*api.PodTemplate), old.(*api.PodTemplate))
} }

View File

@ -25,7 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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 // resourcequotaStrategy implements behavior for ResourceQuota objects
@ -57,7 +57,7 @@ func (resourcequotaStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new resourcequota. // 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) resourcequota := obj.(*api.ResourceQuota)
return validation.ValidateResourceQuota(resourcequota) return validation.ValidateResourceQuota(resourcequota)
} }
@ -72,7 +72,7 @@ func (resourcequotaStrategy) AllowCreateOnUpdate() bool {
} }
// ValidateUpdate is the default update validation for an end user. // 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)) errorList := validation.ValidateResourceQuota(obj.(*api.ResourceQuota))
return append(errorList, validation.ValidateResourceQuotaUpdate(obj.(*api.ResourceQuota), old.(*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 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)) return validation.ValidateResourceQuotaStatusUpdate(obj.(*api.ResourceQuota), old.(*api.ResourceQuota))
} }

View File

@ -26,7 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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 // strategy implements behavior for Secret objects
@ -50,7 +50,7 @@ func (strategy) NamespaceScoped() bool {
func (strategy) PrepareForCreate(obj runtime.Object) { 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)) return validation.ValidateSecret(obj.(*api.Secret))
} }
@ -64,7 +64,7 @@ func (strategy) AllowCreateOnUpdate() bool {
func (strategy) PrepareForUpdate(obj, old runtime.Object) { 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)) return validation.ValidateSecretUpdate(obj.(*api.Secret), old.(*api.Secret))
} }

View File

@ -35,7 +35,7 @@ import (
"k8s.io/kubernetes/pkg/registry/service/portallocator" "k8s.io/kubernetes/pkg/registry/service/portallocator"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/watch" "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. // Allocate next available.
ip, err := rs.serviceIPs.AllocateNext() ip, err := rs.serviceIPs.AllocateNext()
if err != nil { if err != nil {
el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "clusterIP"), service.Spec.ClusterIP, err.Error())} // TODO: what error should be returned here? It's not a
return nil, errors.NewInvalid("Service", service.Name, el) // 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() service.Spec.ClusterIP = ip.String()
releaseServiceIP = true releaseServiceIP = true
} else if api.IsServiceIPSet(service) { } else if api.IsServiceIPSet(service) {
// Try to respect the requested IP. // Try to respect the requested IP.
if err := rs.serviceIPs.Allocate(net.ParseIP(service.Spec.ClusterIP)); err != nil { 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.NewInvalidError(field.NewPath("spec", "clusterIP"), service.Spec.ClusterIP, err.Error())}
return nil, errors.NewInvalid("Service", service.Name, el) return nil, errors.NewInvalid("Service", service.Name, el)
} }
releaseServiceIP = true releaseServiceIP = true
@ -104,14 +107,17 @@ func (rs *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, err
if servicePort.NodePort != 0 { if servicePort.NodePort != 0 {
err := nodePortOp.Allocate(servicePort.NodePort) err := nodePortOp.Allocate(servicePort.NodePort)
if err != nil { 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.NewInvalidError(field.NewPath("spec", "ports").Index(i).Child("nodePort"), servicePort.NodePort, err.Error())}
return nil, errors.NewInvalid("Service", service.Name, el) return nil, errors.NewInvalid("Service", service.Name, el)
} }
} else if assignNodePorts { } else if assignNodePorts {
nodePort, err := nodePortOp.AllocateNext() nodePort, err := nodePortOp.AllocateNext()
if err != nil { if err != nil {
el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "ports").Index(i).Child("nodePort"), servicePort.NodePort, err.Error())} // TODO: what error should be returned here? It's not a
return nil, errors.NewInvalid("Service", service.Name, el) // 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 servicePort.NodePort = nodePort
} }
@ -223,15 +229,17 @@ func (rs *REST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, boo
if !contains(oldNodePorts, nodePort) { if !contains(oldNodePorts, nodePort) {
err := nodePortOp.Allocate(nodePort) err := nodePortOp.Allocate(nodePort)
if err != nil { if err != nil {
el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "ports").Index(i).Child("nodePort"), nodePort, err.Error())} el := field.ErrorList{field.NewInvalidError(field.NewPath("spec", "ports").Index(i).Child("nodePort"), nodePort, err.Error())}
return nil, false, errors.NewInvalid("Service", service.Name, el) return nil, false, errors.NewInvalid("Service", service.Name, el)
} }
} }
} else { } else {
nodePort, err = nodePortOp.AllocateNext() nodePort, err = nodePortOp.AllocateNext()
if err != nil { if err != nil {
el := utilvalidation.ErrorList{utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("spec", "ports").Index(i).Child("nodePort"), nodePort, err.Error())} // TODO: what error should be returned here? It's not a
return nil, false, errors.NewInvalid("Service", service.Name, el) // 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 servicePort.NodePort = nodePort
} }

View File

@ -25,7 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
utilvalidation "k8s.io/kubernetes/pkg/util/validation" "k8s.io/kubernetes/pkg/util/validation/field"
) )
// svcStrategy implements behavior for Services // svcStrategy implements behavior for Services
@ -58,7 +58,7 @@ func (svcStrategy) PrepareForUpdate(obj, old runtime.Object) {
} }
// Validate validates a new service. // 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) service := obj.(*api.Service)
return validation.ValidateService(service) return validation.ValidateService(service)
} }
@ -71,7 +71,7 @@ func (svcStrategy) AllowCreateOnUpdate() bool {
return true 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)) return validation.ValidateServiceUpdate(obj.(*api.Service), old.(*api.Service))
} }

View File

@ -25,7 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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 // strategy implements behavior for ServiceAccount objects
@ -46,7 +46,7 @@ func (strategy) PrepareForCreate(obj runtime.Object) {
cleanSecretReferences(obj.(*api.ServiceAccount)) 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)) 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)) return validation.ValidateServiceAccountUpdate(obj.(*api.ServiceAccount), old.(*api.ServiceAccount))
} }

View File

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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 // strategy implements behavior for ThirdPartyResource objects
@ -51,7 +51,7 @@ func (strategy) NamespaceScoped() bool {
func (strategy) PrepareForCreate(obj runtime.Object) { 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)) return validation.ValidateThirdPartyResource(obj.(*extensions.ThirdPartyResource))
} }
@ -66,7 +66,7 @@ func (strategy) AllowCreateOnUpdate() bool {
func (strategy) PrepareForUpdate(obj, old runtime.Object) { 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)) return validation.ValidateThirdPartyResourceUpdate(obj.(*extensions.ThirdPartyResource), old.(*extensions.ThirdPartyResource))
} }

View File

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "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 // strategy implements behavior for ThirdPartyResource objects
@ -51,7 +51,7 @@ func (strategy) NamespaceScoped() bool {
func (strategy) PrepareForCreate(obj runtime.Object) { 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)) return validation.ValidateThirdPartyResourceData(obj.(*extensions.ThirdPartyResourceData))
} }
@ -66,7 +66,7 @@ func (strategy) AllowCreateOnUpdate() bool {
func (strategy) PrepareForUpdate(obj, old runtime.Object) { 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)) return validation.ValidateThirdPartyResourceDataUpdate(obj.(*extensions.ThirdPartyResourceData), old.(*extensions.ThirdPartyResourceData))
} }

View File

@ -24,7 +24,7 @@ import (
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/runtime" "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) 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) version, err := strconv.ParseUint(resourceVersion, 10, 64)
if err != nil { if err != nil {
return 0, errors.NewInvalid("", "", utilvalidation.ErrorList{ return 0, errors.NewInvalid("", "", field.ErrorList{
// Validation errors are supposed to return version-specific field // Validation errors are supposed to return version-specific field
// paths, but this is probably close enough. // paths, but this is probably close enough.
utilvalidation.NewInvalidError(utilvalidation.NewFieldPath("resourceVersion"), resourceVersion, err.Error()), field.NewInvalidError(field.NewPath("resourceVersion"), resourceVersion, err.Error()),
}) })
} }
return version + 1, nil return version + 1, nil

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package validation package field
import ( import (
"fmt" "fmt"
@ -26,7 +26,7 @@ import (
) )
// Error is an implementation of the 'error' interface, which represents a // Error is an implementation of the 'error' interface, which represents a
// validation error. // field-level validation error.
type Error struct { type Error struct {
Type ErrorType Type ErrorType
Field string Field string
@ -121,33 +121,33 @@ func (t ErrorType) String() string {
// NewNotFoundError returns a *Error indicating "value not found". This is // 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). // used to report failure to find a requested value (e.g. looking up an ID).
func NewNotFoundError(field *FieldPath, value interface{}) *Error { func NewNotFoundError(field *Path, value interface{}) *Error {
return &Error{ErrorTypeNotFound, field.String(), value, ""} return &Error{ErrorTypeNotFound, field.String(), value, ""}
} }
// NewRequiredError returns a *Error indicating "value required". This is used // NewRequiredError returns a *Error indicating "value required". This is used
// to report required values that are not provided (e.g. empty strings, null // to report required values that are not provided (e.g. empty strings, null
// values, or empty arrays). // values, or empty arrays).
func NewRequiredError(field *FieldPath) *Error { func NewRequiredError(field *Path) *Error {
return &Error{ErrorTypeRequired, field.String(), "", ""} return &Error{ErrorTypeRequired, field.String(), "", ""}
} }
// NewDuplicateError returns a *Error indicating "duplicate value". This is // NewDuplicateError returns a *Error indicating "duplicate value". This is
// used to report collisions of values that must be unique (e.g. names or IDs). // used to report collisions of values that must be unique (e.g. names or IDs).
func NewDuplicateError(field *FieldPath, value interface{}) *Error { func NewDuplicateError(field *Path, value interface{}) *Error {
return &Error{ErrorTypeDuplicate, field.String(), value, ""} return &Error{ErrorTypeDuplicate, field.String(), value, ""}
} }
// NewInvalidError returns a *Error indicating "invalid value". This is used // NewInvalidError returns a *Error indicating "invalid value". This is used
// to report malformed values (e.g. failed regex match, too long, out of bounds). // to report malformed values (e.g. failed regex match, too long, out of bounds).
func NewInvalidError(field *FieldPath, value interface{}, detail string) *Error { func NewInvalidError(field *Path, value interface{}, detail string) *Error {
return &Error{ErrorTypeInvalid, field.String(), value, detail} return &Error{ErrorTypeInvalid, field.String(), value, detail}
} }
// NewNotSupportedError returns a *Error indicating "unsupported value". // NewNotSupportedError returns a *Error indicating "unsupported value".
// This is used to report unknown values for enumerated fields (e.g. a list of // This is used to report unknown values for enumerated fields (e.g. a list of
// valid values). // valid values).
func NewNotSupportedError(field *FieldPath, value interface{}, validValues []string) *Error { func NewNotSupportedError(field *Path, value interface{}, validValues []string) *Error {
detail := "" detail := ""
if validValues != nil && len(validValues) > 0 { if validValues != nil && len(validValues) > 0 {
detail = "supported values: " + strings.Join(validValues, ", ") 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 // report valid (as per formatting rules) values which would be accepted under
// some conditions, but which are not permitted by current conditions (e.g. // some conditions, but which are not permitted by current conditions (e.g.
// security policy). // security policy).
func NewForbiddenError(field *FieldPath, value interface{}) *Error { func NewForbiddenError(field *Path, value interface{}) *Error {
return &Error{ErrorTypeForbidden, field.String(), value, ""} 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 // report that the given value is too long. This is similar to
// NewInvalidError, but the returned error will not include the too-long // NewInvalidError, but the returned error will not include the too-long
// value. // value.
func NewTooLongError(field *FieldPath, value interface{}, maxLength int) *Error { func NewTooLongError(field *Path, value interface{}, maxLength int) *Error {
return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d characters", maxLength)} 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 // NewInternalError returns a *Error indicating "internal error". This is used
// to signal that an error was found that was not directly related to user // to signal that an error was found that was not directly related to user
// input. The err argument must be non-nil. // input. The err argument must be non-nil.
func NewInternalError(field *FieldPath, err error) *Error { func NewInternalError(field *Path, err error) *Error {
return &Error{ErrorTypeInternal, field.String(), nil, err.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 type ErrorList []*Error
// NewErrorTypeMatcher returns an errors.Matcher that returns true // NewErrorTypeMatcher returns an errors.Matcher that returns true

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package validation package field
import ( import (
"fmt" "fmt"
@ -28,27 +28,27 @@ func TestMakeFuncs(t *testing.T) {
expected ErrorType expected ErrorType
}{ }{
{ {
func() *Error { return NewInvalidError(NewFieldPath("f"), "v", "d") }, func() *Error { return NewInvalidError(NewPath("f"), "v", "d") },
ErrorTypeInvalid, ErrorTypeInvalid,
}, },
{ {
func() *Error { return NewNotSupportedError(NewFieldPath("f"), "v", nil) }, func() *Error { return NewNotSupportedError(NewPath("f"), "v", nil) },
ErrorTypeNotSupported, ErrorTypeNotSupported,
}, },
{ {
func() *Error { return NewDuplicateError(NewFieldPath("f"), "v") }, func() *Error { return NewDuplicateError(NewPath("f"), "v") },
ErrorTypeDuplicate, ErrorTypeDuplicate,
}, },
{ {
func() *Error { return NewNotFoundError(NewFieldPath("f"), "v") }, func() *Error { return NewNotFoundError(NewPath("f"), "v") },
ErrorTypeNotFound, ErrorTypeNotFound,
}, },
{ {
func() *Error { return NewRequiredError(NewFieldPath("f")) }, func() *Error { return NewRequiredError(NewPath("f")) },
ErrorTypeRequired, ErrorTypeRequired,
}, },
{ {
func() *Error { return NewInternalError(NewFieldPath("f"), fmt.Errorf("e")) }, func() *Error { return NewInternalError(NewPath("f"), fmt.Errorf("e")) },
ErrorTypeInternal, ErrorTypeInternal,
}, },
} }
@ -62,7 +62,7 @@ func TestMakeFuncs(t *testing.T) {
} }
func TestErrorUsefulMessage(t *testing.T) { func TestErrorUsefulMessage(t *testing.T) {
s := NewInvalidError(NewFieldPath("foo"), "bar", "deet").Error() s := NewInvalidError(NewPath("foo"), "bar", "deet").Error()
t.Logf("message: %v", s) t.Logf("message: %v", s)
for _, part := range []string{"foo", "bar", "deet", ErrorTypeInvalid.String()} { for _, part := range []string{"foo", "bar", "deet", ErrorTypeInvalid.String()} {
if !strings.Contains(s, part) { if !strings.Contains(s, part) {
@ -77,7 +77,7 @@ func TestErrorUsefulMessage(t *testing.T) {
KV map[string]int KV map[string]int
} }
s = NewInvalidError( s = NewInvalidError(
NewFieldPath("foo"), NewPath("foo"),
&complicated{ &complicated{
Baz: 1, Baz: 1,
Qux: "aoeu", Qux: "aoeu",
@ -102,8 +102,8 @@ func TestToAggregate(t *testing.T) {
testCases := []ErrorList{ testCases := []ErrorList{
nil, nil,
{}, {},
{NewInvalidError(NewFieldPath("f"), "v", "d")}, {NewInvalidError(NewPath("f"), "v", "d")},
{NewInvalidError(NewFieldPath("f"), "v", "d"), NewInternalError(NewFieldPath(""), fmt.Errorf("e"))}, {NewInvalidError(NewPath("f"), "v", "d"), NewInternalError(NewPath(""), fmt.Errorf("e"))},
} }
for i, tc := range testCases { for i, tc := range testCases {
agg := tc.ToAggregate() agg := tc.ToAggregate()
@ -121,9 +121,9 @@ func TestToAggregate(t *testing.T) {
func TestErrListFilter(t *testing.T) { func TestErrListFilter(t *testing.T) {
list := ErrorList{ list := ErrorList{
NewInvalidError(NewFieldPath("test.field"), "", ""), NewInvalidError(NewPath("test.field"), "", ""),
NewInvalidError(NewFieldPath("field.test"), "", ""), NewInvalidError(NewPath("field.test"), "", ""),
NewDuplicateError(NewFieldPath("test"), "value"), NewDuplicateError(NewPath("test"), "value"),
} }
if len(list.Filter(NewErrorTypeMatcher(ErrorTypeDuplicate))) != 2 { if len(list.Filter(NewErrorTypeMatcher(ErrorTypeDuplicate))) != 2 {
t.Errorf("should not filter") t.Errorf("should not filter")

View File

@ -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()
}

View File

@ -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())
}
}
}

View File

@ -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()
}

View File

@ -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())
}
}
}