diff --git a/cmd/libs/go2idl/client-gen/main.go b/cmd/libs/go2idl/client-gen/main.go index c14fe6aa8a5..afff4d01263 100644 --- a/cmd/libs/go2idl/client-gen/main.go +++ b/cmd/libs/go2idl/client-gen/main.go @@ -34,7 +34,7 @@ import ( var ( test = flag.BoolP("test", "t", false, "set this flag to generate the client code for the testdata") - inputVersions = flag.StringSlice("input", []string{"api/", "extensions/", "batch/"}, "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\". Default to \"api/,extensions/,batch/\"") + inputVersions = flag.StringSlice("input", []string{"api/", "extensions/", "autoscaling/", "batch/"}, "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\". Default to \"api/,extensions/,autoscaling/,batch/\"") basePath = flag.String("input-base", "k8s.io/kubernetes/pkg/apis", "base path to look for the api group. Default to \"k8s.io/kubernetes/pkg/apis\"") clientsetName = flag.StringP("clientset-name", "n", "internalclientset", "the name of the generated clientset package.") clientsetPath = flag.String("clientset-path", "k8s.io/kubernetes/pkg/client/clientset_generated/", "the generated clientset will be output to /. Default to \"k8s.io/kubernetes/pkg/client/clientset_generated/\"") diff --git a/cmd/libs/go2idl/conversion-gen/generators/conversion.go b/cmd/libs/go2idl/conversion-gen/generators/conversion.go index 3afae34983f..ea5ca27c6b9 100644 --- a/cmd/libs/go2idl/conversion-gen/generators/conversion.go +++ b/cmd/libs/go2idl/conversion-gen/generators/conversion.go @@ -70,6 +70,7 @@ func DefaultNameSystem() string { var fallbackPackages = []string{ "k8s.io/kubernetes/pkg/api/unversioned", "k8s.io/kubernetes/pkg/apis/extensions", + "k8s.io/kubernetes/pkg/apis/autoscaling", "k8s.io/kubernetes/pkg/apis/batch", } diff --git a/pkg/api/testing/fuzzer.go b/pkg/api/testing/fuzzer.go index 052ce3f4957..c4bcb381c1c 100644 --- a/pkg/api/testing/fuzzer.go +++ b/pkg/api/testing/fuzzer.go @@ -27,6 +27,7 @@ import ( "k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/fields" @@ -377,15 +378,12 @@ func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source) c.FuzzNoCustom(s) s.Allocatable = s.Capacity }, - func(s *extensions.HorizontalPodAutoscalerSpec, c fuzz.Continue) { + func(s *autoscaling.HorizontalPodAutoscalerSpec, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again minReplicas := int32(c.Rand.Int31()) s.MinReplicas = &minReplicas - s.CPUUtilization = &extensions.CPUTargetUtilization{TargetPercentage: int32(c.RandUint64())} - }, - func(s *extensions.SubresourceReference, c fuzz.Continue) { - c.FuzzNoCustom(s) // fuzz self without calling this function again - s.Subresource = "scale" + targetCpu := int32(c.RandUint64()) + s.TargetCPUUtilizationPercentage = &targetCpu }, func(psp *extensions.PodSecurityPolicySpec, c fuzz.Continue) { c.FuzzNoCustom(psp) // fuzz self without calling this function again diff --git a/pkg/apis/autoscaling/register.go b/pkg/apis/autoscaling/register.go index dfc86f24d2c..7af72124307 100644 --- a/pkg/apis/autoscaling/register.go +++ b/pkg/apis/autoscaling/register.go @@ -19,7 +19,6 @@ package autoscaling import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" - "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/runtime" ) @@ -48,10 +47,12 @@ func AddToScheme(scheme *runtime.Scheme) { func addKnownTypes(scheme *runtime.Scheme) { scheme.AddKnownTypes(SchemeGroupVersion, &Scale{}, - &extensions.HorizontalPodAutoscaler{}, - &extensions.HorizontalPodAutoscalerList{}, + &HorizontalPodAutoscaler{}, + &HorizontalPodAutoscalerList{}, &api.ListOptions{}, ) } -func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *HorizontalPodAutoscaler) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *HorizontalPodAutoscalerList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } diff --git a/pkg/apis/autoscaling/types.go b/pkg/apis/autoscaling/types.go index aa49e5a24c8..3e60def9235 100644 --- a/pkg/apis/autoscaling/types.go +++ b/pkg/apis/autoscaling/types.go @@ -51,3 +51,70 @@ type ScaleStatus struct { // More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors Selector string `json:"selector,omitempty"` } + +// CrossVersionObjectReference contains enough information to let you identify the referred resource. +type CrossVersionObjectReference struct { + // Kind of the referent; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" + Kind string `json:"kind" protobuf:"bytes,1,opt,name=kind"` + // Name of the referent; More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names + Name string `json:"name" protobuf:"bytes,2,opt,name=name"` + // API version of the referent + APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,3,opt,name=apiVersion"` +} + +// specification of a horizontal pod autoscaler. +type HorizontalPodAutoscalerSpec struct { + // reference to scaled resource; horizontal pod autoscaler will learn the current resource consumption + // and will set the desired number of pods by using its Scale subresource. + ScaleTargetRef CrossVersionObjectReference `json:"scaleTargetRef"` + // lower limit for the number of pods that can be set by the autoscaler, default 1. + MinReplicas *int32 `json:"minReplicas,omitempty"` + // upper limit for the number of pods that can be set by the autoscaler. It cannot be smaller than MinReplicas. + MaxReplicas int32 `json:"maxReplicas"` + // target average CPU utilization (represented as a percentage of requested CPU) over all the pods; + // if not specified the default autoscaling policy will be used. + TargetCPUUtilizationPercentage *int32 `json:"targetCPUUtilizationPercentage,omitempty"` +} + +// current status of a horizontal pod autoscaler +type HorizontalPodAutoscalerStatus struct { + // most recent generation observed by this autoscaler. + ObservedGeneration *int64 `json:"observedGeneration,omitempty"` + + // last time the HorizontalPodAutoscaler scaled the number of pods; + // used by the autoscaler to control how often the number of pods is changed. + LastScaleTime *unversioned.Time `json:"lastScaleTime,omitempty"` + + // current number of replicas of pods managed by this autoscaler. + CurrentReplicas int32 `json:"currentReplicas"` + + // desired number of replicas of pods managed by this autoscaler. + DesiredReplicas int32 `json:"desiredReplicas"` + + // current average CPU utilization over all pods, represented as a percentage of requested CPU, + // e.g. 70 means that an average pod is using now 70% of its requested CPU. + CurrentCPUUtilizationPercentage *int32 `json:"currentCPUUtilizationPercentage,omitempty"` +} + +// +genclient=true + +// configuration of a horizontal pod autoscaler. +type HorizontalPodAutoscaler struct { + unversioned.TypeMeta `json:",inline"` + api.ObjectMeta `json:"metadata,omitempty"` + + // behaviour of autoscaler. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. + Spec HorizontalPodAutoscalerSpec `json:"spec,omitempty"` + + // current information about the autoscaler. + Status HorizontalPodAutoscalerStatus `json:"status,omitempty"` +} + +// list of horizontal pod autoscaler objects. +type HorizontalPodAutoscalerList struct { + unversioned.TypeMeta `json:",inline"` + unversioned.ListMeta `json:"metadata,omitempty"` + + // list of horizontal pod autoscaler objects. + Items []HorizontalPodAutoscaler `json:"items"` +} diff --git a/pkg/apis/autoscaling/v1/conversion.go b/pkg/apis/autoscaling/v1/conversion.go deleted file mode 100644 index 47131c65f39..00000000000 --- a/pkg/apis/autoscaling/v1/conversion.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -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 v1 - -import ( - "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/conversion" - "k8s.io/kubernetes/pkg/runtime" -) - -func addConversionFuncs(scheme *runtime.Scheme) { - // Add non-generated conversion functions - err := scheme.AddConversionFuncs( - Convert_extensions_SubresourceReference_To_v1_CrossVersionObjectReference, - Convert_v1_CrossVersionObjectReference_To_extensions_SubresourceReference, - Convert_extensions_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec, - Convert_v1_HorizontalPodAutoscalerSpec_To_extensions_HorizontalPodAutoscalerSpec, - ) - if err != nil { - // If one of the conversion functions is malformed, detect it immediately. - panic(err) - } -} - -func Convert_extensions_SubresourceReference_To_v1_CrossVersionObjectReference(in *extensions.SubresourceReference, out *CrossVersionObjectReference, s conversion.Scope) error { - out.Kind = in.Kind - out.Name = in.Name - out.APIVersion = in.APIVersion - return nil -} - -func Convert_v1_CrossVersionObjectReference_To_extensions_SubresourceReference(in *CrossVersionObjectReference, out *extensions.SubresourceReference, s conversion.Scope) error { - out.Kind = in.Kind - out.Name = in.Name - out.APIVersion = in.APIVersion - out.Subresource = "scale" - return nil -} - -func Convert_extensions_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec(in *extensions.HorizontalPodAutoscalerSpec, out *HorizontalPodAutoscalerSpec, s conversion.Scope) error { - if err := Convert_extensions_SubresourceReference_To_v1_CrossVersionObjectReference(&in.ScaleRef, &out.ScaleTargetRef, s); err != nil { - return err - } - if in.MinReplicas != nil { - out.MinReplicas = new(int32) - *out.MinReplicas = int32(*in.MinReplicas) - } else { - out.MinReplicas = nil - } - out.MaxReplicas = int32(in.MaxReplicas) - if in.CPUUtilization != nil { - out.TargetCPUUtilizationPercentage = new(int32) - *out.TargetCPUUtilizationPercentage = int32(in.CPUUtilization.TargetPercentage) - } - return nil -} - -func Convert_v1_HorizontalPodAutoscalerSpec_To_extensions_HorizontalPodAutoscalerSpec(in *HorizontalPodAutoscalerSpec, out *extensions.HorizontalPodAutoscalerSpec, s conversion.Scope) error { - if err := Convert_v1_CrossVersionObjectReference_To_extensions_SubresourceReference(&in.ScaleTargetRef, &out.ScaleRef, s); err != nil { - return err - } - if in.MinReplicas != nil { - out.MinReplicas = new(int32) - *out.MinReplicas = *in.MinReplicas - } else { - out.MinReplicas = nil - } - out.MaxReplicas = in.MaxReplicas - if in.TargetCPUUtilizationPercentage != nil { - out.CPUUtilization = &extensions.CPUTargetUtilization{TargetPercentage: *in.TargetCPUUtilizationPercentage} - } - return nil -} diff --git a/pkg/apis/autoscaling/v1/register.go b/pkg/apis/autoscaling/v1/register.go index 9a7e369c621..dc3cff1576e 100644 --- a/pkg/apis/autoscaling/v1/register.go +++ b/pkg/apis/autoscaling/v1/register.go @@ -32,7 +32,6 @@ var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: "v1 func AddToScheme(scheme *runtime.Scheme) { addKnownTypes(scheme) addDefaultingFuncs(scheme) - addConversionFuncs(scheme) } // Adds the list of known types to api.Scheme. diff --git a/pkg/apis/autoscaling/validation/validation.go b/pkg/apis/autoscaling/validation/validation.go index 8b9a21a9de7..fee11196161 100644 --- a/pkg/apis/autoscaling/validation/validation.go +++ b/pkg/apis/autoscaling/validation/validation.go @@ -17,8 +17,12 @@ limitations under the License. package validation import ( + "encoding/json" + apivalidation "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/controller/podautoscaler" "k8s.io/kubernetes/pkg/util/validation/field" ) @@ -32,3 +36,92 @@ func ValidateScale(scale *autoscaling.Scale) field.ErrorList { return allErrs } + +// ValidateHorizontalPodAutoscaler can be used to check whether the given autoscaler name is valid. +// Prefix indicates this name will be used as part of generation, in which case trailing dashes are allowed. +func ValidateHorizontalPodAutoscalerName(name string, prefix bool) (bool, string) { + // TODO: finally move it to pkg/api/validation and use nameIsDNSSubdomain function + return apivalidation.ValidateReplicationControllerName(name, prefix) +} + +func validateHorizontalPodAutoscalerSpec(autoscaler autoscaling.HorizontalPodAutoscalerSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if autoscaler.MinReplicas != nil && *autoscaler.MinReplicas < 1 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("minReplicas"), *autoscaler.MinReplicas, "must be greater than 0")) + } + if autoscaler.MaxReplicas < 1 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, "must be greater than 0")) + } + if autoscaler.MinReplicas != nil && autoscaler.MaxReplicas < *autoscaler.MinReplicas { + allErrs = append(allErrs, field.Invalid(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, "must be greater than or equal to `minReplicas`")) + } + if autoscaler.TargetCPUUtilizationPercentage != nil && *autoscaler.TargetCPUUtilizationPercentage < 1 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("targetCPUUtilizationPercentage"), autoscaler.TargetCPUUtilizationPercentage, "must be greater than 0")) + } + if refErrs := ValidateCrossVersionObjectReference(autoscaler.ScaleTargetRef, fldPath.Child("scaleTargetRef")); len(refErrs) > 0 { + allErrs = append(allErrs, refErrs...) + } + return allErrs +} + +func ValidateCrossVersionObjectReference(ref autoscaling.CrossVersionObjectReference, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if len(ref.Kind) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) + } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Kind); !ok { + allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ref.Kind, msg)) + } + + if len(ref.Name) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) + } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Name); !ok { + allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ref.Name, msg)) + } + + return allErrs +} + +func validateHorizontalPodAutoscalerAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if annotationValue, found := annotations[podautoscaler.HpaCustomMetricsTargetAnnotationName]; found { + // Try to parse the annotation + var targetList extensions.CustomMetricTargetList + if err := json.Unmarshal([]byte(annotationValue), &targetList); err != nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations"), annotations, "failed to parse custom metrics target annotation")) + } else { + if len(targetList.Items) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("annotations", "items"), "custom metrics target must not be empty")) + } + for _, target := range targetList.Items { + if target.Name == "" { + allErrs = append(allErrs, field.Required(fldPath.Child("annotations", "items", "name"), "missing custom metric target name")) + } + if target.TargetValue.MilliValue() <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations", "items", "value"), target.TargetValue, "custom metric target value must be greater than 0")) + } + } + } + } + return allErrs +} + +func ValidateHorizontalPodAutoscaler(autoscaler *autoscaling.HorizontalPodAutoscaler) field.ErrorList { + allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata")) + allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...) + allErrs = append(allErrs, validateHorizontalPodAutoscalerAnnotations(autoscaler.Annotations, field.NewPath("metadata"))...) + return allErrs +} + +func ValidateHorizontalPodAutoscalerUpdate(newAutoscaler, oldAutoscaler *autoscaling.HorizontalPodAutoscaler) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, field.NewPath("metadata")) + allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(newAutoscaler.Spec, field.NewPath("spec"))...) + return allErrs +} + +func ValidateHorizontalPodAutoscalerStatusUpdate(newAutoscaler, oldAutoscaler *autoscaling.HorizontalPodAutoscaler) field.ErrorList { + allErrs := apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, field.NewPath("metadata")) + status := newAutoscaler.Status + allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.CurrentReplicas), field.NewPath("status", "currentReplicas"))...) + allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredReplicas), field.NewPath("status", "desiredReplicasa"))...) + return allErrs +} diff --git a/pkg/apis/autoscaling/validation/validation_test.go b/pkg/apis/autoscaling/validation/validation_test.go index ac8921ee04c..06d93c9eaa8 100644 --- a/pkg/apis/autoscaling/validation/validation_test.go +++ b/pkg/apis/autoscaling/validation/validation_test.go @@ -22,6 +22,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/controller/podautoscaler" ) func TestValidateScale(t *testing.T) { @@ -87,3 +88,251 @@ func TestValidateScale(t *testing.T) { } } } + +func TestValidateHorizontalPodAutoscaler(t *testing.T) { + successCases := []autoscaling.HorizontalPodAutoscaler{ + { + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: newInt32(1), + MaxReplicas: 5, + TargetCPUUtilizationPercentage: newInt32(70), + }, + }, + { + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: newInt32(1), + MaxReplicas: 5, + }, + }, + { + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + Annotations: map[string]string{ + podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"20\"}]}", + }, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: newInt32(1), + MaxReplicas: 5, + }, + }, + } + for _, successCase := range successCases { + if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + + errorCases := []struct { + horizontalPodAutoscaler autoscaling.HorizontalPodAutoscaler + msg string + }{ + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"}, + MinReplicas: newInt32(1), + MaxReplicas: 5, + TargetCPUUtilizationPercentage: newInt32(70), + }, + }, + msg: "scaleTargetRef.kind: Required", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"}, + MinReplicas: newInt32(1), + MaxReplicas: 5, + TargetCPUUtilizationPercentage: newInt32(70), + }, + }, + msg: "scaleTargetRef.kind: Invalid", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"}, + MinReplicas: newInt32(1), + MaxReplicas: 5, + TargetCPUUtilizationPercentage: newInt32(70), + }, + }, + msg: "scaleTargetRef.name: Required", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."}, + MinReplicas: newInt32(1), + MaxReplicas: 5, + TargetCPUUtilizationPercentage: newInt32(70), + }, + }, + msg: "scaleTargetRef.name: Invalid", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{}, + MinReplicas: newInt32(-1), + MaxReplicas: 5, + }, + }, + msg: "must be greater than 0", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{}, + MinReplicas: newInt32(7), + MaxReplicas: 5, + }, + }, + msg: "must be greater than or equal to `minReplicas`", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{}, + MinReplicas: newInt32(1), + MaxReplicas: 5, + TargetCPUUtilizationPercentage: newInt32(-70), + }, + }, + msg: "must be greater than 0", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + Annotations: map[string]string{ + podautoscaler.HpaCustomMetricsTargetAnnotationName: "broken", + }, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: newInt32(1), + MaxReplicas: 5, + }, + }, + msg: "failed to parse custom metrics target annotation", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + Annotations: map[string]string{ + podautoscaler.HpaCustomMetricsTargetAnnotationName: "{}", + }, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: newInt32(1), + MaxReplicas: 5, + }, + }, + msg: "custom metrics target must not be empty", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + Annotations: map[string]string{ + podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"value\":\"20\"}]}", + }, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: newInt32(1), + MaxReplicas: 5, + }, + }, + msg: "missing custom metric target name", + }, + { + horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{ + Name: "myautoscaler", + Namespace: api.NamespaceDefault, + Annotations: map[string]string{ + podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"0\"}]}", + }, + }, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", + }, + MinReplicas: newInt32(1), + MaxReplicas: 5, + }, + }, + msg: "custom metric target value must be greater than 0", + }, + } + + for _, c := range errorCases { + errs := ValidateHorizontalPodAutoscaler(&c.horizontalPodAutoscaler) + if len(errs) == 0 { + t.Errorf("expected failure for %q", c.msg) + } else if !strings.Contains(errs[0].Error(), c.msg) { + t.Errorf("unexpected error: %q, expected: %q", errs[0], c.msg) + } + } +} + +func newInt32(val int32) *int32 { + p := new(int32) + *p = val + return p +} diff --git a/pkg/apis/extensions/install/install_test.go b/pkg/apis/extensions/install/install_test.go index 311fad56da9..3252462a1d5 100644 --- a/pkg/apis/extensions/install/install_test.go +++ b/pkg/apis/extensions/install/install_test.go @@ -78,10 +78,9 @@ func TestInterfacesFor(t *testing.T) { func TestRESTMapper(t *testing.T) { gv := v1beta1.SchemeGroupVersion - hpaGVK := gv.WithKind("HorizontalPodAutoscaler") daemonSetGVK := gv.WithKind("DaemonSet") - if gvk, err := registered.GroupOrDie(extensions.GroupName).RESTMapper.KindFor(gv.WithResource("horizontalpodautoscalers")); err != nil || gvk != hpaGVK { + if gvk, err := registered.GroupOrDie(extensions.GroupName).RESTMapper.KindFor(gv.WithResource("daemonsets")); err != nil || gvk != daemonSetGVK { t.Errorf("unexpected version mapping: %v %v", gvk, err) } @@ -90,12 +89,12 @@ func TestRESTMapper(t *testing.T) { } for _, version := range registered.GroupOrDie(extensions.GroupName).GroupVersions { - mapping, err := registered.GroupOrDie(extensions.GroupName).RESTMapper.RESTMapping(hpaGVK.GroupKind(), version.Version) + mapping, err := registered.GroupOrDie(extensions.GroupName).RESTMapper.RESTMapping(daemonSetGVK.GroupKind(), version.Version) if err != nil { t.Errorf("unexpected error: %v", err) } - if mapping.Resource != "horizontalpodautoscalers" { + if mapping.Resource != "daemonsets" { t.Errorf("incorrect resource name: %#v", mapping) } if mapping.GroupVersionKind.GroupVersion() != version { @@ -107,7 +106,7 @@ func TestRESTMapper(t *testing.T) { t.Errorf("unexpected: %#v, expected: %#v", mapping, interfaces) } - rc := &extensions.HorizontalPodAutoscaler{ObjectMeta: api.ObjectMeta{Name: "foo"}} + rc := &extensions.DaemonSet{ObjectMeta: api.ObjectMeta{Name: "foo"}} name, err := mapping.MetadataAccessor.Name(rc) if err != nil { t.Errorf("unexpected error: %v", err) diff --git a/pkg/apis/extensions/register.go b/pkg/apis/extensions/register.go index 712adf91d98..52059392ae6 100644 --- a/pkg/apis/extensions/register.go +++ b/pkg/apis/extensions/register.go @@ -19,6 +19,7 @@ package extensions import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/runtime" ) @@ -51,8 +52,8 @@ func addKnownTypes(scheme *runtime.Scheme) { &Deployment{}, &DeploymentList{}, &DeploymentRollback{}, - &HorizontalPodAutoscaler{}, - &HorizontalPodAutoscalerList{}, + &autoscaling.HorizontalPodAutoscaler{}, + &autoscaling.HorizontalPodAutoscalerList{}, &batch.Job{}, &batch.JobList{}, &ReplicationControllerDummy{}, @@ -74,22 +75,20 @@ func addKnownTypes(scheme *runtime.Scheme) { ) } -func (obj *Deployment) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *DeploymentList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *DeploymentRollback) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *HorizontalPodAutoscaler) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *HorizontalPodAutoscalerList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *ReplicationControllerDummy) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *ThirdPartyResource) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *ThirdPartyResourceList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *DaemonSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *DaemonSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *ThirdPartyResourceData) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *ThirdPartyResourceDataList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *Ingress) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *IngressList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *ReplicaSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *ReplicaSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *PodSecurityPolicy) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } -func (obj *PodSecurityPolicyList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *Deployment) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *DeploymentList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *DeploymentRollback) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *ReplicationControllerDummy) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *ThirdPartyResource) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *ThirdPartyResourceList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *DaemonSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *DaemonSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *ThirdPartyResourceData) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *ThirdPartyResourceDataList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *Ingress) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *IngressList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *ReplicaSet) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *ReplicaSetList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *PodSecurityPolicy) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } +func (obj *PodSecurityPolicyList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta } diff --git a/pkg/apis/extensions/types.go b/pkg/apis/extensions/types.go index 52cd171369c..475abd5827c 100644 --- a/pkg/apis/extensions/types.go +++ b/pkg/apis/extensions/types.go @@ -71,24 +71,6 @@ type ReplicationControllerDummy struct { unversioned.TypeMeta `json:",inline"` } -// SubresourceReference contains enough information to let you inspect or modify the referred subresource. -type SubresourceReference struct { - // Kind of the referent; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds" - Kind string `json:"kind,omitempty"` - // Name of the referent; More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names - Name string `json:"name,omitempty"` - // API version of the referent - APIVersion string `json:"apiVersion,omitempty"` - // Subresource name of the referent - Subresource string `json:"subresource,omitempty"` -} - -type CPUTargetUtilization struct { - // fraction of the requested CPU that should be utilized/used, - // e.g. 70 means that 70% of the requested CPU should be in use. - TargetPercentage int32 `json:"targetPercentage"` -} - // Alpha-level support for Custom Metrics in HPA (as annotations). type CustomMetricTarget struct { // Custom Metric name. @@ -112,63 +94,6 @@ type CustomMetricCurrentStatusList struct { Items []CustomMetricCurrentStatus `json:"items"` } -// specification of a horizontal pod autoscaler. -type HorizontalPodAutoscalerSpec struct { - // reference to Scale subresource; horizontal pod autoscaler will learn the current resource consumption from its status, - // and will set the desired number of pods by modifying its spec. - ScaleRef SubresourceReference `json:"scaleRef"` - // lower limit for the number of pods that can be set by the autoscaler, default 1. - MinReplicas *int32 `json:"minReplicas,omitempty"` - // upper limit for the number of pods that can be set by the autoscaler. It cannot be smaller than MinReplicas. - MaxReplicas int32 `json:"maxReplicas"` - // target average CPU utilization (represented as a percentage of requested CPU) over all the pods; - // if not specified it defaults to the target CPU utilization at 80% of the requested resources. - CPUUtilization *CPUTargetUtilization `json:"cpuUtilization,omitempty"` -} - -// current status of a horizontal pod autoscaler -type HorizontalPodAutoscalerStatus struct { - // most recent generation observed by this autoscaler. - ObservedGeneration *int64 `json:"observedGeneration,omitempty"` - - // last time the HorizontalPodAutoscaler scaled the number of pods; - // used by the autoscaler to control how often the number of pods is changed. - LastScaleTime *unversioned.Time `json:"lastScaleTime,omitempty"` - - // current number of replicas of pods managed by this autoscaler. - CurrentReplicas int32 `json:"currentReplicas"` - - // desired number of replicas of pods managed by this autoscaler. - DesiredReplicas int32 `json:"desiredReplicas"` - - // current average CPU utilization over all pods, represented as a percentage of requested CPU, - // e.g. 70 means that an average pod is using now 70% of its requested CPU. - CurrentCPUUtilizationPercentage *int32 `json:"currentCPUUtilizationPercentage,omitempty"` -} - -// +genclient=true - -// configuration of a horizontal pod autoscaler. -type HorizontalPodAutoscaler struct { - unversioned.TypeMeta `json:",inline"` - api.ObjectMeta `json:"metadata,omitempty"` - - // behaviour of autoscaler. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. - Spec HorizontalPodAutoscalerSpec `json:"spec,omitempty"` - - // current information about the autoscaler. - Status HorizontalPodAutoscalerStatus `json:"status,omitempty"` -} - -// list of horizontal pod autoscaler objects. -type HorizontalPodAutoscalerList struct { - unversioned.TypeMeta `json:",inline"` - unversioned.ListMeta `json:"metadata,omitempty"` - - // list of horizontal pod autoscaler objects. - Items []HorizontalPodAutoscaler `json:"items"` -} - // +genclient=true,nonNamespaced=true // A ThirdPartyResource is a generic representation of a resource, it is used by add-ons and plugins to add new resource diff --git a/pkg/apis/extensions/v1beta1/conversion.go b/pkg/apis/extensions/v1beta1/conversion.go index 988e5c8c930..ad5c91c90e5 100644 --- a/pkg/apis/extensions/v1beta1/conversion.go +++ b/pkg/apis/extensions/v1beta1/conversion.go @@ -22,6 +22,7 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" v1 "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/conversion" @@ -42,6 +43,11 @@ func addConversionFuncs(scheme *runtime.Scheme) { Convert_v1beta1_RollingUpdateDeployment_To_extensions_RollingUpdateDeployment, Convert_extensions_ReplicaSetSpec_To_v1beta1_ReplicaSetSpec, Convert_v1beta1_ReplicaSetSpec_To_extensions_ReplicaSetSpec, + // autoscaling + Convert_autoscaling_CrossVersionObjectReference_To_v1beta1_SubresourceReference, + Convert_v1beta1_SubresourceReference_To_autoscaling_CrossVersionObjectReference, + Convert_autoscaling_HorizontalPodAutoscalerSpec_To_v1beta1_HorizontalPodAutoscalerSpec, + Convert_v1beta1_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPodAutoscalerSpec, // batch Convert_batch_JobSpec_To_v1beta1_JobSpec, Convert_v1beta1_JobSpec_To_batch_JobSpec, @@ -346,3 +352,53 @@ func Convert_v1beta1_JobSpec_To_batch_JobSpec(in *JobSpec, out *batch.JobSpec, s } return nil } + +func Convert_autoscaling_CrossVersionObjectReference_To_v1beta1_SubresourceReference(in *autoscaling.CrossVersionObjectReference, out *SubresourceReference, s conversion.Scope) error { + out.Kind = in.Kind + out.Name = in.Name + out.APIVersion = in.APIVersion + out.Subresource = "scale" + return nil +} + +func Convert_v1beta1_SubresourceReference_To_autoscaling_CrossVersionObjectReference(in *SubresourceReference, out *autoscaling.CrossVersionObjectReference, s conversion.Scope) error { + out.Kind = in.Kind + out.Name = in.Name + out.APIVersion = in.APIVersion + return nil +} + +func Convert_autoscaling_HorizontalPodAutoscalerSpec_To_v1beta1_HorizontalPodAutoscalerSpec(in *autoscaling.HorizontalPodAutoscalerSpec, out *HorizontalPodAutoscalerSpec, s conversion.Scope) error { + if err := Convert_autoscaling_CrossVersionObjectReference_To_v1beta1_SubresourceReference(&in.ScaleTargetRef, &out.ScaleRef, s); err != nil { + return err + } + if in.MinReplicas != nil { + out.MinReplicas = new(int32) + *out.MinReplicas = *in.MinReplicas + } else { + out.MinReplicas = nil + } + out.MaxReplicas = in.MaxReplicas + if in.TargetCPUUtilizationPercentage != nil { + out.CPUUtilization = &CPUTargetUtilization{TargetPercentage: *in.TargetCPUUtilizationPercentage} + } + return nil +} + +func Convert_v1beta1_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPodAutoscalerSpec(in *HorizontalPodAutoscalerSpec, out *autoscaling.HorizontalPodAutoscalerSpec, s conversion.Scope) error { + if err := Convert_v1beta1_SubresourceReference_To_autoscaling_CrossVersionObjectReference(&in.ScaleRef, &out.ScaleTargetRef, s); err != nil { + return err + } + if in.MinReplicas != nil { + out.MinReplicas = new(int32) + *out.MinReplicas = int32(*in.MinReplicas) + } else { + out.MinReplicas = nil + } + out.MaxReplicas = int32(in.MaxReplicas) + if in.CPUUtilization != nil { + out.TargetCPUUtilizationPercentage = new(int32) + *out.TargetCPUUtilizationPercentage = int32(in.CPUUtilization.TargetPercentage) + } + return nil +} diff --git a/pkg/apis/extensions/validation/validation.go b/pkg/apis/extensions/validation/validation.go index c13a119f837..ddb24505b92 100644 --- a/pkg/apis/extensions/validation/validation.go +++ b/pkg/apis/extensions/validation/validation.go @@ -17,7 +17,6 @@ limitations under the License. package validation import ( - "encoding/json" "net" "regexp" "strconv" @@ -28,7 +27,6 @@ import ( unversionedvalidation "k8s.io/kubernetes/pkg/api/unversioned/validation" apivalidation "k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/controller/podautoscaler" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/sets" @@ -36,102 +34,6 @@ import ( "k8s.io/kubernetes/pkg/util/validation/field" ) -// ValidateHorizontalPodAutoscaler can be used to check whether the given autoscaler name is valid. -// Prefix indicates this name will be used as part of generation, in which case trailing dashes are allowed. -func ValidateHorizontalPodAutoscalerName(name string, prefix bool) (bool, string) { - // TODO: finally move it to pkg/api/validation and use nameIsDNSSubdomain function - return apivalidation.ValidateReplicationControllerName(name, prefix) -} - -func validateHorizontalPodAutoscalerSpec(autoscaler extensions.HorizontalPodAutoscalerSpec, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if autoscaler.MinReplicas != nil && *autoscaler.MinReplicas < 1 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("minReplicas"), *autoscaler.MinReplicas, "must be greater than 0")) - } - if autoscaler.MaxReplicas < 1 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, "must be greater than 0")) - } - if autoscaler.MinReplicas != nil && autoscaler.MaxReplicas < *autoscaler.MinReplicas { - allErrs = append(allErrs, field.Invalid(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, "must be greater than or equal to `minReplicas`")) - } - if autoscaler.CPUUtilization != nil && autoscaler.CPUUtilization.TargetPercentage < 1 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("cpuUtilization", "targetPercentage"), autoscaler.CPUUtilization.TargetPercentage, "must be greater than 0")) - } - if refErrs := ValidateSubresourceReference(autoscaler.ScaleRef, fldPath.Child("scaleRef")); len(refErrs) > 0 { - allErrs = append(allErrs, refErrs...) - } else if autoscaler.ScaleRef.Subresource != "scale" { - allErrs = append(allErrs, field.NotSupported(fldPath.Child("scaleRef", "subresource"), autoscaler.ScaleRef.Subresource, []string{"scale"})) - } - return allErrs -} - -func ValidateSubresourceReference(ref extensions.SubresourceReference, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if len(ref.Kind) == 0 { - allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) - } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Kind); !ok { - allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ref.Kind, msg)) - } - - if len(ref.Name) == 0 { - allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) - } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Name); !ok { - allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ref.Name, msg)) - } - - if len(ref.Subresource) == 0 { - allErrs = append(allErrs, field.Required(fldPath.Child("subresource"), "")) - } else if ok, msg := apivalidation.IsValidPathSegmentName(ref.Subresource); !ok { - allErrs = append(allErrs, field.Invalid(fldPath.Child("subresource"), ref.Subresource, msg)) - } - return allErrs -} - -func validateHorizontalPodAutoscalerAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - if annotationValue, found := annotations[podautoscaler.HpaCustomMetricsTargetAnnotationName]; found { - // Try to parse the annotation - var targetList extensions.CustomMetricTargetList - if err := json.Unmarshal([]byte(annotationValue), &targetList); err != nil { - allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations"), annotations, "failed to parse custom metrics target annotation")) - } else { - if len(targetList.Items) == 0 { - allErrs = append(allErrs, field.Required(fldPath.Child("annotations", "items"), "custom metrics target must not be empty")) - } - for _, target := range targetList.Items { - if target.Name == "" { - allErrs = append(allErrs, field.Required(fldPath.Child("annotations", "items", "name"), "missing custom metric target name")) - } - if target.TargetValue.MilliValue() <= 0 { - allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations", "items", "value"), target.TargetValue, "custom metric target value must be greater than 0")) - } - } - } - } - return allErrs -} - -func ValidateHorizontalPodAutoscaler(autoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList { - allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata")) - allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...) - allErrs = append(allErrs, validateHorizontalPodAutoscalerAnnotations(autoscaler.Annotations, field.NewPath("metadata"))...) - return allErrs -} - -func ValidateHorizontalPodAutoscalerUpdate(newAutoscaler, oldAutoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList { - allErrs := apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, field.NewPath("metadata")) - allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(newAutoscaler.Spec, field.NewPath("spec"))...) - return allErrs -} - -func ValidateHorizontalPodAutoscalerStatusUpdate(newAutoscaler, oldAutoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList { - allErrs := apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, field.NewPath("metadata")) - status := newAutoscaler.Status - allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.CurrentReplicas), field.NewPath("status", "currentReplicas"))...) - allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredReplicas), field.NewPath("status", "desiredReplicasa"))...) - return allErrs -} - func ValidateThirdPartyResourceUpdate(update, old *extensions.ThirdPartyResource) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))...) diff --git a/pkg/apis/extensions/validation/validation_test.go b/pkg/apis/extensions/validation/validation_test.go index 51e09597b7d..c1632fa6d81 100644 --- a/pkg/apis/extensions/validation/validation_test.go +++ b/pkg/apis/extensions/validation/validation_test.go @@ -24,301 +24,9 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/controller/podautoscaler" "k8s.io/kubernetes/pkg/util/intstr" ) -func TestValidateHorizontalPodAutoscaler(t *testing.T) { - successCases := []extensions.HorizontalPodAutoscaler{ - { - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: "ReplicationController", - Name: "myrc", - Subresource: "scale", - }, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, - }, - }, - { - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: "ReplicationController", - Name: "myrc", - Subresource: "scale", - }, - MinReplicas: newInt32(1), - MaxReplicas: 5, - }, - }, - { - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - Annotations: map[string]string{ - podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"20\"}]}", - }, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: "ReplicationController", - Name: "myrc", - Subresource: "scale", - }, - MinReplicas: newInt32(1), - MaxReplicas: 5, - }, - }, - } - for _, successCase := range successCases { - if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 { - t.Errorf("expected success: %v", errs) - } - } - - errorCases := []struct { - horizontalPodAutoscaler extensions.HorizontalPodAutoscaler - msg string - }{ - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{Name: "myrc", Subresource: "scale"}, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, - }, - }, - msg: "scaleRef.kind: Required", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{Kind: "..", Name: "myrc", Subresource: "scale"}, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, - }, - }, - msg: "scaleRef.kind: Invalid", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{Kind: "ReplicationController", Subresource: "scale"}, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, - }, - }, - msg: "scaleRef.name: Required", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{Kind: "ReplicationController", Name: "..", Subresource: "scale"}, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, - }, - }, - msg: "scaleRef.name: Invalid", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{Kind: "ReplicationController", Name: "myrc", Subresource: ""}, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, - }, - }, - msg: "scaleRef.subresource: Required", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{Kind: "ReplicationController", Name: "myrc", Subresource: ".."}, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, - }, - }, - msg: "scaleRef.subresource: Invalid", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{Name: "myautoscaler", Namespace: api.NamespaceDefault}, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{Kind: "ReplicationController", Name: "myrc", Subresource: "randomsubresource"}, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, - }, - }, - msg: "scaleRef.subresource: Unsupported", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Subresource: "scale", - }, - MinReplicas: newInt32(-1), - MaxReplicas: 5, - }, - }, - msg: "must be greater than 0", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Subresource: "scale", - }, - MinReplicas: newInt32(7), - MaxReplicas: 5, - }, - }, - msg: "must be greater than or equal to `minReplicas`", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Subresource: "scale", - }, - MinReplicas: newInt32(1), - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: -70}, - }, - }, - msg: "must be greater than 0", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - Annotations: map[string]string{ - podautoscaler.HpaCustomMetricsTargetAnnotationName: "broken", - }, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: "ReplicationController", - Name: "myrc", - Subresource: "scale", - }, - MinReplicas: newInt32(1), - MaxReplicas: 5, - }, - }, - msg: "failed to parse custom metrics target annotation", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - Annotations: map[string]string{ - podautoscaler.HpaCustomMetricsTargetAnnotationName: "{}", - }, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: "ReplicationController", - Name: "myrc", - Subresource: "scale", - }, - MinReplicas: newInt32(1), - MaxReplicas: 5, - }, - }, - msg: "custom metrics target must not be empty", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - Annotations: map[string]string{ - podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"value\":\"20\"}]}", - }, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: "ReplicationController", - Name: "myrc", - Subresource: "scale", - }, - MinReplicas: newInt32(1), - MaxReplicas: 5, - }, - }, - msg: "missing custom metric target name", - }, - { - horizontalPodAutoscaler: extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{ - Name: "myautoscaler", - Namespace: api.NamespaceDefault, - Annotations: map[string]string{ - podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"0\"}]}", - }, - }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: "ReplicationController", - Name: "myrc", - Subresource: "scale", - }, - MinReplicas: newInt32(1), - MaxReplicas: 5, - }, - }, - msg: "custom metric target value must be greater than 0", - }, - } - - for _, c := range errorCases { - errs := ValidateHorizontalPodAutoscaler(&c.horizontalPodAutoscaler) - if len(errs) == 0 { - t.Errorf("expected failure for %q", c.msg) - } else if !strings.Contains(errs[0].Error(), c.msg) { - t.Errorf("unexpected error: %q, expected: %q", errs[0], c.msg) - } - } -} - func TestValidateDaemonSetStatusUpdate(t *testing.T) { type dsUpdateTest struct { old extensions.DaemonSet @@ -1709,12 +1417,6 @@ func TestValidateReplicaSet(t *testing.T) { } } -func newInt32(val int32) *int32 { - p := new(int32) - *p = val - return p -} - func TestValidatePodSecurityPolicy(t *testing.T) { validSCC := func() *extensions.PodSecurityPolicy { return &extensions.PodSecurityPolicy{ diff --git a/pkg/client/unversioned/autoscaling.go b/pkg/client/unversioned/autoscaling.go index 7566042544f..9e543c9d3ae 100644 --- a/pkg/client/unversioned/autoscaling.go +++ b/pkg/client/unversioned/autoscaling.go @@ -33,7 +33,7 @@ type AutoscalingClient struct { } func (c *AutoscalingClient) HorizontalPodAutoscalers(namespace string) HorizontalPodAutoscalerInterface { - return newHorizontalPodAutoscalersV1(c, namespace) + return newHorizontalPodAutoscalers(c, namespace) } func NewAutoscaling(c *restclient.Config) (*AutoscalingClient, error) { diff --git a/pkg/client/unversioned/extensions.go b/pkg/client/unversioned/extensions.go index 7716d7ca979..6dfe46fe665 100644 --- a/pkg/client/unversioned/extensions.go +++ b/pkg/client/unversioned/extensions.go @@ -28,7 +28,6 @@ import ( // Features of Extensions group are not supported and may be changed or removed in // incompatible ways at any time. type ExtensionsInterface interface { - HorizontalPodAutoscalersNamespacer ScaleNamespacer DaemonSetsNamespacer DeploymentsNamespacer @@ -50,10 +49,6 @@ func (c *ExtensionsClient) PodSecurityPolicies() PodSecurityPolicyInterface { return newPodSecurityPolicy(c) } -func (c *ExtensionsClient) HorizontalPodAutoscalers(namespace string) HorizontalPodAutoscalerInterface { - return newHorizontalPodAutoscalers(c, namespace) -} - func (c *ExtensionsClient) Scales(namespace string) ScaleInterface { return newScales(c, namespace) } diff --git a/pkg/client/unversioned/horizontalpodautoscaler.go b/pkg/client/unversioned/horizontalpodautoscaler.go index a4efc232a41..8cdba3a265c 100644 --- a/pkg/client/unversioned/horizontalpodautoscaler.go +++ b/pkg/client/unversioned/horizontalpodautoscaler.go @@ -18,7 +18,7 @@ package unversioned import ( "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/watch" ) @@ -29,23 +29,23 @@ type HorizontalPodAutoscalersNamespacer interface { // HorizontalPodAutoscalerInterface has methods to work with HorizontalPodAutoscaler resources. type HorizontalPodAutoscalerInterface interface { - List(opts api.ListOptions) (*extensions.HorizontalPodAutoscalerList, error) - Get(name string) (*extensions.HorizontalPodAutoscaler, error) + List(opts api.ListOptions) (*autoscaling.HorizontalPodAutoscalerList, error) + Get(name string) (*autoscaling.HorizontalPodAutoscaler, error) Delete(name string, options *api.DeleteOptions) error - Create(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) - Update(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) - UpdateStatus(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) + Create(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) + Update(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) + UpdateStatus(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) Watch(opts api.ListOptions) (watch.Interface, error) } -// horizontalPodAutoscalers implements HorizontalPodAutoscalersNamespacer interface +// horizontalPodAutoscalers implements HorizontalPodAutoscalersNamespacer interface using AutoscalingClient internally type horizontalPodAutoscalers struct { - client *ExtensionsClient + client *AutoscalingClient ns string } // newHorizontalPodAutoscalers returns a horizontalPodAutoscalers -func newHorizontalPodAutoscalers(c *ExtensionsClient, namespace string) *horizontalPodAutoscalers { +func newHorizontalPodAutoscalers(c *AutoscalingClient, namespace string) *horizontalPodAutoscalers { return &horizontalPodAutoscalers{ client: c, ns: namespace, @@ -53,15 +53,15 @@ func newHorizontalPodAutoscalers(c *ExtensionsClient, namespace string) *horizon } // List takes label and field selectors, and returns the list of horizontalPodAutoscalers that match those selectors. -func (c *horizontalPodAutoscalers) List(opts api.ListOptions) (result *extensions.HorizontalPodAutoscalerList, err error) { - result = &extensions.HorizontalPodAutoscalerList{} +func (c *horizontalPodAutoscalers) List(opts api.ListOptions) (result *autoscaling.HorizontalPodAutoscalerList, err error) { + result = &autoscaling.HorizontalPodAutoscalerList{} err = c.client.Get().Namespace(c.ns).Resource("horizontalPodAutoscalers").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) return } // Get takes the name of the horizontalPodAutoscaler, and returns the corresponding HorizontalPodAutoscaler object, and an error if it occurs -func (c *horizontalPodAutoscalers) Get(name string) (result *extensions.HorizontalPodAutoscaler, err error) { - result = &extensions.HorizontalPodAutoscaler{} +func (c *horizontalPodAutoscalers) Get(name string) (result *autoscaling.HorizontalPodAutoscaler, err error) { + result = &autoscaling.HorizontalPodAutoscaler{} err = c.client.Get().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(name).Do().Into(result) return } @@ -72,22 +72,22 @@ func (c *horizontalPodAutoscalers) Delete(name string, options *api.DeleteOption } // Create takes the representation of a horizontalPodAutoscaler and creates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. -func (c *horizontalPodAutoscalers) Create(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (result *extensions.HorizontalPodAutoscaler, err error) { - result = &extensions.HorizontalPodAutoscaler{} +func (c *horizontalPodAutoscalers) Create(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (result *autoscaling.HorizontalPodAutoscaler, err error) { + result = &autoscaling.HorizontalPodAutoscaler{} err = c.client.Post().Namespace(c.ns).Resource("horizontalPodAutoscalers").Body(horizontalPodAutoscaler).Do().Into(result) return } // Update takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. -func (c *horizontalPodAutoscalers) Update(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (result *extensions.HorizontalPodAutoscaler, err error) { - result = &extensions.HorizontalPodAutoscaler{} +func (c *horizontalPodAutoscalers) Update(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (result *autoscaling.HorizontalPodAutoscaler, err error) { + result = &autoscaling.HorizontalPodAutoscaler{} err = c.client.Put().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(horizontalPodAutoscaler.Name).Body(horizontalPodAutoscaler).Do().Into(result) return } // UpdateStatus takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. -func (c *horizontalPodAutoscalers) UpdateStatus(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (result *extensions.HorizontalPodAutoscaler, err error) { - result = &extensions.HorizontalPodAutoscaler{} +func (c *horizontalPodAutoscalers) UpdateStatus(horizontalPodAutoscaler *autoscaling.HorizontalPodAutoscaler) (result *autoscaling.HorizontalPodAutoscaler, err error) { + result = &autoscaling.HorizontalPodAutoscaler{} err = c.client.Put().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(horizontalPodAutoscaler.Name).SubResource("status").Body(horizontalPodAutoscaler).Do().Into(result) return } @@ -101,68 +101,3 @@ func (c *horizontalPodAutoscalers) Watch(opts api.ListOptions) (watch.Interface, VersionedParams(&opts, api.ParameterCodec). Watch() } - -// horizontalPodAutoscalersV1 implements HorizontalPodAutoscalersNamespacer interface using AutoscalingClient internally -// TODO(piosz): get back to one client implementation once HPA will be graduated to GA completely -type horizontalPodAutoscalersV1 struct { - client *AutoscalingClient - ns string -} - -// newHorizontalPodAutoscalers returns a horizontalPodAutoscalers -func newHorizontalPodAutoscalersV1(c *AutoscalingClient, namespace string) *horizontalPodAutoscalersV1 { - return &horizontalPodAutoscalersV1{ - client: c, - ns: namespace, - } -} - -// List takes label and field selectors, and returns the list of horizontalPodAutoscalers that match those selectors. -func (c *horizontalPodAutoscalersV1) List(opts api.ListOptions) (result *extensions.HorizontalPodAutoscalerList, err error) { - result = &extensions.HorizontalPodAutoscalerList{} - err = c.client.Get().Namespace(c.ns).Resource("horizontalPodAutoscalers").VersionedParams(&opts, api.ParameterCodec).Do().Into(result) - return -} - -// Get takes the name of the horizontalPodAutoscaler, and returns the corresponding HorizontalPodAutoscaler object, and an error if it occurs -func (c *horizontalPodAutoscalersV1) Get(name string) (result *extensions.HorizontalPodAutoscaler, err error) { - result = &extensions.HorizontalPodAutoscaler{} - err = c.client.Get().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(name).Do().Into(result) - return -} - -// Delete takes the name of the horizontalPodAutoscaler and deletes it. Returns an error if one occurs. -func (c *horizontalPodAutoscalersV1) Delete(name string, options *api.DeleteOptions) error { - return c.client.Delete().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(name).Body(options).Do().Error() -} - -// Create takes the representation of a horizontalPodAutoscaler and creates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. -func (c *horizontalPodAutoscalersV1) Create(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (result *extensions.HorizontalPodAutoscaler, err error) { - result = &extensions.HorizontalPodAutoscaler{} - err = c.client.Post().Namespace(c.ns).Resource("horizontalPodAutoscalers").Body(horizontalPodAutoscaler).Do().Into(result) - return -} - -// Update takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. -func (c *horizontalPodAutoscalersV1) Update(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (result *extensions.HorizontalPodAutoscaler, err error) { - result = &extensions.HorizontalPodAutoscaler{} - err = c.client.Put().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(horizontalPodAutoscaler.Name).Body(horizontalPodAutoscaler).Do().Into(result) - return -} - -// UpdateStatus takes the representation of a horizontalPodAutoscaler and updates it. Returns the server's representation of the horizontalPodAutoscaler, and an error, if it occurs. -func (c *horizontalPodAutoscalersV1) UpdateStatus(horizontalPodAutoscaler *extensions.HorizontalPodAutoscaler) (result *extensions.HorizontalPodAutoscaler, err error) { - result = &extensions.HorizontalPodAutoscaler{} - err = c.client.Put().Namespace(c.ns).Resource("horizontalPodAutoscalers").Name(horizontalPodAutoscaler.Name).SubResource("status").Body(horizontalPodAutoscaler).Do().Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested horizontalPodAutoscalers. -func (c *horizontalPodAutoscalersV1) Watch(opts api.ListOptions) (watch.Interface, error) { - return c.client.Get(). - Prefix("watch"). - Namespace(c.ns). - Resource("horizontalPodAutoscalers"). - VersionedParams(&opts, api.ParameterCodec). - Watch() -} diff --git a/pkg/client/unversioned/horizontalpodautoscaler_test.go b/pkg/client/unversioned/horizontalpodautoscaler_test.go index 550dae6ec1c..b893a29ad8a 100644 --- a/pkg/client/unversioned/horizontalpodautoscaler_test.go +++ b/pkg/client/unversioned/horizontalpodautoscaler_test.go @@ -23,8 +23,6 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/apis/autoscaling" - "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/client/unversioned" "k8s.io/kubernetes/pkg/client/unversioned/testclient/simple" ) @@ -32,21 +30,9 @@ func getHorizontalPodAutoscalersResoureName() string { return "horizontalpodautoscalers" } -func getHPAClient(t *testing.T, c *simple.Client, ns, resourceGroup string) unversioned.HorizontalPodAutoscalerInterface { - switch resourceGroup { - case autoscaling.GroupName: - return c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns) - case extensions.GroupName: - return c.Setup(t).Extensions().HorizontalPodAutoscalers(ns) - default: - t.Fatalf("Unknown group %v", resourceGroup) - } - return nil -} - -func testHorizontalPodAutoscalerCreate(t *testing.T, group testapi.TestGroup, resourceGroup string) { +func TestHorizontalPodAutoscalerCreate(t *testing.T) { ns := api.NamespaceDefault - horizontalPodAutoscaler := extensions.HorizontalPodAutoscaler{ + horizontalPodAutoscaler := autoscaling.HorizontalPodAutoscaler{ ObjectMeta: api.ObjectMeta{ Name: "abc", Namespace: ns, @@ -55,15 +41,15 @@ func testHorizontalPodAutoscalerCreate(t *testing.T, group testapi.TestGroup, re c := &simple.Client{ Request: simple.Request{ Method: "POST", - Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, ""), + Path: testapi.Autoscaling.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, ""), Query: simple.BuildQueryValues(nil), Body: &horizontalPodAutoscaler, }, Response: simple.Response{StatusCode: 200, Body: &horizontalPodAutoscaler}, - ResourceGroup: resourceGroup, + ResourceGroup: autoscaling.GroupName, } - response, err := getHPAClient(t, c, ns, resourceGroup).Create(&horizontalPodAutoscaler) + response, err := c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns).Create(&horizontalPodAutoscaler) defer c.Close() if err != nil { t.Fatalf("unexpected error: %v", err) @@ -71,14 +57,9 @@ func testHorizontalPodAutoscalerCreate(t *testing.T, group testapi.TestGroup, re c.Validate(t, response, err) } -func TestHorizontalPodAutoscalerCreate(t *testing.T) { - testHorizontalPodAutoscalerCreate(t, testapi.Extensions, extensions.GroupName) - testHorizontalPodAutoscalerCreate(t, testapi.Autoscaling, autoscaling.GroupName) -} - -func testHorizontalPodAutoscalerGet(t *testing.T, group testapi.TestGroup, resourceGroup string) { +func TestHorizontalPodAutoscalerGet(t *testing.T) { ns := api.NamespaceDefault - horizontalPodAutoscaler := &extensions.HorizontalPodAutoscaler{ + horizontalPodAutoscaler := &autoscaling.HorizontalPodAutoscaler{ ObjectMeta: api.ObjectMeta{ Name: "abc", Namespace: ns, @@ -87,28 +68,23 @@ func testHorizontalPodAutoscalerGet(t *testing.T, group testapi.TestGroup, resou c := &simple.Client{ Request: simple.Request{ Method: "GET", - Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc"), + Path: testapi.Autoscaling.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc"), Query: simple.BuildQueryValues(nil), Body: nil, }, Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler}, - ResourceGroup: resourceGroup, + ResourceGroup: autoscaling.GroupName, } - response, err := getHPAClient(t, c, ns, resourceGroup).Get("abc") + response, err := c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns).Get("abc") defer c.Close() c.Validate(t, response, err) } -func TestHorizontalPodAutoscalerGet(t *testing.T) { - testHorizontalPodAutoscalerGet(t, testapi.Extensions, extensions.GroupName) - testHorizontalPodAutoscalerGet(t, testapi.Autoscaling, autoscaling.GroupName) -} - -func testHorizontalPodAutoscalerList(t *testing.T, group testapi.TestGroup, resourceGroup string) { +func TestHorizontalPodAutoscalerList(t *testing.T) { ns := api.NamespaceDefault - horizontalPodAutoscalerList := &extensions.HorizontalPodAutoscalerList{ - Items: []extensions.HorizontalPodAutoscaler{ + horizontalPodAutoscalerList := &autoscaling.HorizontalPodAutoscalerList{ + Items: []autoscaling.HorizontalPodAutoscaler{ { ObjectMeta: api.ObjectMeta{ Name: "foo", @@ -120,50 +96,21 @@ func testHorizontalPodAutoscalerList(t *testing.T, group testapi.TestGroup, reso c := &simple.Client{ Request: simple.Request{ Method: "GET", - Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, ""), + Path: testapi.Autoscaling.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, ""), Query: simple.BuildQueryValues(nil), Body: nil, }, Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscalerList}, - ResourceGroup: resourceGroup, + ResourceGroup: autoscaling.GroupName, } - response, err := getHPAClient(t, c, ns, resourceGroup).List(api.ListOptions{}) - defer c.Close() - c.Validate(t, response, err) -} - -func TestHorizontalPodAutoscalerList(t *testing.T) { - testHorizontalPodAutoscalerList(t, testapi.Extensions, extensions.GroupName) - testHorizontalPodAutoscalerList(t, testapi.Autoscaling, autoscaling.GroupName) -} - -func testHorizontalPodAutoscalerUpdate(t *testing.T, group testapi.TestGroup, resourceGroup string) { - ns := api.NamespaceDefault - horizontalPodAutoscaler := &extensions.HorizontalPodAutoscaler{ - ObjectMeta: api.ObjectMeta{ - Name: "abc", - Namespace: ns, - ResourceVersion: "1", - }, - } - c := &simple.Client{ - Request: simple.Request{Method: "PUT", Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc"), Query: simple.BuildQueryValues(nil)}, - Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler}, - ResourceGroup: resourceGroup, - } - response, err := getHPAClient(t, c, ns, resourceGroup).Update(horizontalPodAutoscaler) + response, err := c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns).List(api.ListOptions{}) defer c.Close() c.Validate(t, response, err) } func TestHorizontalPodAutoscalerUpdate(t *testing.T) { - testHorizontalPodAutoscalerUpdate(t, testapi.Extensions, extensions.GroupName) - testHorizontalPodAutoscalerUpdate(t, testapi.Autoscaling, autoscaling.GroupName) -} - -func testHorizontalPodAutoscalerUpdateStatus(t *testing.T, group testapi.TestGroup, resourceGroup string) { ns := api.NamespaceDefault - horizontalPodAutoscaler := &extensions.HorizontalPodAutoscaler{ + horizontalPodAutoscaler := &autoscaling.HorizontalPodAutoscaler{ ObjectMeta: api.ObjectMeta{ Name: "abc", Namespace: ns, @@ -171,52 +118,56 @@ func testHorizontalPodAutoscalerUpdateStatus(t *testing.T, group testapi.TestGro }, } c := &simple.Client{ - Request: simple.Request{Method: "PUT", Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc") + "/status", Query: simple.BuildQueryValues(nil)}, + Request: simple.Request{Method: "PUT", Path: testapi.Autoscaling.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc"), Query: simple.BuildQueryValues(nil)}, Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler}, - ResourceGroup: resourceGroup, + ResourceGroup: autoscaling.GroupName, } - response, err := getHPAClient(t, c, ns, resourceGroup).UpdateStatus(horizontalPodAutoscaler) + response, err := c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns).Update(horizontalPodAutoscaler) defer c.Close() c.Validate(t, response, err) } func TestHorizontalPodAutoscalerUpdateStatus(t *testing.T) { - testHorizontalPodAutoscalerUpdateStatus(t, testapi.Extensions, extensions.GroupName) - testHorizontalPodAutoscalerUpdateStatus(t, testapi.Autoscaling, autoscaling.GroupName) -} - -func testHorizontalPodAutoscalerDelete(t *testing.T, group testapi.TestGroup, resourceGroup string) { ns := api.NamespaceDefault - c := &simple.Client{ - Request: simple.Request{Method: "DELETE", Path: group.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "foo"), Query: simple.BuildQueryValues(nil)}, - Response: simple.Response{StatusCode: 200}, - ResourceGroup: resourceGroup, + horizontalPodAutoscaler := &autoscaling.HorizontalPodAutoscaler{ + ObjectMeta: api.ObjectMeta{ + Name: "abc", + Namespace: ns, + ResourceVersion: "1", + }, } - err := getHPAClient(t, c, ns, resourceGroup).Delete("foo", nil) + c := &simple.Client{ + Request: simple.Request{Method: "PUT", Path: testapi.Autoscaling.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "abc") + "/status", Query: simple.BuildQueryValues(nil)}, + Response: simple.Response{StatusCode: 200, Body: horizontalPodAutoscaler}, + ResourceGroup: autoscaling.GroupName, + } + response, err := c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns).UpdateStatus(horizontalPodAutoscaler) defer c.Close() - c.Validate(t, nil, err) + c.Validate(t, response, err) } func TestHorizontalPodAutoscalerDelete(t *testing.T) { - testHorizontalPodAutoscalerDelete(t, testapi.Extensions, extensions.GroupName) - testHorizontalPodAutoscalerDelete(t, testapi.Autoscaling, autoscaling.GroupName) -} - -func testHorizontalPodAutoscalerWatch(t *testing.T, group testapi.TestGroup, resourceGroup string) { + ns := api.NamespaceDefault c := &simple.Client{ - Request: simple.Request{ - Method: "GET", - Path: group.ResourcePathWithPrefix("watch", getHorizontalPodAutoscalersResoureName(), "", ""), - Query: url.Values{"resourceVersion": []string{}}}, + Request: simple.Request{Method: "DELETE", Path: testapi.Autoscaling.ResourcePath(getHorizontalPodAutoscalersResoureName(), ns, "foo"), Query: simple.BuildQueryValues(nil)}, Response: simple.Response{StatusCode: 200}, - ResourceGroup: resourceGroup, + ResourceGroup: autoscaling.GroupName, } - _, err := getHPAClient(t, c, api.NamespaceAll, resourceGroup).Watch(api.ListOptions{}) + err := c.Setup(t).Autoscaling().HorizontalPodAutoscalers(ns).Delete("foo", nil) defer c.Close() c.Validate(t, nil, err) } func TestHorizontalPodAutoscalerWatch(t *testing.T) { - testHorizontalPodAutoscalerWatch(t, testapi.Extensions, extensions.GroupName) - testHorizontalPodAutoscalerWatch(t, testapi.Autoscaling, autoscaling.GroupName) + c := &simple.Client{ + Request: simple.Request{ + Method: "GET", + Path: testapi.Autoscaling.ResourcePathWithPrefix("watch", getHorizontalPodAutoscalersResoureName(), "", ""), + Query: url.Values{"resourceVersion": []string{}}}, + Response: simple.Response{StatusCode: 200}, + ResourceGroup: autoscaling.GroupName, + } + _, err := c.Setup(t).Autoscaling().HorizontalPodAutoscalers(api.NamespaceAll).Watch(api.ListOptions{}) + defer c.Close() + c.Validate(t, nil, err) } diff --git a/pkg/client/unversioned/testclient/fake_horizontal_pod_autoscalers.go b/pkg/client/unversioned/testclient/fake_horizontal_pod_autoscalers.go index e50b326d914..c299679f0b8 100644 --- a/pkg/client/unversioned/testclient/fake_horizontal_pod_autoscalers.go +++ b/pkg/client/unversioned/testclient/fake_horizontal_pod_autoscalers.go @@ -18,7 +18,7 @@ package testclient import ( "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/watch" ) @@ -26,21 +26,21 @@ import ( // FakeHorizontalPodAutoscalers implements HorizontalPodAutoscalerInterface. Meant to be embedded into a struct to get a default // implementation. This makes faking out just the methods you want to test easier. type FakeHorizontalPodAutoscalers struct { - Fake *FakeExperimental + Fake *FakeAutoscaling Namespace string } -func (c *FakeHorizontalPodAutoscalers) Get(name string) (*extensions.HorizontalPodAutoscaler, error) { - obj, err := c.Fake.Invokes(NewGetAction("horizontalpodautoscalers", c.Namespace, name), &extensions.HorizontalPodAutoscaler{}) +func (c *FakeHorizontalPodAutoscalers) Get(name string) (*autoscaling.HorizontalPodAutoscaler, error) { + obj, err := c.Fake.Invokes(NewGetAction("horizontalpodautoscalers", c.Namespace, name), &autoscaling.HorizontalPodAutoscaler{}) if obj == nil { return nil, err } - return obj.(*extensions.HorizontalPodAutoscaler), err + return obj.(*autoscaling.HorizontalPodAutoscaler), err } -func (c *FakeHorizontalPodAutoscalers) List(opts api.ListOptions) (*extensions.HorizontalPodAutoscalerList, error) { - obj, err := c.Fake.Invokes(NewListAction("horizontalpodautoscalers", c.Namespace, opts), &extensions.HorizontalPodAutoscalerList{}) +func (c *FakeHorizontalPodAutoscalers) List(opts api.ListOptions) (*autoscaling.HorizontalPodAutoscalerList, error) { + obj, err := c.Fake.Invokes(NewListAction("horizontalpodautoscalers", c.Namespace, opts), &autoscaling.HorizontalPodAutoscalerList{}) if obj == nil { return nil, err } @@ -48,8 +48,8 @@ func (c *FakeHorizontalPodAutoscalers) List(opts api.ListOptions) (*extensions.H if label == nil { label = labels.Everything() } - list := &extensions.HorizontalPodAutoscalerList{} - for _, a := range obj.(*extensions.HorizontalPodAutoscalerList).Items { + list := &autoscaling.HorizontalPodAutoscalerList{} + for _, a := range obj.(*autoscaling.HorizontalPodAutoscalerList).Items { if label.Matches(labels.Set(a.Labels)) { list.Items = append(list.Items, a) } @@ -57,108 +57,37 @@ func (c *FakeHorizontalPodAutoscalers) List(opts api.ListOptions) (*extensions.H return list, err } -func (c *FakeHorizontalPodAutoscalers) Create(a *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) { +func (c *FakeHorizontalPodAutoscalers) Create(a *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) { obj, err := c.Fake.Invokes(NewCreateAction("horizontalpodautoscalers", c.Namespace, a), a) if obj == nil { return nil, err } - return obj.(*extensions.HorizontalPodAutoscaler), err + return obj.(*autoscaling.HorizontalPodAutoscaler), err } -func (c *FakeHorizontalPodAutoscalers) Update(a *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) { +func (c *FakeHorizontalPodAutoscalers) Update(a *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) { obj, err := c.Fake.Invokes(NewUpdateAction("horizontalpodautoscalers", c.Namespace, a), a) if obj == nil { return nil, err } - return obj.(*extensions.HorizontalPodAutoscaler), err + return obj.(*autoscaling.HorizontalPodAutoscaler), err } -func (c *FakeHorizontalPodAutoscalers) UpdateStatus(a *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) { - obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("horizontalpodautoscalers", "status", c.Namespace, a), &extensions.HorizontalPodAutoscaler{}) +func (c *FakeHorizontalPodAutoscalers) UpdateStatus(a *autoscaling.HorizontalPodAutoscaler) (*autoscaling.HorizontalPodAutoscaler, error) { + obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("horizontalpodautoscalers", "status", c.Namespace, a), &autoscaling.HorizontalPodAutoscaler{}) if obj == nil { return nil, err } - return obj.(*extensions.HorizontalPodAutoscaler), err + return obj.(*autoscaling.HorizontalPodAutoscaler), err } func (c *FakeHorizontalPodAutoscalers) Delete(name string, options *api.DeleteOptions) error { - _, err := c.Fake.Invokes(NewDeleteAction("horizontalpodautoscalers", c.Namespace, name), &extensions.HorizontalPodAutoscaler{}) + _, err := c.Fake.Invokes(NewDeleteAction("horizontalpodautoscalers", c.Namespace, name), &autoscaling.HorizontalPodAutoscaler{}) return err } func (c *FakeHorizontalPodAutoscalers) Watch(opts api.ListOptions) (watch.Interface, error) { return c.Fake.InvokesWatch(NewWatchAction("horizontalpodautoscalers", c.Namespace, opts)) } - -// FakeHorizontalPodAutoscalers implements HorizontalPodAutoscalerInterface. Meant to be embedded into a struct to get a default -// implementation. This makes faking out just the methods you want to test easier. -// This is a test implementation of HorizontalPodAutoscalersV1 -// TODO(piosz): get back to one client implementation once HPA will be graduated to GA completely -type FakeHorizontalPodAutoscalersV1 struct { - Fake *FakeAutoscaling - Namespace string -} - -func (c *FakeHorizontalPodAutoscalersV1) Get(name string) (*extensions.HorizontalPodAutoscaler, error) { - obj, err := c.Fake.Invokes(NewGetAction("horizontalpodautoscalers", c.Namespace, name), &extensions.HorizontalPodAutoscaler{}) - if obj == nil { - return nil, err - } - - return obj.(*extensions.HorizontalPodAutoscaler), err -} - -func (c *FakeHorizontalPodAutoscalersV1) List(opts api.ListOptions) (*extensions.HorizontalPodAutoscalerList, error) { - obj, err := c.Fake.Invokes(NewListAction("horizontalpodautoscalers", c.Namespace, opts), &extensions.HorizontalPodAutoscalerList{}) - if obj == nil { - return nil, err - } - label := opts.LabelSelector - if label == nil { - label = labels.Everything() - } - list := &extensions.HorizontalPodAutoscalerList{} - for _, a := range obj.(*extensions.HorizontalPodAutoscalerList).Items { - if label.Matches(labels.Set(a.Labels)) { - list.Items = append(list.Items, a) - } - } - return list, err -} - -func (c *FakeHorizontalPodAutoscalersV1) Create(a *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) { - obj, err := c.Fake.Invokes(NewCreateAction("horizontalpodautoscalers", c.Namespace, a), a) - if obj == nil { - return nil, err - } - - return obj.(*extensions.HorizontalPodAutoscaler), err -} - -func (c *FakeHorizontalPodAutoscalersV1) Update(a *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) { - obj, err := c.Fake.Invokes(NewUpdateAction("horizontalpodautoscalers", c.Namespace, a), a) - if obj == nil { - return nil, err - } - - return obj.(*extensions.HorizontalPodAutoscaler), err -} - -func (c *FakeHorizontalPodAutoscalersV1) UpdateStatus(a *extensions.HorizontalPodAutoscaler) (*extensions.HorizontalPodAutoscaler, error) { - obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("horizontalpodautoscalers", "status", c.Namespace, a), &extensions.HorizontalPodAutoscaler{}) - if obj == nil { - return nil, err - } - return obj.(*extensions.HorizontalPodAutoscaler), err -} - -func (c *FakeHorizontalPodAutoscalersV1) Delete(name string, options *api.DeleteOptions) error { - _, err := c.Fake.Invokes(NewDeleteAction("horizontalpodautoscalers", c.Namespace, name), &extensions.HorizontalPodAutoscaler{}) - return err -} - -func (c *FakeHorizontalPodAutoscalersV1) Watch(opts api.ListOptions) (watch.Interface, error) { - return c.Fake.InvokesWatch(NewWatchAction("horizontalpodautoscalers", c.Namespace, opts)) -} diff --git a/pkg/client/unversioned/testclient/testclient.go b/pkg/client/unversioned/testclient/testclient.go index 258a0f5afbb..0155da8a904 100644 --- a/pkg/client/unversioned/testclient/testclient.go +++ b/pkg/client/unversioned/testclient/testclient.go @@ -325,7 +325,7 @@ type FakeAutoscaling struct { } func (c *FakeAutoscaling) HorizontalPodAutoscalers(namespace string) client.HorizontalPodAutoscalerInterface { - return &FakeHorizontalPodAutoscalersV1{Fake: c, Namespace: namespace} + return &FakeHorizontalPodAutoscalers{Fake: c, Namespace: namespace} } // NewSimpleFakeBatch returns a client that will respond with the provided objects @@ -354,10 +354,6 @@ func (c *FakeExperimental) DaemonSets(namespace string) client.DaemonSetInterfac return &FakeDaemonSets{Fake: c, Namespace: namespace} } -func (c *FakeExperimental) HorizontalPodAutoscalers(namespace string) client.HorizontalPodAutoscalerInterface { - return &FakeHorizontalPodAutoscalers{Fake: c, Namespace: namespace} -} - func (c *FakeExperimental) Deployments(namespace string) client.DeploymentInterface { return &FakeDeployments{Fake: c, Namespace: namespace} } diff --git a/pkg/controller/podautoscaler/horizontal.go b/pkg/controller/podautoscaler/horizontal.go index 6f48b959055..a8e092cafe9 100644 --- a/pkg/controller/podautoscaler/horizontal.go +++ b/pkg/controller/podautoscaler/horizontal.go @@ -26,8 +26,10 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/client/cache" + unversionedautoscaling "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/autoscaling/unversioned" unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned" unversionedextensions "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/unversioned" "k8s.io/kubernetes/pkg/client/record" @@ -51,7 +53,7 @@ const ( type HorizontalController struct { scaleNamespacer unversionedextensions.ScalesGetter - hpaNamespacer unversionedextensions.HorizontalPodAutoscalersGetter + hpaNamespacer unversionedautoscaling.HorizontalPodAutoscalersGetter metricsClient metrics.MetricsClient eventRecorder record.EventRecorder @@ -75,12 +77,12 @@ func newInformer(controller *HorizontalController, resyncPeriod time.Duration) ( return controller.hpaNamespacer.HorizontalPodAutoscalers(api.NamespaceAll).Watch(options) }, }, - &extensions.HorizontalPodAutoscaler{}, + &autoscaling.HorizontalPodAutoscaler{}, resyncPeriod, framework.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { - hpa := obj.(*extensions.HorizontalPodAutoscaler) - hasCPUPolicy := hpa.Spec.CPUUtilization != nil + hpa := obj.(*autoscaling.HorizontalPodAutoscaler) + hasCPUPolicy := hpa.Spec.TargetCPUUtilizationPercentage != nil _, hasCustomMetricsPolicy := hpa.Annotations[HpaCustomMetricsTargetAnnotationName] if !hasCPUPolicy && !hasCustomMetricsPolicy { controller.eventRecorder.Event(hpa, api.EventTypeNormal, "DefaultPolicy", "No scaling policy specified - will use default one. See documentation for details") @@ -91,7 +93,7 @@ func newInformer(controller *HorizontalController, resyncPeriod time.Duration) ( } }, UpdateFunc: func(old, cur interface{}) { - hpa := cur.(*extensions.HorizontalPodAutoscaler) + hpa := cur.(*autoscaling.HorizontalPodAutoscaler) err := controller.reconcileAutoscaler(hpa) if err != nil { glog.Warningf("Failed to reconcile %s: %v", hpa.Name, err) @@ -102,7 +104,7 @@ func newInformer(controller *HorizontalController, resyncPeriod time.Duration) ( ) } -func NewHorizontalController(evtNamespacer unversionedcore.EventsGetter, scaleNamespacer unversionedextensions.ScalesGetter, hpaNamespacer unversionedextensions.HorizontalPodAutoscalersGetter, metricsClient metrics.MetricsClient, resyncPeriod time.Duration) *HorizontalController { +func NewHorizontalController(evtNamespacer unversionedcore.EventsGetter, scaleNamespacer unversionedextensions.ScalesGetter, hpaNamespacer unversionedautoscaling.HorizontalPodAutoscalersGetter, metricsClient metrics.MetricsClient, resyncPeriod time.Duration) *HorizontalController { broadcaster := record.NewBroadcaster() broadcaster.StartRecordingToSink(&unversionedcore.EventSinkImpl{Interface: evtNamespacer.Events("")}) recorder := broadcaster.NewRecorder(api.EventSource{Component: "horizontal-pod-autoscaler"}) @@ -128,10 +130,10 @@ func (a *HorizontalController) Run(stopCh <-chan struct{}) { glog.Infof("Shutting down HPA Controller") } -func (a *HorizontalController) computeReplicasForCPUUtilization(hpa *extensions.HorizontalPodAutoscaler, scale *extensions.Scale) (int32, *int32, time.Time, error) { +func (a *HorizontalController) computeReplicasForCPUUtilization(hpa *autoscaling.HorizontalPodAutoscaler, scale *extensions.Scale) (int32, *int32, time.Time, error) { targetUtilization := int32(defaultTargetCPUUtilizationPercentage) - if hpa.Spec.CPUUtilization != nil { - targetUtilization = hpa.Spec.CPUUtilization.TargetPercentage + if hpa.Spec.TargetCPUUtilizationPercentage != nil { + targetUtilization = *hpa.Spec.TargetCPUUtilizationPercentage } currentReplicas := scale.Status.Replicas @@ -170,7 +172,7 @@ func (a *HorizontalController) computeReplicasForCPUUtilization(hpa *extensions. // Returns number of replicas, metric which required highest number of replicas, // status string (also json-serialized extensions.CustomMetricsCurrentStatusList), // last timestamp of the metrics involved in computations or error, if occurred. -func (a *HorizontalController) computeReplicasForCustomMetrics(hpa *extensions.HorizontalPodAutoscaler, scale *extensions.Scale, +func (a *HorizontalController) computeReplicasForCustomMetrics(hpa *autoscaling.HorizontalPodAutoscaler, scale *extensions.Scale, cmAnnotation string) (replicas int32, metric string, status string, timestamp time.Time, err error) { currentReplicas := scale.Status.Replicas @@ -246,10 +248,10 @@ func (a *HorizontalController) computeReplicasForCustomMetrics(hpa *extensions.H return replicas, metric, string(byteStatusList), timestamp, nil } -func (a *HorizontalController) reconcileAutoscaler(hpa *extensions.HorizontalPodAutoscaler) error { - reference := fmt.Sprintf("%s/%s/%s", hpa.Spec.ScaleRef.Kind, hpa.Namespace, hpa.Spec.ScaleRef.Name) +func (a *HorizontalController) reconcileAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler) error { + reference := fmt.Sprintf("%s/%s/%s", hpa.Spec.ScaleTargetRef.Kind, hpa.Namespace, hpa.Spec.ScaleTargetRef.Name) - scale, err := a.scaleNamespacer.Scales(hpa.Namespace).Get(hpa.Spec.ScaleRef.Kind, hpa.Spec.ScaleRef.Name) + scale, err := a.scaleNamespacer.Scales(hpa.Namespace).Get(hpa.Spec.ScaleTargetRef.Kind, hpa.Spec.ScaleTargetRef.Name) if err != nil { a.eventRecorder.Event(hpa, api.EventTypeWarning, "FailedGetScale", err.Error()) return fmt.Errorf("failed to query scale subresource for %s: %v", reference, err) @@ -282,7 +284,7 @@ func (a *HorizontalController) reconcileAutoscaler(hpa *extensions.HorizontalPod // All basic scenarios covered, the state should be sane, lets use metrics. cmAnnotation, cmAnnotationFound := hpa.Annotations[HpaCustomMetricsTargetAnnotationName] - if hpa.Spec.CPUUtilization != nil || !cmAnnotationFound { + if hpa.Spec.TargetCPUUtilizationPercentage != nil || !cmAnnotationFound { cpuDesiredReplicas, cpuCurrentUtilization, cpuTimestamp, err = a.computeReplicasForCPUUtilization(hpa, scale) if err != nil { a.updateCurrentReplicasInStatus(hpa, currentReplicas) @@ -334,7 +336,7 @@ func (a *HorizontalController) reconcileAutoscaler(hpa *extensions.HorizontalPod rescale := shouldScale(hpa, currentReplicas, desiredReplicas, timestamp) if rescale { scale.Spec.Replicas = desiredReplicas - _, err = a.scaleNamespacer.Scales(hpa.Namespace).Update(hpa.Spec.ScaleRef.Kind, scale) + _, err = a.scaleNamespacer.Scales(hpa.Namespace).Update(hpa.Spec.ScaleTargetRef.Kind, scale) if err != nil { a.eventRecorder.Eventf(hpa, api.EventTypeWarning, "FailedRescale", "New size: %d; reason: %s; error: %v", desiredReplicas, rescaleReason, err.Error()) return fmt.Errorf("failed to rescale %s: %v", reference, err) @@ -349,7 +351,7 @@ func (a *HorizontalController) reconcileAutoscaler(hpa *extensions.HorizontalPod return a.updateStatus(hpa, currentReplicas, desiredReplicas, cpuCurrentUtilization, cmStatus, rescale) } -func shouldScale(hpa *extensions.HorizontalPodAutoscaler, currentReplicas, desiredReplicas int32, timestamp time.Time) bool { +func shouldScale(hpa *autoscaling.HorizontalPodAutoscaler, currentReplicas, desiredReplicas int32, timestamp time.Time) bool { if desiredReplicas != currentReplicas { // Going down only if the usageRatio dropped significantly below the target // and there was no rescaling in the last downscaleForbiddenWindow. @@ -370,15 +372,15 @@ func shouldScale(hpa *extensions.HorizontalPodAutoscaler, currentReplicas, desir return false } -func (a *HorizontalController) updateCurrentReplicasInStatus(hpa *extensions.HorizontalPodAutoscaler, currentReplicas int32) { +func (a *HorizontalController) updateCurrentReplicasInStatus(hpa *autoscaling.HorizontalPodAutoscaler, currentReplicas int32) { err := a.updateStatus(hpa, currentReplicas, hpa.Status.DesiredReplicas, hpa.Status.CurrentCPUUtilizationPercentage, hpa.Annotations[HpaCustomMetricsStatusAnnotationName], false) if err != nil { glog.Errorf("%v", err) } } -func (a *HorizontalController) updateStatus(hpa *extensions.HorizontalPodAutoscaler, currentReplicas, desiredReplicas int32, cpuCurrentUtilization *int32, cmStatus string, rescale bool) error { - hpa.Status = extensions.HorizontalPodAutoscalerStatus{ +func (a *HorizontalController) updateStatus(hpa *autoscaling.HorizontalPodAutoscaler, currentReplicas, desiredReplicas int32, cpuCurrentUtilization *int32, cmStatus string, rescale bool) error { + hpa.Status = autoscaling.HorizontalPodAutoscalerStatus{ CurrentReplicas: currentReplicas, DesiredReplicas: desiredReplicas, CurrentCPUUtilizationPercentage: cpuCurrentUtilization, diff --git a/pkg/controller/podautoscaler/horizontal_test.go b/pkg/controller/podautoscaler/horizontal_test.go index 97b61abf125..ce1135e351c 100644 --- a/pkg/controller/podautoscaler/horizontal_test.go +++ b/pkg/controller/podautoscaler/horizontal_test.go @@ -28,6 +28,7 @@ import ( "k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/unversioned" _ "k8s.io/kubernetes/pkg/apimachinery/registered" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned" @@ -138,25 +139,24 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset { tc.Lock() defer tc.Unlock() - obj := &extensions.HorizontalPodAutoscalerList{ - Items: []extensions.HorizontalPodAutoscaler{ + obj := &autoscaling.HorizontalPodAutoscalerList{ + Items: []autoscaling.HorizontalPodAutoscaler{ { ObjectMeta: api.ObjectMeta{ Name: hpaName, Namespace: namespace, SelfLink: "experimental/v1/namespaces/" + namespace + "/horizontalpodautoscalers/" + hpaName, }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: tc.resource.kind, - Name: tc.resource.name, - APIVersion: tc.resource.apiVersion, - Subresource: "scale", + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: tc.resource.kind, + Name: tc.resource.name, + APIVersion: tc.resource.apiVersion, }, MinReplicas: &tc.minReplicas, MaxReplicas: tc.maxReplicas, }, - Status: extensions.HorizontalPodAutoscalerStatus{ + Status: autoscaling.HorizontalPodAutoscalerStatus{ CurrentReplicas: tc.initialReplicas, DesiredReplicas: tc.initialReplicas, }, @@ -165,7 +165,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset { } if tc.CPUTarget > 0.0 { - obj.Items[0].Spec.CPUUtilization = &extensions.CPUTargetUtilization{TargetPercentage: tc.CPUTarget} + obj.Items[0].Spec.TargetCPUUtilizationPercentage = &tc.CPUTarget } if tc.cmTarget != nil { b, err := json.Marshal(tc.cmTarget) @@ -327,7 +327,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset { tc.Lock() defer tc.Unlock() - obj := action.(core.UpdateAction).GetObject().(*extensions.HorizontalPodAutoscaler) + obj := action.(core.UpdateAction).GetObject().(*autoscaling.HorizontalPodAutoscaler) assert.Equal(t, namespace, obj.Namespace) assert.Equal(t, hpaName, obj.Name) assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas) @@ -383,7 +383,7 @@ func (tc *testCase) runTest(t *testing.T) { metricsClient: metricsClient, eventRecorder: recorder, scaleNamespacer: testClient.Extensions(), - hpaNamespacer: testClient.Extensions(), + hpaNamespacer: testClient.Autoscaling(), } store, frameworkController := newInformer(hpaController, time.Minute) diff --git a/pkg/kubectl/autoscale.go b/pkg/kubectl/autoscale.go index 5aa9b0bfd9e..e3a7fc088a9 100644 --- a/pkg/kubectl/autoscale.go +++ b/pkg/kubectl/autoscale.go @@ -21,7 +21,7 @@ import ( "strconv" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/runtime" ) @@ -86,16 +86,15 @@ func (HorizontalPodAutoscalerV1Beta1) Generate(genericParams map[string]interfac } } - scaler := extensions.HorizontalPodAutoscaler{ + scaler := autoscaling.HorizontalPodAutoscaler{ ObjectMeta: api.ObjectMeta{ Name: name, }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: params["scaleRef-kind"], - Name: params["scaleRef-name"], - APIVersion: params["scaleRef-apiVersion"], - Subresource: scaleSubResource, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: params["scaleRef-kind"], + Name: params["scaleRef-name"], + APIVersion: params["scaleRef-apiVersion"], }, MaxReplicas: int32(max), }, @@ -105,7 +104,8 @@ func (HorizontalPodAutoscalerV1Beta1) Generate(genericParams map[string]interfac scaler.Spec.MinReplicas = &v } if cpu >= 0 { - scaler.Spec.CPUUtilization = &extensions.CPUTargetUtilization{TargetPercentage: int32(cpu)} + c := int32(cpu) + scaler.Spec.TargetCPUUtilizationPercentage = &c } return &scaler, nil } diff --git a/pkg/kubectl/describe.go b/pkg/kubectl/describe.go index 97bc876ed39..d359a71a4c6 100644 --- a/pkg/kubectl/describe.go +++ b/pkg/kubectl/describe.go @@ -1710,7 +1710,7 @@ type HorizontalPodAutoscalerDescriber struct { } func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) { - hpa, err := d.client.Extensions().HorizontalPodAutoscalers(namespace).Get(name) + hpa, err := d.client.Autoscaling().HorizontalPodAutoscalers(namespace).Get(name) if err != nil { return "", err } @@ -1720,12 +1720,11 @@ func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, desc printLabelsMultiline(out, "Labels", hpa.Labels) printLabelsMultiline(out, "Annotations", hpa.Annotations) fmt.Fprintf(out, "CreationTimestamp:\t%s\n", hpa.CreationTimestamp.Time.Format(time.RFC1123Z)) - fmt.Fprintf(out, "Reference:\t%s/%s/%s\n", - hpa.Spec.ScaleRef.Kind, - hpa.Spec.ScaleRef.Name, - hpa.Spec.ScaleRef.Subresource) - if hpa.Spec.CPUUtilization != nil { - fmt.Fprintf(out, "Target CPU utilization:\t%d%%\n", hpa.Spec.CPUUtilization.TargetPercentage) + fmt.Fprintf(out, "Reference:\t%s/%s\n", + hpa.Spec.ScaleTargetRef.Kind, + hpa.Spec.ScaleTargetRef.Name) + if hpa.Spec.TargetCPUUtilizationPercentage != nil { + fmt.Fprintf(out, "Target CPU utilization:\t%d%%\n", *hpa.Spec.TargetCPUUtilizationPercentage) fmt.Fprintf(out, "Current CPU utilization:\t") if hpa.Status.CurrentCPUUtilizationPercentage != nil { fmt.Fprintf(out, "%d%%\n", *hpa.Status.CurrentCPUUtilizationPercentage) @@ -1741,9 +1740,9 @@ func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, desc fmt.Fprintf(out, "Max replicas:\t%d\n", hpa.Spec.MaxReplicas) // TODO: switch to scale subresource once the required code is submitted. - if strings.ToLower(hpa.Spec.ScaleRef.Kind) == "replicationcontroller" { + if strings.ToLower(hpa.Spec.ScaleTargetRef.Kind) == "replicationcontroller" { fmt.Fprintf(out, "ReplicationController pods:\t") - rc, err := d.client.ReplicationControllers(hpa.Namespace).Get(hpa.Spec.ScaleRef.Name) + rc, err := d.client.ReplicationControllers(hpa.Namespace).Get(hpa.Spec.ScaleTargetRef.Name) if err == nil { fmt.Fprintf(out, "%d current / %d desired\n", rc.Status.Replicas, rc.Spec.Replicas) } else { diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index 59533ccec82..5c605877936 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -36,6 +36,7 @@ import ( "k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apis/apps" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/labels" @@ -1607,16 +1608,15 @@ func printDeploymentList(list *extensions.DeploymentList, w io.Writer, options P return nil } -func printHorizontalPodAutoscaler(hpa *extensions.HorizontalPodAutoscaler, w io.Writer, options PrintOptions) error { +func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io.Writer, options PrintOptions) error { namespace := hpa.Namespace name := hpa.Name - reference := fmt.Sprintf("%s/%s/%s", - hpa.Spec.ScaleRef.Kind, - hpa.Spec.ScaleRef.Name, - hpa.Spec.ScaleRef.Subresource) + reference := fmt.Sprintf("%s/%s", + hpa.Spec.ScaleTargetRef.Kind, + hpa.Spec.ScaleTargetRef.Name) target := "" - if hpa.Spec.CPUUtilization != nil { - target = fmt.Sprintf("%d%%", hpa.Spec.CPUUtilization.TargetPercentage) + if hpa.Spec.TargetCPUUtilizationPercentage != nil { + target = fmt.Sprintf("%d%%", *hpa.Spec.TargetCPUUtilizationPercentage) } current := "" if hpa.Status.CurrentCPUUtilizationPercentage != nil { @@ -1651,7 +1651,7 @@ func printHorizontalPodAutoscaler(hpa *extensions.HorizontalPodAutoscaler, w io. return err } -func printHorizontalPodAutoscalerList(list *extensions.HorizontalPodAutoscalerList, w io.Writer, options PrintOptions) error { +func printHorizontalPodAutoscalerList(list *autoscaling.HorizontalPodAutoscalerList, w io.Writer, options PrintOptions) error { for i := range list.Items { if err := printHorizontalPodAutoscaler(&list.Items[i], w, options); err != nil { return err diff --git a/pkg/registry/horizontalpodautoscaler/etcd/etcd.go b/pkg/registry/horizontalpodautoscaler/etcd/etcd.go index a4e0e1e5276..d6d74b50cc6 100644 --- a/pkg/registry/horizontalpodautoscaler/etcd/etcd.go +++ b/pkg/registry/horizontalpodautoscaler/etcd/etcd.go @@ -18,7 +18,7 @@ package etcd import ( "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/cachesize" @@ -36,12 +36,12 @@ type REST struct { func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) { prefix := "/horizontalpodautoscalers" - newListFunc := func() runtime.Object { return &extensions.HorizontalPodAutoscalerList{} } + newListFunc := func() runtime.Object { return &autoscaling.HorizontalPodAutoscalerList{} } storageInterface := opts.Decorator( - opts.Storage, cachesize.GetWatchCacheSizeByResource(cachesize.HorizontalPodAutoscalers), &extensions.HorizontalPodAutoscaler{}, prefix, horizontalpodautoscaler.Strategy, newListFunc) + opts.Storage, cachesize.GetWatchCacheSizeByResource(cachesize.HorizontalPodAutoscalers), &autoscaling.HorizontalPodAutoscaler{}, prefix, horizontalpodautoscaler.Strategy, newListFunc) store := ®istry.Store{ - NewFunc: func() runtime.Object { return &extensions.HorizontalPodAutoscaler{} }, + NewFunc: func() runtime.Object { return &autoscaling.HorizontalPodAutoscaler{} }, // NewListFunc returns an object capable of storing results of an etcd list. NewListFunc: newListFunc, // Produces a path that etcd understands, to the root of the resource @@ -56,13 +56,13 @@ func NewREST(opts generic.RESTOptions) (*REST, *StatusREST) { }, // Retrieve the name field of an autoscaler ObjectNameFunc: func(obj runtime.Object) (string, error) { - return obj.(*extensions.HorizontalPodAutoscaler).Name, nil + return obj.(*autoscaling.HorizontalPodAutoscaler).Name, nil }, // Used to match objects based on labels/fields for list PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher { return horizontalpodautoscaler.MatchAutoscaler(label, field) }, - QualifiedResource: extensions.Resource("horizontalpodautoscalers"), + QualifiedResource: autoscaling.Resource("horizontalpodautoscalers"), DeleteCollectionWorkers: opts.DeleteCollectionWorkers, // Used to validate autoscaler creation @@ -85,7 +85,7 @@ type StatusREST struct { } func (r *StatusREST) New() runtime.Object { - return &extensions.HorizontalPodAutoscaler{} + return &autoscaling.HorizontalPodAutoscaler{} } // Update alters the status subset of an object. diff --git a/pkg/registry/horizontalpodautoscaler/etcd/etcd_test.go b/pkg/registry/horizontalpodautoscaler/etcd/etcd_test.go index 3f3ba38916f..bc926d57d78 100644 --- a/pkg/registry/horizontalpodautoscaler/etcd/etcd_test.go +++ b/pkg/registry/horizontalpodautoscaler/etcd/etcd_test.go @@ -20,9 +20,9 @@ import ( "testing" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" - // Ensure that extensions/v1beta1 package is initialized. - _ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" + "k8s.io/kubernetes/pkg/apis/autoscaling" + // Ensure that autoscaling/v1 package is initialized. + _ "k8s.io/kubernetes/pkg/apis/autoscaling/v1" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" @@ -32,26 +32,26 @@ import ( ) func newStorage(t *testing.T) (*REST, *StatusREST, *etcdtesting.EtcdTestServer) { - etcdStorage, server := registrytest.NewEtcdStorage(t, extensions.GroupName) + etcdStorage, server := registrytest.NewEtcdStorage(t, autoscaling.GroupName) restOptions := generic.RESTOptions{Storage: etcdStorage, Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1} horizontalPodAutoscalerStorage, statusStorage := NewREST(restOptions) return horizontalPodAutoscalerStorage, statusStorage, server } -func validNewHorizontalPodAutoscaler(name string) *extensions.HorizontalPodAutoscaler { - return &extensions.HorizontalPodAutoscaler{ +func validNewHorizontalPodAutoscaler(name string) *autoscaling.HorizontalPodAutoscaler { + cpu := int32(70) + return &autoscaling.HorizontalPodAutoscaler{ ObjectMeta: api.ObjectMeta{ Name: name, Namespace: api.NamespaceDefault, }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: "ReplicationController", - Name: "myrc", - Subresource: "scale", + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: "ReplicationController", + Name: "myrc", }, - MaxReplicas: 5, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: 70}, + MaxReplicas: 5, + TargetCPUUtilizationPercentage: &cpu, }, } } @@ -66,7 +66,7 @@ func TestCreate(t *testing.T) { // valid autoscaler, // invalid - &extensions.HorizontalPodAutoscaler{}, + &autoscaling.HorizontalPodAutoscaler{}, ) } @@ -79,7 +79,7 @@ func TestUpdate(t *testing.T) { validNewHorizontalPodAutoscaler("foo"), // updateFunc func(obj runtime.Object) runtime.Object { - object := obj.(*extensions.HorizontalPodAutoscaler) + object := obj.(*autoscaling.HorizontalPodAutoscaler) object.Spec.MaxReplicas = object.Spec.MaxReplicas + 1 return object }, diff --git a/pkg/registry/horizontalpodautoscaler/strategy.go b/pkg/registry/horizontalpodautoscaler/strategy.go index 3a8ade0794e..419beb6b1b5 100644 --- a/pkg/registry/horizontalpodautoscaler/strategy.go +++ b/pkg/registry/horizontalpodautoscaler/strategy.go @@ -20,8 +20,8 @@ import ( "fmt" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/apis/extensions/validation" + "k8s.io/kubernetes/pkg/apis/autoscaling" + "k8s.io/kubernetes/pkg/apis/autoscaling/validation" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/generic" @@ -46,15 +46,15 @@ func (autoscalerStrategy) NamespaceScoped() bool { // PrepareForCreate clears fields that are not allowed to be set by end users on creation. func (autoscalerStrategy) PrepareForCreate(obj runtime.Object) { - newHPA := obj.(*extensions.HorizontalPodAutoscaler) + newHPA := obj.(*autoscaling.HorizontalPodAutoscaler) // create cannot set status - newHPA.Status = extensions.HorizontalPodAutoscalerStatus{} + newHPA.Status = autoscaling.HorizontalPodAutoscalerStatus{} } // Validate validates a new autoscaler. func (autoscalerStrategy) Validate(ctx api.Context, obj runtime.Object) field.ErrorList { - autoscaler := obj.(*extensions.HorizontalPodAutoscaler) + autoscaler := obj.(*autoscaling.HorizontalPodAutoscaler) return validation.ValidateHorizontalPodAutoscaler(autoscaler) } @@ -69,22 +69,22 @@ func (autoscalerStrategy) AllowCreateOnUpdate() bool { // PrepareForUpdate clears fields that are not allowed to be set by end users on update. func (autoscalerStrategy) PrepareForUpdate(obj, old runtime.Object) { - newHPA := obj.(*extensions.HorizontalPodAutoscaler) - oldHPA := old.(*extensions.HorizontalPodAutoscaler) + newHPA := obj.(*autoscaling.HorizontalPodAutoscaler) + oldHPA := old.(*autoscaling.HorizontalPodAutoscaler) // Update is not allowed to set status newHPA.Status = oldHPA.Status } // ValidateUpdate is the default update validation for an end user. 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.(*autoscaling.HorizontalPodAutoscaler), old.(*autoscaling.HorizontalPodAutoscaler)) } func (autoscalerStrategy) AllowUnconditionalUpdate() bool { return true } -func AutoscalerToSelectableFields(limitRange *extensions.HorizontalPodAutoscaler) fields.Set { +func AutoscalerToSelectableFields(limitRange *autoscaling.HorizontalPodAutoscaler) fields.Set { return fields.Set{} } @@ -93,7 +93,7 @@ func MatchAutoscaler(label labels.Selector, field fields.Selector) generic.Match Label: label, Field: field, GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { - hpa, ok := obj.(*extensions.HorizontalPodAutoscaler) + hpa, ok := obj.(*autoscaling.HorizontalPodAutoscaler) if !ok { return nil, nil, fmt.Errorf("given object is not a horizontal pod autoscaler.") } @@ -109,12 +109,12 @@ type autoscalerStatusStrategy struct { var StatusStrategy = autoscalerStatusStrategy{Strategy} func (autoscalerStatusStrategy) PrepareForUpdate(obj, old runtime.Object) { - newAutoscaler := obj.(*extensions.HorizontalPodAutoscaler) - oldAutoscaler := old.(*extensions.HorizontalPodAutoscaler) + newAutoscaler := obj.(*autoscaling.HorizontalPodAutoscaler) + oldAutoscaler := old.(*autoscaling.HorizontalPodAutoscaler) // status changes are not allowed to update spec newAutoscaler.Spec = oldAutoscaler.Spec } 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.(*autoscaling.HorizontalPodAutoscaler), old.(*autoscaling.HorizontalPodAutoscaler)) } diff --git a/pkg/registry/horizontalpodautoscaler/strategy_test.go b/pkg/registry/horizontalpodautoscaler/strategy_test.go index 992238bae62..121f6b7b402 100644 --- a/pkg/registry/horizontalpodautoscaler/strategy_test.go +++ b/pkg/registry/horizontalpodautoscaler/strategy_test.go @@ -22,15 +22,15 @@ import ( _ "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" - "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/labels" ) func TestSelectableFieldLabelConversions(t *testing.T) { apitesting.TestSelectableFieldLabelConversionsOfKind(t, - testapi.Extensions.GroupVersion().String(), + testapi.Autoscaling.GroupVersion().String(), "Autoscaler", - labels.Set(AutoscalerToSelectableFields(&extensions.HorizontalPodAutoscaler{})), + labels.Set(AutoscalerToSelectableFields(&autoscaling.HorizontalPodAutoscaler{})), nil, ) } diff --git a/test/e2e/horizontal_pod_autoscaling.go b/test/e2e/horizontal_pod_autoscaling.go index 6686c0adbff..dace16116bc 100644 --- a/test/e2e/horizontal_pod_autoscaling.go +++ b/test/e2e/horizontal_pod_autoscaling.go @@ -20,7 +20,7 @@ import ( "time" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/apis/extensions" + "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/test/e2e/framework" . "github.com/onsi/ginkgo" @@ -87,7 +87,7 @@ var _ = framework.KubeDescribe("Horizontal pod autoscaling (scale resource: CPU) } scaleTest.run("rc-light", kindRC, rc, f) }) - It("Should scale from 2 pods to 1 pod using HPA version v1", func() { + It("Should scale from 2 pods to 1 pod", func() { scaleTest := &HPAScaleTest{ initPods: 2, totalInitialCPUUsage: 50, @@ -96,7 +96,6 @@ var _ = framework.KubeDescribe("Horizontal pod autoscaling (scale resource: CPU) minPods: 1, maxPods: 2, firstScale: 1, - useV1: true, } scaleTest.run("rc-light", kindRC, rc, f) }) @@ -116,7 +115,6 @@ type HPAScaleTest struct { cpuBurst int secondScale int32 secondScaleStasis time.Duration - useV1 bool } // run is a method which runs an HPA lifecycle, from a starting state, to an expected @@ -127,7 +125,7 @@ type HPAScaleTest struct { func (scaleTest *HPAScaleTest) run(name, kind string, rc *ResourceConsumer, f *framework.Framework) { rc = NewDynamicResourceConsumer(name, kind, int(scaleTest.initPods), int(scaleTest.totalInitialCPUUsage), 0, 0, scaleTest.perPodCPURequest, 100, f) defer rc.CleanUp() - createCPUHorizontalPodAutoscaler(rc, scaleTest.targetCPUUtilizationPercent, scaleTest.minPods, scaleTest.maxPods, scaleTest.useV1) + createCPUHorizontalPodAutoscaler(rc, scaleTest.targetCPUUtilizationPercent, scaleTest.minPods, scaleTest.maxPods) rc.WaitForReplicas(int(scaleTest.firstScale)) if scaleTest.firstScaleStasis > 0 { rc.EnsureDesiredReplicas(int(scaleTest.firstScale), scaleTest.firstScaleStasis) @@ -170,28 +168,22 @@ func scaleDown(name, kind string, rc *ResourceConsumer, f *framework.Framework) scaleTest.run(name, kind, rc, f) } -func createCPUHorizontalPodAutoscaler(rc *ResourceConsumer, cpu, minReplicas, maxRepl int32, useV1 bool) { - hpa := &extensions.HorizontalPodAutoscaler{ +func createCPUHorizontalPodAutoscaler(rc *ResourceConsumer, cpu, minReplicas, maxRepl int32) { + hpa := &autoscaling.HorizontalPodAutoscaler{ ObjectMeta: api.ObjectMeta{ Name: rc.name, Namespace: rc.framework.Namespace.Name, }, - Spec: extensions.HorizontalPodAutoscalerSpec{ - ScaleRef: extensions.SubresourceReference{ - Kind: rc.kind, - Name: rc.name, - Subresource: subresource, + Spec: autoscaling.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscaling.CrossVersionObjectReference{ + Kind: rc.kind, + Name: rc.name, }, - MinReplicas: &minReplicas, - MaxReplicas: maxRepl, - CPUUtilization: &extensions.CPUTargetUtilization{TargetPercentage: cpu}, + MinReplicas: &minReplicas, + MaxReplicas: maxRepl, + TargetCPUUtilizationPercentage: &cpu, }, } - var errHPA error - if useV1 { - _, errHPA = rc.framework.Client.Autoscaling().HorizontalPodAutoscalers(rc.framework.Namespace.Name).Create(hpa) - } else { - _, errHPA = rc.framework.Client.Extensions().HorizontalPodAutoscalers(rc.framework.Namespace.Name).Create(hpa) - } + _, errHPA := rc.framework.Client.Autoscaling().HorizontalPodAutoscalers(rc.framework.Namespace.Name).Create(hpa) framework.ExpectNoError(errHPA) }