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/extensions/v1beta1`,
|
||||||
`k8s.io/kubernetes/pkg/apis/autoscaling/v1`,
|
`k8s.io/kubernetes/pkg/apis/autoscaling/v1`,
|
||||||
`k8s.io/kubernetes/pkg/apis/authorization/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/authorization/v1beta1`,
|
||||||
`k8s.io/kubernetes/pkg/apis/batch/v1`,
|
`k8s.io/kubernetes/pkg/apis/batch/v1`,
|
||||||
`k8s.io/kubernetes/pkg/apis/batch/v2alpha1`,
|
`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
|
||||||
pkg/client/informers/informers_generated/autoscaling/internalversion
|
pkg/client/informers/informers_generated/autoscaling/internalversion
|
||||||
pkg/client/informers/informers_generated/autoscaling/v1
|
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
|
||||||
pkg/client/informers/informers_generated/batch/internalversion
|
pkg/client/informers/informers_generated/batch/internalversion
|
||||||
pkg/client/informers/informers_generated/batch/v1
|
pkg/client/informers/informers_generated/batch/v1
|
||||||
|
@ -126,6 +127,7 @@ pkg/client/listers/authorization/v1
|
||||||
pkg/client/listers/authorization/v1beta1
|
pkg/client/listers/authorization/v1beta1
|
||||||
pkg/client/listers/autoscaling/internalversion
|
pkg/client/listers/autoscaling/internalversion
|
||||||
pkg/client/listers/autoscaling/v1
|
pkg/client/listers/autoscaling/v1
|
||||||
|
pkg/client/listers/autoscaling/v2alpha1
|
||||||
pkg/client/listers/batch/internalversion
|
pkg/client/listers/batch/internalversion
|
||||||
pkg/client/listers/batch/v1
|
pkg/client/listers/batch/v1
|
||||||
pkg/client/listers/batch/v2alpha1
|
pkg/client/listers/batch/v2alpha1
|
||||||
|
|
|
@ -58,6 +58,7 @@ authentication.k8s.io/v1beta1 \
|
||||||
authorization.k8s.io/v1 \
|
authorization.k8s.io/v1 \
|
||||||
authorization.k8s.io/v1beta1 \
|
authorization.k8s.io/v1beta1 \
|
||||||
autoscaling/v1 \
|
autoscaling/v1 \
|
||||||
|
autoscaling/v2alpha1 \
|
||||||
batch/v1 \
|
batch/v1 \
|
||||||
batch/v2alpha1 \
|
batch/v2alpha1 \
|
||||||
certificates.k8s.io/v1beta1 \
|
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[@]}")
|
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
|
# 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
|
# 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 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 <no value>'
|
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"
|
kube::test::if_has_string "${output_message}" "Object 'Kind' is missing"
|
||||||
kubectl delete hpa busybox0 "${kube_flags[@]}"
|
kubectl delete hpa busybox0 "${kube_flags[@]}"
|
||||||
kubectl delete hpa busybox1 "${kube_flags[@]}"
|
kubectl delete hpa busybox1 "${kube_flags[@]}"
|
||||||
|
@ -2221,7 +2221,7 @@ run_rc_tests() {
|
||||||
kubectl delete hpa frontend "${kube_flags[@]}"
|
kubectl delete hpa frontend "${kube_flags[@]}"
|
||||||
# autoscale 2~3 pods, no CPU utilization specified, rc specified by name
|
# autoscale 2~3 pods, no CPU utilization specified, rc specified by name
|
||||||
kubectl autoscale rc frontend "${kube_flags[@]}" --min=2 --max=3
|
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[@]}"
|
kubectl delete hpa frontend "${kube_flags[@]}"
|
||||||
# autoscale without specifying --max should fail
|
# autoscale without specifying --max should fail
|
||||||
! kubectl autoscale rc frontend "${kube_flags[@]}"
|
! 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:'
|
kube::test::get_object_assert deployment "{{range.items}}{{$id_field}}:{{end}}" 'nginx-deployment:'
|
||||||
# autoscale 2~3 pods, no CPU utilization specified
|
# autoscale 2~3 pods, no CPU utilization specified
|
||||||
kubectl-with-retry autoscale deployment nginx-deployment "${kube_flags[@]}" --min=2 --max=3
|
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
|
# Clean up
|
||||||
# Note that we should delete hpa first, otherwise it may fight with the deployment reaper.
|
# Note that we should delete hpa first, otherwise it may fight with the deployment reaper.
|
||||||
kubectl delete hpa nginx-deployment "${kube_flags[@]}"
|
kubectl delete hpa nginx-deployment "${kube_flags[@]}"
|
||||||
|
@ -2471,7 +2471,7 @@ run_rs_tests() {
|
||||||
kubectl delete hpa frontend "${kube_flags[@]}"
|
kubectl delete hpa frontend "${kube_flags[@]}"
|
||||||
# autoscale 2~3 pods, no CPU utilization specified, replica set specified by name
|
# autoscale 2~3 pods, no CPU utilization specified, replica set specified by name
|
||||||
kubectl autoscale rs frontend "${kube_flags[@]}" --min=2 --max=3
|
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[@]}"
|
kubectl delete hpa frontend "${kube_flags[@]}"
|
||||||
# autoscale without specifying --max should fail
|
# autoscale without specifying --max should fail
|
||||||
! kubectl autoscale rs frontend "${kube_flags[@]}"
|
! 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
|
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||||
minReplicas := int32(c.Rand.Int31())
|
minReplicas := int32(c.Rand.Int31())
|
||||||
s.MinReplicas = &minReplicas
|
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(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"annotations.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
"register.go",
|
"register.go",
|
||||||
"types.go",
|
"types.go",
|
||||||
|
@ -17,6 +18,8 @@ go_library(
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
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/apis/meta/v1",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/conversion",
|
"//vendor:k8s.io/apimachinery/pkg/conversion",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
|
@ -37,6 +40,7 @@ filegroup(
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
"//pkg/apis/autoscaling/install:all-srcs",
|
"//pkg/apis/autoscaling/install:all-srcs",
|
||||||
"//pkg/apis/autoscaling/v1:all-srcs",
|
"//pkg/apis/autoscaling/v1:all-srcs",
|
||||||
|
"//pkg/apis/autoscaling/v2alpha1:all-srcs",
|
||||||
"//pkg/apis/autoscaling/validation:all-srcs",
|
"//pkg/apis/autoscaling/validation:all-srcs",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
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/api:go_default_library",
|
||||||
"//pkg/apis/autoscaling:go_default_library",
|
"//pkg/apis/autoscaling:go_default_library",
|
||||||
"//pkg/apis/autoscaling/v1: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/announced",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apimachinery/registered",
|
"//vendor:k8s.io/apimachinery/pkg/apimachinery/registered",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
"k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/autoscaling/v2alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -36,12 +37,13 @@ func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *r
|
||||||
if err := announced.NewGroupMetaFactory(
|
if err := announced.NewGroupMetaFactory(
|
||||||
&announced.GroupMetaFactoryArgs{
|
&announced.GroupMetaFactoryArgs{
|
||||||
GroupName: autoscaling.GroupName,
|
GroupName: autoscaling.GroupName,
|
||||||
VersionPreferenceOrder: []string{v1.SchemeGroupVersion.Version},
|
VersionPreferenceOrder: []string{v1.SchemeGroupVersion.Version, v2alpha1.SchemeGroupVersion.Version},
|
||||||
ImportPrefix: "k8s.io/kubernetes/pkg/apis/autoscaling",
|
ImportPrefix: "k8s.io/kubernetes/pkg/apis/autoscaling",
|
||||||
AddInternalObjectsToScheme: autoscaling.AddToScheme,
|
AddInternalObjectsToScheme: autoscaling.AddToScheme,
|
||||||
},
|
},
|
||||||
announced.VersionToSchemeFunc{
|
announced.VersionToSchemeFunc{
|
||||||
v1.SchemeGroupVersion.Version: v1.AddToScheme,
|
v1.SchemeGroupVersion.Version: v1.AddToScheme,
|
||||||
|
v2alpha1.SchemeGroupVersion.Version: v2alpha1.AddToScheme,
|
||||||
},
|
},
|
||||||
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
|
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -17,7 +17,9 @@ limitations under the License.
|
||||||
package autoscaling
|
package autoscaling
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scale represents a scaling request for a resource.
|
// Scale represents a scaling request for a resource.
|
||||||
|
@ -67,68 +69,237 @@ type CrossVersionObjectReference struct {
|
||||||
APIVersion string
|
APIVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
// specification of a horizontal pod autoscaler.
|
// HorizontalPodAutoscalerSpec describes the desired functionality of the HorizontalPodAutoscaler.
|
||||||
type HorizontalPodAutoscalerSpec struct {
|
type HorizontalPodAutoscalerSpec struct {
|
||||||
// reference to scaled resource; horizontal pod autoscaler will learn the current resource consumption
|
// ScaleTargetRef points to the target resource to scale, and is used to the pods for which metrics
|
||||||
// and will set the desired number of pods by using its Scale subresource.
|
// should be collected, as well as to actually change the replica count.
|
||||||
ScaleTargetRef CrossVersionObjectReference
|
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
|
// +optional
|
||||||
MinReplicas *int32
|
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
|
MaxReplicas int32
|
||||||
// target average CPU utilization (represented as a percentage of requested CPU) over all the pods;
|
// Metrics contains the specifications for which to use to calculate the
|
||||||
// if not specified the default autoscaling policy will be used.
|
// 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
|
// +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 {
|
type HorizontalPodAutoscalerStatus struct {
|
||||||
// most recent generation observed by this autoscaler.
|
// ObservedGeneration is the most recent generation observed by this autoscaler.
|
||||||
// +optional
|
// +optional
|
||||||
ObservedGeneration *int64
|
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.
|
// used by the autoscaler to control how often the number of pods is changed.
|
||||||
// +optional
|
// +optional
|
||||||
LastScaleTime *metav1.Time
|
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
|
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
|
DesiredReplicas int32
|
||||||
|
|
||||||
// current average CPU utilization over all pods, represented as a percentage of requested CPU,
|
// CurrentMetrics is the last read state of the metrics used by this autoscaler.
|
||||||
// e.g. 70 means that an average pod is using now 70% of its requested CPU.
|
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
|
// +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
|
// +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 {
|
type HorizontalPodAutoscaler struct {
|
||||||
metav1.TypeMeta
|
metav1.TypeMeta
|
||||||
|
// Metadata is the standard object metadata.
|
||||||
|
// More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata
|
||||||
// +optional
|
// +optional
|
||||||
metav1.ObjectMeta
|
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
|
// +optional
|
||||||
Spec HorizontalPodAutoscalerSpec
|
Spec HorizontalPodAutoscalerSpec
|
||||||
|
|
||||||
// current information about the autoscaler.
|
// Status is the current information about the autoscaler.
|
||||||
// +optional
|
// +optional
|
||||||
Status HorizontalPodAutoscalerStatus
|
Status HorizontalPodAutoscalerStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
// list of horizontal pod autoscaler objects.
|
// HorizontalPodAutoscaler is a list of horizontal pod autoscaler objects.
|
||||||
type HorizontalPodAutoscalerList struct {
|
type HorizontalPodAutoscalerList struct {
|
||||||
metav1.TypeMeta
|
metav1.TypeMeta
|
||||||
|
// Metadata is the standard list metadata.
|
||||||
// +optional
|
// +optional
|
||||||
metav1.ListMeta
|
metav1.ListMeta
|
||||||
|
|
||||||
// list of horizontal pod autoscaler objects.
|
// Items is the list of horizontal pod autoscaler objects.
|
||||||
Items []HorizontalPodAutoscaler
|
Items []HorizontalPodAutoscaler
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ load(
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"conversion.go",
|
||||||
"defaults.go",
|
"defaults.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
"generated.pb.go",
|
"generated.pb.go",
|
||||||
|
@ -24,6 +25,7 @@ go_library(
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/apis/autoscaling:go_default_library",
|
"//pkg/apis/autoscaling:go_default_library",
|
||||||
"//vendor:github.com/gogo/protobuf/proto",
|
"//vendor:github.com/gogo/protobuf/proto",
|
||||||
"//vendor:github.com/ugorji/go/codec",
|
"//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)
|
minReplicas := int32(1)
|
||||||
obj.Spec.MinReplicas = &minReplicas
|
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 (
|
var (
|
||||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs)
|
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
|
||||||
AddToScheme = SchemeBuilder.AddToScheme
|
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 = [
|
deps = [
|
||||||
"//pkg/api/validation:go_default_library",
|
"//pkg/api/validation:go_default_library",
|
||||||
"//pkg/apis/autoscaling: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/api/validation/path",
|
||||||
|
"//vendor:k8s.io/apimachinery/pkg/util/sets",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
"//vendor:k8s.io/apimachinery/pkg/util/validation/field",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -28,8 +27,9 @@ go_test(
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/apis/autoscaling: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",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,14 +17,13 @@ limitations under the License.
|
||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"strings"
|
||||||
|
|
||||||
pathvalidation "k8s.io/apimachinery/pkg/api/validation/path"
|
pathvalidation "k8s.io/apimachinery/pkg/api/validation/path"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"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 {
|
func ValidateScale(scale *autoscaling.Scale) field.ErrorList {
|
||||||
|
@ -53,12 +52,12 @@ func validateHorizontalPodAutoscalerSpec(autoscaler autoscaling.HorizontalPodAut
|
||||||
if autoscaler.MinReplicas != nil && autoscaler.MaxReplicas < *autoscaler.MinReplicas {
|
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`"))
|
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 {
|
if refErrs := ValidateCrossVersionObjectReference(autoscaler.ScaleTargetRef, fldPath.Child("scaleTargetRef")); len(refErrs) > 0 {
|
||||||
allErrs = append(allErrs, refErrs...)
|
allErrs = append(allErrs, refErrs...)
|
||||||
}
|
}
|
||||||
|
if refErrs := validateMetrics(autoscaler.Metrics, fldPath.Child("metrics")); len(refErrs) > 0 {
|
||||||
|
allErrs = append(allErrs, refErrs...)
|
||||||
|
}
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,34 +82,9 @@ func ValidateCrossVersionObjectReference(ref autoscaling.CrossVersionObjectRefer
|
||||||
return allErrs
|
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 {
|
func ValidateHorizontalPodAutoscaler(autoscaler *autoscaling.HorizontalPodAutoscaler) field.ErrorList {
|
||||||
allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata"))
|
allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata"))
|
||||||
allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...)
|
allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...)
|
||||||
allErrs = append(allErrs, validateHorizontalPodAutoscalerAnnotations(autoscaler.Annotations, field.NewPath("metadata"))...)
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,3 +101,124 @@ func ValidateHorizontalPodAutoscalerStatusUpdate(newAutoscaler, oldAutoscaler *a
|
||||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredReplicas), field.NewPath("status", "desiredReplicasa"))...)
|
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredReplicas), field.NewPath("status", "desiredReplicasa"))...)
|
||||||
return allErrs
|
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"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
"k8s.io/kubernetes/pkg/controller/podautoscaler"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateScale(t *testing.T) {
|
func TestValidateScale(t *testing.T) {
|
||||||
|
@ -101,9 +102,17 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
Kind: "ReplicationController",
|
Kind: "ReplicationController",
|
||||||
Name: "myrc",
|
Name: "myrc",
|
||||||
},
|
},
|
||||||
MinReplicas: newInt32(1),
|
MinReplicas: newInt32(1),
|
||||||
MaxReplicas: 5,
|
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{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "myautoscaler",
|
Name: "myautoscaler",
|
||||||
Namespace: metav1.NamespaceDefault,
|
Namespace: metav1.NamespaceDefault,
|
||||||
Annotations: map[string]string{
|
|
||||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"20\"}]}",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||||
|
@ -135,6 +141,65 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
},
|
},
|
||||||
MinReplicas: newInt32(1),
|
MinReplicas: newInt32(1),
|
||||||
MaxReplicas: 5,
|
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),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -152,10 +217,18 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"},
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"},
|
||||||
MinReplicas: newInt32(1),
|
MinReplicas: newInt32(1),
|
||||||
MaxReplicas: 5,
|
MaxReplicas: 5,
|
||||||
TargetCPUUtilizationPercentage: newInt32(70),
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
Name: api.ResourceCPU,
|
||||||
|
TargetAverageUtilization: newInt32(70),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "scaleTargetRef.kind: Required",
|
msg: "scaleTargetRef.kind: Required",
|
||||||
|
@ -164,10 +237,18 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"},
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"},
|
||||||
MinReplicas: newInt32(1),
|
MinReplicas: newInt32(1),
|
||||||
MaxReplicas: 5,
|
MaxReplicas: 5,
|
||||||
TargetCPUUtilizationPercentage: newInt32(70),
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
Name: api.ResourceCPU,
|
||||||
|
TargetAverageUtilization: newInt32(70),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "scaleTargetRef.kind: Invalid",
|
msg: "scaleTargetRef.kind: Invalid",
|
||||||
|
@ -176,10 +257,18 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"},
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"},
|
||||||
MinReplicas: newInt32(1),
|
MinReplicas: newInt32(1),
|
||||||
MaxReplicas: 5,
|
MaxReplicas: 5,
|
||||||
TargetCPUUtilizationPercentage: newInt32(70),
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
Name: api.ResourceCPU,
|
||||||
|
TargetAverageUtilization: newInt32(70),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "scaleTargetRef.name: Required",
|
msg: "scaleTargetRef.name: Required",
|
||||||
|
@ -188,10 +277,18 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."},
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."},
|
||||||
MinReplicas: newInt32(1),
|
MinReplicas: newInt32(1),
|
||||||
MaxReplicas: 5,
|
MaxReplicas: 5,
|
||||||
TargetCPUUtilizationPercentage: newInt32(70),
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
Name: api.ResourceCPU,
|
||||||
|
TargetAverageUtilization: newInt32(70),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "scaleTargetRef.name: Invalid",
|
msg: "scaleTargetRef.name: Invalid",
|
||||||
|
@ -231,10 +328,21 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
Namespace: metav1.NamespaceDefault,
|
Namespace: metav1.NamespaceDefault,
|
||||||
},
|
},
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{},
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
||||||
MinReplicas: newInt32(1),
|
Kind: "ReplicationController",
|
||||||
MaxReplicas: 5,
|
Name: "myrc",
|
||||||
TargetCPUUtilizationPercentage: newInt32(-70),
|
},
|
||||||
|
MinReplicas: newInt32(1),
|
||||||
|
MaxReplicas: 5,
|
||||||
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
Name: api.ResourceCPU,
|
||||||
|
TargetAverageUtilization: newInt32(-70),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "must be greater than 0",
|
msg: "must be greater than 0",
|
||||||
|
@ -244,80 +352,220 @@ func TestValidateHorizontalPodAutoscaler(t *testing.T) {
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "myautoscaler",
|
Name: "myautoscaler",
|
||||||
Namespace: metav1.NamespaceDefault,
|
Namespace: metav1.NamespaceDefault,
|
||||||
Annotations: map[string]string{
|
|
||||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "broken",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
|
||||||
Kind: "ReplicationController",
|
MinReplicas: newInt32(1),
|
||||||
Name: "myrc",
|
MaxReplicas: 5,
|
||||||
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
Name: api.ResourceCPU,
|
||||||
|
TargetAverageUtilization: newInt32(70),
|
||||||
|
TargetAverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
MinReplicas: newInt32(1),
|
|
||||||
MaxReplicas: 5,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "failed to parse custom metrics target annotation",
|
msg: "may not set both a target raw value and a target utilization",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||||
Name: "myautoscaler",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
Annotations: map[string]string{
|
|
||||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "{}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
|
||||||
Kind: "ReplicationController",
|
MinReplicas: newInt32(1),
|
||||||
Name: "myrc",
|
MaxReplicas: 5,
|
||||||
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
TargetAverageUtilization: newInt32(70),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
MinReplicas: newInt32(1),
|
|
||||||
MaxReplicas: 5,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "custom metrics target must not be empty",
|
msg: "must specify a resource name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||||
Name: "myautoscaler",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
Annotations: map[string]string{
|
|
||||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"value\":\"20\"}]}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
|
||||||
Kind: "ReplicationController",
|
MinReplicas: newInt32(1),
|
||||||
Name: "myrc",
|
MaxReplicas: 5,
|
||||||
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
Name: api.ResourceCPU,
|
||||||
|
TargetAverageUtilization: newInt32(-10),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
MinReplicas: newInt32(1),
|
|
||||||
MaxReplicas: 5,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "missing custom metric target name",
|
msg: "must be greater than 0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
|
||||||
Name: "myautoscaler",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
Annotations: map[string]string{
|
|
||||||
podautoscaler.HpaCustomMetricsTargetAnnotationName: "{\"items\":[{\"name\":\"qps\",\"value\":\"0\"}]}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
Spec: autoscaling.HorizontalPodAutoscalerSpec{
|
||||||
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
|
ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
|
||||||
Kind: "ReplicationController",
|
MinReplicas: newInt32(1),
|
||||||
Name: "myrc",
|
MaxReplicas: 5,
|
||||||
|
Metrics: []autoscaling.MetricSpec{
|
||||||
|
{
|
||||||
|
Type: autoscaling.ResourceMetricSourceType,
|
||||||
|
Resource: &autoscaling.ResourceMetricSource{
|
||||||
|
Name: api.ResourceCPU,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
MinReplicas: newInt32(1),
|
|
||||||
MaxReplicas: 5,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
msg: "custom metric target value must be greater than 0",
|
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: "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)
|
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 {
|
func newInt32(val int32) *int32 {
|
||||||
|
|
|
@ -14,6 +14,7 @@ go_test(
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//pkg/api:go_default_library",
|
||||||
"//pkg/apis/autoscaling:go_default_library",
|
"//pkg/apis/autoscaling:go_default_library",
|
||||||
"//pkg/apis/autoscaling/v1:go_default_library",
|
"//pkg/apis/autoscaling/v1:go_default_library",
|
||||||
"//pkg/registry/registrytest:go_default_library",
|
"//pkg/registry/registrytest:go_default_library",
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
// Ensure that autoscaling/v1 package is initialized.
|
// Ensure that autoscaling/v1 package is initialized.
|
||||||
"k8s.io/apimachinery/pkg/fields"
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
|
@ -55,8 +56,16 @@ func validNewHorizontalPodAutoscaler(name string) *autoscaling.HorizontalPodAuto
|
||||||
Kind: "ReplicationController",
|
Kind: "ReplicationController",
|
||||||
Name: "myrc",
|
Name: "myrc",
|
||||||
},
|
},
|
||||||
MaxReplicas: 5,
|
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/api:go_default_library",
|
||||||
"//pkg/apis/autoscaling:go_default_library",
|
"//pkg/apis/autoscaling:go_default_library",
|
||||||
"//pkg/apis/autoscaling/v1: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",
|
"//pkg/registry/autoscaling/horizontalpodautoscaler/storage:go_default_library",
|
||||||
"//vendor:k8s.io/apiserver/pkg/registry/generic",
|
"//vendor:k8s.io/apiserver/pkg/registry/generic",
|
||||||
"//vendor:k8s.io/apiserver/pkg/registry/rest",
|
"//vendor:k8s.io/apiserver/pkg/registry/rest",
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||||
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
|
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"
|
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.VersionedResourcesStorageMap[autoscalingapiv1.SchemeGroupVersion.Version] = p.v1Storage(apiResourceConfigSource, restOptionsGetter)
|
||||||
apiGroupInfo.GroupMeta.GroupVersion = autoscalingapiv1.SchemeGroupVersion
|
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
|
return apiGroupInfo, true
|
||||||
}
|
}
|
||||||
|
@ -51,6 +56,18 @@ func (p RESTStorageProvider) v1Storage(apiResourceConfigSource genericapiserver.
|
||||||
return storage
|
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 {
|
func (p RESTStorageProvider) GroupName() string {
|
||||||
return autoscaling.GroupName
|
return autoscaling.GroupName
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue