From afe17246956ec3bb27861eb148a7a3c277d88eef Mon Sep 17 00:00:00 2001 From: Beata Skiba Date: Fri, 23 Feb 2018 16:42:59 +0100 Subject: [PATCH 1/2] 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 8c789fcb810..c96da784348 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 dc0775055e2..9c5f06bbccb 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 b164e0d8596..197a8ddbdc8 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 140544b4d7c..1f6f16b5135 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{ From d003550bd2004953a8d966dcfd5089e9bd5e1a87 Mon Sep 17 00:00:00 2001 From: Beata Skiba Date: Mon, 26 Feb 2018 18:27:14 +0100 Subject: [PATCH 2/2] Differentiate between target and target average value --- pkg/printers/internalversion/describe.go | 4 ++-- pkg/printers/internalversion/printers.go | 2 +- pkg/printers/internalversion/printers_test.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/printers/internalversion/describe.go b/pkg/printers/internalversion/describe.go index c96da784348..40f6a4e03c8 100644 --- a/pkg/printers/internalversion/describe.go +++ b/pkg/printers/internalversion/describe.go @@ -2830,13 +2830,13 @@ func describeHorizontalPodAutoscaler(hpa *autoscaling.HorizontalPodAutoscaler, e 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()) + w.Write(LEVEL_1, "%q (target average value):\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()) + w.Write(LEVEL_1, "%q (target value):\t%s / %s\n", metric.External.MetricName, current, metric.External.TargetValue.String()) } case autoscaling.PodsMetricSourceType: diff --git a/pkg/printers/internalversion/printers.go b/pkg/printers/internalversion/printers.go index 197a8ddbdc8..56feeaff3ae 100644 --- a/pkg/printers/internalversion/printers.go +++ b/pkg/printers/internalversion/printers.go @@ -1497,7 +1497,7 @@ func formatHPAMetrics(specs []autoscaling.MetricSpec, statuses []autoscaling.Met 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())) + list = append(list, fmt.Sprintf("%s/%s (avg)", current, spec.External.TargetAverageValue.String())) } else { current := "" if len(statuses) > i && statuses[i].External != nil { diff --git a/pkg/printers/internalversion/printers_test.go b/pkg/printers/internalversion/printers_test.go index 1f6f16b5135..474e599a3ea 100644 --- a/pkg/printers/internalversion/printers_test.go +++ b/pkg/printers/internalversion/printers_test.go @@ -2200,7 +2200,7 @@ func TestPrintHPA(t *testing.T) { DesiredReplicas: 5, }, }, - "some-hpa\tReplicationController/some-rc\t/100m\t2\t10\t4\t\n", + "some-hpa\tReplicationController/some-rc\t/100m (avg)\t2\t10\t4\t\n", }, // external source type, target average value { @@ -2247,7 +2247,7 @@ func TestPrintHPA(t *testing.T) { }, }, }, - "some-hpa\tReplicationController/some-rc\t50m/100m\t2\t10\t4\t\n", + "some-hpa\tReplicationController/some-rc\t50m/100m (avg)\t2\t10\t4\t\n", }, // external source type, target value (no current) {