Update kubectl to work with new HPA objects

This commit updates kubectl to work with the changes to the unversioned
HPA object made to support the HPA v2alpha1 API.
pull/6/head
Solly Ross 2016-11-30 15:58:58 -05:00
parent f6c78eb0de
commit 946ecb549e
6 changed files with 858 additions and 21 deletions

View File

@ -154,6 +154,7 @@ go_test(
"//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/batch:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",

View File

@ -22,6 +22,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/autoscaling"
)
@ -109,7 +110,15 @@ func generateHPA(genericParams map[string]interface{}) (runtime.Object, error) {
}
if cpu >= 0 {
c := int32(cpu)
scaler.Spec.TargetCPUUtilizationPercentage = &c
scaler.Spec.Metrics = []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageUtilization: &c,
},
},
}
}
return &scaler, nil
}

View File

@ -2191,13 +2191,43 @@ func (d *HorizontalPodAutoscalerDescriber) Describe(namespace, name string, desc
w.Write(LEVEL_0, "Reference:\t%s/%s\n",
hpa.Spec.ScaleTargetRef.Kind,
hpa.Spec.ScaleTargetRef.Name)
if hpa.Spec.TargetCPUUtilizationPercentage != nil {
w.Write(LEVEL_0, "Target CPU utilization:\t%d%%\n", *hpa.Spec.TargetCPUUtilizationPercentage)
w.Write(LEVEL_0, "Current CPU utilization:\t")
if hpa.Status.CurrentCPUUtilizationPercentage != nil {
w.Write(LEVEL_0, "%d%%\n", *hpa.Status.CurrentCPUUtilizationPercentage)
} else {
w.Write(LEVEL_0, "<unset>\n")
w.Write(LEVEL_0, "Metrics:\t( current / target )\n")
for i, metric := range hpa.Spec.Metrics {
switch metric.Type {
case autoscaling.PodsMetricSourceType:
current := "<unknown>"
if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Pods != nil {
current = hpa.Status.CurrentMetrics[i].Pods.CurrentAverageValue.String()
}
w.Write(LEVEL_1, "%q on pods:\t%s / %s\n", metric.Pods.MetricName, current, metric.Pods.TargetAverageValue.String())
case autoscaling.ObjectMetricSourceType:
current := "<unknown>"
if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Object != nil {
current = hpa.Status.CurrentMetrics[i].Object.CurrentValue.String()
}
w.Write(LEVEL_1, "%q on %s/%s:\t%s / %s\n", metric.Object.MetricName, metric.Object.Target.Kind, metric.Object.Target.Name, current, metric.Object.TargetValue.String())
case autoscaling.ResourceMetricSourceType:
w.Write(LEVEL_1, "resource %s on pods", string(metric.Resource.Name))
if metric.Resource.TargetAverageValue != nil {
current := "<unknown>"
if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Resource != nil {
current = hpa.Status.CurrentMetrics[i].Resource.CurrentAverageValue.String()
}
w.Write(LEVEL_0, ":\t%s / %s\n", current, metric.Resource.TargetAverageValue.String())
} else {
current := "<unknown>"
if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Resource != nil && hpa.Status.CurrentMetrics[i].Resource.CurrentAverageUtilization != nil {
current = fmt.Sprintf("%d%% (%s)", *hpa.Status.CurrentMetrics[i].Resource.CurrentAverageUtilization, hpa.Status.CurrentMetrics[i].Resource.CurrentAverageValue.String())
}
target := "<auto>"
if metric.Resource.TargetAverageUtilization != nil {
target = fmt.Sprintf("%d%%", *metric.Resource.TargetAverageUtilization)
}
w.Write(LEVEL_1, "(as a percentage of request):\t%s / %s\n", current, target)
}
default:
w.Write(LEVEL_1, "<unknown metric type %q>", string(metric.Type))
}
}
minReplicas := "<unset>"

View File

@ -33,6 +33,7 @@ import (
fedfake "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset/fake"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
"k8s.io/kubernetes/pkg/apis/policy"
@ -766,6 +767,364 @@ func TestDescribePodDisruptionBudget(t *testing.T) {
}
}
func TestDescribeHorizontalPodAutoscaler(t *testing.T) {
minReplicasVal := int32(2)
targetUtilizationVal := int32(80)
currentUtilizationVal := int32(50)
tests := []struct {
name string
hpa autoscaling.HorizontalPodAutoscaler
}{
{
"minReplicas unset",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MaxReplicas: 10,
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
},
{
"pods source type (no current)",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricSource{
MetricName: "some-pods-metric",
TargetAverageValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
},
{
"pods source type (with current)",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricSource{
MetricName: "some-pods-metric",
TargetAverageValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricStatus{
MetricName: "some-pods-metric",
CurrentAverageValue: *resource.NewMilliQuantity(50, resource.DecimalSI),
},
},
},
},
},
},
{
"object source type (no current)",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ObjectMetricSourceType,
Object: &autoscaling.ObjectMetricSource{
Target: autoscaling.CrossVersionObjectReference{
Name: "some-service",
Kind: "Service",
},
MetricName: "some-service-metric",
TargetValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
},
{
"object source type (with current)",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ObjectMetricSourceType,
Object: &autoscaling.ObjectMetricSource{
Target: autoscaling.CrossVersionObjectReference{
Name: "some-service",
Kind: "Service",
},
MetricName: "some-service-metric",
TargetValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.ObjectMetricSourceType,
Object: &autoscaling.ObjectMetricStatus{
Target: autoscaling.CrossVersionObjectReference{
Name: "some-service",
Kind: "Service",
},
MetricName: "some-service-metric",
CurrentValue: *resource.NewMilliQuantity(50, resource.DecimalSI),
},
},
},
},
},
},
{
"resource source type, target average value (no current)",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
},
{
"resource source type, target average value (with current)",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricStatus{
Name: api.ResourceCPU,
CurrentAverageValue: *resource.NewMilliQuantity(50, resource.DecimalSI),
},
},
},
},
},
},
{
"resource source type, target utilization (no current)",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageUtilization: &targetUtilizationVal,
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
},
{
"resource source type, target utilization (with current)",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageUtilization: &targetUtilizationVal,
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricStatus{
Name: api.ResourceCPU,
CurrentAverageUtilization: &currentUtilizationVal,
CurrentAverageValue: *resource.NewMilliQuantity(40, resource.DecimalSI),
},
},
},
},
},
},
{
"multiple metrics",
autoscaling.HorizontalPodAutoscaler{
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricSource{
MetricName: "some-pods-metric",
TargetAverageValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageUtilization: &targetUtilizationVal,
},
},
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricSource{
MetricName: "other-pods-metric",
TargetAverageValue: *resource.NewMilliQuantity(400, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricStatus{
MetricName: "some-pods-metric",
CurrentAverageValue: *resource.NewMilliQuantity(50, resource.DecimalSI),
},
},
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricStatus{
Name: api.ResourceCPU,
CurrentAverageUtilization: &currentUtilizationVal,
CurrentAverageValue: *resource.NewMilliQuantity(40, resource.DecimalSI),
},
},
},
},
},
},
}
for _, test := range tests {
test.hpa.ObjectMeta = metav1.ObjectMeta{
Name: "bar",
Namespace: "foo",
}
fake := fake.NewSimpleClientset(&test.hpa)
desc := HorizontalPodAutoscalerDescriber{fake}
str, err := desc.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
if err != nil {
t.Errorf("Unexpected error for test %s: %v", test.name, err)
}
if str == "" {
t.Errorf("Unexpected empty string for test %s. Expected HPA Describer output", test.name)
}
t.Logf("Description for %q:\n%s", test.name, str)
}
}
func TestDescribeEvents(t *testing.T) {
events := &api.EventList{
@ -815,7 +1174,6 @@ func TestDescribeEvents(t *testing.T) {
}, events),
},
// TODO(jchaloup): add tests for:
// - HorizontalPodAutoscalerDescriber
// - IngressDescriber
// - JobDescriber
"NodeDescriber": &NodeDescriber{
@ -874,6 +1232,14 @@ func TestDescribeEvents(t *testing.T) {
},
}, events),
},
"HorizontalPodAutoscaler": &HorizontalPodAutoscalerDescriber{
fake.NewSimpleClientset(&autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{
Name: "bar",
Namespace: "foo",
},
}, events),
},
}
for name, d := range m {

View File

@ -533,7 +533,7 @@ var (
// TODO: consider having 'KIND' for third party resource data
thirdPartyResourceDataColumns = []string{"NAME", "LABELS", "DATA"}
horizontalPodAutoscalerColumns = []string{"NAME", "REFERENCE", "TARGET", "CURRENT", "MINPODS", "MAXPODS", "REPLICAS", "AGE"}
horizontalPodAutoscalerColumns = []string{"NAME", "REFERENCE", "TARGETS", "MINPODS", "MAXPODS", "REPLICAS", "AGE"}
withNamespacePrefixColumns = []string{"NAMESPACE"} // TODO(erictune): print cluster name too.
deploymentColumns = []string{"NAME", "DESIRED", "CURRENT", "UP-TO-DATE", "AVAILABLE", "AGE"}
deploymentWideColumns = []string{"CONTAINER(S)", "IMAGE(S)", "SELECTOR"}
@ -2145,6 +2145,66 @@ func printDeploymentList(list *extensions.DeploymentList, w io.Writer, options P
return nil
}
func formatHPAMetrics(specs []autoscaling.MetricSpec, statuses []autoscaling.MetricStatus) string {
if len(specs) == 0 {
return "<none>"
}
list := []string{}
max := 2
more := false
count := 0
for i, spec := range specs {
switch spec.Type {
case autoscaling.PodsMetricSourceType:
current := "<unknown>"
if len(statuses) > i && statuses[i].Pods != nil {
current = statuses[i].Pods.CurrentAverageValue.String()
}
list = append(list, fmt.Sprintf("%s / %s", current, spec.Pods.TargetAverageValue.String()))
case autoscaling.ObjectMetricSourceType:
current := "<unknown>"
if len(statuses) > i && statuses[i].Object != nil {
current = statuses[i].Object.CurrentValue.String()
}
list = append(list, fmt.Sprintf("%s / %s", current, spec.Object.TargetValue.String()))
case autoscaling.ResourceMetricSourceType:
if spec.Resource.TargetAverageValue != nil {
current := "<unknown>"
if len(statuses) > i && statuses[i].Resource != nil {
current = statuses[i].Resource.CurrentAverageValue.String()
}
list = append(list, fmt.Sprintf("%s / %s", current, spec.Resource.TargetAverageValue.String()))
} else {
current := "<unknown>"
if len(statuses) > i && statuses[i].Resource != nil && statuses[i].Resource.CurrentAverageUtilization != nil {
current = fmt.Sprintf("%d%%", *statuses[i].Resource.CurrentAverageUtilization)
}
target := "<auto>"
if spec.Resource.TargetAverageUtilization != nil {
target = fmt.Sprintf("%d%%", *spec.Resource.TargetAverageUtilization)
}
list = append(list, fmt.Sprintf("%s / %s", current, target))
}
default:
list = append(list, "<unknown type>")
}
count++
}
if count > max {
list = list[:max]
more = true
}
ret := strings.Join(list, ", ")
if more {
return fmt.Sprintf("%s + %d more...", ret, count-max)
}
return ret
}
func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io.Writer, options PrintOptions) error {
namespace := hpa.Namespace
name := formatResourceName(options.Kind, hpa.Name, options.WithKind)
@ -2152,15 +2212,8 @@ func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io
reference := fmt.Sprintf("%s/%s",
hpa.Spec.ScaleTargetRef.Kind,
hpa.Spec.ScaleTargetRef.Name)
target := "<unset>"
if hpa.Spec.TargetCPUUtilizationPercentage != nil {
target = fmt.Sprintf("%d%%", *hpa.Spec.TargetCPUUtilizationPercentage)
}
current := "<waiting>"
if hpa.Status.CurrentCPUUtilizationPercentage != nil {
current = fmt.Sprintf("%d%%", *hpa.Status.CurrentCPUUtilizationPercentage)
}
minPods := "<unset>"
metrics := formatHPAMetrics(hpa.Spec.Metrics, hpa.Status.CurrentMetrics)
if hpa.Spec.MinReplicas != nil {
minPods = fmt.Sprintf("%d", *hpa.Spec.MinReplicas)
}
@ -2173,11 +2226,10 @@ func printHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, w io
}
}
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%d\t%d\t%s",
if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%d\t%d\t%s",
name,
reference,
target,
current,
metrics,
minPods,
maxPods,
currentReplicas,

View File

@ -26,6 +26,7 @@ import (
"testing"
"time"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -36,6 +37,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/policy"
@ -1650,6 +1652,383 @@ func TestPrintJob(t *testing.T) {
}
}
func TestPrintHPA(t *testing.T) {
minReplicasVal := int32(2)
targetUtilizationVal := int32(80)
currentUtilizationVal := int32(50)
tests := []struct {
hpa autoscaling.HorizontalPodAutoscaler
expected string
}{
// minReplicas unset
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MaxReplicas: 10,
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
"some-hpa\tReplicationController/some-rc\t<none>\t<unset>\t10\t4\t<unknown>\n",
},
// pods source type (no current)
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricSource{
MetricName: "some-pods-metric",
TargetAverageValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
"some-hpa\tReplicationController/some-rc\t<unknown> / 100m\t2\t10\t4\t<unknown>\n",
},
// pods source type
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricSource{
MetricName: "some-pods-metric",
TargetAverageValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricStatus{
MetricName: "some-pods-metric",
CurrentAverageValue: *resource.NewMilliQuantity(50, resource.DecimalSI),
},
},
},
},
},
"some-hpa\tReplicationController/some-rc\t50m / 100m\t2\t10\t4\t<unknown>\n",
},
// object source type (no current)
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ObjectMetricSourceType,
Object: &autoscaling.ObjectMetricSource{
Target: autoscaling.CrossVersionObjectReference{
Name: "some-service",
Kind: "Service",
},
MetricName: "some-service-metric",
TargetValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
"some-hpa\tReplicationController/some-rc\t<unknown> / 100m\t2\t10\t4\t<unknown>\n",
},
// object source type
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ObjectMetricSourceType,
Object: &autoscaling.ObjectMetricSource{
Target: autoscaling.CrossVersionObjectReference{
Name: "some-service",
Kind: "Service",
},
MetricName: "some-service-metric",
TargetValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.ObjectMetricSourceType,
Object: &autoscaling.ObjectMetricStatus{
Target: autoscaling.CrossVersionObjectReference{
Name: "some-service",
Kind: "Service",
},
MetricName: "some-service-metric",
CurrentValue: *resource.NewMilliQuantity(50, resource.DecimalSI),
},
},
},
},
},
"some-hpa\tReplicationController/some-rc\t50m / 100m\t2\t10\t4\t<unknown>\n",
},
// resource source type, targetVal (no current)
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
"some-hpa\tReplicationController/some-rc\t<unknown> / 100m\t2\t10\t4\t<unknown>\n",
},
// resource source type, targetVal
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricStatus{
Name: api.ResourceCPU,
CurrentAverageValue: *resource.NewMilliQuantity(50, resource.DecimalSI),
},
},
},
},
},
"some-hpa\tReplicationController/some-rc\t50m / 100m\t2\t10\t4\t<unknown>\n",
},
// resource source type, targetUtil (no current)
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageUtilization: &targetUtilizationVal,
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
},
},
"some-hpa\tReplicationController/some-rc\t<unknown> / 80%\t2\t10\t4\t<unknown>\n",
},
// resource source type, targetUtil
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageUtilization: &targetUtilizationVal,
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricStatus{
Name: api.ResourceCPU,
CurrentAverageUtilization: &currentUtilizationVal,
CurrentAverageValue: *resource.NewMilliQuantity(40, resource.DecimalSI),
},
},
},
},
},
"some-hpa\tReplicationController/some-rc\t50% / 80%\t2\t10\t4\t<unknown>\n",
},
// multiple specs
{
autoscaling.HorizontalPodAutoscaler{
ObjectMeta: metav1.ObjectMeta{Name: "some-hpa"},
Spec: autoscaling.HorizontalPodAutoscalerSpec{
ScaleTargetRef: autoscaling.CrossVersionObjectReference{
Name: "some-rc",
Kind: "ReplicationController",
},
MinReplicas: &minReplicasVal,
MaxReplicas: 10,
Metrics: []autoscaling.MetricSpec{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricSource{
MetricName: "some-pods-metric",
TargetAverageValue: *resource.NewMilliQuantity(100, resource.DecimalSI),
},
},
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricSource{
Name: api.ResourceCPU,
TargetAverageUtilization: &targetUtilizationVal,
},
},
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricSource{
MetricName: "other-pods-metric",
TargetAverageValue: *resource.NewMilliQuantity(400, resource.DecimalSI),
},
},
},
},
Status: autoscaling.HorizontalPodAutoscalerStatus{
CurrentReplicas: 4,
DesiredReplicas: 5,
CurrentMetrics: []autoscaling.MetricStatus{
{
Type: autoscaling.PodsMetricSourceType,
Pods: &autoscaling.PodsMetricStatus{
MetricName: "some-pods-metric",
CurrentAverageValue: *resource.NewMilliQuantity(50, resource.DecimalSI),
},
},
{
Type: autoscaling.ResourceMetricSourceType,
Resource: &autoscaling.ResourceMetricStatus{
Name: api.ResourceCPU,
CurrentAverageUtilization: &currentUtilizationVal,
CurrentAverageValue: *resource.NewMilliQuantity(40, resource.DecimalSI),
},
},
},
},
},
"some-hpa\tReplicationController/some-rc\t50m / 100m, 50% / 80% + 1 more...\t2\t10\t4\t<unknown>\n",
},
}
buff := bytes.NewBuffer([]byte{})
for _, test := range tests {
err := printHorizontalPodAutoscaler(&test.hpa, buff, PrintOptions{})
if err != nil {
t.Errorf("expected %q, got error: %v", test.expected, err)
buff.Reset()
continue
}
if buff.String() != test.expected {
t.Errorf("expected %q, got %q", test.expected, buff.String())
}
buff.Reset()
}
}
func TestPrintPodShowLabels(t *testing.T) {
tests := []struct {
pod api.Pod