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:
Solly Ross 2015-11-02 13:50:43 -05:00
parent fd03c2c1d7
commit e5ef9e1406
4 changed files with 89 additions and 0 deletions

View File

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

View File

@ -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

View File

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

View File

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