requested changes: fix return type variables

This commit is contained in:
Kushagra 2022-09-22 08:59:02 +00:00
parent cbea8d2248
commit 01b553145c
4 changed files with 73 additions and 73 deletions

View File

@ -373,7 +373,7 @@ func (a *HorizontalController) reconcileKey(ctx context.Context, key string) (de
// computeStatusForObjectMetric computes the desired number of replicas for the specified metric of type ObjectMetricSourceType. // computeStatusForObjectMetric computes the desired number of replicas for the specified metric of type ObjectMetricSourceType.
func (a *HorizontalController) computeStatusForObjectMetric(specReplicas, statusReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus, metricSelector labels.Selector) (replicas int32, timestamp time.Time, metricName string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) { func (a *HorizontalController) computeStatusForObjectMetric(specReplicas, statusReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus, metricSelector labels.Selector) (replicas int32, timestamp time.Time, metricName string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) {
if metricSpec.Object.Target.Type == autoscalingv2.ValueMetricType { if metricSpec.Object.Target.Type == autoscalingv2.ValueMetricType {
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetObjectMetricReplicas(specReplicas, metricSpec.Object.Target.Value.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, selector, metricSelector) replicaCountProposal, usageProposal, timestampProposal, err := a.replicaCalc.GetObjectMetricReplicas(specReplicas, metricSpec.Object.Target.Value.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, selector, metricSelector)
if err != nil { if err != nil {
condition := a.getUnableComputeReplicaCountCondition(hpa, "FailedGetObjectMetric", err) condition := a.getUnableComputeReplicaCountCondition(hpa, "FailedGetObjectMetric", err)
return 0, timestampProposal, "", condition, err return 0, timestampProposal, "", condition, err
@ -387,13 +387,13 @@ func (a *HorizontalController) computeStatusForObjectMetric(specReplicas, status
Selector: metricSpec.Object.Metric.Selector, Selector: metricSpec.Object.Metric.Selector,
}, },
Current: autoscalingv2.MetricValueStatus{ Current: autoscalingv2.MetricValueStatus{
Value: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), Value: resource.NewMilliQuantity(usageProposal, resource.DecimalSI),
}, },
}, },
} }
return replicaCountProposal, timestampProposal, fmt.Sprintf("%s metric %s", metricSpec.Object.DescribedObject.Kind, metricSpec.Object.Metric.Name), autoscalingv2.HorizontalPodAutoscalerCondition{}, nil return replicaCountProposal, timestampProposal, fmt.Sprintf("%s metric %s", metricSpec.Object.DescribedObject.Kind, metricSpec.Object.Metric.Name), autoscalingv2.HorizontalPodAutoscalerCondition{}, nil
} else if metricSpec.Object.Target.Type == autoscalingv2.AverageValueMetricType { } else if metricSpec.Object.Target.Type == autoscalingv2.AverageValueMetricType {
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetObjectPerPodMetricReplicas(statusReplicas, metricSpec.Object.Target.AverageValue.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, metricSelector) replicaCountProposal, usageProposal, timestampProposal, err := a.replicaCalc.GetObjectPerPodMetricReplicas(statusReplicas, metricSpec.Object.Target.AverageValue.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, metricSelector)
if err != nil { if err != nil {
condition := a.getUnableComputeReplicaCountCondition(hpa, "FailedGetObjectMetric", err) condition := a.getUnableComputeReplicaCountCondition(hpa, "FailedGetObjectMetric", err)
return 0, time.Time{}, "", condition, fmt.Errorf("failed to get %s object metric: %v", metricSpec.Object.Metric.Name, err) return 0, time.Time{}, "", condition, fmt.Errorf("failed to get %s object metric: %v", metricSpec.Object.Metric.Name, err)
@ -406,7 +406,7 @@ func (a *HorizontalController) computeStatusForObjectMetric(specReplicas, status
Selector: metricSpec.Object.Metric.Selector, Selector: metricSpec.Object.Metric.Selector,
}, },
Current: autoscalingv2.MetricValueStatus{ Current: autoscalingv2.MetricValueStatus{
AverageValue: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), AverageValue: resource.NewMilliQuantity(usageProposal, resource.DecimalSI),
}, },
}, },
} }
@ -420,7 +420,7 @@ func (a *HorizontalController) computeStatusForObjectMetric(specReplicas, status
// computeStatusForPodsMetric computes the desired number of replicas for the specified metric of type PodsMetricSourceType. // 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, metricSelector labels.Selector) (replicaCountProposal int32, timestampProposal time.Time, metricNameProposal string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) { func (a *HorizontalController) computeStatusForPodsMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus, metricSelector labels.Selector) (replicaCountProposal int32, timestampProposal time.Time, metricNameProposal string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) {
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetMetricReplicas(currentReplicas, metricSpec.Pods.Target.AverageValue.MilliValue(), metricSpec.Pods.Metric.Name, hpa.Namespace, selector, metricSelector) replicaCountProposal, usageProposal, timestampProposal, err := a.replicaCalc.GetMetricReplicas(currentReplicas, metricSpec.Pods.Target.AverageValue.MilliValue(), metricSpec.Pods.Metric.Name, hpa.Namespace, selector, metricSelector)
if err != nil { if err != nil {
condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetPodsMetric", err) condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetPodsMetric", err)
return 0, timestampProposal, "", condition, err return 0, timestampProposal, "", condition, err
@ -433,7 +433,7 @@ func (a *HorizontalController) computeStatusForPodsMetric(currentReplicas int32,
Selector: metricSpec.Pods.Metric.Selector, Selector: metricSpec.Pods.Metric.Selector,
}, },
Current: autoscalingv2.MetricValueStatus{ Current: autoscalingv2.MetricValueStatus{
AverageValue: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), AverageValue: resource.NewMilliQuantity(usageProposal, resource.DecimalSI),
}, },
}, },
} }
@ -449,7 +449,7 @@ func (a *HorizontalController) computeStatusForResourceMetricGeneric(ctx context
var rawProposal int64 var rawProposal int64
replicaCountProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetRawResourceReplicas(ctx, currentReplicas, target.AverageValue.MilliValue(), resourceName, namespace, selector, container) replicaCountProposal, rawProposal, timestampProposal, err := a.replicaCalc.GetRawResourceReplicas(ctx, currentReplicas, target.AverageValue.MilliValue(), resourceName, namespace, selector, container)
if err != nil { if err != nil {
return 0, nil, time.Time{}, "", condition, fmt.Errorf("failed to get %s utilization: %v", resourceName, err) return 0, nil, time.Time{}, "", condition, fmt.Errorf("failed to get %s usage: %v", resourceName, err)
} }
metricNameProposal = fmt.Sprintf("%s resource", resourceName.String()) metricNameProposal = fmt.Sprintf("%s resource", resourceName.String())
status := autoscalingv2.MetricValueStatus{ status := autoscalingv2.MetricValueStatus{
@ -459,7 +459,7 @@ func (a *HorizontalController) computeStatusForResourceMetricGeneric(ctx context
} }
if target.AverageUtilization == nil { if target.AverageUtilization == nil {
errMsg := "invalid resource metric source: neither an average utilization target nor an average value target was set" errMsg := "invalid resource metric source: neither an average utilization target nor an average value (usage) target was set"
return 0, nil, time.Time{}, "", condition, fmt.Errorf(errMsg) return 0, nil, time.Time{}, "", condition, fmt.Errorf(errMsg)
} }
@ -519,7 +519,7 @@ func (a *HorizontalController) computeStatusForContainerResourceMetric(ctx conte
// computeStatusForExternalMetric computes the desired number of replicas for the specified metric of type ExternalMetricSourceType. // computeStatusForExternalMetric computes the desired number of replicas for the specified metric of type ExternalMetricSourceType.
func (a *HorizontalController) computeStatusForExternalMetric(specReplicas, statusReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (replicaCountProposal int32, timestampProposal time.Time, metricNameProposal string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) { func (a *HorizontalController) computeStatusForExternalMetric(specReplicas, statusReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (replicaCountProposal int32, timestampProposal time.Time, metricNameProposal string, condition autoscalingv2.HorizontalPodAutoscalerCondition, err error) {
if metricSpec.External.Target.AverageValue != nil { if metricSpec.External.Target.AverageValue != nil {
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalPerPodMetricReplicas(statusReplicas, metricSpec.External.Target.AverageValue.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector) replicaCountProposal, usageProposal, timestampProposal, err := a.replicaCalc.GetExternalPerPodMetricReplicas(statusReplicas, metricSpec.External.Target.AverageValue.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector)
if err != nil { if err != nil {
condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetExternalMetric", err) condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetExternalMetric", err)
return 0, time.Time{}, "", condition, fmt.Errorf("failed to get %s external metric: %v", metricSpec.External.Metric.Name, err) return 0, time.Time{}, "", condition, fmt.Errorf("failed to get %s external metric: %v", metricSpec.External.Metric.Name, err)
@ -532,14 +532,14 @@ func (a *HorizontalController) computeStatusForExternalMetric(specReplicas, stat
Selector: metricSpec.External.Metric.Selector, Selector: metricSpec.External.Metric.Selector,
}, },
Current: autoscalingv2.MetricValueStatus{ Current: autoscalingv2.MetricValueStatus{
AverageValue: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), AverageValue: resource.NewMilliQuantity(usageProposal, resource.DecimalSI),
}, },
}, },
} }
return replicaCountProposal, timestampProposal, fmt.Sprintf("external metric %s(%+v)", metricSpec.External.Metric.Name, metricSpec.External.Metric.Selector), autoscalingv2.HorizontalPodAutoscalerCondition{}, nil return replicaCountProposal, timestampProposal, fmt.Sprintf("external metric %s(%+v)", metricSpec.External.Metric.Name, metricSpec.External.Metric.Selector), autoscalingv2.HorizontalPodAutoscalerCondition{}, nil
} }
if metricSpec.External.Target.Value != nil { if metricSpec.External.Target.Value != nil {
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalMetricReplicas(specReplicas, metricSpec.External.Target.Value.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector, selector) replicaCountProposal, usageProposal, timestampProposal, err := a.replicaCalc.GetExternalMetricReplicas(specReplicas, metricSpec.External.Target.Value.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector, selector)
if err != nil { if err != nil {
condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetExternalMetric", err) condition = a.getUnableComputeReplicaCountCondition(hpa, "FailedGetExternalMetric", err)
return 0, time.Time{}, "", condition, fmt.Errorf("failed to get external metric %s: %v", metricSpec.External.Metric.Name, err) return 0, time.Time{}, "", condition, fmt.Errorf("failed to get external metric %s: %v", metricSpec.External.Metric.Name, err)
@ -552,7 +552,7 @@ func (a *HorizontalController) computeStatusForExternalMetric(specReplicas, stat
Selector: metricSpec.External.Metric.Selector, Selector: metricSpec.External.Metric.Selector,
}, },
Current: autoscalingv2.MetricValueStatus{ Current: autoscalingv2.MetricValueStatus{
Value: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), Value: resource.NewMilliQuantity(usageProposal, resource.DecimalSI),
}, },
}, },
} }

View File

@ -51,16 +51,16 @@ func GetResourceUtilizationRatio(metrics PodMetricsInfo, requests map[string]int
return float64(currentUtilization) / float64(targetUtilization), currentUtilization, metricsTotal / int64(numEntries), nil return float64(currentUtilization) / float64(targetUtilization), currentUtilization, metricsTotal / int64(numEntries), nil
} }
// GetMetricUtilizationRatio takes in a set of metrics and a target utilization value, // GetMetricUsageRatio takes in a set of metrics and a target usage value,
// and calculates the ratio of desired to actual utilization // and calculates the ratio of desired to actual usage
// (returning that and the actual utilization) // (returning that and the actual usage)
func GetMetricUtilizationRatio(metrics PodMetricsInfo, targetUtilization int64) (utilizationRatio float64, currentUtilization int64) { func GetMetricUsageRatio(metrics PodMetricsInfo, targetUsage int64) (usageRatio float64, currentUsage int64) {
metricsTotal := int64(0) metricsTotal := int64(0)
for _, metric := range metrics { for _, metric := range metrics {
metricsTotal += metric.Value metricsTotal += metric.Value
} }
currentUtilization = metricsTotal / int64(len(metrics)) currentUsage = metricsTotal / int64(len(metrics))
return float64(currentUtilization) / float64(targetUtilization), currentUtilization return float64(currentUsage) / float64(targetUsage), currentUsage
} }

View File

@ -49,19 +49,19 @@ func (tc *resourceUtilizationRatioTestCase) runTest(t *testing.T) {
assert.Equal(t, tc.expectedRawAverageValue, actualRawAverageValue, "the raw average value should be as expected") assert.Equal(t, tc.expectedRawAverageValue, actualRawAverageValue, "the raw average value should be as expected")
} }
type metricUtilizationRatioTestCase struct { type metricUsageRatioTestCase struct {
metrics PodMetricsInfo metrics PodMetricsInfo
targetUtilization int64 targetUsage int64
expectedUtilizationRatio float64 expectedUsageRatio float64
expectedCurrentUtilization int64 expectedCurrentUsage int64
} }
func (tc *metricUtilizationRatioTestCase) runTest(t *testing.T) { func (tc *metricUsageRatioTestCase) runTest(t *testing.T) {
actualUtilizationRatio, actualCurrentUtilization := GetMetricUtilizationRatio(tc.metrics, tc.targetUtilization) actualUsageRatio, actualCurrentUsage := GetMetricUsageRatio(tc.metrics, tc.targetUsage)
assert.Equal(t, tc.expectedUtilizationRatio, actualUtilizationRatio, "the utilization ratios should be as expected") assert.Equal(t, tc.expectedUsageRatio, actualUsageRatio, "the usage ratios should be as expected")
assert.Equal(t, tc.expectedCurrentUtilization, actualCurrentUtilization, "the current utilization should be as expected") assert.Equal(t, tc.expectedCurrentUsage, actualCurrentUsage, "the current usage should be as expected")
} }
func TestGetResourceUtilizationRatioBaseCase(t *testing.T) { func TestGetResourceUtilizationRatioBaseCase(t *testing.T) {
@ -135,14 +135,14 @@ func TestGetResourceUtilizationRatioNoRequests(t *testing.T) {
tc.runTest(t) tc.runTest(t)
} }
func TestGetMetricUtilizationRatioBaseCase(t *testing.T) { func TestGetMetricUsageRatioBaseCase(t *testing.T) {
tc := metricUtilizationRatioTestCase{ tc := metricUsageRatioTestCase{
metrics: PodMetricsInfo{ metrics: PodMetricsInfo{
"test-pod-0": {Value: 5000}, "test-pod-1": {Value: 10000}, "test-pod-0": {Value: 5000}, "test-pod-1": {Value: 10000},
}, },
targetUtilization: 10000, targetUsage: 10000,
expectedUtilizationRatio: .75, expectedUsageRatio: .75,
expectedCurrentUtilization: 7500, expectedCurrentUsage: 7500,
} }
tc.runTest(t) tc.runTest(t)

View File

@ -149,33 +149,33 @@ func (c *ReplicaCalculator) GetResourceReplicas(ctx context.Context, currentRepl
return newReplicas, utilization, rawUtilization, timestamp, nil return newReplicas, utilization, rawUtilization, timestamp, nil
} }
// GetRawResourceReplicas calculates the desired replica count based on a target resource utilization (as a raw milli-value) // GetRawResourceReplicas calculates the desired replica count based on a target resource usage (as a raw milli-value)
// for pods matching the given selector in the given namespace, and the current replica count // for pods matching the given selector in the given namespace, and the current replica count
func (c *ReplicaCalculator) GetRawResourceReplicas(ctx context.Context, currentReplicas int32, targetUsage int64, resource v1.ResourceName, namespace string, selector labels.Selector, container string) (replicaCount int32, utilization int64, timestamp time.Time, err error) { func (c *ReplicaCalculator) GetRawResourceReplicas(ctx context.Context, currentReplicas int32, targetUsage int64, resource v1.ResourceName, namespace string, selector labels.Selector, container string) (replicaCount int32, usage int64, timestamp time.Time, err error) {
metrics, timestamp, err := c.metricsClient.GetResourceMetric(ctx, resource, namespace, selector, container) metrics, timestamp, err := c.metricsClient.GetResourceMetric(ctx, resource, namespace, selector, container)
if err != nil { if err != nil {
return 0, 0, time.Time{}, fmt.Errorf("unable to get metrics for resource %s: %v", resource, err) return 0, 0, time.Time{}, fmt.Errorf("unable to get metrics for resource %s: %v", resource, err)
} }
replicaCount, utilization, err = c.calcPlainMetricReplicas(metrics, currentReplicas, targetUsage, namespace, selector, resource) replicaCount, usage, err = c.calcPlainMetricReplicas(metrics, currentReplicas, targetUsage, namespace, selector, resource)
return replicaCount, utilization, timestamp, err return replicaCount, usage, timestamp, err
} }
// GetMetricReplicas calculates the desired replica count based on a target metric utilization // GetMetricReplicas calculates the desired replica count based on a target metric usage
// (as a milli-value) for pods matching the given selector in the given namespace, and the // (as a milli-value) for pods matching the given selector in the given namespace, and the
// current replica count // current replica count
func (c *ReplicaCalculator) GetMetricReplicas(currentReplicas int32, targetUsage int64, metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { func (c *ReplicaCalculator) GetMetricReplicas(currentReplicas int32, targetUsage int64, metricName string, namespace string, selector labels.Selector, metricSelector labels.Selector) (replicaCount int32, usage int64, timestamp time.Time, err error) {
metrics, timestamp, err := c.metricsClient.GetRawMetric(metricName, namespace, selector, metricSelector) metrics, timestamp, err := c.metricsClient.GetRawMetric(metricName, namespace, selector, metricSelector)
if err != nil { if err != nil {
return 0, 0, time.Time{}, fmt.Errorf("unable to get metric %s: %v", metricName, err) return 0, 0, time.Time{}, fmt.Errorf("unable to get metric %s: %v", metricName, err)
} }
replicaCount, utilization, err = c.calcPlainMetricReplicas(metrics, currentReplicas, targetUsage, namespace, selector, v1.ResourceName("")) replicaCount, usage, err = c.calcPlainMetricReplicas(metrics, currentReplicas, targetUsage, namespace, selector, v1.ResourceName(""))
return replicaCount, utilization, timestamp, err return replicaCount, usage, timestamp, err
} }
// calcPlainMetricReplicas calculates the desired replicas for plain (i.e. non-utilization percentage) metrics. // calcPlainMetricReplicas calculates the desired replicas for plain (i.e. non-utilization percentage) metrics.
func (c *ReplicaCalculator) calcPlainMetricReplicas(metrics metricsclient.PodMetricsInfo, currentReplicas int32, targetUsage int64, namespace string, selector labels.Selector, resource v1.ResourceName) (replicaCount int32, utilization int64, err error) { func (c *ReplicaCalculator) calcPlainMetricReplicas(metrics metricsclient.PodMetricsInfo, currentReplicas int32, targetUsage int64, namespace string, selector labels.Selector, resource v1.ResourceName) (replicaCount int32, usage int64, err error) {
podList, err := c.podLister.Pods(namespace).List(selector) podList, err := c.podLister.Pods(namespace).List(selector)
if err != nil { if err != nil {
@ -194,18 +194,18 @@ func (c *ReplicaCalculator) calcPlainMetricReplicas(metrics metricsclient.PodMet
return 0, 0, fmt.Errorf("did not receive metrics for any ready pods") return 0, 0, fmt.Errorf("did not receive metrics for any ready pods")
} }
usageRatio, utilization := metricsclient.GetMetricUtilizationRatio(metrics, targetUsage) usageRatio, usage := metricsclient.GetMetricUsageRatio(metrics, targetUsage)
scaleUpWithUnready := len(unreadyPods) > 0 && usageRatio > 1.0 scaleUpWithUnready := len(unreadyPods) > 0 && usageRatio > 1.0
if !scaleUpWithUnready && len(missingPods) == 0 { if !scaleUpWithUnready && len(missingPods) == 0 {
if math.Abs(1.0-usageRatio) <= c.tolerance { if math.Abs(1.0-usageRatio) <= c.tolerance {
// return the current replicas if the change would be too small // return the current replicas if the change would be too small
return currentReplicas, utilization, nil return currentReplicas, usage, nil
} }
// if we don't have any unready or missing pods, we can calculate the new replica count now // if we don't have any unready or missing pods, we can calculate the new replica count now
return int32(math.Ceil(usageRatio * float64(readyPodCount))), utilization, nil return int32(math.Ceil(usageRatio * float64(readyPodCount))), usage, nil
} }
if len(missingPods) > 0 { if len(missingPods) > 0 {
@ -229,37 +229,37 @@ func (c *ReplicaCalculator) calcPlainMetricReplicas(metrics metricsclient.PodMet
} }
} }
// re-run the utilization calculation with our new numbers // re-run the usage calculation with our new numbers
newUsageRatio, _ := metricsclient.GetMetricUtilizationRatio(metrics, targetUsage) newUsageRatio, _ := metricsclient.GetMetricUsageRatio(metrics, targetUsage)
if math.Abs(1.0-newUsageRatio) <= c.tolerance || (usageRatio < 1.0 && newUsageRatio > 1.0) || (usageRatio > 1.0 && newUsageRatio < 1.0) { if math.Abs(1.0-newUsageRatio) <= c.tolerance || (usageRatio < 1.0 && newUsageRatio > 1.0) || (usageRatio > 1.0 && newUsageRatio < 1.0) {
// return the current replicas if the change would be too small, // return the current replicas if the change would be too small,
// or if the new usage ratio would cause a change in scale direction // or if the new usage ratio would cause a change in scale direction
return currentReplicas, utilization, nil return currentReplicas, usage, nil
} }
newReplicas := int32(math.Ceil(newUsageRatio * float64(len(metrics)))) newReplicas := int32(math.Ceil(newUsageRatio * float64(len(metrics))))
if (newUsageRatio < 1.0 && newReplicas > currentReplicas) || (newUsageRatio > 1.0 && newReplicas < currentReplicas) { if (newUsageRatio < 1.0 && newReplicas > currentReplicas) || (newUsageRatio > 1.0 && newReplicas < currentReplicas) {
// return the current replicas if the change of metrics length would cause a change in scale direction // return the current replicas if the change of metrics length would cause a change in scale direction
return currentReplicas, utilization, nil return currentReplicas, usage, nil
} }
// return the result, where the number of replicas considered is // return the result, where the number of replicas considered is
// however many replicas factored into our calculation // however many replicas factored into our calculation
return newReplicas, utilization, nil return newReplicas, usage, nil
} }
// GetObjectMetricReplicas calculates the desired replica count based on a target metric utilization (as a milli-value) // GetObjectMetricReplicas calculates the desired replica count based on a target metric usage (as a milli-value)
// for the given object in the given namespace, and the current replica count. // for the given object in the given namespace, and the current replica count.
func (c *ReplicaCalculator) GetObjectMetricReplicas(currentReplicas int32, targetUsage int64, metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, selector labels.Selector, metricSelector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { func (c *ReplicaCalculator) GetObjectMetricReplicas(currentReplicas int32, targetUsage int64, metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, selector labels.Selector, metricSelector labels.Selector) (replicaCount int32, usage int64, timestamp time.Time, err error) {
utilization, _, err = c.metricsClient.GetObjectMetric(metricName, namespace, objectRef, metricSelector) usage, _, err = c.metricsClient.GetObjectMetric(metricName, namespace, objectRef, metricSelector)
if err != nil { 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) return 0, 0, time.Time{}, fmt.Errorf("unable to get metric %s: %v on %s %s/%s", metricName, objectRef.Kind, namespace, objectRef.Name, err)
} }
usageRatio := float64(utilization) / float64(targetUsage) usageRatio := float64(usage) / float64(targetUsage)
replicaCount, timestamp, err = c.getUsageRatioReplicaCount(currentReplicas, usageRatio, namespace, selector) replicaCount, timestamp, err = c.getUsageRatioReplicaCount(currentReplicas, usageRatio, namespace, selector)
return replicaCount, utilization, timestamp, err return replicaCount, usage, timestamp, err
} }
// getUsageRatioReplicaCount calculates the desired replica count based on usageRatio and ready pods count. // getUsageRatioReplicaCount calculates the desired replica count based on usageRatio and ready pods count.
@ -284,22 +284,22 @@ func (c *ReplicaCalculator) getUsageRatioReplicaCount(currentReplicas int32, usa
return replicaCount, timestamp, err return replicaCount, timestamp, err
} }
// GetObjectPerPodMetricReplicas calculates the desired replica count based on a target metric utilization (as a milli-value) // GetObjectPerPodMetricReplicas calculates the desired replica count based on a target metric usage (as a milli-value)
// for the given object in the given namespace, and the current replica count. // for the given object in the given namespace, and the current replica count.
func (c *ReplicaCalculator) GetObjectPerPodMetricReplicas(statusReplicas int32, targetAverageUtilization int64, metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, metricSelector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { func (c *ReplicaCalculator) GetObjectPerPodMetricReplicas(statusReplicas int32, targetAverageUsage int64, metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, metricSelector labels.Selector) (replicaCount int32, usage int64, timestamp time.Time, err error) {
utilization, timestamp, err = c.metricsClient.GetObjectMetric(metricName, namespace, objectRef, metricSelector) usage, timestamp, err = c.metricsClient.GetObjectMetric(metricName, namespace, objectRef, metricSelector)
if err != nil { 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) return 0, 0, time.Time{}, fmt.Errorf("unable to get metric %s: %v on %s %s/%s", metricName, objectRef.Kind, namespace, objectRef.Name, err)
} }
replicaCount = statusReplicas replicaCount = statusReplicas
usageRatio := float64(utilization) / (float64(targetAverageUtilization) * float64(replicaCount)) usageRatio := float64(usage) / (float64(targetAverageUsage) * float64(replicaCount))
if math.Abs(1.0-usageRatio) > c.tolerance { if math.Abs(1.0-usageRatio) > c.tolerance {
// update number of replicas if change is large enough // update number of replicas if change is large enough
replicaCount = int32(math.Ceil(float64(utilization) / float64(targetAverageUtilization))) replicaCount = int32(math.Ceil(float64(usage) / float64(targetAverageUsage)))
} }
utilization = int64(math.Ceil(float64(utilization) / float64(statusReplicas))) usage = int64(math.Ceil(float64(usage) / float64(statusReplicas)))
return replicaCount, utilization, timestamp, nil return replicaCount, usage, timestamp, nil
} }
// @TODO(mattjmcnaughton) Many different functions in this module use variations // @TODO(mattjmcnaughton) Many different functions in this module use variations
@ -329,7 +329,7 @@ func (c *ReplicaCalculator) getReadyPodsCount(namespace string, selector labels.
// GetExternalMetricReplicas calculates the desired replica count based on a // GetExternalMetricReplicas calculates the desired replica count based on a
// target metric value (as a milli-value) for the external metric in the given // target metric value (as a milli-value) for the external metric in the given
// namespace, and the current replica count. // namespace, and the current replica count.
func (c *ReplicaCalculator) GetExternalMetricReplicas(currentReplicas int32, targetUsage int64, metricName, namespace string, metricSelector *metav1.LabelSelector, podSelector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { func (c *ReplicaCalculator) GetExternalMetricReplicas(currentReplicas int32, targetUsage int64, metricName, namespace string, metricSelector *metav1.LabelSelector, podSelector labels.Selector) (replicaCount int32, usage int64, timestamp time.Time, err error) {
metricLabelSelector, err := metav1.LabelSelectorAsSelector(metricSelector) metricLabelSelector, err := metav1.LabelSelectorAsSelector(metricSelector)
if err != nil { if err != nil {
return 0, 0, time.Time{}, err return 0, 0, time.Time{}, err
@ -338,20 +338,20 @@ func (c *ReplicaCalculator) GetExternalMetricReplicas(currentReplicas int32, tar
if err != nil { if err != nil {
return 0, 0, time.Time{}, fmt.Errorf("unable to get external metric %s/%s/%+v: %s", namespace, metricName, metricSelector, err) return 0, 0, time.Time{}, fmt.Errorf("unable to get external metric %s/%s/%+v: %s", namespace, metricName, metricSelector, err)
} }
utilization = 0 usage = 0
for _, val := range metrics { for _, val := range metrics {
utilization = utilization + val usage = usage + val
} }
usageRatio := float64(utilization) / float64(targetUsage) usageRatio := float64(usage) / float64(targetUsage)
replicaCount, timestamp, err = c.getUsageRatioReplicaCount(currentReplicas, usageRatio, namespace, podSelector) replicaCount, timestamp, err = c.getUsageRatioReplicaCount(currentReplicas, usageRatio, namespace, podSelector)
return replicaCount, utilization, timestamp, err return replicaCount, usage, timestamp, err
} }
// GetExternalPerPodMetricReplicas calculates the desired replica count based on a // GetExternalPerPodMetricReplicas calculates the desired replica count based on a
// target metric value per pod (as a milli-value) for the external metric in the // target metric value per pod (as a milli-value) for the external metric in the
// given namespace, and the current replica count. // given namespace, and the current replica count.
func (c *ReplicaCalculator) GetExternalPerPodMetricReplicas(statusReplicas int32, targetUsagePerPod int64, metricName, namespace string, metricSelector *metav1.LabelSelector) (replicaCount int32, utilization int64, timestamp time.Time, err error) { func (c *ReplicaCalculator) GetExternalPerPodMetricReplicas(statusReplicas int32, targetUsagePerPod int64, metricName, namespace string, metricSelector *metav1.LabelSelector) (replicaCount int32, usage int64, timestamp time.Time, err error) {
metricLabelSelector, err := metav1.LabelSelectorAsSelector(metricSelector) metricLabelSelector, err := metav1.LabelSelectorAsSelector(metricSelector)
if err != nil { if err != nil {
return 0, 0, time.Time{}, err return 0, 0, time.Time{}, err
@ -360,19 +360,19 @@ func (c *ReplicaCalculator) GetExternalPerPodMetricReplicas(statusReplicas int32
if err != nil { if err != nil {
return 0, 0, time.Time{}, fmt.Errorf("unable to get external metric %s/%s/%+v: %s", namespace, metricName, metricSelector, err) return 0, 0, time.Time{}, fmt.Errorf("unable to get external metric %s/%s/%+v: %s", namespace, metricName, metricSelector, err)
} }
utilization = 0 usage = 0
for _, val := range metrics { for _, val := range metrics {
utilization = utilization + val usage = usage + val
} }
replicaCount = statusReplicas replicaCount = statusReplicas
usageRatio := float64(utilization) / (float64(targetUsagePerPod) * float64(replicaCount)) usageRatio := float64(usage) / (float64(targetUsagePerPod) * float64(replicaCount))
if math.Abs(1.0-usageRatio) > c.tolerance { if math.Abs(1.0-usageRatio) > c.tolerance {
// update number of replicas if the change is large enough // update number of replicas if the change is large enough
replicaCount = int32(math.Ceil(float64(utilization) / float64(targetUsagePerPod))) replicaCount = int32(math.Ceil(float64(usage) / float64(targetUsagePerPod)))
} }
utilization = int64(math.Ceil(float64(utilization) / float64(statusReplicas))) usage = int64(math.Ceil(float64(usage) / float64(statusReplicas)))
return replicaCount, utilization, timestamp, nil return replicaCount, usage, timestamp, nil
} }
func groupPods(pods []*v1.Pod, metrics metricsclient.PodMetricsInfo, resource v1.ResourceName, cpuInitializationPeriod, delayOfInitialReadinessStatus time.Duration) (readyPodCount int, unreadyPods, missingPods, ignoredPods sets.String) { func groupPods(pods []*v1.Pod, metrics metricsclient.PodMetricsInfo, resource v1.ResourceName, cpuInitializationPeriod, delayOfInitialReadinessStatus time.Duration) (readyPodCount int, unreadyPods, missingPods, ignoredPods sets.String) {