Skip to content

Commit cf7662d

Browse files
authored
Merge pull request kubernetes#79035 from josephburnett/hparunaway
Fix HPA feedback from writing status.replicas to spec.replicas.
2 parents 6b5f551 + 39c4875 commit cf7662d

File tree

3 files changed

+24
-23
lines changed

3 files changed

+24
-23
lines changed

pkg/controller/podautoscaler/horizontal.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,8 @@ func (a *HorizontalController) processNextWorkItem() bool {
235235
func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.HorizontalPodAutoscaler, scale *autoscalingv1.Scale,
236236
metricSpecs []autoscalingv2.MetricSpec) (replicas int32, metric string, statuses []autoscalingv2.MetricStatus, timestamp time.Time, err error) {
237237

238-
currentReplicas := scale.Status.Replicas
238+
specReplicas := scale.Spec.Replicas
239+
statusReplicas := scale.Status.Replicas
239240

240241
statuses = make([]autoscalingv2.MetricStatus, len(metricSpecs))
241242

@@ -258,7 +259,7 @@ func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.Hori
258259
var invalidMetricError error
259260

260261
for i, metricSpec := range metricSpecs {
261-
replicaCountProposal, metricNameProposal, timestampProposal, err := a.computeReplicasForMetric(hpa, metricSpec, currentReplicas, selector, &statuses[i])
262+
replicaCountProposal, metricNameProposal, timestampProposal, err := a.computeReplicasForMetric(hpa, metricSpec, specReplicas, statusReplicas, selector, &statuses[i])
262263

263264
if err != nil {
264265
invalidMetricsCount++
@@ -274,7 +275,7 @@ func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.Hori
274275
// If all metrics are invalid or some are invalid and we would scale down,
275276
// return an error and set the condition of the hpa based on the first invalid metric.
276277
// Otherwise set the condition as scaling active as we're going to scale
277-
if invalidMetricsCount >= len(metricSpecs) || (invalidMetricsCount > 0 && replicas < currentReplicas) {
278+
if invalidMetricsCount >= len(metricSpecs) || (invalidMetricsCount > 0 && replicas < specReplicas) {
278279
return 0, "", statuses, time.Time{}, fmt.Errorf("Invalid metrics (%v invalid out of %v), last error was: %v", invalidMetricsCount, len(metricSpecs), invalidMetricError)
279280
} else {
280281
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionTrue, "ValidMetricFound", "the HPA was able to successfully calculate a replica count from %v", metric)
@@ -284,7 +285,7 @@ func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.Hori
284285

285286
// computeReplicasForMetric computes the desired number of replicas for for a specific hpa and single metric specification.
286287
func (a *HorizontalController) computeReplicasForMetric(hpa *autoscalingv2.HorizontalPodAutoscaler, spec autoscalingv2.MetricSpec,
287-
currentReplicas int32, selector labels.Selector, status *autoscalingv2.MetricStatus) (replicaCountProposal int32, metricNameProposal string,
288+
specReplicas, statusReplicas int32, selector labels.Selector, status *autoscalingv2.MetricStatus) (replicaCountProposal int32, metricNameProposal string,
288289
timestampProposal time.Time, err error) {
289290

290291
switch spec.Type {
@@ -295,7 +296,7 @@ func (a *HorizontalController) computeReplicasForMetric(hpa *autoscalingv2.Horiz
295296
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetObjectMetric", "the HPA was unable to compute the replica count: %v", err)
296297
return 0, "", time.Time{}, fmt.Errorf("failed to get object metric value: %v", err)
297298
}
298-
replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForObjectMetric(currentReplicas, spec, hpa, selector, status, metricSelector)
299+
replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForObjectMetric(specReplicas, statusReplicas, spec, hpa, selector, status, metricSelector)
299300
if err != nil {
300301
return 0, "", time.Time{}, fmt.Errorf("failed to get object metric value: %v", err)
301302
}
@@ -306,17 +307,17 @@ func (a *HorizontalController) computeReplicasForMetric(hpa *autoscalingv2.Horiz
306307
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetPodsMetric", "the HPA was unable to compute the replica count: %v", err)
307308
return 0, "", time.Time{}, fmt.Errorf("failed to get pods metric value: %v", err)
308309
}
309-
replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForPodsMetric(currentReplicas, spec, hpa, selector, status, metricSelector)
310+
replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForPodsMetric(specReplicas, spec, hpa, selector, status, metricSelector)
310311
if err != nil {
311312
return 0, "", time.Time{}, fmt.Errorf("failed to get object metric value: %v", err)
312313
}
313314
case autoscalingv2.ResourceMetricSourceType:
314-
replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForResourceMetric(currentReplicas, spec, hpa, selector, status)
315+
replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForResourceMetric(specReplicas, spec, hpa, selector, status)
315316
if err != nil {
316317
return 0, "", time.Time{}, err
317318
}
318319
case autoscalingv2.ExternalMetricSourceType:
319-
replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForExternalMetric(currentReplicas, spec, hpa, selector, status)
320+
replicaCountProposal, timestampProposal, metricNameProposal, err = a.computeStatusForExternalMetric(specReplicas, statusReplicas, spec, hpa, selector, status)
320321
if err != nil {
321322
return 0, "", time.Time{}, err
322323
}
@@ -346,9 +347,9 @@ func (a *HorizontalController) reconcileKey(key string) (deleted bool, err error
346347
}
347348

348349
// computeStatusForObjectMetric computes the desired number of replicas for the specified metric of type ObjectMetricSourceType.
349-
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) {
350+
func (a *HorizontalController) computeStatusForObjectMetric(specReplicas, statusReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus, metricSelector labels.Selector) (int32, time.Time, string, error) {
350351
if metricSpec.Object.Target.Type == autoscalingv2.ValueMetricType {
351-
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetObjectMetricReplicas(currentReplicas, metricSpec.Object.Target.Value.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, selector, metricSelector)
352+
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetObjectMetricReplicas(specReplicas, metricSpec.Object.Target.Value.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, selector, metricSelector)
352353
if err != nil {
353354
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetObjectMetric", err.Error())
354355
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetObjectMetric", "the HPA was unable to compute the replica count: %v", err)
@@ -369,7 +370,7 @@ func (a *HorizontalController) computeStatusForObjectMetric(currentReplicas int3
369370
}
370371
return replicaCountProposal, timestampProposal, fmt.Sprintf("%s metric %s", metricSpec.Object.DescribedObject.Kind, metricSpec.Object.Metric.Name), nil
371372
} else if metricSpec.Object.Target.Type == autoscalingv2.AverageValueMetricType {
372-
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetObjectPerPodMetricReplicas(currentReplicas, metricSpec.Object.Target.AverageValue.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, metricSelector)
373+
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetObjectPerPodMetricReplicas(statusReplicas, metricSpec.Object.Target.AverageValue.MilliValue(), metricSpec.Object.Metric.Name, hpa.Namespace, &metricSpec.Object.DescribedObject, metricSelector)
373374
if err != nil {
374375
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetObjectMetric", err.Error())
375376
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetObjectMetric", "the HPA was unable to compute the replica count: %v", err)
@@ -472,9 +473,9 @@ func (a *HorizontalController) computeStatusForResourceMetric(currentReplicas in
472473
}
473474

474475
// computeStatusForExternalMetric computes the desired number of replicas for the specified metric of type ExternalMetricSourceType.
475-
func (a *HorizontalController) computeStatusForExternalMetric(currentReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (int32, time.Time, string, error) {
476+
func (a *HorizontalController) computeStatusForExternalMetric(specReplicas, statusReplicas int32, metricSpec autoscalingv2.MetricSpec, hpa *autoscalingv2.HorizontalPodAutoscaler, selector labels.Selector, status *autoscalingv2.MetricStatus) (int32, time.Time, string, error) {
476477
if metricSpec.External.Target.AverageValue != nil {
477-
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalPerPodMetricReplicas(currentReplicas, metricSpec.External.Target.AverageValue.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector)
478+
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalPerPodMetricReplicas(statusReplicas, metricSpec.External.Target.AverageValue.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector)
478479
if err != nil {
479480
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetExternalMetric", err.Error())
480481
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetExternalMetric", "the HPA was unable to compute the replica count: %v", err)
@@ -495,7 +496,7 @@ func (a *HorizontalController) computeStatusForExternalMetric(currentReplicas in
495496
return replicaCountProposal, timestampProposal, fmt.Sprintf("external metric %s(%+v)", metricSpec.External.Metric.Name, metricSpec.External.Metric.Selector), nil
496497
}
497498
if metricSpec.External.Target.Value != nil {
498-
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalMetricReplicas(currentReplicas, metricSpec.External.Target.Value.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector, selector)
499+
replicaCountProposal, utilizationProposal, timestampProposal, err := a.replicaCalc.GetExternalMetricReplicas(specReplicas, metricSpec.External.Target.Value.MilliValue(), metricSpec.External.Metric.Name, hpa.Namespace, metricSpec.External.Metric.Selector, selector)
499500
if err != nil {
500501
a.eventRecorder.Event(hpa, v1.EventTypeWarning, "FailedGetExternalMetric", err.Error())
501502
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetExternalMetric", "the HPA was unable to compute the replica count: %v", err)
@@ -570,7 +571,7 @@ func (a *HorizontalController) reconcileAutoscaler(hpav1Shared *autoscalingv1.Ho
570571
return fmt.Errorf("failed to query scale subresource for %s: %v", reference, err)
571572
}
572573
setCondition(hpa, autoscalingv2.AbleToScale, v1.ConditionTrue, "SucceededGetScale", "the HPA controller was able to get the target's current scale")
573-
currentReplicas := scale.Status.Replicas
574+
currentReplicas := scale.Spec.Replicas
574575
a.recordInitialRecommendation(currentReplicas, key)
575576

576577
var (

pkg/controller/podautoscaler/replica_calculator.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"time"
2323

2424
autoscaling "k8s.io/api/autoscaling/v2beta2"
25-
"k8s.io/api/core/v1"
25+
v1 "k8s.io/api/core/v1"
2626
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2727
"k8s.io/apimachinery/pkg/labels"
2828
"k8s.io/apimachinery/pkg/util/sets"
@@ -259,19 +259,19 @@ func (c *ReplicaCalculator) GetObjectMetricReplicas(currentReplicas int32, targe
259259

260260
// GetObjectPerPodMetricReplicas calculates the desired replica count based on a target metric utilization (as a milli-value)
261261
// for the given object in the given namespace, and the current replica count.
262-
func (c *ReplicaCalculator) GetObjectPerPodMetricReplicas(currentReplicas int32, targetAverageUtilization int64, metricName string, namespace string, objectRef *autoscaling.CrossVersionObjectReference, metricSelector labels.Selector) (replicaCount int32, utilization int64, timestamp time.Time, err error) {
262+
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) {
263263
utilization, timestamp, err = c.metricsClient.GetObjectMetric(metricName, namespace, objectRef, metricSelector)
264264
if err != nil {
265265
return 0, 0, time.Time{}, fmt.Errorf("unable to get metric %s: %v on %s %s/%s", metricName, objectRef.Kind, namespace, objectRef.Name, err)
266266
}
267267

268-
replicaCount = currentReplicas
268+
replicaCount = statusReplicas
269269
usageRatio := float64(utilization) / (float64(targetAverageUtilization) * float64(replicaCount))
270270
if math.Abs(1.0-usageRatio) > c.tolerance {
271271
// update number of replicas if change is large enough
272272
replicaCount = int32(math.Ceil(float64(utilization) / float64(targetAverageUtilization)))
273273
}
274-
utilization = int64(math.Ceil(float64(utilization) / float64(currentReplicas)))
274+
utilization = int64(math.Ceil(float64(utilization) / float64(statusReplicas)))
275275
return replicaCount, utilization, timestamp, nil
276276
}
277277

@@ -334,7 +334,7 @@ func (c *ReplicaCalculator) GetExternalMetricReplicas(currentReplicas int32, tar
334334
// GetExternalPerPodMetricReplicas calculates the desired replica count based on a
335335
// target metric value per pod (as a milli-value) for the external metric in the
336336
// given namespace, and the current replica count.
337-
func (c *ReplicaCalculator) GetExternalPerPodMetricReplicas(currentReplicas int32, targetUtilizationPerPod int64, metricName, namespace string, metricSelector *metav1.LabelSelector) (replicaCount int32, utilization int64, timestamp time.Time, err error) {
337+
func (c *ReplicaCalculator) GetExternalPerPodMetricReplicas(statusReplicas int32, targetUtilizationPerPod int64, metricName, namespace string, metricSelector *metav1.LabelSelector) (replicaCount int32, utilization int64, timestamp time.Time, err error) {
338338
metricLabelSelector, err := metav1.LabelSelectorAsSelector(metricSelector)
339339
if err != nil {
340340
return 0, 0, time.Time{}, err
@@ -348,13 +348,13 @@ func (c *ReplicaCalculator) GetExternalPerPodMetricReplicas(currentReplicas int3
348348
utilization = utilization + val
349349
}
350350

351-
replicaCount = currentReplicas
351+
replicaCount = statusReplicas
352352
usageRatio := float64(utilization) / (float64(targetUtilizationPerPod) * float64(replicaCount))
353353
if math.Abs(1.0-usageRatio) > c.tolerance {
354354
// update number of replicas if the change is large enough
355355
replicaCount = int32(math.Ceil(float64(utilization) / float64(targetUtilizationPerPod)))
356356
}
357-
utilization = int64(math.Ceil(float64(utilization) / float64(currentReplicas)))
357+
utilization = int64(math.Ceil(float64(utilization) / float64(statusReplicas)))
358358
return replicaCount, utilization, timestamp, nil
359359
}
360360

pkg/controller/podautoscaler/replica_calculator_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"time"
2424

2525
autoscalingv2 "k8s.io/api/autoscaling/v2beta2"
26-
"k8s.io/api/core/v1"
26+
v1 "k8s.io/api/core/v1"
2727
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
2828
"k8s.io/apimachinery/pkg/api/resource"
2929
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

0 commit comments

Comments
 (0)