mirror of https://github.com/k3s-io/k3s
Introduce HPA v2 API Objects
This commit introduces the autoscaling/v2alpha1 API group, which currently contains the first alpha of the new HorizontalPodAutoscaler object.pull/6/head
parent
3f6dd889f3
commit
86c430b881
|
@ -73,6 +73,7 @@ func New() *Generator {
|
|||
`k8s.io/kubernetes/pkg/apis/extensions/v1beta1`,
|
||||
`k8s.io/kubernetes/pkg/apis/autoscaling/v1`,
|
||||
`k8s.io/kubernetes/pkg/apis/authorization/v1`,
|
||||
`k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1`,
|
||||
`k8s.io/kubernetes/pkg/apis/authorization/v1beta1`,
|
||||
`k8s.io/kubernetes/pkg/apis/batch/v1`,
|
||||
`k8s.io/kubernetes/pkg/apis/batch/v2alpha1`,
|
||||
|
|
|
@ -94,6 +94,7 @@ pkg/client/informers/informers_generated/apps/v1beta1
|
|||
pkg/client/informers/informers_generated/autoscaling
|
||||
pkg/client/informers/informers_generated/autoscaling/internalversion
|
||||
pkg/client/informers/informers_generated/autoscaling/v1
|
||||
pkg/client/informers/informers_generated/autoscaling/v2alpha1
|
||||
pkg/client/informers/informers_generated/batch
|
||||
pkg/client/informers/informers_generated/batch/internalversion
|
||||
pkg/client/informers/informers_generated/batch/v1
|
||||
|
@ -126,6 +127,7 @@ pkg/client/listers/authorization/v1
|
|||
pkg/client/listers/authorization/v1beta1
|
||||
pkg/client/listers/autoscaling/internalversion
|
||||
pkg/client/listers/autoscaling/v1
|
||||
pkg/client/listers/autoscaling/v2alpha1
|
||||
pkg/client/listers/batch/internalversion
|
||||
pkg/client/listers/batch/v1
|
||||
pkg/client/listers/batch/v2alpha1
|
||||
|
|
|
@ -58,6 +58,7 @@ authentication.k8s.io/v1beta1 \
|
|||
authorization.k8s.io/v1 \
|
||||
authorization.k8s.io/v1beta1 \
|
||||
autoscaling/v1 \
|
||||
autoscaling/v2alpha1 \
|
||||
batch/v1 \
|
||||
batch/v2alpha1 \
|
||||
certificates.k8s.io/v1beta1 \
|
||||
|
|
|
@ -1612,8 +1612,8 @@ run_recursive_resources_tests() {
|
|||
output_message=$(! kubectl autoscale --min=1 --max=2 -f hack/testdata/recursive/rc --recursive 2>&1 "${kube_flags[@]}")
|
||||
# Post-condition: busybox0 & busybox replication controllers are autoscaled
|
||||
# with min. of 1 replica & max of 2 replicas, and since busybox2 is malformed, it should error
|
||||
kube::test::get_object_assert 'hpa busybox0' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '1 2 <no value>'
|
||||
kube::test::get_object_assert 'hpa busybox1' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '1 2 <no value>'
|
||||
kube::test::get_object_assert 'hpa busybox0' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '1 2 80'
|
||||
kube::test::get_object_assert 'hpa busybox1' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '1 2 80'
|
||||
kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
|
||||
kubectl delete hpa busybox0 "${kube_flags[@]}"
|
||||
kubectl delete hpa busybox1 "${kube_flags[@]}"
|
||||
|
@ -2221,7 +2221,7 @@ run_rc_tests() {
|
|||
kubectl delete hpa frontend "${kube_flags[@]}"
|
||||
# autoscale 2~3 pods, no CPU utilization specified, rc specified by name
|
||||
kubectl autoscale rc frontend "${kube_flags[@]}" --min=2 --max=3
|
||||
kube::test::get_object_assert 'hpa frontend' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '2 3 <no value>'
|
||||
kube::test::get_object_assert 'hpa frontend' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '2 3 80'
|
||||
kubectl delete hpa frontend "${kube_flags[@]}"
|
||||
# autoscale without specifying --max should fail
|
||||
! kubectl autoscale rc frontend "${kube_flags[@]}"
|
||||
|
@ -2280,7 +2280,7 @@ run_deployment_tests() {
|
|||
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx-deployment:'
|
||||
# autoscale 2~3 pods, no CPU utilization specified
|
||||
kubectl-with-retry autoscale deployment nginx-deployment "${kube_flags[@]}" --min=2 --max=3
|
||||
kube::test::get_object_assert 'hpa nginx-deployment' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '2 3 <no value>'
|
||||
kube::test::get_object_assert 'hpa nginx-deployment' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '2 3 80'
|
||||
# Clean up
|
||||
# Note that we should delete hpa first, otherwise it may fight with the deployment reaper.
|
||||
kubectl delete hpa nginx-deployment "${kube_flags[@]}"
|
||||
|
@ -2471,7 +2471,7 @@ run_rs_tests() {
|
|||
kubectl delete hpa frontend "${kube_flags[@]}"
|
||||
# autoscale 2~3 pods, no CPU utilization specified, replica set specified by name
|
||||
kubectl autoscale rs frontend "${kube_flags[@]}" --min=2 --max=3
|
||||
kube::test::get_object_assert 'hpa frontend' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '2 3 <no value>'
|
||||
kube::test::get_object_assert 'hpa frontend' "{{$hpa_min_field}} {{$hpa_max_field}} {{$hpa_cpu_field}}" '2 3 80'
|
||||
kubectl delete hpa frontend "${kube_flags[@]}"
|
||||
# autoscale without specifying --max should fail
|
||||
! kubectl autoscale rs frontend "${kube_flags[@]}"
|
||||
|
|
|
@ -546,8 +546,36 @@ func autoscalingFuncs(t apitesting.TestingCommon) []interface{} {
|
|||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
minReplicas := int32(c.Rand.Int31())
|
||||
s.MinReplicas = &minReplicas
|
||||
targetCpu := int32(c.RandUint64())
|
||||
s.TargetCPUUtilizationPercentage = &targetCpu
|
||||
|
||||
// NB: since this is used for round-tripping, we can only fuzz
|
||||
// fields that round-trip successfully, so only the resource source
|
||||
// type is usable here
|
||||
targetUtilization := int32(c.RandUint64())
|
||||
s.Metrics = []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: &targetUtilization,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
func(s *autoscaling.HorizontalPodAutoscalerStatus, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||
// NB: since this is used for round-tripping, we can only fuzz
|
||||
// fields that round-trip successfully, so only the resource status
|
||||
// type is usable here
|
||||
currentUtilization := int32(c.RandUint64())
|
||||
s.CurrentMetrics = []autoscaling.MetricStatus{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricStatus{
|
||||
Name: api.ResourceCPU,
|
||||
CurrentAverageUtilization: ¤tUtilization,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ load(
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"annotations.go",
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
|
@ -17,6 +18,8 @@ go_library(
|
|||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/conversion",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
|
@ -37,6 +40,7 @@ filegroup(
|
|||
":package-srcs",
|
||||
"//pkg/apis/autoscaling/install:all-srcs",
|
||||
"//pkg/apis/autoscaling/v1:all-srcs",
|
||||
"//pkg/apis/autoscaling/v2alpha1:all-srcs",
|
||||
"//pkg/apis/autoscaling/validation:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package autoscaling
|
||||
|
||||
// OtherMetricsAnnotation is the annotation which holds non-CPU-utilization HPA metric
|
||||
// specs when converting the `Metrics` field from autoscaling/v2alpha1
|
||||
const OtherMetricsAnnotation = "autoscaling.alpha.kubernetes.io/metrics"
|
||||
|
||||
// CurrentMetricsAnnotation is the annotation which holds non-CPU-utilization HPA metric
|
||||
// statuses when converting the `CurrentMetrics` field from autoscaling/v2alpha1
|
||||
const CurrentMetricsAnnotation = "autoscaling.alpha.kubernetes.io/current-metrics"
|
||||
|
||||
// DefaultCPUUtilization is the default value for CPU utilization, provided no other
|
||||
// metrics are present. This is here because it's used by both the v2alpha1 defaulting
|
||||
// logic, and the pseudo-defaulting done in v1 conversion.
|
||||
const DefaultCPUUtilization = 80
|
|
@ -15,6 +15,7 @@ go_library(
|
|||
"//pkg/api:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/autoscaling/v1:go_default_library",
|
||||
"//pkg/apis/autoscaling/v2alpha1:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apimachinery/announced",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apimachinery/registered",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -36,12 +37,13 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r
|
|||
if err := announced.NewGroupMetaFactory(
|
||||
&announced.GroupMetaFactoryArgs{
|
||||
GroupName: autoscaling.GroupName,
|
||||
VersionPreferenceOrder: []string{v1.SchemeGroupVersion.Version},
|
||||
VersionPreferenceOrder: []string{v1.SchemeGroupVersion.Version, v2alpha1.SchemeGroupVersion.Version},
|
||||
ImportPrefix: "k8s.io/kubernetes/pkg/apis/autoscaling",
|
||||
AddInternalObjectsToScheme: autoscaling.AddToScheme,
|
||||
},
|
||||
announced.VersionToSchemeFunc{
|
||||
v1.SchemeGroupVersion.Version: v1.AddToScheme,
|
||||
v2alpha1.SchemeGroupVersion.Version: v2alpha1.AddToScheme,
|
||||
},
|
||||
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -17,7 +17,9 @@ limitations under the License.
|
|||
package autoscaling
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
)
|
||||
|
||||
// Scale represents a scaling request for a resource.
|
||||
|
@ -67,68 +69,237 @@ type CrossVersionObjectReference struct {
|
|||
APIVersion string
|
||||
}
|
||||
|
||||
// specification of a horizontal pod autoscaler.
|
||||
// HorizontalPodAutoscalerSpec describes the desired functionality of the HorizontalPodAutoscaler.
|
||||
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 points to the target resource to scale, and is used to the pods for which metrics
|
||||
// should be collected, as well as to actually change the replica count.
|
||||
ScaleTargetRef CrossVersionObjectReference
|
||||
// lower limit for the number of pods that can be set by the autoscaler, default 1.
|
||||
// MinReplicas is the lower limit for the number of replicas to which the autoscaler can scale down.
|
||||
// It defaults to 1 pod.
|
||||
// +optional
|
||||
MinReplicas *int32
|
||||
// upper limit for the number of pods that can be set by the autoscaler. It cannot be smaller than MinReplicas.
|
||||
// MaxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up.
|
||||
// It cannot be less that minReplicas.
|
||||
MaxReplicas int32
|
||||
// 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.
|
||||
// Metrics contains the specifications for which to use to calculate the
|
||||
// desired replica count (the maximum replica count across all metrics will
|
||||
// be used). The desired replica count is calculated multiplying the
|
||||
// ratio between the target value and the current value by the current
|
||||
// number of pods. Ergo, metrics used must decrease as the pod count is
|
||||
// increased, and vice-versa. See the individual metric source types for
|
||||
// more information about how each type of metric must respond.
|
||||
// +optional
|
||||
TargetCPUUtilizationPercentage *int32
|
||||
Metrics []MetricSpec
|
||||
}
|
||||
|
||||
// current status of a horizontal pod autoscaler
|
||||
// MetricSourceType indicates the type of metric.
|
||||
type MetricSourceType string
|
||||
|
||||
var (
|
||||
// ObjectMetricSourceType is a metric describing a kubernetes object
|
||||
// (for example, hits-per-second on an Ingress object).
|
||||
ObjectMetricSourceType MetricSourceType = "Object"
|
||||
// PodsMetricSourceType is a metric describing each pod in the current scale
|
||||
// target (for example, transactions-processed-per-second). The values
|
||||
// will be averaged together before being compared to the target value.
|
||||
PodsMetricSourceType MetricSourceType = "Pods"
|
||||
// ResourceMetricSourceType is a resource metric known to Kubernetes, as
|
||||
// specified in requests and limits, describing each pod in the current
|
||||
// scale target (e.g. CPU or memory). Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available
|
||||
// to normal per-pod metrics (the "pods" source).
|
||||
ResourceMetricSourceType MetricSourceType = "Resource"
|
||||
)
|
||||
|
||||
// MetricSpec specifies how to scale based on a single metric
|
||||
// (only `type` and one other matching field should be set at once).
|
||||
type MetricSpec struct {
|
||||
// Type is the type of metric source. It should match one of the fields below.
|
||||
Type MetricSourceType
|
||||
|
||||
// Object refers to a metric describing a single kubernetes object
|
||||
// (for example, hits-per-second on an Ingress object).
|
||||
// +optional
|
||||
Object *ObjectMetricSource
|
||||
// Pods refers to a metric describing each pod in the current scale target
|
||||
// (for example, transactions-processed-per-second). The values will be
|
||||
// averaged together before being compared to the target value.
|
||||
// +optional
|
||||
Pods *PodsMetricSource
|
||||
// Resource refers to a resource metric (such as those specified in
|
||||
// requests and limits) known to Kubernetes describing each pod in the
|
||||
// current scale target (e.g. CPU or memory). Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available
|
||||
// to normal per-pod metrics using the "pods" source.
|
||||
// +optional
|
||||
Resource *ResourceMetricSource
|
||||
}
|
||||
|
||||
// ObjectMetricSource indicates how to scale on a metric describing a
|
||||
// kubernetes object (for example, hits-per-second on an Ingress object).
|
||||
type ObjectMetricSource struct {
|
||||
// Target is the described Kubernetes object.
|
||||
Target CrossVersionObjectReference
|
||||
|
||||
// MetricName is the name of the metric in question.
|
||||
MetricName string
|
||||
// TargetValue is the target value of the metric (as a quantity).
|
||||
TargetValue resource.Quantity
|
||||
}
|
||||
|
||||
// PodsMetricSource indicates how to scale on a metric describing each pod in
|
||||
// the current scale target (for example, transactions-processed-per-second).
|
||||
// The values will be averaged together before being compared to the target
|
||||
// value.
|
||||
type PodsMetricSource struct {
|
||||
// MetricName is the name of the metric in question
|
||||
MetricName string
|
||||
// TargetAverageValue is the target value of the average of the
|
||||
// metric across all relevant pods (as a quantity)
|
||||
TargetAverageValue resource.Quantity
|
||||
}
|
||||
|
||||
// ResourceMetricSource indicates how to scale on a resource metric known to
|
||||
// Kubernetes, as specified in requests and limits, describing each pod in the
|
||||
// current scale target (e.g. CPU or memory). The values will be averaged
|
||||
// together before being compared to the target. Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available to
|
||||
// normal per-pod metrics using the "pods" source. Only one "target" type
|
||||
// should be set.
|
||||
type ResourceMetricSource struct {
|
||||
// Name is the name of the resource in question.
|
||||
Name api.ResourceName
|
||||
// TargetAverageUtilization is the target value of the average of the
|
||||
// resource metric across all relevant pods, represented as a percentage of
|
||||
// the requested value of the resource for the pods.
|
||||
// +optional
|
||||
TargetAverageUtilization *int32
|
||||
// TargetAverageValue is the the target value of the average of the
|
||||
// resource metric across all relevant pods, as a raw value (instead of as
|
||||
// a percentage of the request), similar to the "pods" metric source type.
|
||||
// +optional
|
||||
TargetAverageValue *resource.Quantity
|
||||
}
|
||||
|
||||
// HorizontalPodAutoscalerStatus describes the current status of a horizontal pod autoscaler.
|
||||
type HorizontalPodAutoscalerStatus struct {
|
||||
// most recent generation observed by this autoscaler.
|
||||
// ObservedGeneration is the most recent generation observed by this autoscaler.
|
||||
// +optional
|
||||
ObservedGeneration *int64
|
||||
|
||||
// last time the HorizontalPodAutoscaler scaled the number of pods;
|
||||
// LastScaleTime is the last time the HorizontalPodAutoscaler scaled the number of pods,
|
||||
// used by the autoscaler to control how often the number of pods is changed.
|
||||
// +optional
|
||||
LastScaleTime *metav1.Time
|
||||
|
||||
// current number of replicas of pods managed by this autoscaler.
|
||||
// CurrentReplicas is current number of replicas of pods managed by this autoscaler,
|
||||
// as last seen by the autoscaler.
|
||||
CurrentReplicas int32
|
||||
|
||||
// desired number of replicas of pods managed by this autoscaler.
|
||||
// DesiredReplicas is the desired number of replicas of pods managed by this autoscaler,
|
||||
// as last calculated by the autoscaler.
|
||||
DesiredReplicas int32
|
||||
|
||||
// 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.
|
||||
// CurrentMetrics is the last read state of the metrics used by this autoscaler.
|
||||
CurrentMetrics []MetricStatus
|
||||
}
|
||||
|
||||
// MetricStatus describes the last-read state of a single metric.
|
||||
type MetricStatus struct {
|
||||
// Type is the type of metric source. It will match one of the fields below.
|
||||
Type MetricSourceType
|
||||
|
||||
// Object refers to a metric describing a single kubernetes object
|
||||
// (for example, hits-per-second on an Ingress object).
|
||||
// +optional
|
||||
CurrentCPUUtilizationPercentage *int32
|
||||
Object *ObjectMetricStatus
|
||||
// Pods refers to a metric describing each pod in the current scale target
|
||||
// (for example, transactions-processed-per-second). The values will be
|
||||
// averaged together before being compared to the target value.
|
||||
// +optional
|
||||
Pods *PodsMetricStatus
|
||||
// Resource refers to a resource metric (such as those specified in
|
||||
// requests and limits) known to Kubernetes describing each pod in the
|
||||
// current scale target (e.g. CPU or memory). Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available
|
||||
// to normal per-pod metrics using the "pods" source.
|
||||
// +optional
|
||||
Resource *ResourceMetricStatus
|
||||
}
|
||||
|
||||
// ObjectMetricStatus indicates the current value of a metric describing a
|
||||
// kubernetes object (for example, hits-per-second on an Ingress object).
|
||||
type ObjectMetricStatus struct {
|
||||
// Target is the described Kubernetes object.
|
||||
Target CrossVersionObjectReference
|
||||
|
||||
// MetricName is the name of the metric in question.
|
||||
MetricName string
|
||||
// CurrentValue is the current value of the metric (as a quantity).
|
||||
CurrentValue resource.Quantity
|
||||
}
|
||||
|
||||
// PodsMetricStatus indicates the current value of a metric describing each pod in
|
||||
// the current scale target (for example, transactions-processed-per-second).
|
||||
type PodsMetricStatus struct {
|
||||
// MetricName is the name of the metric in question
|
||||
MetricName string
|
||||
// CurrentAverageValue is the current value of the average of the
|
||||
// metric across all relevant pods (as a quantity)
|
||||
CurrentAverageValue resource.Quantity
|
||||
}
|
||||
|
||||
// ResourceMetricStatus indicates the current value of a resource metric known to
|
||||
// Kubernetes, as specified in requests and limits, describing each pod in the
|
||||
// current scale target (e.g. CPU or memory). Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available to
|
||||
// normal per-pod metrics using the "pods" source.
|
||||
type ResourceMetricStatus struct {
|
||||
// Name is the name of the resource in question.
|
||||
Name api.ResourceName
|
||||
// CurrentAverageUtilization is the current value of the average of the
|
||||
// resource metric across all relevant pods, represented as a percentage of
|
||||
// the requested value of the resource for the pods. It will only be
|
||||
// present if `targetAverageValue` was set in the corresponding metric
|
||||
// specification.
|
||||
// +optional
|
||||
CurrentAverageUtilization *int32
|
||||
// CurrentAverageValue is the the current value of the average of the
|
||||
// resource metric across all relevant pods, as a raw value (instead of as
|
||||
// a percentage of the request), similar to the "pods" metric source type.
|
||||
// It will always be set, regardless of the corresponding metric specification.
|
||||
CurrentAverageValue resource.Quantity
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
|
||||
// configuration of a horizontal pod autoscaler.
|
||||
// HorizontalPodAutoscaler is the configuration for a horizontal pod
|
||||
// autoscaler, which automatically manages the replica count of any resource
|
||||
// implementing the scale subresource based on the metrics specified.
|
||||
type HorizontalPodAutoscaler struct {
|
||||
metav1.TypeMeta
|
||||
// Metadata is the standard object metadata.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
metav1.ObjectMeta
|
||||
|
||||
// behaviour of autoscaler. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status.
|
||||
// Spec is the specification for the behaviour of the autoscaler.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status.
|
||||
// +optional
|
||||
Spec HorizontalPodAutoscalerSpec
|
||||
|
||||
// current information about the autoscaler.
|
||||
// Status is the current information about the autoscaler.
|
||||
// +optional
|
||||
Status HorizontalPodAutoscalerStatus
|
||||
}
|
||||
|
||||
// list of horizontal pod autoscaler objects.
|
||||
// HorizontalPodAutoscaler is a list of horizontal pod autoscaler objects.
|
||||
type HorizontalPodAutoscalerList struct {
|
||||
metav1.TypeMeta
|
||||
// Metadata is the standard list metadata.
|
||||
// +optional
|
||||
metav1.ListMeta
|
||||
|
||||
// list of horizontal pod autoscaler objects.
|
||||
// Items is the list of horizontal pod autoscaler objects.
|
||||
Items []HorizontalPodAutoscaler
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ load(
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"conversion.go",
|
||||
"defaults.go",
|
||||
"doc.go",
|
||||
"generated.pb.go",
|
||||
|
@ -24,6 +25,7 @@ go_library(
|
|||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//vendor:github.com/gogo/protobuf/proto",
|
||||
"//vendor:github.com/ugorji/go/codec",
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
)
|
||||
|
||||
func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
// Add non-generated conversion functions
|
||||
err := scheme.AddConversionFuncs(
|
||||
Convert_autoscaling_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler,
|
||||
Convert_v1_HorizontalPodAutoscaler_To_autoscaling_HorizontalPodAutoscaler,
|
||||
Convert_autoscaling_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec,
|
||||
Convert_v1_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPodAutoscalerSpec,
|
||||
Convert_autoscaling_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerStatus,
|
||||
Convert_v1_HorizontalPodAutoscalerStatus_To_autoscaling_HorizontalPodAutoscalerStatus,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_autoscaling_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler(in *autoscaling.HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, s conversion.Scope) error {
|
||||
if err := autoConvert_autoscaling_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
otherMetrics := make([]autoscaling.MetricSpec, 0, len(in.Spec.Metrics))
|
||||
for _, metric := range in.Spec.Metrics {
|
||||
if metric.Type == autoscaling.ResourceMetricSourceType && metric.Resource != nil && metric.Resource.Name == api.ResourceCPU && metric.Resource.TargetAverageUtilization != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
otherMetrics = append(otherMetrics, metric)
|
||||
}
|
||||
|
||||
// NB: we need to save the status even if it maps to a CPU utilization status in order to save the raw value as well
|
||||
if len(otherMetrics) > 0 || len(in.Status.CurrentMetrics) > 0 {
|
||||
old := out.Annotations
|
||||
out.Annotations = make(map[string]string, len(old)+2)
|
||||
if old != nil {
|
||||
for k, v := range old {
|
||||
out.Annotations[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(otherMetrics) > 0 {
|
||||
otherMetricsEnc, err := json.Marshal(otherMetrics)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Annotations[autoscaling.OtherMetricsAnnotation] = string(otherMetricsEnc)
|
||||
}
|
||||
|
||||
if len(in.Status.CurrentMetrics) > 0 {
|
||||
currentMetricsEnc, err := json.Marshal(in.Status.CurrentMetrics)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Annotations[autoscaling.CurrentMetricsAnnotation] = string(currentMetricsEnc)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_HorizontalPodAutoscaler_To_autoscaling_HorizontalPodAutoscaler(in *HorizontalPodAutoscaler, out *autoscaling.HorizontalPodAutoscaler, s conversion.Scope) error {
|
||||
if err := autoConvert_v1_HorizontalPodAutoscaler_To_autoscaling_HorizontalPodAutoscaler(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if otherMetricsEnc, hasOtherMetrics := out.Annotations[autoscaling.OtherMetricsAnnotation]; hasOtherMetrics {
|
||||
var otherMetrics []autoscaling.MetricSpec
|
||||
if err := json.Unmarshal([]byte(otherMetricsEnc), &otherMetrics); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, metric := range otherMetrics {
|
||||
out.Spec.Metrics = append(out.Spec.Metrics, metric)
|
||||
}
|
||||
}
|
||||
|
||||
if currentMetricsEnc, hasCurrentMetrics := out.Annotations[autoscaling.CurrentMetricsAnnotation]; hasCurrentMetrics {
|
||||
// ignore any existing status values -- the ones here have more information
|
||||
out.Status.CurrentMetrics = nil
|
||||
if err := json.Unmarshal([]byte(currentMetricsEnc), &out.Status.CurrentMetrics); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// autoscaling/v1 formerly had an implicit default applied in the controller. In v2alpha1, we apply it explicitly.
|
||||
// We apply it here, explicitly, since we have access to the full set of metrics from the annotation.
|
||||
if len(out.Spec.Metrics) == 0 {
|
||||
// no other metrics, no explicit CPU value set
|
||||
out.Spec.Metrics = []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
},
|
||||
},
|
||||
}
|
||||
out.Spec.Metrics[0].Resource.TargetAverageUtilization = new(int32)
|
||||
*out.Spec.Metrics[0].Resource.TargetAverageUtilization = autoscaling.DefaultCPUUtilization
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_autoscaling_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec(in *autoscaling.HorizontalPodAutoscalerSpec, out *HorizontalPodAutoscalerSpec, s conversion.Scope) error {
|
||||
if err := Convert_autoscaling_CrossVersionObjectReference_To_v1_CrossVersionObjectReference(&in.ScaleTargetRef, &out.ScaleTargetRef, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out.MinReplicas = in.MinReplicas
|
||||
out.MaxReplicas = in.MaxReplicas
|
||||
|
||||
for _, metric := range in.Metrics {
|
||||
if metric.Type == autoscaling.ResourceMetricSourceType && metric.Resource != nil && metric.Resource.Name == api.ResourceCPU {
|
||||
if metric.Resource.TargetAverageUtilization != nil {
|
||||
out.TargetCPUUtilizationPercentage = new(int32)
|
||||
*out.TargetCPUUtilizationPercentage = *metric.Resource.TargetAverageUtilization
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_HorizontalPodAutoscalerSpec_To_autoscaling_HorizontalPodAutoscalerSpec(in *HorizontalPodAutoscalerSpec, out *autoscaling.HorizontalPodAutoscalerSpec, s conversion.Scope) error {
|
||||
if err := Convert_v1_CrossVersionObjectReference_To_autoscaling_CrossVersionObjectReference(&in.ScaleTargetRef, &out.ScaleTargetRef, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out.MinReplicas = in.MinReplicas
|
||||
out.MaxReplicas = in.MaxReplicas
|
||||
|
||||
if in.TargetCPUUtilizationPercentage != nil {
|
||||
out.Metrics = []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
},
|
||||
},
|
||||
}
|
||||
out.Metrics[0].Resource.TargetAverageUtilization = new(int32)
|
||||
*out.Metrics[0].Resource.TargetAverageUtilization = *in.TargetCPUUtilizationPercentage
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_autoscaling_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerStatus(in *autoscaling.HorizontalPodAutoscalerStatus, out *HorizontalPodAutoscalerStatus, s conversion.Scope) error {
|
||||
out.ObservedGeneration = in.ObservedGeneration
|
||||
out.LastScaleTime = in.LastScaleTime
|
||||
|
||||
out.CurrentReplicas = in.CurrentReplicas
|
||||
out.DesiredReplicas = in.DesiredReplicas
|
||||
|
||||
for _, metric := range in.CurrentMetrics {
|
||||
if metric.Type == autoscaling.ResourceMetricSourceType && metric.Resource != nil && metric.Resource.Name == api.ResourceCPU {
|
||||
if metric.Resource.CurrentAverageUtilization != nil {
|
||||
|
||||
out.CurrentCPUUtilizationPercentage = new(int32)
|
||||
*out.CurrentCPUUtilizationPercentage = *metric.Resource.CurrentAverageUtilization
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_HorizontalPodAutoscalerStatus_To_autoscaling_HorizontalPodAutoscalerStatus(in *HorizontalPodAutoscalerStatus, out *autoscaling.HorizontalPodAutoscalerStatus, s conversion.Scope) error {
|
||||
out.ObservedGeneration = in.ObservedGeneration
|
||||
out.LastScaleTime = in.LastScaleTime
|
||||
|
||||
out.CurrentReplicas = in.CurrentReplicas
|
||||
out.DesiredReplicas = in.DesiredReplicas
|
||||
|
||||
if in.CurrentCPUUtilizationPercentage != nil {
|
||||
out.CurrentMetrics = []autoscaling.MetricStatus{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricStatus{
|
||||
Name: api.ResourceCPU,
|
||||
},
|
||||
},
|
||||
}
|
||||
out.CurrentMetrics[0].Resource.CurrentAverageUtilization = new(int32)
|
||||
*out.CurrentMetrics[0].Resource.CurrentAverageUtilization = *in.CurrentCPUUtilizationPercentage
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -32,4 +32,7 @@ func SetDefaults_HorizontalPodAutoscaler(obj *HorizontalPodAutoscaler) {
|
|||
minReplicas := int32(1)
|
||||
obj.Spec.MinReplicas = &minReplicas
|
||||
}
|
||||
|
||||
// NB: we apply a default for CPU utilization in conversion because
|
||||
// we need access to the annotations to properly apply the default.
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func Resource(resource string) schema.GroupResource {
|
|||
}
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs)
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"defaults.go",
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 v2alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
)
|
||||
|
||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
||||
return scheme.AddDefaultingFuncs(
|
||||
SetDefaults_HorizontalPodAutoscaler,
|
||||
)
|
||||
}
|
||||
|
||||
func SetDefaults_HorizontalPodAutoscaler(obj *HorizontalPodAutoscaler) {
|
||||
if obj.Spec.MinReplicas == nil {
|
||||
minReplicas := int32(1)
|
||||
obj.Spec.MinReplicas = &minReplicas
|
||||
}
|
||||
|
||||
if len(obj.Spec.Metrics) == 0 {
|
||||
utilizationDefaultVal := int32(autoscaling.DefaultCPUUtilization)
|
||||
obj.Spec.Metrics = []MetricSpec{
|
||||
{
|
||||
Type: ResourceMetricSourceType,
|
||||
Resource: &ResourceMetricSource{
|
||||
Name: v1.ResourceCPU,
|
||||
TargetAverageUtilization: &utilizationDefaultVal,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/autoscaling
|
||||
// +k8s:openapi-gen=true
|
||||
|
||||
package v2alpha1 // import "k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1"
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 v2alpha1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "autoscaling"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v2alpha1"}
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// Adds the list of known types to api.Scheme.
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&HorizontalPodAutoscaler{},
|
||||
&HorizontalPodAutoscalerList{},
|
||||
&v1.ListOptions{},
|
||||
&v1.DeleteOptions{},
|
||||
&metav1.GetOptions{},
|
||||
&metav1.ExportOptions{},
|
||||
)
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
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 v2alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
)
|
||||
|
||||
// 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://kubernetes.io/docs/user-guide/identifiers#names
|
||||
Name string `json:"name" protobuf:"bytes,2,opt,name=name"`
|
||||
// API version of the referent
|
||||
// +optional
|
||||
APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,3,opt,name=apiVersion"`
|
||||
}
|
||||
|
||||
// HorizontalPodAutoscalerSpec describes the desired functionality of the HorizontalPodAutoscaler.
|
||||
type HorizontalPodAutoscalerSpec struct {
|
||||
// scaleTargetRef points to the target resource to scale, and is used to the pods for which metrics
|
||||
// should be collected, as well as to actually change the replica count.
|
||||
ScaleTargetRef CrossVersionObjectReference `json:"scaleTargetRef" protobuf:"bytes,1,opt,name=scaleTargetRef"`
|
||||
// minReplicas is the lower limit for the number of replicas to which the autoscaler can scale down.
|
||||
// It defaults to 1 pod.
|
||||
// +optional
|
||||
MinReplicas *int32 `json:"minReplicas,omitempty" protobuf:"varint,2,opt,name=minReplicas"`
|
||||
// maxReplicas is the upper limit for the number of replicas to which the autoscaler can scale up.
|
||||
// It cannot be less that minReplicas.
|
||||
MaxReplicas int32 `json:"maxReplicas" protobuf:"varint,3,opt,name=maxReplicas"`
|
||||
// metrics contains the specifications for which to use to calculate the
|
||||
// desired replica count (the maximum replica count across all metrics will
|
||||
// be used). The desired replica count is calculated multiplying the
|
||||
// ratio between the target value and the current value by the current
|
||||
// number of pods. Ergo, metrics used must decrease as the pod count is
|
||||
// increased, and vice-versa. See the individual metric source types for
|
||||
// more information about how each type of metric must respond.
|
||||
// +optional
|
||||
Metrics []MetricSpec `json:"metrics,omitempty" protobuf:"bytes,4,rep,name=metrics"`
|
||||
}
|
||||
|
||||
// MetricSourceType indicates the type of metric.
|
||||
type MetricSourceType string
|
||||
|
||||
var (
|
||||
// ObjectMetricSourceType is a metric describing a kubernetes object
|
||||
// (for example, hits-per-second on an Ingress object).
|
||||
ObjectMetricSourceType MetricSourceType = "Object"
|
||||
// PodsMetricSourceType is a metric describing each pod in the current scale
|
||||
// target (for example, transactions-processed-per-second). The values
|
||||
// will be averaged together before being compared to the target value.
|
||||
PodsMetricSourceType MetricSourceType = "Pods"
|
||||
// ResourceMetricSourceType is a resource metric known to Kubernetes, as
|
||||
// specified in requests and limits, describing each pod in the current
|
||||
// scale target (e.g. CPU or memory). Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available
|
||||
// to normal per-pod metrics (the "pods" source).
|
||||
ResourceMetricSourceType MetricSourceType = "Resource"
|
||||
)
|
||||
|
||||
// MetricSpec specifies how to scale based on a single metric
|
||||
// (only `type` and one other matching field should be set at once).
|
||||
type MetricSpec struct {
|
||||
// type is the type of metric source. It should match one of the fields below.
|
||||
Type MetricSourceType `json:"type" protobuf:"bytes,1,name=type"`
|
||||
|
||||
// object refers to a metric describing a single kubernetes object
|
||||
// (for example, hits-per-second on an Ingress object).
|
||||
// +optional
|
||||
Object *ObjectMetricSource `json:"object,omitempty" protobuf:"bytes,2,opt,name=object"`
|
||||
// pods refers to a metric describing each pod in the current scale target
|
||||
// (for example, transactions-processed-per-second). The values will be
|
||||
// averaged together before being compared to the target value.
|
||||
// +optional
|
||||
Pods *PodsMetricSource `json:"pods,omitempty" protobuf:"bytes,3,opt,name=pods"`
|
||||
// resource refers to a resource metric (such as those specified in
|
||||
// requests and limits) known to Kubernetes describing each pod in the
|
||||
// current scale target (e.g. CPU or memory). Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available
|
||||
// to normal per-pod metrics using the "pods" source.
|
||||
// +optional
|
||||
Resource *ResourceMetricSource `json:"resource,omitempty" protobuf:"bytes,4,opt,name=resource"`
|
||||
}
|
||||
|
||||
// ObjectMetricSource indicates how to scale on a metric describing a
|
||||
// kubernetes object (for example, hits-per-second on an Ingress object).
|
||||
type ObjectMetricSource struct {
|
||||
// target is the described Kubernetes object.
|
||||
Target CrossVersionObjectReference `json:"target" protobuf:"bytes,1,name=target"`
|
||||
|
||||
// metricName is the name of the metric in question.
|
||||
MetricName string `json:"metricName" protobuf:"bytes,2,name=metricName"`
|
||||
// targetValue is the target value of the metric (as a quantity).
|
||||
TargetValue resource.Quantity `json:"targetValue" protobuf:"bytes,3,name=targetValue"`
|
||||
}
|
||||
|
||||
// PodsMetricSource indicates how to scale on a metric describing each pod in
|
||||
// the current scale target (for example, transactions-processed-per-second).
|
||||
// The values will be averaged together before being compared to the target
|
||||
// value.
|
||||
type PodsMetricSource struct {
|
||||
// metricName is the name of the metric in question
|
||||
MetricName string `json:"metricName" protobuf:"bytes,1,name=metricName"`
|
||||
// targetAverageValue is the target value of the average of the
|
||||
// metric across all relevant pods (as a quantity)
|
||||
TargetAverageValue resource.Quantity `json:"targetAverageValue" protobuf:"bytes,2,name=targetAverageValue"`
|
||||
}
|
||||
|
||||
// ResourceMetricSource indicates how to scale on a resource metric known to
|
||||
// Kubernetes, as specified in requests and limits, describing each pod in the
|
||||
// current scale target (e.g. CPU or memory). The values will be averaged
|
||||
// together before being compared to the target. Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available to
|
||||
// normal per-pod metrics using the "pods" source. Only one "target" type
|
||||
// should be set.
|
||||
type ResourceMetricSource struct {
|
||||
// name is the name of the resource in question.
|
||||
Name v1.ResourceName `json:"name" protobuf:"bytes,1,name=name"`
|
||||
// targetAverageUtilization is the target value of the average of the
|
||||
// resource metric across all relevant pods, represented as a percentage of
|
||||
// the requested value of the resource for the pods.
|
||||
// +optional
|
||||
TargetAverageUtilization *int32 `json:"targetAverageUtilization,omitempty" protobuf:"varint,2,opt,name=targetAverageUtilization"`
|
||||
// targetAverageValue is the the target value of the average of the
|
||||
// resource metric across all relevant pods, as a raw value (instead of as
|
||||
// a percentage of the request), similar to the "pods" metric source type.
|
||||
// +optional
|
||||
TargetAverageValue *resource.Quantity `json:"targetAverageValue,omitempty" protobuf:"bytes,3,opt,name=targetAverageValue"`
|
||||
}
|
||||
|
||||
// HorizontalPodAutoscalerStatus describes the current status of a horizontal pod autoscaler.
|
||||
type HorizontalPodAutoscalerStatus struct {
|
||||
// observedGeneration is the most recent generation observed by this autoscaler.
|
||||
// +optional
|
||||
ObservedGeneration *int64 `json:"observedGeneration,omitempty" protobuf:"varint,1,opt,name=observedGeneration"`
|
||||
|
||||
// lastScaleTime is the last time the HorizontalPodAutoscaler scaled the number of pods,
|
||||
// used by the autoscaler to control how often the number of pods is changed.
|
||||
// +optional
|
||||
LastScaleTime *metav1.Time `json:"lastScaleTime,omitempty" protobuf:"bytes,2,opt,name=lastScaleTime"`
|
||||
|
||||
// currentReplicas is current number of replicas of pods managed by this autoscaler,
|
||||
// as last seen by the autoscaler.
|
||||
CurrentReplicas int32 `json:"currentReplicas" protobuf:"varint,3,opt,name=currentReplicas"`
|
||||
|
||||
// desiredReplicas is the desired number of replicas of pods managed by this autoscaler,
|
||||
// as last calculated by the autoscaler.
|
||||
DesiredReplicas int32 `json:"desiredReplicas" protobuf:"varint,4,opt,name=desiredReplicas"`
|
||||
|
||||
// currentMetrics is the last read state of the metrics used by this autoscaler.
|
||||
CurrentMetrics []MetricStatus `json:"currentMetrics" protobuf:"bytes,5,rep,name=currentMetrics"`
|
||||
}
|
||||
|
||||
// MetricStatus describes the last-read state of a single metric.
|
||||
type MetricStatus struct {
|
||||
// type is the type of metric source. It will match one of the fields below.
|
||||
Type MetricSourceType `json:"type" protobuf:"bytes,1,name=type"`
|
||||
|
||||
// object refers to a metric describing a single kubernetes object
|
||||
// (for example, hits-per-second on an Ingress object).
|
||||
// +optional
|
||||
Object *ObjectMetricStatus `json:"object,omitempty" protobuf:"bytes,2,opt,name=object"`
|
||||
// pods refers to a metric describing each pod in the current scale target
|
||||
// (for example, transactions-processed-per-second). The values will be
|
||||
// averaged together before being compared to the target value.
|
||||
// +optional
|
||||
Pods *PodsMetricStatus `json:"pods,omitempty" protobuf:"bytes,3,opt,name=pods"`
|
||||
// resource refers to a resource metric (such as those specified in
|
||||
// requests and limits) known to Kubernetes describing each pod in the
|
||||
// current scale target (e.g. CPU or memory). Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available
|
||||
// to normal per-pod metrics using the "pods" source.
|
||||
// +optional
|
||||
Resource *ResourceMetricStatus `json:"resource,omitempty" protobuf:"bytes,4,opt,name=resource"`
|
||||
}
|
||||
|
||||
// ObjectMetricStatus indicates the current value of a metric describing a
|
||||
// kubernetes object (for example, hits-per-second on an Ingress object).
|
||||
type ObjectMetricStatus struct {
|
||||
// target is the described Kubernetes object.
|
||||
Target CrossVersionObjectReference `json:"target" protobuf:"bytes,1,name=target"`
|
||||
|
||||
// metricName is the name of the metric in question.
|
||||
MetricName string `json:"metricName" protobuf:"bytes,2,name=metricName"`
|
||||
// currentValue is the current value of the metric (as a quantity).
|
||||
CurrentValue resource.Quantity `json:"currentValue" protobuf:"bytes,3,name=currentValue"`
|
||||
}
|
||||
|
||||
// PodsMetricStatus indicates the current value of a metric describing each pod in
|
||||
// the current scale target (for example, transactions-processed-per-second).
|
||||
type PodsMetricStatus struct {
|
||||
// metricName is the name of the metric in question
|
||||
MetricName string `json:"metricName" protobuf:"bytes,1,name=metricName"`
|
||||
// currentAverageValue is the current value of the average of the
|
||||
// metric across all relevant pods (as a quantity)
|
||||
CurrentAverageValue resource.Quantity `json:"currentAverageValue" protobuf:"bytes,2,name=currentAverageValue"`
|
||||
}
|
||||
|
||||
// ResourceMetricStatus indicates the current value of a resource metric known to
|
||||
// Kubernetes, as specified in requests and limits, describing each pod in the
|
||||
// current scale target (e.g. CPU or memory). Such metrics are built in to
|
||||
// Kubernetes, and have special scaling options on top of those available to
|
||||
// normal per-pod metrics using the "pods" source.
|
||||
type ResourceMetricStatus struct {
|
||||
// name is the name of the resource in question.
|
||||
Name v1.ResourceName `json:"name" protobuf:"bytes,1,name=name"`
|
||||
// currentAverageUtilization is the current value of the average of the
|
||||
// resource metric across all relevant pods, represented as a percentage of
|
||||
// the requested value of the resource for the pods. It will only be
|
||||
// present if `targetAverageValue` was set in the corresponding metric
|
||||
// specification.
|
||||
// +optional
|
||||
CurrentAverageUtilization *int32 `json:"currentAverageUtilization,omitempty" protobuf:"bytes,2,opt,name=currentAverageUtilization"`
|
||||
// currentAverageValue is the the current value of the average of the
|
||||
// resource metric across all relevant pods, as a raw value (instead of as
|
||||
// a percentage of the request), similar to the "pods" metric source type.
|
||||
// It will always be set, regardless of the corresponding metric specification.
|
||||
CurrentAverageValue resource.Quantity `json:"currentAverageValue" protobuf:"bytes,3,name=currentAverageValue"`
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
|
||||
// HorizontalPodAutoscaler is the configuration for a horizontal pod
|
||||
// autoscaler, which automatically manages the replica count of any resource
|
||||
// implementing the scale subresource based on the metrics specified.
|
||||
type HorizontalPodAutoscaler struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// metadata is the standard object metadata.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
||||
// +optional
|
||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// spec is the specification for the behaviour of the autoscaler.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status.
|
||||
// +optional
|
||||
Spec HorizontalPodAutoscalerSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
|
||||
|
||||
// status is the current information about the autoscaler.
|
||||
// +optional
|
||||
Status HorizontalPodAutoscalerStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// HorizontalPodAutoscaler is a list of horizontal pod autoscaler objects.
|
||||
type HorizontalPodAutoscalerList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// metadata is the standard list metadata.
|
||||
// +optional
|
||||
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||
|
||||
// items is the list of horizontal pod autoscaler objects.
|
||||
Items []HorizontalPodAutoscaler `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
|
@ -15,9 +15,8 @@ go_library(
|
|||
deps = [
|
||||
"//pkg/api/validation:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/extensions/v1beta1:go_default_library",
|
||||
"//pkg/controller/podautoscaler:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/validation/path",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
||||
],
|
||||
)
|
||||
|
@ -28,8 +27,9 @@ go_test(
|
|||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/controller/podautoscaler:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/resource",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -17,14 +17,13 @@ limitations under the License.
|
|||
package validation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
pathvalidation "k8s.io/apimachinery/pkg/api/validation/path"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/controller/podautoscaler"
|
||||
)
|
||||
|
||||
func ValidateScale(scale *autoscaling.Scale) field.ErrorList {
|
||||
|
@ -53,12 +52,12 @@ func validateHorizontalPodAutoscalerSpec(autoscaler autoscaling.HorizontalPodAut
|
|||
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...)
|
||||
}
|
||||
if refErrs := validateMetrics(autoscaler.Metrics, fldPath.Child("metrics")); len(refErrs) > 0 {
|
||||
allErrs = append(allErrs, refErrs...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
@ -83,34 +82,9 @@ func ValidateCrossVersionObjectReference(ref autoscaling.CrossVersionObjectRefer
|
|||
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 v1beta1.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
|
||||
}
|
||||
|
||||
|
@ -127,3 +101,124 @@ func ValidateHorizontalPodAutoscalerStatusUpdate(newAutoscaler, oldAutoscaler *a
|
|||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredReplicas), field.NewPath("status", "desiredReplicasa"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateMetrics(metrics []autoscaling.MetricSpec, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
for i, metricSpec := range metrics {
|
||||
idxPath := fldPath.Index(i)
|
||||
if targetErrs := validateMetricSpec(metricSpec, idxPath); len(targetErrs) > 0 {
|
||||
allErrs = append(allErrs, targetErrs...)
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
var validMetricSourceTypes = sets.NewString(string(autoscaling.ObjectMetricSourceType), string(autoscaling.PodsMetricSourceType), string(autoscaling.ResourceMetricSourceType))
|
||||
var validMetricSourceTypesList = validMetricSourceTypes.List()
|
||||
|
||||
func validateMetricSpec(spec autoscaling.MetricSpec, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if len(string(spec.Type)) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("type"), "must specify a metric source type"))
|
||||
}
|
||||
|
||||
if !validMetricSourceTypes.Has(string(spec.Type)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), spec.Type, validMetricSourceTypesList))
|
||||
}
|
||||
|
||||
typesPresent := sets.NewString()
|
||||
if spec.Object != nil {
|
||||
typesPresent.Insert("object")
|
||||
if typesPresent.Len() == 1 {
|
||||
allErrs = append(allErrs, validateObjectSource(spec.Object, fldPath.Child("object"))...)
|
||||
}
|
||||
}
|
||||
|
||||
if spec.Pods != nil {
|
||||
typesPresent.Insert("pods")
|
||||
if typesPresent.Len() == 1 {
|
||||
allErrs = append(allErrs, validatePodsSource(spec.Pods, fldPath.Child("pods"))...)
|
||||
}
|
||||
}
|
||||
|
||||
if spec.Resource != nil {
|
||||
typesPresent.Insert("resource")
|
||||
if typesPresent.Len() == 1 {
|
||||
allErrs = append(allErrs, validateResourceSource(spec.Resource, fldPath.Child("resource"))...)
|
||||
}
|
||||
}
|
||||
|
||||
expectedField := strings.ToLower(string(spec.Type))
|
||||
|
||||
if !typesPresent.Has(expectedField) {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child(expectedField), "must populate information for the given metric source"))
|
||||
}
|
||||
|
||||
if typesPresent.Len() != 1 {
|
||||
typesPresent.Delete(expectedField)
|
||||
for typ := range typesPresent {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child(typ), "must populate the given metric source only"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateObjectSource(src *autoscaling.ObjectMetricSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
allErrs = append(allErrs, ValidateCrossVersionObjectReference(src.Target, fldPath.Child("target"))...)
|
||||
|
||||
if len(src.MetricName) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("metricName"), "must specify a metric name"))
|
||||
}
|
||||
|
||||
if src.TargetValue.Sign() != 1 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("targetValue"), "must specify a positive target value"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validatePodsSource(src *autoscaling.PodsMetricSource, 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.TargetAverageValue.Sign() != 1 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("targetAverageValue"), "must specify a positive target value"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateResourceSource(src *autoscaling.ResourceMetricSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if len(src.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "must specify a resource name"))
|
||||
}
|
||||
|
||||
if src.TargetAverageUtilization == nil && src.TargetAverageValue == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("targetAverageUtilization"), "must set either a target raw value or a target utilization"))
|
||||
}
|
||||
|
||||
if src.TargetAverageUtilization != nil && *src.TargetAverageUtilization < 1 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("targetAverageUtilization"), src.TargetAverageUtilization, "must be greater than 0"))
|
||||
}
|
||||
|
||||
if src.TargetAverageUtilization != nil && src.TargetAverageValue != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("targetAverageValue"), "may not set both a target raw value and a target utilization"))
|
||||
}
|
||||
|
||||
if src.TargetAverageValue != nil && src.TargetAverageValue.Sign() != 1 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("targetAverageValue"), src.TargetAverageValue, "must be positive"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
|
|
@ -20,9 +20,10 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/controller/podautoscaler"
|
||||
)
|
||||
|
||||
func TestValidateScale(t *testing.T) {
|
||||
|
@ -103,7 +104,15 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
TargetCPUUtilizationPercentage: newInt32(70),
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: newInt32(70),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -124,9 +133,6 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myautoscaler",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Annotations: map[string]string{
|
||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"20\"}]}",
|
||||
},
|
||||
},
|
||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||
|
@ -135,6 +141,65 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageValue: 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.PodsMetricSourceType,
|
||||
Pods: &autoscaling.PodsMetricSource{
|
||||
MetricName: "some/metric",
|
||||
TargetAverageValue: *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.ObjectMetricSourceType,
|
||||
Object: &autoscaling.ObjectMetricSource{
|
||||
Target: autoscaling.CrossVersionObjectReference{
|
||||
Kind: "ReplicationController",
|
||||
Name: "myrc",
|
||||
},
|
||||
MetricName: "some/metric",
|
||||
TargetValue: *resource.NewMilliQuantity(300, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -155,7 +220,15 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
TargetCPUUtilizationPercentage: newInt32(70),
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: newInt32(70),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "scaleTargetRef.kind: Required",
|
||||
|
@ -167,7 +240,15 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
TargetCPUUtilizationPercentage: newInt32(70),
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: newInt32(70),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "scaleTargetRef.kind: Invalid",
|
||||
|
@ -179,7 +260,15 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
TargetCPUUtilizationPercentage: newInt32(70),
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: newInt32(70),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "scaleTargetRef.name: Required",
|
||||
|
@ -191,7 +280,15 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
TargetCPUUtilizationPercentage: newInt32(70),
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: newInt32(70),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "scaleTargetRef.name: Invalid",
|
||||
|
@ -231,10 +328,21 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
Namespace: metav1.NamespaceDefault,
|
||||
},
|
||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{},
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||
Kind: "ReplicationController",
|
||||
Name: "myrc",
|
||||
},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
TargetCPUUtilizationPercentage: newInt32(-70),
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: newInt32(-70),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "must be greater than 0",
|
||||
|
@ -244,80 +352,220 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myautoscaler",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Annotations: map[string]string{
|
||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "broken",
|
||||
},
|
||||
},
|
||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||
Kind: "ReplicationController",
|
||||
Name: "myrc",
|
||||
},
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: newInt32(70),
|
||||
TargetAverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
msg: "failed to parse custom metrics target annotation",
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "may not set both a target raw value and a target utilization",
|
||||
},
|
||||
{
|
||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myautoscaler",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Annotations: map[string]string{
|
||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "{}",
|
||||
},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||
Kind: "ReplicationController",
|
||||
Name: "myrc",
|
||||
},
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
TargetAverageUtilization: newInt32(70),
|
||||
},
|
||||
},
|
||||
msg: "custom metrics target must not be empty",
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "must specify a resource name",
|
||||
},
|
||||
{
|
||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myautoscaler",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Annotations: map[string]string{
|
||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"value\":\"20\"}]}",
|
||||
},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||
Kind: "ReplicationController",
|
||||
Name: "myrc",
|
||||
},
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: newInt32(-10),
|
||||
},
|
||||
},
|
||||
msg: "missing custom metric target name",
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "must be greater than 0",
|
||||
},
|
||||
{
|
||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myautoscaler",
|
||||
Namespace: metav1.NamespaceDefault,
|
||||
Annotations: map[string]string{
|
||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"0\"}]}",
|
||||
},
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
|
||||
MinReplicas: newInt32(1),
|
||||
MaxReplicas: 5,
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "must set either a target raw value or a target utilization",
|
||||
},
|
||||
{
|
||||
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.PodsMetricSourceType,
|
||||
Pods: &autoscaling.PodsMetricSource{
|
||||
TargetAverageValue: *resource.NewMilliQuantity(100, 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.PodsMetricSourceType,
|
||||
Pods: &autoscaling.PodsMetricSource{
|
||||
MetricName: "some/metric",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "must specify a positive target value",
|
||||
},
|
||||
{
|
||||
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.ObjectMetricSourceType,
|
||||
Object: &autoscaling.ObjectMetricSource{
|
||||
Target: autoscaling.CrossVersionObjectReference{
|
||||
Name: "myrc",
|
||||
},
|
||||
MetricName: "some/metric",
|
||||
TargetValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "target.kind: Required",
|
||||
},
|
||||
{
|
||||
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.ObjectMetricSourceType,
|
||||
Object: &autoscaling.ObjectMetricSource{
|
||||
Target: autoscaling.CrossVersionObjectReference{
|
||||
Kind: "ReplicationController",
|
||||
Name: "myrc",
|
||||
},
|
||||
TargetValue: *resource.NewMilliQuantity(100, 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{
|
||||
{},
|
||||
},
|
||||
},
|
||||
msg: "custom metric target value must be greater than 0",
|
||||
},
|
||||
msg: "must specify a metric source type",
|
||||
},
|
||||
{
|
||||
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.MetricSourceType("InvalidType"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "type: Unsupported value",
|
||||
},
|
||||
{
|
||||
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.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
},
|
||||
Pods: &autoscaling.PodsMetricSource{
|
||||
MetricName: "some/metric",
|
||||
TargetAverageValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "must populate the given metric source only",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -329,6 +577,58 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
|||
t.Errorf("unexpected error: %q, expected: %q", errs[0], c.msg)
|
||||
}
|
||||
}
|
||||
|
||||
sourceTypes := map[autoscaling.MetricSourceType]autoscaling.MetricSpec{
|
||||
autoscaling.ResourceMetricSourceType: {
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
autoscaling.PodsMetricSourceType: {
|
||||
Pods: &autoscaling.PodsMetricSource{
|
||||
MetricName: "some/metric",
|
||||
TargetAverageValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
autoscaling.ObjectMetricSourceType: {
|
||||
Object: &autoscaling.ObjectMetricSource{
|
||||
Target: autoscaling.CrossVersionObjectReference{
|
||||
Kind: "ReplicationController",
|
||||
Name: "myrc",
|
||||
},
|
||||
MetricName: "some/metric",
|
||||
TargetValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for correctType, spec := range sourceTypes {
|
||||
for incorrectType := range sourceTypes {
|
||||
if correctType == incorrectType {
|
||||
continue
|
||||
}
|
||||
|
||||
spec.Type = incorrectType
|
||||
|
||||
errs := ValidateHorizontalPodAutoscaler(&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{spec},
|
||||
},
|
||||
})
|
||||
|
||||
expectedMsg := "must populate information for the given metric source"
|
||||
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected failure with type of %v and spec for %v", incorrectType, correctType)
|
||||
} else if !strings.Contains(errs[0].Error(), expectedMsg) {
|
||||
t.Errorf("unexpected error: %q, expected %q", errs[0], expectedMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newInt32(val int32) *int32 {
|
||||
|
|
|
@ -14,6 +14,7 @@ go_test(
|
|||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/autoscaling/v1:go_default_library",
|
||||
"//pkg/registry/registrytest:go_default_library",
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
// Ensure that autoscaling/v1 package is initialized.
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
|
@ -56,7 +57,15 @@ func validNewHorizontalPodAutoscaler(name string) *autoscaling.HorizontalPodAuto
|
|||
Name: "myrc",
|
||||
},
|
||||
MaxReplicas: 5,
|
||||
TargetCPUUtilizationPercentage: &cpu,
|
||||
Metrics: []autoscaling.MetricSpec{
|
||||
{
|
||||
Type: autoscaling.ResourceMetricSourceType,
|
||||
Resource: &autoscaling.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
TargetAverageUtilization: &cpu,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ go_library(
|
|||
"//pkg/api:go_default_library",
|
||||
"//pkg/apis/autoscaling:go_default_library",
|
||||
"//pkg/apis/autoscaling/v1:go_default_library",
|
||||
"//pkg/apis/autoscaling/v2alpha1:go_default_library",
|
||||
"//pkg/registry/autoscaling/horizontalpodautoscaler/storage:go_default_library",
|
||||
"//vendor:k8s.io/apiserver/pkg/registry/generic",
|
||||
"//vendor:k8s.io/apiserver/pkg/registry/rest",
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
||||
autoscalingapiv2alpha1 "k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1"
|
||||
horizontalpodautoscalerstore "k8s.io/kubernetes/pkg/registry/autoscaling/horizontalpodautoscaler/storage"
|
||||
)
|
||||
|
||||
|
@ -35,6 +36,10 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource genericapise
|
|||
apiGroupInfo.VersionedResourcesStorageMap[autoscalingapiv1.SchemeGroupVersion.Version] = p.v1Storage(apiResourceConfigSource, restOptionsGetter)
|
||||
apiGroupInfo.GroupMeta.GroupVersion = autoscalingapiv1.SchemeGroupVersion
|
||||
}
|
||||
if apiResourceConfigSource.AnyResourcesForVersionEnabled(autoscalingapiv2alpha1.SchemeGroupVersion) {
|
||||
apiGroupInfo.VersionedResourcesStorageMap[autoscalingapiv2alpha1.SchemeGroupVersion.Version] = p.v2alpha1Storage(apiResourceConfigSource, restOptionsGetter)
|
||||
apiGroupInfo.GroupMeta.GroupVersion = autoscalingapiv2alpha1.SchemeGroupVersion
|
||||
}
|
||||
|
||||
return apiGroupInfo, true
|
||||
}
|
||||
|
@ -51,6 +56,18 @@ func (p RESTStorageProvider) v1Storage(apiResourceConfigSource genericapiserver.
|
|||
return storage
|
||||
}
|
||||
|
||||
func (p RESTStorageProvider) v2alpha1Storage(apiResourceConfigSource genericapiserver.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage {
|
||||
version := autoscalingapiv2alpha1.SchemeGroupVersion
|
||||
|
||||
storage := map[string]rest.Storage{}
|
||||
if apiResourceConfigSource.ResourceEnabled(version.WithResource("horizontalpodautoscalers")) {
|
||||
hpaStorage, hpaStatusStorage := horizontalpodautoscalerstore.NewREST(restOptionsGetter)
|
||||
storage["horizontalpodautoscalers"] = hpaStorage
|
||||
storage["horizontalpodautoscalers/status"] = hpaStatusStorage
|
||||
}
|
||||
return storage
|
||||
}
|
||||
|
||||
func (p RESTStorageProvider) GroupName() string {
|
||||
return autoscaling.GroupName
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue