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
Migrate scheduler api types to sized integers #82283
Migrate scheduler api types to sized integers #82283
Conversation
Hi @ahmad-diaa. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. 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.
/ok-to-test
pkg/scheduler/api/v1/types.go
Outdated
@@ -137,17 +137,17 @@ type RequestedToCapacityRatioArguments struct { | |||
// UtilizationShapePoint represents single point of priority function shape. | |||
type UtilizationShapePoint struct { | |||
// Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100. | |||
Utilization int `json:"utilization"` | |||
Utilization int8 `json:"utilization"` |
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.
I don't think we should change it to int8 which is not common in the k/k
$ ag int8 pkg
pkg/controller/daemon/daemon_controller_test.go
580: for pass := uint8(0); expectedLimit <= podControl.FakePodControl.CreateLimit; pass++ {
pkg/controller/job/job_controller_test.go
360: for pass := uint8(0); expectedLimit <= tc.podLimit; pass++ {
pkg/controller/replicaset/replica_set_test.go
269: for pass := uint8(0); expectedLimit <= fakePodControl.CreateLimit; pass++ {
pkg/kubelet/apis/podresources/v1alpha1/api.pb.go
398: dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
402: dAtA[i] = uint8(l)
412: dAtA[offset] = uint8(v&0x7f | 0x80)
416: dAtA[offset] = uint8(v)
pkg/kubelet/apis/pluginregistration/v1/api.pb.go
309: dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
313: dAtA[i] = uint8(l)
393: dAtA[offset] = uint8(v&0x7f | 0x80)
397: dAtA[offset] = uint8(v)
pkg/kubelet/apis/pluginregistration/v1alpha1/api.pb.go
560: dAtA[offset] = uint8(v&0x7f | 0x80)
564: dAtA[offset] = uint8(v)
pkg/kubelet/apis/pluginregistration/v1beta1/api.pb.go
560: dAtA[offset] = uint8(v&0x7f | 0x80)
564: dAtA[offset] = uint8(v)
pkg/kubelet/apis/deviceplugin/v1alpha/api.pb.go
1169: dAtA[offset] = uint8(v&0x7f | 0x80)
1173: dAtA[offset] = uint8(v)
pkg/kubelet/apis/deviceplugin/v1beta1/api.pb.go
1857: dAtA[offset] = uint8(v&0x7f | 0x80)
1861: dAtA[offset] = uint8(v)
pkg/kubelet/pluginmanager/pluginwatcher/example_plugin_apis/v1beta2/api.pb.go
324: dAtA[offset] = uint8(v&0x7f | 0x80)
328: dAtA[offset] = uint8(v)
pkg/kubelet/pluginmanager/pluginwatcher/example_plugin_apis/v1beta1/api.pb.go
323: dAtA[offset] = uint8(v&0x7f | 0x80)
327: dAtA[offset] = uint8(v)
pkg/registry/core/service/allocator/utils.go
31:var bitCounts = []int8{
pkg/kubectl/cmd/get/sorter.go
174: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
176: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
211: case uint8:
212: if jtype, ok := j.Interface().(uint8); ok {
227: case int8:
228: if jtype, ok := j.Interface().(int8); ok {
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 you think it's better to use int32 like other fields even if it's bounded by (0-100)?
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.
I agree with @draveness, let's prefer int32 and int64.
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.
Done
pkg/scheduler/api/types.go
Outdated
@@ -34,7 +35,7 @@ const ( | |||
// MaxPriority defines the max priority value. | |||
MaxPriority = 10 | |||
// MaxWeight defines the max weight value. | |||
MaxWeight = MaxInt / MaxPriority | |||
MaxWeight = int32(math.MaxInt32 / MaxPriority) |
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.
side note... why are we exporting a MaxInt constant? Maybe we should consider removing it. Can you open an issue for it? cc @ahg-g
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.
Maybe that's because MaxInt is not exported by the math
package and it's used by plugins_test.go
. Is that what you were referring to?
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.
exporting because of a test is a bad reason, specially in an API package.
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.
MaxWeight
could used by the user of kubernetes which could help them to limit the range of weight in extender or prioritiy functions.
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.
@draveness unexporting MaxInt does not have anything to do with keeping MaxWeight Exported. Am I missing anything?
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.
We should ask if we can change the values, I don't know whether or not this is considered part of the v1 API.
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.
We should ask if we can change the values, I don't know whether or not this is considered part of the v1 API.
Previously, a config file could specify a weight up to 9,223,372,036,854,775,807 / 10
, right? This change limits weights to 2,147,483,647 / 10
. Is there a reason not to switch to sized ints at int64 for compatibility?
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, we can do that. I get your point now on what we should be preserving.
pkg/scheduler/api/v1/types.go
Outdated
@@ -137,17 +137,17 @@ type RequestedToCapacityRatioArguments struct { | |||
// UtilizationShapePoint represents single point of priority function shape. | |||
type UtilizationShapePoint struct { | |||
// Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100. | |||
Utilization int `json:"utilization"` | |||
Utilization int8 `json:"utilization"` |
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.
I agree with @draveness, let's prefer int32 and int64.
@@ -39,7 +39,7 @@ type SchedulerExtender interface { | |||
// Prioritize based on extender-implemented priority functions. The returned scores & weight | |||
// are used to compute the weighted score for an extender. The weighted scores are added to | |||
// the scores computed by Kubernetes scheduler. The total scores are used to do the host selection. | |||
Prioritize(pod *v1.Pod, nodes []*v1.Node) (hostPriorities *schedulerapi.HostPriorityList, weight int, err error) | |||
Prioritize(pod *v1.Pod, nodes []*v1.Node) (hostPriorities *schedulerapi.HostPriorityList, weight int32, err 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.
I'm ok with leaving non-API types as int
. It is guaranteed that int
is at least 32 bits.
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.
Done.
pkg/scheduler/api/types.go
Outdated
@@ -86,7 +87,7 @@ type PriorityPolicy struct { | |||
Name string | |||
// The numeric multiplier for the node scores that the priority function generates | |||
// The weight should be a positive integer | |||
Weight int | |||
Weight int32 |
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.
I would say this should be int64, as there is the possibility that some users might be relying on big numbers.
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.
I used the the framework scoring step as a reference:
kubernetes/pkg/scheduler/apis/config/types.go
Lines 196 to 201 in 1855901
type Plugin struct { | |
// Name defines the name of plugin | |
Name string | |
// Weight defines the weight of plugin, only used for Score plugins. | |
Weight int32 | |
} |
Also, don't you think that int32 would be enough to represent a big range of numbers?
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.
I don't have a strong opinion on this. Let's see what other reviewers think.
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.
int32 should be good enough.
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.
unless there's a strong reason not to, keeping int64 for compatibility with all possible existing config files is preferable
@@ -50,7 +50,7 @@ type PriorityConfig struct { | |||
// TODO: Remove it after migrating all functions to | |||
// Map-Reduce pattern. | |||
Function PriorityFunction | |||
Weight int | |||
Weight int32 |
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 leave this one as int too?
@@ -1087,7 +1087,7 @@ func selectVictimsOnNode( | |||
fitPredicates map[string]predicates.FitPredicate, | |||
queue internalqueue.SchedulingQueue, | |||
pdbs []*policy.PodDisruptionBudget, | |||
) ([]*v1.Pod, int, bool) { | |||
) ([]*v1.Pod, int32, bool) { |
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.
is this change necessary? I prefer we just change the API
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.
It wouldn't be safe to return an int then cast it to int32
kubernetes/pkg/scheduler/core/generic_scheduler.go
Lines 1014 to 1021 in 84fe3db
pods, numPDBViolations, fits := selectVictimsOnNode(pod, metaCopy, nodeNameToInfo[nodeName], fitPredicates, queue, pdbs) | |
if fits { | |
resultLock.Lock() | |
victims := schedulerapi.Victims{ | |
Pods: pods, | |
NumPDBViolations: numPDBViolations, | |
} | |
nodeToVictims[potentialNodes[i]] = &victims |
should we change schedulerapi.Victims.NumPDBViolations
to int64 then?
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.
+1 to Aldo's suggestion because even this current code is susceptible to overflow at https://github.com/kubernetes/kubernetes/pull/82283/files#diff-c237cdd9e4cb201118ca380732d7f361R1149.
I suggest you just cast to int32 at line 1018, and keep everything else the same.
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.
changing NumPDBViolations to int64 will solve this issue.
@ahmad-diaa , would you help to send an email to api-machinery group on whether we should keep backward compatibility in code level? for example, the user have to update his code if he import those APIs. |
similar comments on /cc @wgliang |
@liggitt can you please provide guidance here? we are trying to move to sized integers in this old API, we are wondering how we should do that given that this is already a v1 API, can we just change types? what about values of constants, are we allowed to change them? |
The important thing is to be able to continue deserializing config files you previously accepted. The safest way to do that is to switch unsized integers to int64. json/yaml integers can't reliable serialize beyond 52 bits of precision (c.f. #17095), so someone using the highest possible int64 values could run into trouble with other json libraries, but that's less of a concern with config files consumed by a single binary than for REST APIs consumed by lots of clients implemented in lots of languages. |
The APIs we guarantee compatibility on are the REST APIs, config files, CLI flags, and persisted data. We do not guarantee go struct/interface/method compatibility release to release. This PR is changing code inside the kubernetes/kubernetes repo that is not published for consumption as a go library, which is fine. For repos we publish as libraries (things underneath the |
if I understand correctly, this implies that we are allowed to change (or even remove) the constants we define in https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/api/types.go#L27-L41 (those aren't even published under the versioned type: https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/api/v1/types.go). |
pkg/scheduler/factory/plugins.go
Outdated
@@ -385,7 +385,7 @@ func RegisterCustomPriorityFunction(policy schedulerapi.PriorityPolicy) string { | |||
policy.Argument.LabelPreference.Presence, | |||
) | |||
}, | |||
Weight: policy.Weight, | |||
Weight: int(policy.Weight), |
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.
unless there's a strong reason not to, keeping int64 for compatibility with all possible existing config files is preferable
@ahg-g @liggitt @alculquicondor I think this would be a reason to have PriorityPolicy.Weight
as int32 and not int64, otherwise we would change the type of PriorityConfigFactory.Weight
to int64. What do you think?
Great to know that, that'll be easier for us to refine the code :) |
@@ -42,7 +42,7 @@ func NormalizeReduce(maxPriority int, reverse bool) PriorityReduceFunction { | |||
if maxCount == 0 { | |||
if reverse { | |||
for i := range result { | |||
result[i].Score = maxPriority | |||
result[i].Score = int64(maxPriority) |
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.
maybe maxPriority should be int64, as it comes from a constant of an int64 value.
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 you mean changing the type passed to NormalizeReduce
?
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
@@ -80,15 +80,15 @@ func (s *SelectorSpread) CalculateSpreadPriorityMap(pod *v1.Pod, meta interface{ | |||
if len(selectors) == 0 { | |||
return schedulerapi.HostPriority{ | |||
Host: node.Name, | |||
Score: int(0), | |||
Score: int64(0), |
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.
doesn't this just work as Score: 0
?
@@ -261,7 +261,7 @@ func (s *ServiceAntiAffinity) CalculateAntiAffinityPriorityReduce(pod *v1.Pod, m | |||
label, ok := labelNodesStatus[hostPriority.Host] | |||
if !ok { | |||
result[i].Host = hostPriority.Host | |||
result[i].Score = int(0) | |||
result[i].Score = int64(0) |
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.
result[i].Score = 0
should work
@@ -50,7 +50,7 @@ type PriorityConfig struct { | |||
// TODO: Remove it after migrating all functions to | |||
// Map-Reduce pattern. | |||
Function PriorityFunction | |||
Weight int | |||
Weight int64 |
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.
I think this can safely be int
. Even though the API type is int64
, it's value is validated to be less than MaxWeight
before assigning it 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.
For doing so, we should keep MaxWeight as MaxInt/MaxPriority
and avoid changing it to MaxInt64/MaxPriority
.. right?
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 should the same check (to validate that the weight is less than MaxWeight) be added to ExtenderConfigs weight in
if len(extender.PrioritizeVerb) > 0 && extender.Weight <= 0 { |
like the one done in:
if priority.Weight <= 0 || priority.Weight >= schedulerapi.MaxWeight { |
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.
I read that wrong. MaxWeight could still be big. I was thinking of Maxpriority.
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 it be kept as it is then?
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
/lgtm |
// Score assigned to given utilization (y axis). Valid values are 0 to 10. | ||
Score int | ||
Score int32 |
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.
sounds strange that we use int64 here, but int32 in another place below (line 345) for semantically a similar parameter.
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.
That's because at this part values are constrained to (1-100) and (0-10). Do you still think it should be changed?
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.
All of the other cases have the same constraint. So I think we can make all of them int64 or int32.
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.
actually it is not, but still I prefer to make them consistent.
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.
I take that back, I think we should move HostPriority outside the API because it does not belong there.
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 it be moved in another PR, I think this would be out of the scope of this 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.
Also, does that mean that it's ok to keep it as int32 here? or should it be changed to int64 for consistency?
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.
I was just looking at the extender code, it turns out that HostPriorityList is the expected response to one of the extender calls, so we can't move it. This current PR is fine.
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ahg-g, ahmad-diaa 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 |
@ahg-g commits aren't squashed yet. squashing now. |
ab2b20f
to
801cc54
Compare
/lgtm thanks for the squash |
/hold |
/retest |
/hold cancel |
What type of PR is this?
/kind bug
What this PR does / why we need it:
Migrating
int
types to fixed sizes in https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/api/types.go and https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/api/v1/types.go. Having different integer fields led to difficulty in encoding and decoding between both types.Which issue(s) this PR fixes:
Fixes #82138
Special notes for your reviewer:
Does this PR introduce a user-facing change?:
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: