From c7102ee5dc42ac8ee38b76ecf56e3a18d3a42180 Mon Sep 17 00:00:00 2001 From: Mike Dame Date: Thu, 28 Jun 2018 14:28:13 -0400 Subject: [PATCH] Implement autoscaling/v2beta2 features in HPA controller --- pkg/controller/podautoscaler/BUILD | 15 +- pkg/controller/podautoscaler/horizontal.go | 106 +++++--- .../podautoscaler/horizontal_test.go | 227 +++++++++++++----- .../legacy_replica_calculator_test.go | 2 +- pkg/controller/podautoscaler/metrics/BUILD | 18 +- .../podautoscaler/metrics/interfaces.go | 6 +- .../metrics/legacy_metrics_client.go | 6 +- .../metrics/legacy_metrics_client_test.go | 11 +- .../metrics/rest_metrics_client.go | 14 +- .../metrics/rest_metrics_client_test.go | 24 +- .../podautoscaler/replica_calculator.go | 10 +- .../podautoscaler/replica_calculator_test.go | 33 +-- 12 files changed, 304 insertions(+), 168 deletions(-) diff --git a/pkg/controller/podautoscaler/BUILD b/pkg/controller/podautoscaler/BUILD index 80342236639..2988db1c211 100644 --- a/pkg/controller/podautoscaler/BUILD +++ b/pkg/controller/podautoscaler/BUILD @@ -1,10 +1,4 @@ -package(default_visibility = ["//visibility:public"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", @@ -15,13 +9,14 @@ go_library( "replica_calculator.go", ], importpath = "k8s.io/kubernetes/pkg/controller/podautoscaler", + visibility = ["//visibility:public"], deps = [ "//pkg/api/legacyscheme:go_default_library", "//pkg/api/v1/pod:go_default_library", "//pkg/controller:go_default_library", "//pkg/controller/podautoscaler/metrics:go_default_library", "//staging/src/k8s.io/api/autoscaling/v1:go_default_library", - "//staging/src/k8s.io/api/autoscaling/v2beta1:go_default_library", + "//staging/src/k8s.io/api/autoscaling/v2beta2:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", @@ -66,6 +61,7 @@ go_test( "//pkg/controller/podautoscaler/metrics:go_default_library", "//staging/src/k8s.io/api/autoscaling/v1:go_default_library", "//staging/src/k8s.io/api/autoscaling/v2beta1:go_default_library", + "//staging/src/k8s.io/api/autoscaling/v2beta2:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", @@ -80,7 +76,7 @@ go_test( "//staging/src/k8s.io/client-go/rest:go_default_library", "//staging/src/k8s.io/client-go/scale/fake:go_default_library", "//staging/src/k8s.io/client-go/testing:go_default_library", - "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/external_metrics/v1beta1:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/metrics/v1alpha1:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/metrics/v1beta1:go_default_library", @@ -107,4 +103,5 @@ filegroup( "//pkg/controller/podautoscaler/metrics:all-srcs", ], tags = ["automanaged"], + visibility = ["//visibility:public"], ) diff --git a/pkg/controller/podautoscaler/horizontal.go b/pkg/controller/podautoscaler/horizontal.go index d94045d5cfa..b40af893bd5 100644 --- a/pkg/controller/podautoscaler/horizontal.go +++ b/pkg/controller/podautoscaler/horizontal.go @@ -23,7 +23,7 @@ import ( "github.com/golang/glog" autoscalingv1 "k8s.io/api/autoscaling/v1" - autoscalingv2 "k8s.io/api/autoscaling/v2beta1" + autoscalingv2 "k8s.io/api/autoscaling/v2beta2" "k8s.io/api/core/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" @@ -218,12 +218,24 @@ func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.Hori switch metricSpec.Type { case autoscalingv2.ObjectMetricSourceType: - replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForObjectMetric(currentReplicas, metricSpec, hpa, selector, &statuses[i]) + metricSelector, err := metav1.LabelSelectorAsSelector(metricSpec.Object.Metric.Selector) + if err != nil { + a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetObjectMetric", err.Error()) + setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetObjectMetric", "the HPA was unable to compute the replica count: %v", err) + return 0, "", nil, time.Time{}, fmt.Errorf("failed to get object metric value: %v", err) + } + replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForObjectMetric(currentReplicas, metricSpec, hpa, selector, &statuses[i], metricSelector) if err != nil { return 0, "", nil, time.Time{}, fmt.Errorf("failed to get object metric value: %v", err) } case autoscalingv2.PodsMetricSourceType: - replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForPodsMetric(currentReplicas, metricSpec, hpa, selector, &statuses[i]) + metricSelector, err := metav1.LabelSelectorAsSelector(metricSpec.Pods.Metric.Selector) + if err != nil { + a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetPodsMetric", err.Error()) + setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetPodsMetric", "the HPA was unable to compute the replica count: %v", err) + return 0, "", nil, time.Time{}, fmt.Errorf("failed to get pods metric value: %v", err) + } + replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForPodsMetric(currentReplicas, metricSpec, hpa, selector, &statuses[i], metricSelector) if err != nil { return 0, "", nil, time.Time{}, fmt.Errorf("failed to get object metric value: %v", err) } @@ -270,8 +282,8 @@ func (a *HorizontalController) reconcileKey(key string) error { } // computeStatusForObjectMetric computes the desired number of replicas for the specified metric of type ObjectMetricSourceType. -func (a *HorizontalController) computeStatusForObjectMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (int32, time.Time, string, error) { - replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetObjectMetricReplicas(currentReplicas, metricSpec.Object.TargetValue.MilliValue(), metricSpec.Object.MetricName, hpa.Namespace, &metricSpec.Object.Target, selector) +func (a *HorizontalController) computeStatusForObjectMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus, metricSelector labels.Selector) (int32, time.Time, string, error) { + replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetObjectMetricReplicas(currentReplicas, metricSpec.Object.Target.Value.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, selector, metricSelector) if err != nil { a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetObjectMetric", err.Error()) setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetObjectMetric", "the HPA was unable to compute the replica count: %v", err) @@ -280,17 +292,22 @@ func (a *HorizontalController) computeStatusForObjectMetric(currentReplicas int3 *status = autoscalingv2.MetricStatus{ Type: autoscalingv2.ObjectMetricSourceType, Object: &autoscalingv2.ObjectMetricStatus{ - Target: metricSpec.Object.Target, - MetricName: metricSpec.Object.MetricName, - CurrentValue: *resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), + DescribedObject: metricSpec.Object.DescribedObject, + Metric: autoscalingv2.MetricIdentifier{ + Name: metricSpec.Object.Metric.Name, + Selector: metricSpec.Object.Metric.Selector, + }, + Current: autoscalingv2.MetricValueStatus{ + Value: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), + }, }, } - return replicaCountProposal, timestampProposal, fmt.Sprintf("%s metric %s", metricSpec.Object.Target.Kind, metricSpec.Object.MetricName), nil + return replicaCountProposal, timestampProposal, fmt.Sprintf("%s metric %s", metricSpec.Object.DescribedObject.Kind, metricSpec.Object.Metric.Name), nil } // computeStatusForPodsMetric computes the desired number of replicas for the specified metric of type PodsMetricSourceType. -func (a *HorizontalController) computeStatusForPodsMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (int32, time.Time, string, error) { - replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetMetricReplicas(currentReplicas, metricSpec.Pods.TargetAverageValue.MilliValue(), metricSpec.Pods.MetricName, hpa.Namespace, selector) +func (a *HorizontalController) computeStatusForPodsMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus, metricSelector labels.Selector) (int32, time.Time, string, error) { + replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetMetricReplicas(currentReplicas, metricSpec.Pods.Target.AverageValue.MilliValue(), metricSpec.Pods.Metric.Name, hpa.Namespace, selector, metricSelector) if err != nil { a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetPodsMetric", err.Error()) setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetPodsMetric", "the HPA was unable to compute the replica count: %v", err) @@ -299,19 +316,24 @@ func (a *HorizontalController) computeStatusForPodsMetric(currentReplicas int32, *status = autoscalingv2.MetricStatus{ Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricStatus{ - MetricName: metricSpec.Pods.MetricName, - CurrentAverageValue: *resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: metricSpec.Pods.Metric.Name, + Selector: metricSpec.Pods.Metric.Selector, + }, + Current: autoscalingv2.MetricValueStatus{ + AverageValue: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), + }, }, } - return replicaCountProposal, timestampProposal, fmt.Sprintf("pods metric %s", metricSpec.Pods.MetricName), nil + return replicaCountProposal, timestampProposal, fmt.Sprintf("pods metric %s", metricSpec.Pods.Metric.Name), nil } // computeStatusForResourceMetric computes the desired number of replicas for the specified metric of type ResourceMetricSourceType. func (a *HorizontalController) computeStatusForResourceMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (int32, time.Time, string, error) { - if metricSpec.Resource.TargetAverageValue != nil { + if metricSpec.Resource.Target.AverageValue != nil { var rawProposal int64 - replicaCountProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetRawResourceReplicas(currentReplicas, metricSpec.Resource.TargetAverageValue.MilliValue(), metricSpec.Resource.Name, hpa.Namespace, selector) + replicaCountProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetRawResourceReplicas(currentReplicas, metricSpec.Resource.Target.AverageValue.MilliValue(), metricSpec.Resource.Name, hpa.Namespace, selector) if err != nil { a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetResourceMetric", err.Error()) setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetResourceMetric", "the HPA was unable to compute the replica count: %v", err) @@ -321,19 +343,21 @@ func (a *HorizontalController) computeStatusForResourceMetric(currentReplicas in status = &autoscalingv2.MetricStatus{ Type: autoscalingv2.ResourceMetricSourceType, Resource: &autoscalingv2.ResourceMetricStatus{ - Name: metricSpec.Resource.Name, - CurrentAverageValue: *resource.NewMilliQuantity(rawProposal, resource.DecimalSI), + Name: metricSpec.Resource.Name, + Current: autoscalingv2.MetricValueStatus{ + AverageValue: resource.NewMilliQuantity(rawProposal, resource.DecimalSI), + }, }, } return replicaCountProposal, timestampProposal, metricNameProposal, nil } else { - if metricSpec.Resource.TargetAverageUtilization == nil { + if metricSpec.Resource.Target.AverageUtilization == nil { errMsg := "invalid resource metric source: neither a utilization target nor a value target was set" a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetResourceMetric", errMsg) setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetResourceMetric", "the HPA was unable to compute the replica count: %s", errMsg) return 0, time.Time{}, "", fmt.Errorf(errMsg) } - targetUtilization := *metricSpec.Resource.TargetAverageUtilization + targetUtilization := *metricSpec.Resource.Target.AverageUtilization var percentageProposal int32 var rawProposal int64 replicaCountProposal, percentageProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetResourceReplicas(currentReplicas, targetUtilization, metricSpec.Resource.Name, hpa.Namespace, selector) @@ -347,8 +371,10 @@ func (a *HorizontalController) computeStatusForResourceMetric(currentReplicas in Type: autoscalingv2.ResourceMetricSourceType, Resource: &autoscalingv2.ResourceMetricStatus{ Name: metricSpec.Resource.Name, - CurrentAverageUtilization: &percentageProposal, - CurrentAverageValue: *resource.NewMilliQuantity(rawProposal, resource.DecimalSI), + Current: autoscalingv2.MetricValueStatus{ + AverageUtilization: &percentageProposal, + AverageValue: resource.NewMilliQuantity(rawProposal, resource.DecimalSI), + }, }, } return replicaCountProposal, timestampProposal, metricNameProposal, nil @@ -357,39 +383,47 @@ func (a *HorizontalController) computeStatusForResourceMetric(currentReplicas in // computeStatusForExternalMetric computes the desired number of replicas for the specified metric of type ExternalMetricSourceType. func (a *HorizontalController) computeStatusForExternalMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (int32, time.Time, string, error) { - if metricSpec.External.TargetAverageValue != nil { - replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalPerPodMetricReplicas(currentReplicas, metricSpec.External.TargetAverageValue.MilliValue(), metricSpec.External.MetricName, hpa.Namespace, metricSpec.External.MetricSelector) + if metricSpec.External.Target.AverageValue != nil { + replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalPerPodMetricReplicas(currentReplicas, metricSpec.External.Target.AverageValue.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector) if err != nil { a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetExternalMetric", err.Error()) setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetExternalMetric", "the HPA was unable to compute the replica count: %v", err) - return 0, time.Time{}, "", fmt.Errorf("failed to get %s external metric: %v", metricSpec.External.MetricName, err) + return 0, time.Time{}, "", fmt.Errorf("failed to get %s external metric: %v", metricSpec.External.Metric.Name, err) } *status = autoscalingv2.MetricStatus{ Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricStatus{ - MetricSelector: metricSpec.External.MetricSelector, - MetricName: metricSpec.External.MetricName, - CurrentAverageValue: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: metricSpec.External.Metric.Name, + Selector: metricSpec.External.Metric.Selector, + }, + Current: autoscalingv2.MetricValueStatus{ + AverageValue: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), + }, }, } - return replicaCountProposal, timestampProposal, fmt.Sprintf("external metric %s(%+v)", metricSpec.External.MetricName, metricSpec.External.MetricSelector), nil + return replicaCountProposal, timestampProposal, fmt.Sprintf("external metric %s(%+v)", metricSpec.External.Metric.Name, metricSpec.External.Metric.Selector), nil } - if metricSpec.External.TargetValue != nil { - replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalMetricReplicas(currentReplicas, metricSpec.External.TargetValue.MilliValue(), metricSpec.External.MetricName, hpa.Namespace, metricSpec.External.MetricSelector, selector) + if metricSpec.External.Target.Value != nil { + replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalMetricReplicas(currentReplicas, metricSpec.External.Target.Value.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector, selector) if err != nil { a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetExternalMetric", err.Error()) setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetExternalMetric", "the HPA was unable to compute the replica count: %v", err) - return 0, time.Time{}, "", fmt.Errorf("failed to get external metric %s: %v", metricSpec.External.MetricName, err) + return 0, time.Time{}, "", fmt.Errorf("failed to get external metric %s: %v", metricSpec.External.Metric.Name, err) } *status = autoscalingv2.MetricStatus{ Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricStatus{ - MetricSelector: metricSpec.External.MetricSelector, - MetricName: metricSpec.External.MetricName, - CurrentValue: *resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: metricSpec.External.Metric.Name, + Selector: metricSpec.External.Metric.Selector, + }, + Current: autoscalingv2.MetricValueStatus{ + Value: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), + }, }, } - return replicaCountProposal, timestampProposal, fmt.Sprintf("external metric %s(%+v)", metricSpec.External.MetricName, metricSpec.External.MetricSelector), nil + return replicaCountProposal, timestampProposal, fmt.Sprintf("external metric %s(%+v)", metricSpec.External.Metric.Name, metricSpec.External.Metric.Selector), nil } errMsg := "invalid external metric source: neither a value target nor an average value target was set" a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetExternalMetric", errMsg) diff --git a/pkg/controller/podautoscaler/horizontal_test.go b/pkg/controller/podautoscaler/horizontal_test.go index 5be579861dd..b8382f4b7a3 100644 --- a/pkg/controller/podautoscaler/horizontal_test.go +++ b/pkg/controller/podautoscaler/horizontal_test.go @@ -25,7 +25,7 @@ import ( "time" autoscalingv1 "k8s.io/api/autoscaling/v1" - autoscalingv2 "k8s.io/api/autoscaling/v2beta1" + autoscalingv2 "k8s.io/api/autoscaling/v2beta2" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta/testrestmapper" "k8s.io/apimachinery/pkg/api/resource" @@ -42,7 +42,7 @@ import ( "k8s.io/kubernetes/pkg/apis/autoscaling" "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics" - cmapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" + cmapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" emapi "k8s.io/metrics/pkg/apis/external_metrics/v1beta1" metricsapi "k8s.io/metrics/pkg/apis/metrics/v1beta1" metricsfake "k8s.io/metrics/pkg/client/clientset/versioned/fake" @@ -214,7 +214,9 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa Type: autoscalingv2.ResourceMetricSourceType, Resource: &autoscalingv2.ResourceMetricSource{ Name: v1.ResourceCPU, - TargetAverageUtilization: &tc.CPUTarget, + Target: autoscalingv2.MetricTarget{ + AverageUtilization: &tc.CPUTarget, + }, }, }, } @@ -507,9 +509,11 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa Name: fmt.Sprintf("%s-%d", podNamePrefix, i), Namespace: namespace, }, - Timestamp: metav1.Time{Time: time.Now()}, - MetricName: "qps", - Value: *resource.NewMilliQuantity(int64(level), resource.DecimalSI), + Timestamp: metav1.Time{Time: time.Now()}, + Metric: cmapi.MetricIdentifier{ + Name: "qps", + }, + Value: *resource.NewMilliQuantity(int64(level), resource.DecimalSI), } metrics.Items = append(metrics.Items, podMetric) } @@ -522,8 +526,8 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa metrics := &cmapi.MetricValueList{} var matchedTarget *autoscalingv2.MetricSpec for i, target := range tc.metricsTarget { - if target.Type == autoscalingv2.ObjectMetricSourceType && name == target.Object.Target.Name { - gk := schema.FromAPIVersionAndKind(target.Object.Target.APIVersion, target.Object.Target.Kind).GroupKind() + if target.Type == autoscalingv2.ObjectMetricSourceType && name == target.Object.DescribedObject.Name { + gk := schema.FromAPIVersionAndKind(target.Object.DescribedObject.APIVersion, target.Object.DescribedObject.Kind).GroupKind() mapping, err := mapper.RESTMapping(gk) if err != nil { t.Logf("unable to get mapping for %s: %v", gk.String(), err) @@ -542,13 +546,15 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa metrics.Items = []cmapi.MetricValue{ { DescribedObject: v1.ObjectReference{ - Kind: matchedTarget.Object.Target.Kind, - APIVersion: matchedTarget.Object.Target.APIVersion, + Kind: matchedTarget.Object.DescribedObject.Kind, + APIVersion: matchedTarget.Object.DescribedObject.APIVersion, Name: name, }, - Timestamp: metav1.Time{Time: time.Now()}, - MetricName: "qps", - Value: *resource.NewMilliQuantity(int64(tc.reportedLevels[0]), resource.DecimalSI), + Timestamp: metav1.Time{Time: time.Now()}, + Metric: cmapi.MetricIdentifier{ + Name: "qps", + }, + Value: *resource.NewMilliQuantity(int64(tc.reportedLevels[0]), resource.DecimalSI), }, } @@ -847,6 +853,7 @@ func TestScaleUpReplicaSet(t *testing.T) { } func TestScaleUpCM(t *testing.T) { + averageValue := resource.MustParse("15.0") tc := testCase{ minReplicas: 2, maxReplicas: 6, @@ -857,8 +864,12 @@ func TestScaleUpCM(t *testing.T) { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, @@ -869,6 +880,7 @@ func TestScaleUpCM(t *testing.T) { } func TestScaleUpCMUnreadyAndHotCpuNoLessScale(t *testing.T) { + averageValue := resource.MustParse("15.0") tc := testCase{ minReplicas: 2, maxReplicas: 6, @@ -879,8 +891,12 @@ func TestScaleUpCMUnreadyAndHotCpuNoLessScale(t *testing.T) { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, @@ -893,6 +909,7 @@ func TestScaleUpCMUnreadyAndHotCpuNoLessScale(t *testing.T) { } func TestScaleUpCMUnreadyandCpuHot(t *testing.T) { + averageValue := resource.MustParse("15.0") tc := testCase{ minReplicas: 2, maxReplicas: 6, @@ -903,8 +920,12 @@ func TestScaleUpCMUnreadyandCpuHot(t *testing.T) { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, @@ -926,6 +947,7 @@ func TestScaleUpCMUnreadyandCpuHot(t *testing.T) { } func TestScaleUpHotCpuNoScaleWouldScaleDown(t *testing.T) { + averageValue := resource.MustParse("15.0") tc := testCase{ minReplicas: 2, maxReplicas: 6, @@ -936,8 +958,12 @@ func TestScaleUpHotCpuNoScaleWouldScaleDown(t *testing.T) { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, @@ -958,6 +984,7 @@ func TestScaleUpHotCpuNoScaleWouldScaleDown(t *testing.T) { } func TestScaleUpCMObject(t *testing.T) { + targetValue := resource.MustParse("15.0") tc := testCase{ minReplicas: 2, maxReplicas: 6, @@ -968,13 +995,17 @@ func TestScaleUpCMObject(t *testing.T) { { Type: autoscalingv2.ObjectMetricSourceType, Object: &autoscalingv2.ObjectMetricSource{ - Target: autoscalingv2.CrossVersionObjectReference{ + DescribedObject: autoscalingv2.CrossVersionObjectReference{ APIVersion: "extensions/v1beta1", Kind: "Deployment", Name: "some-deployment", }, - MetricName: "qps", - TargetValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + Value: &targetValue, + }, }, }, }, @@ -993,9 +1024,13 @@ func TestScaleUpCMExternal(t *testing.T) { { Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricSource{ - MetricSelector: &metav1.LabelSelector{}, - MetricName: "qps", - TargetValue: resource.NewMilliQuantity(6666, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + Selector: &metav1.LabelSelector{}, + }, + Target: autoscalingv2.MetricTarget{ + Value: resource.NewMilliQuantity(6666, resource.DecimalSI), + }, }, }, }, @@ -1014,9 +1049,13 @@ func TestScaleUpPerPodCMExternal(t *testing.T) { { Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricSource{ - MetricSelector: &metav1.LabelSelector{}, - MetricName: "qps", - TargetAverageValue: resource.NewMilliQuantity(2222, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + Selector: &metav1.LabelSelector{}, + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: resource.NewMilliQuantity(2222, resource.DecimalSI), + }, }, }, }, @@ -1041,6 +1080,7 @@ func TestScaleDown(t *testing.T) { } func TestScaleDownCM(t *testing.T) { + averageValue := resource.MustParse("20.0") tc := testCase{ minReplicas: 2, maxReplicas: 6, @@ -1051,8 +1091,12 @@ func TestScaleDownCM(t *testing.T) { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("20.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, @@ -1063,6 +1107,7 @@ func TestScaleDownCM(t *testing.T) { } func TestScaleDownCMObject(t *testing.T) { + targetValue := resource.MustParse("20.0") tc := testCase{ minReplicas: 2, maxReplicas: 6, @@ -1073,13 +1118,17 @@ func TestScaleDownCMObject(t *testing.T) { { Type: autoscalingv2.ObjectMetricSourceType, Object: &autoscalingv2.ObjectMetricSource{ - Target: autoscalingv2.CrossVersionObjectReference{ + DescribedObject: autoscalingv2.CrossVersionObjectReference{ APIVersion: "extensions/v1beta1", Kind: "Deployment", Name: "some-deployment", }, - MetricName: "qps", - TargetValue: resource.MustParse("20.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + Value: &targetValue, + }, }, }, }, @@ -1099,9 +1148,13 @@ func TestScaleDownCMExternal(t *testing.T) { { Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricSource{ - MetricSelector: &metav1.LabelSelector{}, - MetricName: "qps", - TargetValue: resource.NewMilliQuantity(14400, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + Selector: &metav1.LabelSelector{}, + }, + Target: autoscalingv2.MetricTarget{ + Value: resource.NewMilliQuantity(14400, resource.DecimalSI), + }, }, }, }, @@ -1120,9 +1173,13 @@ func TestScaleDownPerPodCMExternal(t *testing.T) { { Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricSource{ - MetricSelector: &metav1.LabelSelector{}, - MetricName: "qps", - TargetAverageValue: resource.NewMilliQuantity(3000, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + Selector: &metav1.LabelSelector{}, + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: resource.NewMilliQuantity(3000, resource.DecimalSI), + }, }, }, }, @@ -1203,6 +1260,7 @@ func TestTolerance(t *testing.T) { } func TestToleranceCM(t *testing.T) { + averageValue := resource.MustParse("20.0") tc := testCase{ minReplicas: 1, maxReplicas: 5, @@ -1212,8 +1270,12 @@ func TestToleranceCM(t *testing.T) { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("20.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, @@ -1229,6 +1291,7 @@ func TestToleranceCM(t *testing.T) { } func TestToleranceCMObject(t *testing.T) { + targetValue := resource.MustParse("20.0") tc := testCase{ minReplicas: 1, maxReplicas: 5, @@ -1238,13 +1301,17 @@ func TestToleranceCMObject(t *testing.T) { { Type: autoscalingv2.ObjectMetricSourceType, Object: &autoscalingv2.ObjectMetricSource{ - Target: autoscalingv2.CrossVersionObjectReference{ + DescribedObject: autoscalingv2.CrossVersionObjectReference{ APIVersion: "extensions/v1beta1", Kind: "Deployment", Name: "some-deployment", }, - MetricName: "qps", - TargetValue: resource.MustParse("20.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + Value: &targetValue, + }, }, }, }, @@ -1269,9 +1336,13 @@ func TestToleranceCMExternal(t *testing.T) { { Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricSource{ - MetricSelector: &metav1.LabelSelector{}, - MetricName: "qps", - TargetValue: resource.NewMilliQuantity(8666, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + Selector: &metav1.LabelSelector{}, + }, + Target: autoscalingv2.MetricTarget{ + Value: resource.NewMilliQuantity(8666, resource.DecimalSI), + }, }, }, }, @@ -1295,9 +1366,13 @@ func TestTolerancePerPodCMExternal(t *testing.T) { { Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricSource{ - MetricSelector: &metav1.LabelSelector{}, - MetricName: "qps", - TargetAverageValue: resource.NewMilliQuantity(2200, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + Selector: &metav1.LabelSelector{}, + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: resource.NewMilliQuantity(2200, resource.DecimalSI), + }, }, }, }, @@ -1669,14 +1744,20 @@ func TestConditionInvalidSelectorUnparsable(t *testing.T) { } func TestConditionFailedGetMetrics(t *testing.T) { + targetValue := resource.MustParse("15.0") + averageValue := resource.MustParse("15.0") metricsTargets := map[string][]autoscalingv2.MetricSpec{ "FailedGetResourceMetric": nil, "FailedGetPodsMetric": { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, @@ -1684,13 +1765,17 @@ func TestConditionFailedGetMetrics(t *testing.T) { { Type: autoscalingv2.ObjectMetricSourceType, Object: &autoscalingv2.ObjectMetricSource{ - Target: autoscalingv2.CrossVersionObjectReference{ + DescribedObject: autoscalingv2.CrossVersionObjectReference{ APIVersion: "extensions/v1beta1", Kind: "Deployment", Name: "some-deployment", }, - MetricName: "qps", - TargetValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + Value: &targetValue, + }, }, }, }, @@ -1698,9 +1783,13 @@ func TestConditionFailedGetMetrics(t *testing.T) { { Type: autoscalingv2.ExternalMetricSourceType, External: &autoscalingv2.ExternalMetricSource{ - MetricSelector: &metav1.LabelSelector{}, - MetricName: "qps", - TargetValue: resource.NewMilliQuantity(300, resource.DecimalSI), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + Selector: &metav1.LabelSelector{}, + }, + Target: autoscalingv2.MetricTarget{ + Value: resource.NewMilliQuantity(300, resource.DecimalSI), + }, }, }, }, @@ -1857,6 +1946,7 @@ func NoTestBackoffUpscale(t *testing.T) { } func TestNoBackoffUpscaleCM(t *testing.T) { + averageValue := resource.MustParse("15.0") time := metav1.Time{Time: time.Now()} tc := testCase{ minReplicas: 1, @@ -1868,8 +1958,12 @@ func TestNoBackoffUpscaleCM(t *testing.T) { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, @@ -1895,6 +1989,7 @@ func TestNoBackoffUpscaleCM(t *testing.T) { } func TestNoBackoffUpscaleCMNoBackoffCpu(t *testing.T) { + averageValue := resource.MustParse("15.0") time := metav1.Time{Time: time.Now()} tc := testCase{ minReplicas: 1, @@ -1906,8 +2001,12 @@ func TestNoBackoffUpscaleCMNoBackoffCpu(t *testing.T) { { Type: autoscalingv2.PodsMetricSourceType, Pods: &autoscalingv2.PodsMetricSource{ - MetricName: "qps", - TargetAverageValue: resource.MustParse("15.0"), + Metric: autoscalingv2.MetricIdentifier{ + Name: "qps", + }, + Target: autoscalingv2.MetricTarget{ + AverageValue: &averageValue, + }, }, }, }, diff --git a/pkg/controller/podautoscaler/legacy_replica_calculator_test.go b/pkg/controller/podautoscaler/legacy_replica_calculator_test.go index 9fac8a4a000..df42d7133fb 100644 --- a/pkg/controller/podautoscaler/legacy_replica_calculator_test.go +++ b/pkg/controller/podautoscaler/legacy_replica_calculator_test.go @@ -210,7 +210,7 @@ func (tc *legacyReplicaCalcTestCase) runTest(t *testing.T) { assert.True(t, tc.timestamp.Equal(outTimestamp), "timestamp should be as expected") } else { - outReplicas, outUtilization, outTimestamp, err := replicaCalc.GetMetricReplicas(tc.currentReplicas, tc.metric.targetUtilization, tc.metric.name, testNamespace, selector) + outReplicas, outUtilization, outTimestamp, err := replicaCalc.GetMetricReplicas(tc.currentReplicas, tc.metric.targetUtilization, tc.metric.name, testNamespace, selector, nil) if tc.expectedError != nil { require.Error(t, err, "there should be an error calculating the replica count") diff --git a/pkg/controller/podautoscaler/metrics/BUILD b/pkg/controller/podautoscaler/metrics/BUILD index 8abce805215..f745c9ac0ef 100644 --- a/pkg/controller/podautoscaler/metrics/BUILD +++ b/pkg/controller/podautoscaler/metrics/BUILD @@ -1,10 +1,4 @@ -package(default_visibility = ["//visibility:public"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", @@ -15,15 +9,16 @@ go_library( "utilization.go", ], importpath = "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics", + visibility = ["//visibility:public"], deps = [ - "//staging/src/k8s.io/api/autoscaling/v2beta1:go_default_library", + "//staging/src/k8s.io/api/autoscaling/v2beta2:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", - "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/metrics/v1alpha1:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/custom_metrics:go_default_library", @@ -44,7 +39,7 @@ go_test( deps = [ "//pkg/api/legacyscheme:go_default_library", "//pkg/apis/extensions/install:go_default_library", - "//staging/src/k8s.io/api/autoscaling/v2beta1:go_default_library", + "//staging/src/k8s.io/api/autoscaling/v2beta2:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", @@ -55,7 +50,7 @@ go_test( "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", "//staging/src/k8s.io/client-go/rest:go_default_library", "//staging/src/k8s.io/client-go/testing:go_default_library", - "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta1:go_default_library", + "//staging/src/k8s.io/metrics/pkg/apis/custom_metrics/v1beta2:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/external_metrics/v1beta1:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/metrics/v1alpha1:go_default_library", "//staging/src/k8s.io/metrics/pkg/apis/metrics/v1beta1:go_default_library", @@ -78,4 +73,5 @@ filegroup( name = "all-srcs", srcs = [":package-srcs"], tags = ["automanaged"], + visibility = ["//visibility:public"], ) diff --git a/pkg/controller/podautoscaler/metrics/interfaces.go b/pkg/controller/podautoscaler/metrics/interfaces.go index 29fccc48e3a..943a164ae9c 100644 --- a/pkg/controller/podautoscaler/metrics/interfaces.go +++ b/pkg/controller/podautoscaler/metrics/interfaces.go @@ -19,7 +19,7 @@ package metrics import ( "time" - autoscaling "k8s.io/api/autoscaling/v2beta1" + autoscaling "k8s.io/api/autoscaling/v2beta2" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" ) @@ -37,11 +37,11 @@ type MetricsClient interface { // GetRawMetric gets the given metric (and an associated oldest timestamp) // for all pods matching the specified selector in the given namespace - GetRawMetric(metricName string, namespace string, selector labels.Selector) (PodMetricsInfo, time.Time, error) + GetRawMetric(metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (PodMetricsInfo, time.Time, error) // GetObjectMetric gets the given metric (and an associated timestamp) for the given // object in the given namespace - GetObjectMetric(metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference) (int64, time.Time, error) + GetObjectMetric(metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, metricSelector labels.Selector) (int64, time.Time, error) // GetExternalMetric gets all the values of a given external metric // that match the specified selector. diff --git a/pkg/controller/podautoscaler/metrics/legacy_metrics_client.go b/pkg/controller/podautoscaler/metrics/legacy_metrics_client.go index c9846602773..11fdb21db59 100644 --- a/pkg/controller/podautoscaler/metrics/legacy_metrics_client.go +++ b/pkg/controller/podautoscaler/metrics/legacy_metrics_client.go @@ -26,7 +26,7 @@ import ( heapster "k8s.io/heapster/metrics/api/v1/types" metricsapi "k8s.io/metrics/pkg/apis/metrics/v1alpha1" - autoscaling "k8s.io/api/autoscaling/v2beta1" + autoscaling "k8s.io/api/autoscaling/v2beta2" "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -109,7 +109,7 @@ func (h *HeapsterMetricsClient) GetResourceMetric(resource v1.ResourceName, name return res, timestamp, nil } -func (h *HeapsterMetricsClient) GetRawMetric(metricName string, namespace string, selector labels.Selector) (PodMetricsInfo, time.Time, error) { +func (h *HeapsterMetricsClient) GetRawMetric(metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (PodMetricsInfo, time.Time, error) { podList, err := h.podsGetter.Pods(namespace).List(metav1.ListOptions{LabelSelector: selector.String()}) if err != nil { return nil, time.Time{}, fmt.Errorf("failed to get pod list while fetching metrics: %v", err) @@ -173,7 +173,7 @@ func (h *HeapsterMetricsClient) GetRawMetric(metricName string, namespace string return res, *timestamp, nil } -func (h *HeapsterMetricsClient) GetObjectMetric(metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference) (int64, time.Time, error) { +func (h *HeapsterMetricsClient) GetObjectMetric(metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, metricSelector labels.Selector) (int64, time.Time, error) { return 0, time.Time{}, fmt.Errorf("object metrics are not yet supported") } diff --git a/pkg/controller/podautoscaler/metrics/legacy_metrics_client_test.go b/pkg/controller/podautoscaler/metrics/legacy_metrics_client_test.go index 55c016dd199..fd86e3db3b0 100644 --- a/pkg/controller/podautoscaler/metrics/legacy_metrics_client_test.go +++ b/pkg/controller/podautoscaler/metrics/legacy_metrics_client_test.go @@ -71,10 +71,11 @@ type testCase struct { reportedMetricsPoints [][]metricPoint reportedPodMetrics [][]int64 - namespace string - selector labels.Selector - resourceName v1.ResourceName - metricName string + namespace string + selector labels.Selector + metricSelector labels.Selector + resourceName v1.ResourceName + metricName string } func (tc *testCase) prepareTestClient(t *testing.T) *fake.Clientset { @@ -211,7 +212,7 @@ func (tc *testCase) runTest(t *testing.T) { info, timestamp, err := metricsClient.GetResourceMetric(tc.resourceName, tc.namespace, tc.selector) tc.verifyResults(t, info, timestamp, err) } else { - info, timestamp, err := metricsClient.GetRawMetric(tc.metricName, tc.namespace, tc.selector) + info, timestamp, err := metricsClient.GetRawMetric(tc.metricName, tc.namespace, tc.selector, tc.metricSelector) tc.verifyResults(t, info, timestamp, err) } } diff --git a/pkg/controller/podautoscaler/metrics/rest_metrics_client.go b/pkg/controller/podautoscaler/metrics/rest_metrics_client.go index cf26617a4e3..0e4b2e583a7 100644 --- a/pkg/controller/podautoscaler/metrics/rest_metrics_client.go +++ b/pkg/controller/podautoscaler/metrics/rest_metrics_client.go @@ -22,12 +22,12 @@ import ( "github.com/golang/glog" - autoscaling "k8s.io/api/autoscaling/v2beta1" + autoscaling "k8s.io/api/autoscaling/v2beta2" "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" - customapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" + customapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" resourceclient "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1" customclient "k8s.io/metrics/pkg/client/custom_metrics" externalclient "k8s.io/metrics/pkg/client/external_metrics" @@ -101,8 +101,8 @@ type customMetricsClient struct { // GetRawMetric gets the given metric (and an associated oldest timestamp) // for all pods matching the specified selector in the given namespace -func (c *customMetricsClient) GetRawMetric(metricName string, namespace string, selector labels.Selector) (PodMetricsInfo, time.Time, error) { - metrics, err := c.client.NamespacedMetrics(namespace).GetForObjects(schema.GroupKind{Kind: "Pod"}, selector, metricName) +func (c *customMetricsClient) GetRawMetric(metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (PodMetricsInfo, time.Time, error) { + metrics, err := c.client.NamespacedMetrics(namespace).GetForObjects(schema.GroupKind{Kind: "Pod"}, selector, metricName, metricSelector) if err != nil { return nil, time.Time{}, fmt.Errorf("unable to fetch metrics from custom metrics API: %v", err) } @@ -123,7 +123,7 @@ func (c *customMetricsClient) GetRawMetric(metricName string, namespace string, // GetObjectMetric gets the given metric (and an associated timestamp) for the given // object in the given namespace -func (c *customMetricsClient) GetObjectMetric(metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference) (int64, time.Time, error) { +func (c *customMetricsClient) GetObjectMetric(metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, metricSelector labels.Selector) (int64, time.Time, error) { gvk := schema.FromAPIVersionAndKind(objectRef.APIVersion, objectRef.Kind) var metricValue *customapi.MetricValue var err error @@ -131,9 +131,9 @@ func (c *customMetricsClient) GetObjectMetric(metricName string, namespace strin // handle namespace separately // NB: we ignore namespace name here, since CrossVersionObjectReference isn't // supposed to allow you to escape your namespace - metricValue, err = c.client.RootScopedMetrics().GetForObject(gvk.GroupKind(), namespace, metricName) + metricValue, err = c.client.RootScopedMetrics().GetForObject(gvk.GroupKind(), namespace, metricName, metricSelector) } else { - metricValue, err = c.client.NamespacedMetrics(namespace).GetForObject(gvk.GroupKind(), objectRef.Name, metricName) + metricValue, err = c.client.NamespacedMetrics(namespace).GetForObject(gvk.GroupKind(), objectRef.Name, metricName, metricSelector) } if err != nil { diff --git a/pkg/controller/podautoscaler/metrics/rest_metrics_client_test.go b/pkg/controller/podautoscaler/metrics/rest_metrics_client_test.go index d1488d94206..624f2fd3a45 100644 --- a/pkg/controller/podautoscaler/metrics/rest_metrics_client_test.go +++ b/pkg/controller/podautoscaler/metrics/rest_metrics_client_test.go @@ -21,7 +21,7 @@ import ( "testing" "time" - autoscalingapi "k8s.io/api/autoscaling/v2beta1" + autoscalingapi "k8s.io/api/autoscaling/v2beta2" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta/testrestmapper" "k8s.io/apimachinery/pkg/api/resource" @@ -32,7 +32,7 @@ import ( core "k8s.io/client-go/testing" "k8s.io/kubernetes/pkg/api/legacyscheme" _ "k8s.io/kubernetes/pkg/apis/extensions/install" - cmapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" + cmapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" emapi "k8s.io/metrics/pkg/apis/external_metrics/v1beta1" metricsapi "k8s.io/metrics/pkg/apis/metrics/v1beta1" metricsfake "k8s.io/metrics/pkg/client/clientset/versioned/fake" @@ -143,9 +143,11 @@ func (tc *restClientTestCase) prepareTestClient(t *testing.T) (*metricsfake.Clie APIVersion: "v1", Name: fmt.Sprintf("%s-%d", podNamePrefix, i), }, - Value: *resource.NewMilliQuantity(int64(metricPoint.level), resource.DecimalSI), - Timestamp: metav1.Time{Time: timestamp}, - MetricName: tc.metricName, + Value: *resource.NewMilliQuantity(int64(metricPoint.level), resource.DecimalSI), + Timestamp: metav1.Time{Time: timestamp}, + Metric: cmapi.MetricIdentifier{ + Name: tc.metricName, + }, } metrics.Items = append(metrics.Items, metric) @@ -176,9 +178,11 @@ func (tc *restClientTestCase) prepareTestClient(t *testing.T) (*metricsfake.Clie APIVersion: tc.singleObject.APIVersion, Name: tc.singleObject.Name, }, - Timestamp: metav1.Time{Time: timestamp}, - MetricName: tc.metricName, - Value: *resource.NewMilliQuantity(int64(metricPoint.level), resource.DecimalSI), + Timestamp: metav1.Time{Time: timestamp}, + Metric: cmapi.MetricIdentifier{ + Name: tc.metricName, + }, + Value: *resource.NewMilliQuantity(int64(metricPoint.level), resource.DecimalSI), }, }, } @@ -227,10 +231,10 @@ func (tc *restClientTestCase) runTest(t *testing.T) { } tc.verifyResults(t, info, timestamp, err) } else if tc.singleObject == nil { - info, timestamp, err := metricsClient.GetRawMetric(tc.metricName, tc.namespace, tc.selector) + info, timestamp, err := metricsClient.GetRawMetric(tc.metricName, tc.namespace, tc.selector, tc.metricLabelSelector) tc.verifyResults(t, info, timestamp, err) } else { - val, timestamp, err := metricsClient.GetObjectMetric(tc.metricName, tc.namespace, tc.singleObject) + val, timestamp, err := metricsClient.GetObjectMetric(tc.metricName, tc.namespace, tc.singleObject, tc.metricLabelSelector) info := PodMetricsInfo{tc.singleObject.Name: val} tc.verifyResults(t, info, timestamp, err) } diff --git a/pkg/controller/podautoscaler/replica_calculator.go b/pkg/controller/podautoscaler/replica_calculator.go index b4faac41096..38ad64bafaa 100644 --- a/pkg/controller/podautoscaler/replica_calculator.go +++ b/pkg/controller/podautoscaler/replica_calculator.go @@ -22,7 +22,7 @@ import ( "time" "github.com/golang/glog" - autoscaling "k8s.io/api/autoscaling/v2beta1" + autoscaling "k8s.io/api/autoscaling/v2beta2" "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -159,8 +159,8 @@ func (c *ReplicaCalculator) GetRawResourceReplicas(currentReplicas int32, target // GetMetricReplicas calculates the desired replica count based on a target metric utilization // (as a milli-value) for pods matching the given selector in the given namespace, and the // current replica count -func (c *ReplicaCalculator) GetMetricReplicas(currentReplicas int32, targetUtilization int64, metricName string, namespace string, selector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { - metrics, timestamp, err := c.metricsClient.GetRawMetric(metricName, namespace, selector) +func (c *ReplicaCalculator) GetMetricReplicas(currentReplicas int32, targetUtilization int64, metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { + metrics, timestamp, err := c.metricsClient.GetRawMetric(metricName, namespace, selector, metricSelector) if err != nil { return 0, 0, time.Time{}, fmt.Errorf("unable to get metric %s: %v", metricName, err) } @@ -238,8 +238,8 @@ func (c *ReplicaCalculator) calcPlainMetricReplicas(metrics metricsclient.PodMet // GetObjectMetricReplicas calculates the desired replica count based on a target metric utilization (as a milli-value) // for the given object in the given namespace, and the current replica count. -func (c *ReplicaCalculator) GetObjectMetricReplicas(currentReplicas int32, targetUtilization int64, metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, selector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { - utilization, timestamp, err = c.metricsClient.GetObjectMetric(metricName, namespace, objectRef) +func (c *ReplicaCalculator) GetObjectMetricReplicas(currentReplicas int32, targetUtilization int64, metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, selector labels.Selector, metricSelector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { + utilization, timestamp, err = c.metricsClient.GetObjectMetric(metricName, namespace, objectRef, metricSelector) if err != nil { return 0, 0, time.Time{}, fmt.Errorf("unable to get metric %s: %v on %s %s/%s", metricName, objectRef.Kind, namespace, objectRef.Name, err) } diff --git a/pkg/controller/podautoscaler/replica_calculator_test.go b/pkg/controller/podautoscaler/replica_calculator_test.go index fa869a38f47..7cce4849634 100644 --- a/pkg/controller/podautoscaler/replica_calculator_test.go +++ b/pkg/controller/podautoscaler/replica_calculator_test.go @@ -22,20 +22,20 @@ import ( "testing" "time" - autoscalingv2 "k8s.io/api/autoscaling/v2beta1" + autoscalingv2 "k8s.io/api/autoscaling/v2beta2" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta/testrestmapper" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" "k8s.io/kubernetes/pkg/api/legacyscheme" - "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics" metricsclient "k8s.io/kubernetes/pkg/controller/podautoscaler/metrics" - cmapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1" + cmapi "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2" emapi "k8s.io/metrics/pkg/apis/external_metrics/v1beta1" metricsapi "k8s.io/metrics/pkg/apis/metrics/v1beta1" metricsfake "k8s.io/metrics/pkg/client/clientset/versioned/fake" @@ -86,8 +86,9 @@ type replicaCalcTestCase struct { timestamp time.Time - resource *resourceInfo - metric *metricInfo + resource *resourceInfo + metric *metricInfo + metricLabelSelector labels.Selector podReadiness []v1.ConditionStatus podStartTime []metav1.Time @@ -235,9 +236,11 @@ func (tc *replicaCalcTestCase) prepareTestCMClient(t *testing.T) *cmfake.FakeCus Name: fmt.Sprintf("%s-%d", podNamePrefix, i), Namespace: testNamespace, }, - Timestamp: metav1.Time{Time: tc.timestamp}, - MetricName: tc.metric.name, - Value: *resource.NewMilliQuantity(level, resource.DecimalSI), + Timestamp: metav1.Time{Time: tc.timestamp}, + Metric: cmapi.MetricIdentifier{ + Name: tc.metric.name, + }, + Value: *resource.NewMilliQuantity(level, resource.DecimalSI), } metrics.Items = append(metrics.Items, podMetric) } @@ -265,9 +268,11 @@ func (tc *replicaCalcTestCase) prepareTestCMClient(t *testing.T) *cmfake.FakeCus APIVersion: tc.metric.singleObject.APIVersion, Name: name, }, - Timestamp: metav1.Time{Time: tc.timestamp}, - MetricName: tc.metric.name, - Value: *resource.NewMilliQuantity(int64(tc.metric.levels[0]), resource.DecimalSI), + Timestamp: metav1.Time{Time: tc.timestamp}, + Metric: cmapi.MetricIdentifier{ + Name: tc.metric.name, + }, + Value: *resource.NewMilliQuantity(int64(tc.metric.levels[0]), resource.DecimalSI), }, } @@ -322,7 +327,7 @@ func (tc *replicaCalcTestCase) prepareTestClient(t *testing.T) (*fake.Clientset, func (tc *replicaCalcTestCase) runTest(t *testing.T) { testClient, testMetricsClient, testCMClient, testEMClient := tc.prepareTestClient(t) - metricsClient := metrics.NewRESTMetricsClient(testMetricsClient.MetricsV1beta1(), testCMClient, testEMClient) + metricsClient := metricsclient.NewRESTMetricsClient(testMetricsClient.MetricsV1beta1(), testCMClient, testEMClient) replicaCalc := NewReplicaCalculator(metricsClient, testClient.Core(), defaultTestingTolerance, defaultTestingCpuTaintAfterStart, defaultTestingDelayOfInitialReadinessStatus) @@ -357,7 +362,7 @@ func (tc *replicaCalcTestCase) runTest(t *testing.T) { if tc.metric.singleObject == nil { t.Fatal("Metric specified as objectMetric but metric.singleObject is nil.") } - outReplicas, outUtilization, outTimestamp, err = replicaCalc.GetObjectMetricReplicas(tc.currentReplicas, tc.metric.targetUtilization, tc.metric.name, testNamespace, tc.metric.singleObject, selector) + outReplicas, outUtilization, outTimestamp, err = replicaCalc.GetObjectMetricReplicas(tc.currentReplicas, tc.metric.targetUtilization, tc.metric.name, testNamespace, tc.metric.singleObject, selector, nil) case externalMetric: if tc.metric.selector == nil { t.Fatal("Metric specified as externalMetric but metric.selector is nil.") @@ -376,7 +381,7 @@ func (tc *replicaCalcTestCase) runTest(t *testing.T) { outReplicas, outUtilization, outTimestamp, err = replicaCalc.GetExternalPerPodMetricReplicas(tc.currentReplicas, tc.metric.perPodTargetUtilization, tc.metric.name, testNamespace, tc.metric.selector) case podMetric: - outReplicas, outUtilization, outTimestamp, err = replicaCalc.GetMetricReplicas(tc.currentReplicas, tc.metric.targetUtilization, tc.metric.name, testNamespace, selector) + outReplicas, outUtilization, outTimestamp, err = replicaCalc.GetMetricReplicas(tc.currentReplicas, tc.metric.targetUtilization, tc.metric.name, testNamespace, selector, nil) default: t.Fatalf("Unknown metric type: %d", tc.metric.metricType) }