Merge pull request #60096 from MaciekPytel/hpa_api_ext

Automatic merge from submit-queue (batch tested with PRs 60208, 60084, 60183, 59713, 60096). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Add external metric type to HPA API

**What this PR does / why we need it**:
Add external metric type to HPA API proposed in xref https://github.com/kubernetes/community/pull/1801

**Release note**:
```release-note
Allows HorizontalPodAutoscaler to use global metrics not associated with any Kubernetes object (for example metrics from a hoster service running outside of Kubernetes cluster).
```
This commit is contained in:
Kubernetes Submit Queue
2018-02-22 23:17:42 -08:00
committed by GitHub
19 changed files with 2902 additions and 298 deletions

View File

@@ -111,6 +111,12 @@ var (
// Kubernetes, and have special scaling options on top of those available
// to normal per-pod metrics (the "pods" source).
ResourceMetricSourceType MetricSourceType = "Resource"
// ExternalMetricSourceType is a global metric that is not associated
// with any Kubernetes object. It allows autoscaling based on information
// coming from components running outside of cluster
// (for example length of queue in cloud messaging service, or
// QPS from loadbalancer running outside of cluster).
ExternalMetricSourceType MetricSourceType = "External"
)
// MetricSpec specifies how to scale based on a single metric
@@ -136,6 +142,13 @@ type MetricSpec struct {
// to normal per-pod metrics using the "pods" source.
// +optional
Resource *ResourceMetricSource
// External refers to a global metric that is not associated
// with any Kubernetes object. It allows autoscaling based on information
// coming from components running outside of cluster
// (for example length of queue in cloud messaging service, or
// QPS from loadbalancer running outside of cluster).
// +optional
External *ExternalMetricSource
}
// ObjectMetricSource indicates how to scale on a metric describing a
@@ -184,6 +197,26 @@ type ResourceMetricSource struct {
TargetAverageValue *resource.Quantity
}
// ExternalMetricSource indicates how to scale on a metric not associated with
// any Kubernetes object (for example length of queue in cloud
// messaging service, or QPS from loadbalancer running outside of cluster).
type ExternalMetricSource struct {
// metricName is the name of the metric in question.
MetricName string
// MetricSelector is used to identify a specific time series
// within a given metric.
// +optional
MetricSelector *metav1.LabelSelector
// TargetValue is the target value of the metric (as a quantity).
// Mutually exclusive with TargetAverageValue.
// +optional
TargetValue *resource.Quantity
// TargetAverageValue is the target per-pod value of global metric (as a quantity).
// Mutually exclusive with TargetValue.
// +optional
TargetAverageValue *resource.Quantity
}
// HorizontalPodAutoscalerStatus describes the current status of a horizontal pod autoscaler.
type HorizontalPodAutoscalerStatus struct {
// ObservedGeneration is the most recent generation observed by this autoscaler.
@@ -282,6 +315,13 @@ type MetricStatus struct {
// to normal per-pod metrics using the "pods" source.
// +optional
Resource *ResourceMetricStatus
// External refers to a global metric that is not associated
// with any Kubernetes object. It allows autoscaling based on information
// coming from components running outside of cluster
// (for example length of queue in cloud messaging service, or
// QPS from loadbalancer running outside of cluster).
// +optional
External *ExternalMetricStatus
}
// ObjectMetricStatus indicates the current value of a metric describing a
@@ -328,6 +368,23 @@ type ResourceMetricStatus struct {
CurrentAverageValue resource.Quantity
}
// ExternalMetricStatus indicates the current value of a global metric
// not associated with any Kubernetes object.
type ExternalMetricStatus struct {
// MetricName is the name of a metric used for autoscaling in
// metric system.
MetricName string
// MetricSelector is used to identify a specific time series
// within a given metric.
// +optional
MetricSelector *metav1.LabelSelector
// CurrentValue is the current value of the metric (as a quantity)
CurrentValue resource.Quantity
// CurrentAverageValue is the current value of metric averaged over autoscaled pods.
// +optional
CurrentAverageValue *resource.Quantity
}
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@@ -43,6 +43,10 @@ func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v1_CrossVersionObjectReference_To_autoscaling_CrossVersionObjectReference,
Convert_autoscaling_CrossVersionObjectReference_To_v1_CrossVersionObjectReference,
Convert_v1_ExternalMetricSource_To_autoscaling_ExternalMetricSource,
Convert_autoscaling_ExternalMetricSource_To_v1_ExternalMetricSource,
Convert_v1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus,
Convert_autoscaling_ExternalMetricStatus_To_v1_ExternalMetricStatus,
Convert_v1_HorizontalPodAutoscaler_To_autoscaling_HorizontalPodAutoscaler,
Convert_autoscaling_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler,
Convert_v1_HorizontalPodAutoscalerCondition_To_autoscaling_HorizontalPodAutoscalerCondition,
@@ -102,6 +106,58 @@ func Convert_autoscaling_CrossVersionObjectReference_To_v1_CrossVersionObjectRef
return autoConvert_autoscaling_CrossVersionObjectReference_To_v1_CrossVersionObjectReference(in, out, s)
}
func autoConvert_v1_ExternalMetricSource_To_autoscaling_ExternalMetricSource(in *v1.ExternalMetricSource, out *autoscaling.ExternalMetricSource, s conversion.Scope) error {
out.MetricName = in.MetricName
out.MetricSelector = (*meta_v1.LabelSelector)(unsafe.Pointer(in.MetricSelector))
out.TargetValue = (*resource.Quantity)(unsafe.Pointer(in.TargetValue))
out.TargetAverageValue = (*resource.Quantity)(unsafe.Pointer(in.TargetAverageValue))
return nil
}
// Convert_v1_ExternalMetricSource_To_autoscaling_ExternalMetricSource is an autogenerated conversion function.
func Convert_v1_ExternalMetricSource_To_autoscaling_ExternalMetricSource(in *v1.ExternalMetricSource, out *autoscaling.ExternalMetricSource, s conversion.Scope) error {
return autoConvert_v1_ExternalMetricSource_To_autoscaling_ExternalMetricSource(in, out, s)
}
func autoConvert_autoscaling_ExternalMetricSource_To_v1_ExternalMetricSource(in *autoscaling.ExternalMetricSource, out *v1.ExternalMetricSource, s conversion.Scope) error {
out.MetricName = in.MetricName
out.MetricSelector = (*meta_v1.LabelSelector)(unsafe.Pointer(in.MetricSelector))
out.TargetValue = (*resource.Quantity)(unsafe.Pointer(in.TargetValue))
out.TargetAverageValue = (*resource.Quantity)(unsafe.Pointer(in.TargetAverageValue))
return nil
}
// Convert_autoscaling_ExternalMetricSource_To_v1_ExternalMetricSource is an autogenerated conversion function.
func Convert_autoscaling_ExternalMetricSource_To_v1_ExternalMetricSource(in *autoscaling.ExternalMetricSource, out *v1.ExternalMetricSource, s conversion.Scope) error {
return autoConvert_autoscaling_ExternalMetricSource_To_v1_ExternalMetricSource(in, out, s)
}
func autoConvert_v1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus(in *v1.ExternalMetricStatus, out *autoscaling.ExternalMetricStatus, s conversion.Scope) error {
out.MetricName = in.MetricName
out.MetricSelector = (*meta_v1.LabelSelector)(unsafe.Pointer(in.MetricSelector))
out.CurrentValue = in.CurrentValue
out.CurrentAverageValue = (*resource.Quantity)(unsafe.Pointer(in.CurrentAverageValue))
return nil
}
// Convert_v1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus is an autogenerated conversion function.
func Convert_v1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus(in *v1.ExternalMetricStatus, out *autoscaling.ExternalMetricStatus, s conversion.Scope) error {
return autoConvert_v1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus(in, out, s)
}
func autoConvert_autoscaling_ExternalMetricStatus_To_v1_ExternalMetricStatus(in *autoscaling.ExternalMetricStatus, out *v1.ExternalMetricStatus, s conversion.Scope) error {
out.MetricName = in.MetricName
out.MetricSelector = (*meta_v1.LabelSelector)(unsafe.Pointer(in.MetricSelector))
out.CurrentValue = in.CurrentValue
out.CurrentAverageValue = (*resource.Quantity)(unsafe.Pointer(in.CurrentAverageValue))
return nil
}
// Convert_autoscaling_ExternalMetricStatus_To_v1_ExternalMetricStatus is an autogenerated conversion function.
func Convert_autoscaling_ExternalMetricStatus_To_v1_ExternalMetricStatus(in *autoscaling.ExternalMetricStatus, out *v1.ExternalMetricStatus, s conversion.Scope) error {
return autoConvert_autoscaling_ExternalMetricStatus_To_v1_ExternalMetricStatus(in, out, s)
}
func autoConvert_v1_HorizontalPodAutoscaler_To_autoscaling_HorizontalPodAutoscaler(in *v1.HorizontalPodAutoscaler, out *autoscaling.HorizontalPodAutoscaler, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPodAutoscalerSpec(&in.Spec, &out.Spec, s); err != nil {
@@ -238,6 +294,7 @@ func autoConvert_v1_MetricSpec_To_autoscaling_MetricSpec(in *v1.MetricSpec, out
out.Object = (*autoscaling.ObjectMetricSource)(unsafe.Pointer(in.Object))
out.Pods = (*autoscaling.PodsMetricSource)(unsafe.Pointer(in.Pods))
out.Resource = (*autoscaling.ResourceMetricSource)(unsafe.Pointer(in.Resource))
out.External = (*autoscaling.ExternalMetricSource)(unsafe.Pointer(in.External))
return nil
}
@@ -251,6 +308,7 @@ func autoConvert_autoscaling_MetricSpec_To_v1_MetricSpec(in *autoscaling.MetricS
out.Object = (*v1.ObjectMetricSource)(unsafe.Pointer(in.Object))
out.Pods = (*v1.PodsMetricSource)(unsafe.Pointer(in.Pods))
out.Resource = (*v1.ResourceMetricSource)(unsafe.Pointer(in.Resource))
out.External = (*v1.ExternalMetricSource)(unsafe.Pointer(in.External))
return nil
}
@@ -264,6 +322,7 @@ func autoConvert_v1_MetricStatus_To_autoscaling_MetricStatus(in *v1.MetricStatus
out.Object = (*autoscaling.ObjectMetricStatus)(unsafe.Pointer(in.Object))
out.Pods = (*autoscaling.PodsMetricStatus)(unsafe.Pointer(in.Pods))
out.Resource = (*autoscaling.ResourceMetricStatus)(unsafe.Pointer(in.Resource))
out.External = (*autoscaling.ExternalMetricStatus)(unsafe.Pointer(in.External))
return nil
}
@@ -277,6 +336,7 @@ func autoConvert_autoscaling_MetricStatus_To_v1_MetricStatus(in *autoscaling.Met
out.Object = (*v1.ObjectMetricStatus)(unsafe.Pointer(in.Object))
out.Pods = (*v1.PodsMetricStatus)(unsafe.Pointer(in.Pods))
out.Resource = (*v1.ResourceMetricStatus)(unsafe.Pointer(in.Resource))
out.External = (*v1.ExternalMetricStatus)(unsafe.Pointer(in.External))
return nil
}

View File

@@ -24,9 +24,9 @@ import (
unsafe "unsafe"
v2beta1 "k8s.io/api/autoscaling/v2beta1"
v1 "k8s.io/api/core/v1"
core_v1 "k8s.io/api/core/v1"
resource "k8s.io/apimachinery/pkg/api/resource"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling"
@@ -43,6 +43,10 @@ func RegisterConversions(scheme *runtime.Scheme) error {
return scheme.AddGeneratedConversionFuncs(
Convert_v2beta1_CrossVersionObjectReference_To_autoscaling_CrossVersionObjectReference,
Convert_autoscaling_CrossVersionObjectReference_To_v2beta1_CrossVersionObjectReference,
Convert_v2beta1_ExternalMetricSource_To_autoscaling_ExternalMetricSource,
Convert_autoscaling_ExternalMetricSource_To_v2beta1_ExternalMetricSource,
Convert_v2beta1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus,
Convert_autoscaling_ExternalMetricStatus_To_v2beta1_ExternalMetricStatus,
Convert_v2beta1_HorizontalPodAutoscaler_To_autoscaling_HorizontalPodAutoscaler,
Convert_autoscaling_HorizontalPodAutoscaler_To_v2beta1_HorizontalPodAutoscaler,
Convert_v2beta1_HorizontalPodAutoscalerCondition_To_autoscaling_HorizontalPodAutoscalerCondition,
@@ -96,6 +100,58 @@ func Convert_autoscaling_CrossVersionObjectReference_To_v2beta1_CrossVersionObje
return autoConvert_autoscaling_CrossVersionObjectReference_To_v2beta1_CrossVersionObjectReference(in, out, s)
}
func autoConvert_v2beta1_ExternalMetricSource_To_autoscaling_ExternalMetricSource(in *v2beta1.ExternalMetricSource, out *autoscaling.ExternalMetricSource, s conversion.Scope) error {
out.MetricName = in.MetricName
out.MetricSelector = (*v1.LabelSelector)(unsafe.Pointer(in.MetricSelector))
out.TargetValue = (*resource.Quantity)(unsafe.Pointer(in.TargetValue))
out.TargetAverageValue = (*resource.Quantity)(unsafe.Pointer(in.TargetAverageValue))
return nil
}
// Convert_v2beta1_ExternalMetricSource_To_autoscaling_ExternalMetricSource is an autogenerated conversion function.
func Convert_v2beta1_ExternalMetricSource_To_autoscaling_ExternalMetricSource(in *v2beta1.ExternalMetricSource, out *autoscaling.ExternalMetricSource, s conversion.Scope) error {
return autoConvert_v2beta1_ExternalMetricSource_To_autoscaling_ExternalMetricSource(in, out, s)
}
func autoConvert_autoscaling_ExternalMetricSource_To_v2beta1_ExternalMetricSource(in *autoscaling.ExternalMetricSource, out *v2beta1.ExternalMetricSource, s conversion.Scope) error {
out.MetricName = in.MetricName
out.MetricSelector = (*v1.LabelSelector)(unsafe.Pointer(in.MetricSelector))
out.TargetValue = (*resource.Quantity)(unsafe.Pointer(in.TargetValue))
out.TargetAverageValue = (*resource.Quantity)(unsafe.Pointer(in.TargetAverageValue))
return nil
}
// Convert_autoscaling_ExternalMetricSource_To_v2beta1_ExternalMetricSource is an autogenerated conversion function.
func Convert_autoscaling_ExternalMetricSource_To_v2beta1_ExternalMetricSource(in *autoscaling.ExternalMetricSource, out *v2beta1.ExternalMetricSource, s conversion.Scope) error {
return autoConvert_autoscaling_ExternalMetricSource_To_v2beta1_ExternalMetricSource(in, out, s)
}
func autoConvert_v2beta1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus(in *v2beta1.ExternalMetricStatus, out *autoscaling.ExternalMetricStatus, s conversion.Scope) error {
out.MetricName = in.MetricName
out.MetricSelector = (*v1.LabelSelector)(unsafe.Pointer(in.MetricSelector))
out.CurrentValue = in.CurrentValue
out.CurrentAverageValue = (*resource.Quantity)(unsafe.Pointer(in.CurrentAverageValue))
return nil
}
// Convert_v2beta1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus is an autogenerated conversion function.
func Convert_v2beta1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus(in *v2beta1.ExternalMetricStatus, out *autoscaling.ExternalMetricStatus, s conversion.Scope) error {
return autoConvert_v2beta1_ExternalMetricStatus_To_autoscaling_ExternalMetricStatus(in, out, s)
}
func autoConvert_autoscaling_ExternalMetricStatus_To_v2beta1_ExternalMetricStatus(in *autoscaling.ExternalMetricStatus, out *v2beta1.ExternalMetricStatus, s conversion.Scope) error {
out.MetricName = in.MetricName
out.MetricSelector = (*v1.LabelSelector)(unsafe.Pointer(in.MetricSelector))
out.CurrentValue = in.CurrentValue
out.CurrentAverageValue = (*resource.Quantity)(unsafe.Pointer(in.CurrentAverageValue))
return nil
}
// Convert_autoscaling_ExternalMetricStatus_To_v2beta1_ExternalMetricStatus is an autogenerated conversion function.
func Convert_autoscaling_ExternalMetricStatus_To_v2beta1_ExternalMetricStatus(in *autoscaling.ExternalMetricStatus, out *v2beta1.ExternalMetricStatus, s conversion.Scope) error {
return autoConvert_autoscaling_ExternalMetricStatus_To_v2beta1_ExternalMetricStatus(in, out, s)
}
func autoConvert_v2beta1_HorizontalPodAutoscaler_To_autoscaling_HorizontalPodAutoscaler(in *v2beta1.HorizontalPodAutoscaler, out *autoscaling.HorizontalPodAutoscaler, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v2beta1_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPodAutoscalerSpec(&in.Spec, &out.Spec, s); err != nil {
@@ -144,7 +200,7 @@ func Convert_v2beta1_HorizontalPodAutoscalerCondition_To_autoscaling_HorizontalP
func autoConvert_autoscaling_HorizontalPodAutoscalerCondition_To_v2beta1_HorizontalPodAutoscalerCondition(in *autoscaling.HorizontalPodAutoscalerCondition, out *v2beta1.HorizontalPodAutoscalerCondition, s conversion.Scope) error {
out.Type = v2beta1.HorizontalPodAutoscalerConditionType(in.Type)
out.Status = v1.ConditionStatus(in.Status)
out.Status = core_v1.ConditionStatus(in.Status)
out.LastTransitionTime = in.LastTransitionTime
out.Reason = in.Reason
out.Message = in.Message
@@ -210,7 +266,7 @@ func Convert_autoscaling_HorizontalPodAutoscalerSpec_To_v2beta1_HorizontalPodAut
func autoConvert_v2beta1_HorizontalPodAutoscalerStatus_To_autoscaling_HorizontalPodAutoscalerStatus(in *v2beta1.HorizontalPodAutoscalerStatus, out *autoscaling.HorizontalPodAutoscalerStatus, s conversion.Scope) error {
out.ObservedGeneration = (*int64)(unsafe.Pointer(in.ObservedGeneration))
out.LastScaleTime = (*meta_v1.Time)(unsafe.Pointer(in.LastScaleTime))
out.LastScaleTime = (*v1.Time)(unsafe.Pointer(in.LastScaleTime))
out.CurrentReplicas = in.CurrentReplicas
out.DesiredReplicas = in.DesiredReplicas
out.CurrentMetrics = *(*[]autoscaling.MetricStatus)(unsafe.Pointer(&in.CurrentMetrics))
@@ -225,7 +281,7 @@ func Convert_v2beta1_HorizontalPodAutoscalerStatus_To_autoscaling_HorizontalPodA
func autoConvert_autoscaling_HorizontalPodAutoscalerStatus_To_v2beta1_HorizontalPodAutoscalerStatus(in *autoscaling.HorizontalPodAutoscalerStatus, out *v2beta1.HorizontalPodAutoscalerStatus, s conversion.Scope) error {
out.ObservedGeneration = (*int64)(unsafe.Pointer(in.ObservedGeneration))
out.LastScaleTime = (*meta_v1.Time)(unsafe.Pointer(in.LastScaleTime))
out.LastScaleTime = (*v1.Time)(unsafe.Pointer(in.LastScaleTime))
out.CurrentReplicas = in.CurrentReplicas
out.DesiredReplicas = in.DesiredReplicas
out.CurrentMetrics = *(*[]v2beta1.MetricStatus)(unsafe.Pointer(&in.CurrentMetrics))
@@ -243,6 +299,7 @@ func autoConvert_v2beta1_MetricSpec_To_autoscaling_MetricSpec(in *v2beta1.Metric
out.Object = (*autoscaling.ObjectMetricSource)(unsafe.Pointer(in.Object))
out.Pods = (*autoscaling.PodsMetricSource)(unsafe.Pointer(in.Pods))
out.Resource = (*autoscaling.ResourceMetricSource)(unsafe.Pointer(in.Resource))
out.External = (*autoscaling.ExternalMetricSource)(unsafe.Pointer(in.External))
return nil
}
@@ -256,6 +313,7 @@ func autoConvert_autoscaling_MetricSpec_To_v2beta1_MetricSpec(in *autoscaling.Me
out.Object = (*v2beta1.ObjectMetricSource)(unsafe.Pointer(in.Object))
out.Pods = (*v2beta1.PodsMetricSource)(unsafe.Pointer(in.Pods))
out.Resource = (*v2beta1.ResourceMetricSource)(unsafe.Pointer(in.Resource))
out.External = (*v2beta1.ExternalMetricSource)(unsafe.Pointer(in.External))
return nil
}
@@ -269,6 +327,7 @@ func autoConvert_v2beta1_MetricStatus_To_autoscaling_MetricStatus(in *v2beta1.Me
out.Object = (*autoscaling.ObjectMetricStatus)(unsafe.Pointer(in.Object))
out.Pods = (*autoscaling.PodsMetricStatus)(unsafe.Pointer(in.Pods))
out.Resource = (*autoscaling.ResourceMetricStatus)(unsafe.Pointer(in.Resource))
out.External = (*autoscaling.ExternalMetricStatus)(unsafe.Pointer(in.External))
return nil
}
@@ -282,6 +341,7 @@ func autoConvert_autoscaling_MetricStatus_To_v2beta1_MetricStatus(in *autoscalin
out.Object = (*v2beta1.ObjectMetricStatus)(unsafe.Pointer(in.Object))
out.Pods = (*v2beta1.PodsMetricStatus)(unsafe.Pointer(in.Pods))
out.Resource = (*v2beta1.ResourceMetricStatus)(unsafe.Pointer(in.Resource))
out.External = (*v2beta1.ExternalMetricStatus)(unsafe.Pointer(in.External))
return nil
}
@@ -403,7 +463,7 @@ func Convert_v2beta1_ResourceMetricSource_To_autoscaling_ResourceMetricSource(in
}
func autoConvert_autoscaling_ResourceMetricSource_To_v2beta1_ResourceMetricSource(in *autoscaling.ResourceMetricSource, out *v2beta1.ResourceMetricSource, s conversion.Scope) error {
out.Name = v1.ResourceName(in.Name)
out.Name = core_v1.ResourceName(in.Name)
out.TargetAverageUtilization = (*int32)(unsafe.Pointer(in.TargetAverageUtilization))
out.TargetAverageValue = (*resource.Quantity)(unsafe.Pointer(in.TargetAverageValue))
return nil
@@ -427,7 +487,7 @@ func Convert_v2beta1_ResourceMetricStatus_To_autoscaling_ResourceMetricStatus(in
}
func autoConvert_autoscaling_ResourceMetricStatus_To_v2beta1_ResourceMetricStatus(in *autoscaling.ResourceMetricStatus, out *v2beta1.ResourceMetricStatus, s conversion.Scope) error {
out.Name = v1.ResourceName(in.Name)
out.Name = core_v1.ResourceName(in.Name)
out.CurrentAverageUtilization = (*int32)(unsafe.Pointer(in.CurrentAverageUtilization))
out.CurrentAverageValue = in.CurrentAverageValue
return nil

View File

@@ -115,7 +115,7 @@ func validateMetrics(metrics []autoscaling.MetricSpec, fldPath *field.Path) fiel
return allErrs
}
var validMetricSourceTypes = sets.NewString(string(autoscaling.ObjectMetricSourceType), string(autoscaling.PodsMetricSourceType), string(autoscaling.ResourceMetricSourceType))
var validMetricSourceTypes = sets.NewString(string(autoscaling.ObjectMetricSourceType), string(autoscaling.PodsMetricSourceType), string(autoscaling.ResourceMetricSourceType), string(autoscaling.ExternalMetricSourceType))
var validMetricSourceTypesList = validMetricSourceTypes.List()
func validateMetricSpec(spec autoscaling.MetricSpec, fldPath *field.Path) field.ErrorList {
@@ -137,6 +137,13 @@ func validateMetricSpec(spec autoscaling.MetricSpec, fldPath *field.Path) field.
}
}
if spec.External != nil {
typesPresent.Insert("external")
if typesPresent.Len() == 1 {
allErrs = append(allErrs, validateExternalSource(spec.External, fldPath.Child("external"))...)
}
}
if spec.Pods != nil {
typesPresent.Insert("pods")
if typesPresent.Len() == 1 {
@@ -183,6 +190,32 @@ func validateObjectSource(src *autoscaling.ObjectMetricSource, fldPath *field.Pa
return allErrs
}
func validateExternalSource(src *autoscaling.ExternalMetricSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(src.MetricName) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("metricName"), "must specify a metric name"))
}
if src.TargetValue == nil && src.TargetAverageValue == nil {
allErrs = append(allErrs, field.Required(fldPath.Child("targetValue"), "must set either a target value for metric or a per-pod target"))
}
if src.TargetValue != nil && src.TargetAverageValue != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("targetValue"), "may not set both a target value for metric and a per-pod target"))
}
if src.TargetAverageValue != nil && src.TargetAverageValue.Sign() != 1 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("targetAverageValue"), src.TargetAverageValue, "must be positive"))
}
if src.TargetValue != nil && src.TargetValue.Sign() != 1 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("targetValue"), src.TargetValue, "must be positive"))
}
return allErrs
}
func validatePodsSource(src *autoscaling.PodsMetricSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}

View File

@@ -202,6 +202,62 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "myautoscaler",
Namespace: metav1.NamespaceDefault,
},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Kind: "ReplicationController",
Name: "myrc",
},
MinReplicas: newInt32(1),
MaxReplicas: 5,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ExternalMetricSourceType,
External: &autoscaling.ExternalMetricSource{
MetricName: "some/metric",
MetricSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"label": "value",
},
},
TargetValue: resource.NewMilliQuantity(300, resource.DecimalSI),
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "myautoscaler",
Namespace: metav1.NamespaceDefault,
},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Kind: "ReplicationController",
Name: "myrc",
},
MinReplicas: newInt32(1),
MaxReplicas: 5,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ExternalMetricSourceType,
External: &autoscaling.ExternalMetricSource{
MetricName: "some/metric",
MetricSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"label": "value",
},
},
TargetAverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
},
},
},
},
},
}
for _, successCase := range successCases {
if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
@@ -487,6 +543,130 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
},
msg: "must specify a metric name",
},
{
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
MinReplicas: newInt32(1),
MaxReplicas: 5,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ExternalMetricSourceType,
External: &autoscaling.ExternalMetricSource{
MetricSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"label": "value",
},
},
TargetValue: resource.NewMilliQuantity(300, resource.DecimalSI),
},
},
},
},
},
msg: "must specify a metric name",
},
{
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
MinReplicas: newInt32(1),
MaxReplicas: 5,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ExternalMetricSourceType,
External: &autoscaling.ExternalMetricSource{
MetricName: "some/metric",
MetricSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"label": "value",
},
},
},
},
},
},
},
msg: "must set either a target value for metric or a per-pod target",
},
{
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
MinReplicas: newInt32(1),
MaxReplicas: 5,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ExternalMetricSourceType,
External: &autoscaling.ExternalMetricSource{
MetricName: "some/metric",
MetricSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"label": "value",
},
},
TargetValue: resource.NewMilliQuantity(-300, resource.DecimalSI),
},
},
},
},
},
msg: "must be positive",
},
{
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
MinReplicas: newInt32(1),
MaxReplicas: 5,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ExternalMetricSourceType,
External: &autoscaling.ExternalMetricSource{
MetricName: "some/metric",
MetricSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"label": "value",
},
},
TargetAverageValue: resource.NewMilliQuantity(-300, resource.DecimalSI),
},
},
},
},
},
msg: "must be positive",
},
{
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
MinReplicas: newInt32(1),
MaxReplicas: 5,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ExternalMetricSourceType,
External: &autoscaling.ExternalMetricSource{
MetricName: "some/metric",
MetricSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"label": "value",
},
},
TargetValue: resource.NewMilliQuantity(300, resource.DecimalSI),
TargetAverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
},
},
},
},
},
msg: "may not set both a target value for metric and a per-pod target",
},
{
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},

View File

@@ -42,6 +42,84 @@ func (in *CrossVersionObjectReference) DeepCopy() *CrossVersionObjectReference {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExternalMetricSource) DeepCopyInto(out *ExternalMetricSource) {
*out = *in
if in.MetricSelector != nil {
in, out := &in.MetricSelector, &out.MetricSelector
if *in == nil {
*out = nil
} else {
*out = new(v1.LabelSelector)
(*in).DeepCopyInto(*out)
}
}
if in.TargetValue != nil {
in, out := &in.TargetValue, &out.TargetValue
if *in == nil {
*out = nil
} else {
*out = new(resource.Quantity)
**out = (*in).DeepCopy()
}
}
if in.TargetAverageValue != nil {
in, out := &in.TargetAverageValue, &out.TargetAverageValue
if *in == nil {
*out = nil
} else {
*out = new(resource.Quantity)
**out = (*in).DeepCopy()
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalMetricSource.
func (in *ExternalMetricSource) DeepCopy() *ExternalMetricSource {
if in == nil {
return nil
}
out := new(ExternalMetricSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExternalMetricStatus) DeepCopyInto(out *ExternalMetricStatus) {
*out = *in
if in.MetricSelector != nil {
in, out := &in.MetricSelector, &out.MetricSelector
if *in == nil {
*out = nil
} else {
*out = new(v1.LabelSelector)
(*in).DeepCopyInto(*out)
}
}
out.CurrentValue = in.CurrentValue.DeepCopy()
if in.CurrentAverageValue != nil {
in, out := &in.CurrentAverageValue, &out.CurrentAverageValue
if *in == nil {
*out = nil
} else {
*out = new(resource.Quantity)
**out = (*in).DeepCopy()
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalMetricStatus.
func (in *ExternalMetricStatus) DeepCopy() *ExternalMetricStatus {
if in == nil {
return nil
}
out := new(ExternalMetricStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HorizontalPodAutoscaler) DeepCopyInto(out *HorizontalPodAutoscaler) {
*out = *in
@@ -233,6 +311,15 @@ func (in *MetricSpec) DeepCopyInto(out *MetricSpec) {
(*in).DeepCopyInto(*out)
}
}
if in.External != nil {
in, out := &in.External, &out.External
if *in == nil {
*out = nil
} else {
*out = new(ExternalMetricSource)
(*in).DeepCopyInto(*out)
}
}
return
}
@@ -276,6 +363,15 @@ func (in *MetricStatus) DeepCopyInto(out *MetricStatus) {
(*in).DeepCopyInto(*out)
}
}
if in.External != nil {
in, out := &in.External, &out.External
if *in == nil {
*out = nil
} else {
*out = new(ExternalMetricStatus)
(*in).DeepCopyInto(*out)
}
}
return
}