diff --git a/pkg/apis/autoscaling/register.go b/pkg/apis/autoscaling/register.go index 519e8f6be0b..dfc86f24d2c 100644 --- a/pkg/apis/autoscaling/register.go +++ b/pkg/apis/autoscaling/register.go @@ -47,8 +47,11 @@ func AddToScheme(scheme *runtime.Scheme) { // Adds the list of known types to api.Scheme. func addKnownTypes(scheme *runtime.Scheme) { scheme.AddKnownTypes(SchemeGroupVersion, + &Scale{}, &extensions.HorizontalPodAutoscaler{}, &extensions.HorizontalPodAutoscalerList{}, &api.ListOptions{}, ) } + +func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } diff --git a/pkg/apis/autoscaling/types.go b/pkg/apis/autoscaling/types.go new file mode 100644 index 00000000000..a521feefb70 --- /dev/null +++ b/pkg/apis/autoscaling/types.go @@ -0,0 +1,53 @@ +/* +Copyright 2016 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 autoscaling + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/api/unversioned" +) + +// Scale represents a scaling request for a resource. +type Scale struct { + unversioned.TypeMeta `json:",inline"` + // Standard object metadata; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata. + api.ObjectMeta `json:"metadata,omitempty"` + + // defines the behavior of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. + Spec ScaleSpec `json:"spec,omitempty"` + + // current status of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. Read-only. + Status ScaleStatus `json:"status,omitempty"` +} + +// ScaleSpec describes the attributes of a scale subresource. +type ScaleSpec struct { + // desired number of instances for the scaled object. + Replicas int `json:"replicas,omitempty"` +} + +// ScaleStatus represents the current status of a scale subresource. +type ScaleStatus struct { + // actual number of observed instances of the scaled object. + Replicas int `json:"replicas"` + + // label query over pods that should match the replicas count. This is same + // as the label selector but in the string format to avoid introspection + // by clients. The string will be in the same format as the query-param syntax. + // More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors + Selector string `json:"selector,omitempty"` +} diff --git a/pkg/apis/autoscaling/v1/register.go b/pkg/apis/autoscaling/v1/register.go index 1209a4f9b57..5af7611c57f 100644 --- a/pkg/apis/autoscaling/v1/register.go +++ b/pkg/apis/autoscaling/v1/register.go @@ -39,9 +39,11 @@ func addKnownTypes(scheme *runtime.Scheme) { scheme.AddKnownTypes(SchemeGroupVersion, &HorizontalPodAutoscaler{}, &HorizontalPodAutoscalerList{}, + &Scale{}, &v1.ListOptions{}, ) } func (obj *HorizontalPodAutoscaler) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } func (obj *HorizontalPodAutoscalerList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } diff --git a/pkg/apis/autoscaling/v1/types.go b/pkg/apis/autoscaling/v1/types.go index 6ad1d61af04..ff53a5ddc5a 100644 --- a/pkg/apis/autoscaling/v1/types.go +++ b/pkg/apis/autoscaling/v1/types.go @@ -86,3 +86,34 @@ type HorizontalPodAutoscalerList struct { // list of horizontal pod autoscaler objects. Items []HorizontalPodAutoscaler `json:"items"` } + +// Scale represents a scaling request for a resource. +type Scale struct { + unversioned.TypeMeta `json:",inline"` + // Standard object metadata; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata. + v1.ObjectMeta `json:"metadata,omitempty"` + + // defines the behavior of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. + Spec ScaleSpec `json:"spec,omitempty"` + + // current status of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. Read-only. + Status ScaleStatus `json:"status,omitempty"` +} + +// ScaleSpec describes the attributes of a scale subresource. +type ScaleSpec struct { + // desired number of instances for the scaled object. + Replicas int32 `json:"replicas,omitempty"` +} + +// ScaleStatus represents the current status of a scale subresource. +type ScaleStatus struct { + // actual number of observed instances of the scaled object. + Replicas int32 `json:"replicas"` + + // label query over pods that should match the replicas count. This is same + // as the label selector but in the string format to avoid introspection + // by clients. The string will be in the same format as the query-param syntax. + // More info about label selectors: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors + Selector string `json:"selector,omitempty"` +} diff --git a/pkg/apis/autoscaling/validation/validation.go b/pkg/apis/autoscaling/validation/validation.go new file mode 100644 index 00000000000..8b9a21a9de7 --- /dev/null +++ b/pkg/apis/autoscaling/validation/validation.go @@ -0,0 +1,34 @@ +/* +Copyright 2016 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 ( + apivalidation "k8s.io/kubernetes/pkg/api/validation" + "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/util/validation/field" +) + +func ValidateScale(scale *autoscaling.Scale) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&scale.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...) + + if scale.Spec.Replicas < 0 { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "replicas"), scale.Spec.Replicas, "must be greater than or equal to 0")) + } + + return allErrs +} diff --git a/pkg/apis/autoscaling/validation/validation_test.go b/pkg/apis/autoscaling/validation/validation_test.go new file mode 100644 index 00000000000..ac8921ee04c --- /dev/null +++ b/pkg/apis/autoscaling/validation/validation_test.go @@ -0,0 +1,89 @@ +/* +Copyright 2016 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 ( + "strings" + "testing" + + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/apis/autoscaling" +) + +func TestValidateScale(t *testing.T) { + successCases := []autoscaling.Scale{ + { + ObjectMeta: api.ObjectMeta{ + Name: "frontend", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.ScaleSpec{ + Replicas: 1, + }, + }, + { + ObjectMeta: api.ObjectMeta{ + Name: "frontend", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.ScaleSpec{ + Replicas: 10, + }, + }, + { + ObjectMeta: api.ObjectMeta{ + Name: "frontend", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.ScaleSpec{ + Replicas: 0, + }, + }, + } + + for _, successCase := range successCases { + if errs := ValidateScale(&successCase); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + + errorCases := []struct { + scale autoscaling.Scale + msg string + }{ + { + scale: autoscaling.Scale{ + ObjectMeta: api.ObjectMeta{ + Name: "frontend", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.ScaleSpec{ + Replicas: -1, + }, + }, + msg: "must be greater than or equal to 0", + }, + } + + 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) + } + } +}