From afe17246956ec3bb27861eb148a7a3c277d88eef Mon Sep 17 00:00:00 2001 From: Beata Skiba Date: Fri, 23 Feb 2018 16:42:59 +0100 Subject: [PATCH] Add support for external metrics in kubectl --- pkg/printers/internalversion/describe.go | 16 ++ pkg/printers/internalversion/describe_test.go | 152 +++++++++++++++++ pkg/printers/internalversion/printers.go | 14 ++ pkg/printers/internalversion/printers_test.go | 155 ++++++++++++++++++ 4 files changed, 337 insertions(+) diff --git a/pkg/printers/internalversion/describe.go b/pkg/printers/internalversion/describe.go index 8c789fcb81..c96da78434 100644 --- a/pkg/printers/internalversion/describe.go +++ b/pkg/printers/internalversion/describe.go @@ -2823,6 +2823,22 @@ func describeHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, e w.Write(LEVEL_0, "Metrics:\t( current / target )\n") for i, metric := range hpa.Spec.Metrics { switch metric.Type { + case autoscaling.ExternalMetricSourceType: + if metric.External.TargetAverageValue != nil { + current := "" + if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].External != nil && + hpa.Status.CurrentMetrics[i].External.CurrentAverageValue != nil { + current = hpa.Status.CurrentMetrics[i].External.CurrentAverageValue.String() + } + w.Write(LEVEL_1, "%q:\t%s / %s\n", metric.External.MetricName, current, metric.External.TargetAverageValue.String()) + } else { + current := "" + if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].External != nil { + current = hpa.Status.CurrentMetrics[i].External.CurrentValue.String() + } + w.Write(LEVEL_1, "%q:\t%s / %s\n", metric.External.MetricName, current, metric.External.TargetValue.String()) + + } case autoscaling.PodsMetricSourceType: current := "" if len(hpa.Status.CurrentMetrics) > i && hpa.Status.CurrentMetrics[i].Pods != nil { diff --git a/pkg/printers/internalversion/describe_test.go b/pkg/printers/internalversion/describe_test.go index dc0775055e..9c5f06bbcc 100644 --- a/pkg/printers/internalversion/describe_test.go +++ b/pkg/printers/internalversion/describe_test.go @@ -1212,6 +1212,158 @@ func TestDescribeHorizontalPodAutoscaler(t *testing.T) { }, }, }, + { + "external 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.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricSource{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + }, + }, + }, + { + "external 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.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricSource{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + CurrentMetrics: []autoscaling.MetricStatus{ + { + Type: autoscaling.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricStatus{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + CurrentAverageValue: resource.NewMilliQuantity(50, resource.DecimalSI), + }, + }, + }, + }, + }, + }, + { + "external source type, target 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.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricSource{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + TargetValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + }, + }, + }, + { + "external source type, target 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.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricSource{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + TargetValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + CurrentMetrics: []autoscaling.MetricStatus{ + { + Type: autoscaling.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricStatus{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + CurrentValue: *resource.NewMilliQuantity(50, resource.DecimalSI), + }, + }, + }, + }, + }, + }, { "pods source type (no current)", autoscaling.HorizontalPodAutoscaler{ diff --git a/pkg/printers/internalversion/printers.go b/pkg/printers/internalversion/printers.go index b164e0d859..197a8ddbdc 100644 --- a/pkg/printers/internalversion/printers.go +++ b/pkg/printers/internalversion/printers.go @@ -1491,6 +1491,20 @@ func formatHPAMetrics(specs []autoscaling.MetricSpec, statuses []autoscaling.Met count := 0 for i, spec := range specs { switch spec.Type { + case autoscaling.ExternalMetricSourceType: + if spec.External.TargetAverageValue != nil { + current := "" + if len(statuses) > i && statuses[i].External != nil && statuses[i].External.CurrentAverageValue != nil { + current = statuses[i].External.CurrentAverageValue.String() + } + list = append(list, fmt.Sprintf("%s/%s", current, spec.External.TargetAverageValue.String())) + } else { + current := "" + if len(statuses) > i && statuses[i].External != nil { + current = statuses[i].External.CurrentValue.String() + } + list = append(list, fmt.Sprintf("%s/%s", current, spec.External.TargetValue.String())) + } case autoscaling.PodsMetricSourceType: current := "" if len(statuses) > i && statuses[i].Pods != nil { diff --git a/pkg/printers/internalversion/printers_test.go b/pkg/printers/internalversion/printers_test.go index 140544b4d7..1f6f16b513 100644 --- a/pkg/printers/internalversion/printers_test.go +++ b/pkg/printers/internalversion/printers_test.go @@ -2169,6 +2169,161 @@ func TestPrintHPA(t *testing.T) { }, "some-hpa\tReplicationController/some-rc\t\t\t10\t4\t\n", }, + // external source type, target average value (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.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricSource{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + }, + }, + "some-hpa\tReplicationController/some-rc\t/100m\t2\t10\t4\t\n", + }, + // external source type, target average value + { + 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.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricSource{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + TargetAverageValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + CurrentMetrics: []autoscaling.MetricStatus{ + { + Type: autoscaling.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricStatus{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + CurrentAverageValue: resource.NewMilliQuantity(50, resource.DecimalSI), + }, + }, + }, + }, + }, + "some-hpa\tReplicationController/some-rc\t50m/100m\t2\t10\t4\t\n", + }, + // external source type, target value (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.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricSource{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-service-metric", + TargetValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + }, + }, + "some-hpa\tReplicationController/some-rc\t/100m\t2\t10\t4\t\n", + }, + // external source type, target value + { + 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.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricSource{ + MetricSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "label": "value", + }, + }, + MetricName: "some-external-metric", + TargetValue: resource.NewMilliQuantity(100, resource.DecimalSI), + }, + }, + }, + }, + Status: autoscaling.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 4, + DesiredReplicas: 5, + CurrentMetrics: []autoscaling.MetricStatus{ + { + Type: autoscaling.ExternalMetricSourceType, + External: &autoscaling.ExternalMetricStatus{ + MetricName: "some-external-metric", + CurrentValue: *resource.NewMilliQuantity(50, resource.DecimalSI), + }, + }, + }, + }, + }, + "some-hpa\tReplicationController/some-rc\t50m/100m\t2\t10\t4\t\n", + }, // pods source type (no current) { autoscaling.HorizontalPodAutoscaler{