Add Validators for Scale Objects
This commit introduces a validator for use with Scale updates. The validator checks that we have > 0 replica count, as well as the normal ObjectMeta checks (some of which have to be faked since they don't exist on the Scale object).
This commit is contained in:
		| @@ -564,3 +564,14 @@ func ValidatePodSelectorRequirement(sr extensions.PodSelectorRequirement) errs.V | ||||
| 	allErrs = append(allErrs, apivalidation.ValidateLabelName(sr.Key, "key")...) | ||||
| 	return allErrs | ||||
| } | ||||
|  | ||||
| func ValidateScale(scale *extensions.Scale) errs.ValidationErrorList { | ||||
| 	allErrs := errs.ValidationErrorList{} | ||||
| 	allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&scale.ObjectMeta, true, apivalidation.NameIsDNSSubdomain).Prefix("metadata")...) | ||||
|  | ||||
| 	if scale.Spec.Replicas < 0 { | ||||
| 		allErrs = append(allErrs, errs.NewFieldInvalid("spec.replicas", scale.Spec.Replicas, "must be non-negative")) | ||||
| 	} | ||||
|  | ||||
| 	return allErrs | ||||
| } | ||||
|   | ||||
| @@ -1145,6 +1145,70 @@ func TestValidateClusterAutoscaler(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestValidateScale(t *testing.T) { | ||||
| 	successCases := []extensions.Scale{ | ||||
| 		{ | ||||
| 			ObjectMeta: api.ObjectMeta{ | ||||
| 				Name:      "frontend", | ||||
| 				Namespace: api.NamespaceDefault, | ||||
| 			}, | ||||
| 			Spec: extensions.ScaleSpec{ | ||||
| 				Replicas: 1, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ObjectMeta: api.ObjectMeta{ | ||||
| 				Name:      "frontend", | ||||
| 				Namespace: api.NamespaceDefault, | ||||
| 			}, | ||||
| 			Spec: extensions.ScaleSpec{ | ||||
| 				Replicas: 10, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ObjectMeta: api.ObjectMeta{ | ||||
| 				Name:      "frontend", | ||||
| 				Namespace: api.NamespaceDefault, | ||||
| 			}, | ||||
| 			Spec: extensions.ScaleSpec{ | ||||
| 				Replicas: 0, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, successCase := range successCases { | ||||
| 		if errs := ValidateScale(&successCase); len(errs) != 0 { | ||||
| 			t.Errorf("expected success: %v", errs) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	errorCases := []struct { | ||||
| 		scale extensions.Scale | ||||
| 		msg   string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			scale: extensions.Scale{ | ||||
| 				ObjectMeta: api.ObjectMeta{ | ||||
| 					Name:      "frontend", | ||||
| 					Namespace: api.NamespaceDefault, | ||||
| 				}, | ||||
| 				Spec: extensions.ScaleSpec{ | ||||
| 					Replicas: -1, | ||||
| 				}, | ||||
| 			}, | ||||
| 			msg: "must be non-negative", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, c := range errorCases { | ||||
| 		if errs := ValidateScale(&c.scale); len(errs) == 0 { | ||||
| 			t.Errorf("expected failure for %s", c.msg) | ||||
| 		} else if !strings.Contains(errs[0].Error(), c.msg) { | ||||
| 			t.Errorf("unexpected error: %v, expected: %s", errs[0], c.msg) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newInt(val int) *int { | ||||
| 	p := new(int) | ||||
| 	*p = val | ||||
|   | ||||
| @@ -30,6 +30,8 @@ import ( | ||||
| 	etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd" | ||||
| 	"k8s.io/kubernetes/pkg/runtime" | ||||
| 	"k8s.io/kubernetes/pkg/storage" | ||||
|  | ||||
| 	extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" | ||||
| ) | ||||
|  | ||||
| // DeploymentStorage includes dummy storage for Deployments and for Scale subresource. | ||||
| @@ -149,6 +151,11 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, | ||||
| 	if !ok { | ||||
| 		return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) | ||||
| 	} | ||||
|  | ||||
| 	if errs := extvalidation.ValidateScale(scale); len(errs) > 0 { | ||||
| 		return nil, false, errors.NewInvalid("scale", scale.Name, errs) | ||||
| 	} | ||||
|  | ||||
| 	deployment, err := (*r.registry).GetDeployment(ctx, scale.Name) | ||||
| 	if err != nil { | ||||
| 		return nil, false, errors.NewNotFound("scale", scale.Name) | ||||
|   | ||||
| @@ -29,6 +29,8 @@ import ( | ||||
| 	"k8s.io/kubernetes/pkg/registry/controller/etcd" | ||||
|  | ||||
| 	"k8s.io/kubernetes/pkg/apis/extensions" | ||||
|  | ||||
| 	extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" | ||||
| ) | ||||
|  | ||||
| // Container includes dummy storage for RC pods and experimental storage for Scale. | ||||
| @@ -89,6 +91,11 @@ func (r *ScaleREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object, | ||||
| 	if !ok { | ||||
| 		return nil, false, errors.NewBadRequest(fmt.Sprintf("wrong object passed to Scale update: %v", obj)) | ||||
| 	} | ||||
|  | ||||
| 	if errs := extvalidation.ValidateScale(scale); len(errs) > 0 { | ||||
| 		return nil, false, errors.NewInvalid("scale", scale.Name, errs) | ||||
| 	} | ||||
|  | ||||
| 	rc, err := (*r.registry).GetController(ctx, scale.Name) | ||||
| 	if err != nil { | ||||
| 		return nil, false, errors.NewNotFound("scale", scale.Name) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Solly Ross
					Solly Ross