-
Notifications
You must be signed in to change notification settings - Fork 38.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement external metric in HPA #60243
Implement external metric in HPA #60243
Conversation
@MaciekPytel: Adding do-not-merge/release-note-label-needed because the release note process has not been followed. One of the following labels is required "release-note", "release-note-action-required", or "release-note-none". Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comments inline
setCondition(hpa, autoscalingv2.ScalingActive, v1.ConditionFalse, "FailedGetExternalMetric", "the HPA was unable to compute the replica count: %v", err) | ||
return 0, "", nil, time.Time{}, fmt.Errorf("failed to get external metric %s: %v", metricSpec.External.MetricName, err) | ||
} | ||
metricNameProposal = fmt.Sprintf("external metric %s", metricSpec.External.MetricName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should also list label selector here.
@@ -466,8 +467,8 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa | |||
metrics := &cmapi.MetricValueList{} | |||
|
|||
// multiple objects | |||
assert.Equal(t, "pods", getForAction.GetResource().Resource, "the type of object that we requested multiple metrics for should have been pods") | |||
assert.Equal(t, "qps", getForAction.GetMetricName(), "the metric name requested should have been qps, as specified in the metric spec") | |||
assert.Equal(t, "pods", getForAction.GetResource().Resource, fmt.Sprintf("got: %v, want: pods", getForAction.GetResource().Resource)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for the extra fmt.Sprintf
, IIRC -- the terminating arguments here are themselves a format string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, what's with this change -- we already have a "want" and "got" as part of the assert. The message is just providing more context, and the way you've changed it provides less.
|
||
metrics := &emapi.ExternalMetricValueList{} | ||
|
||
assert.Equal(t, "qps", getForAction.GetMetricName(), fmt.Sprintf("got: %v, want: qps", getForAction.GetMetricName())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the message here should be more expressive (see above)
// update number of replicas if the change is large enough | ||
replicaCount = int32(math.Ceil(float64(utilization) / float64(targetUtilizationPerPod))) | ||
} | ||
utilization = int64(math.Ceil(float64(utilization) / float64(currentReplicas))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to follow the same logic as pods
, so it should factor in unready pods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for handling unready pods in pods
is about how to account for such pods when calculating total value of metric. In this case we get a single metric value and just calculate the desired number of pods. I don't see how logic in pods
could apply here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack
@@ -292,7 +326,7 @@ func (tc *replicaCalcTestCase) runTest(t *testing.T) { | |||
require.NoError(t, err, "there should not have been an error calculating the replica count") | |||
assert.Equal(t, tc.expectedReplicas, outReplicas, "replicas should be as expected") | |||
assert.Equal(t, tc.metric.expectedUtilization, outUtilization, "utilization should be as expected") | |||
assert.True(t, tc.timestamp.Equal(outTimestamp), "timestamp should be as expected") | |||
assert.True(t, tc.timestamp.Equal(outTimestamp), fmt.Sprintf("got: %v, want: %v", outTimestamp, tc.timestamp)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, please don't make the message redundant and less expressive
0c0c767
to
d8657e0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor testing nit inline. otherwise looks good
levels: []int64{8600}, | ||
perPodTargetUtilization: 2150, | ||
expectedUtilization: 2867, | ||
selector: &metav1.LabelSelector{}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we get a test that uses LabelSelector and verifies that it's passed through correctly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added LabelSelector to most unittests, created a new test case without it.
// update number of replicas if the change is large enough | ||
replicaCount = int32(math.Ceil(float64(utilization) / float64(targetUtilizationPerPod))) | ||
} | ||
utilization = int64(math.Ceil(float64(utilization) / float64(currentReplicas))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack
d8657e0
to
37204e8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should be good once tests pass
/lgtm |
/retest |
37204e8
to
9928ae0
Compare
/hold cancel |
9928ae0
to
e58411c
Compare
@@ -299,6 +299,45 @@ func (a *HorizontalController) computeReplicasForMetrics(hpa *autoscalingv2.Hori | |||
}, | |||
} | |||
} | |||
case autoscalingv2.ExternalMetricSourceType: | |||
if metricSpec.External.TargetAverageValue != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has it been verified manually E2e?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
CurrentAverageValue: resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), | ||
}, | ||
} | ||
} else if metricSpec.External.TargetValue != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has it been validated manually e2e?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
/approve no-issue |
CurrentValue: *resource.NewMilliQuantity(utilizationProposal, resource.DecimalSI), | ||
}, | ||
} | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a check for this in validate logic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
// GetExternalMetric gets all the values of a given external metric | ||
// that match the specified selector. | ||
GetExternalMetric(metricName string, namespace string, selector labels.Selector) ([]int64, time.Time, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets include Millis in the name of the metrics. It is not obvious from the method name that it returns the value in millis. Here and elsewhere. Can be next PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll do it in a PR later on (it's just a naming change, no functional impact).
/lgtm |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: DirectXMan12, MaciekPytel, mwielgus, wojtek-t The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Automatic merge from submit-queue (batch tested with PRs 60433, 59982, 59128, 60243, 60440). If you want to cherry-pick this change to another branch, please follow the instructions here. |
This implement the changes to HPA introduced in #60096