Skip to content

Commit 3d0f737

Browse files
authored
Merge pull request kubernetes#84816 from liu-cong/nodelabel
Aggregate mulitple NodePreference custom priorities to a single score plugin.
2 parents 6f08d42 + 97d641b commit 3d0f737

File tree

10 files changed

+247
-168
lines changed

10 files changed

+247
-168
lines changed

pkg/scheduler/algorithm/priorities/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ go_test(
6464
"metadata_test.go",
6565
"most_requested_test.go",
6666
"node_affinity_test.go",
67-
"node_label_test.go",
6867
"node_prefer_avoid_pods_test.go",
6968
"requested_to_capacity_ratio_test.go",
7069
"resource_limits_test.go",

pkg/scheduler/algorithm/priorities/node_label.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ import (
2727

2828
// NodeLabelPrioritizer contains information to calculate node label priority.
2929
type NodeLabelPrioritizer struct {
30-
label string
31-
presence bool
30+
presentLabelsPreference []string
31+
absentLabelsPreference []string
3232
}
3333

3434
// NewNodeLabelPriority creates a NodeLabelPrioritizer.
35-
func NewNodeLabelPriority(label string, presence bool) (PriorityMapFunction, PriorityReduceFunction) {
35+
func NewNodeLabelPriority(presentLabelsPreference []string, absentLabelsPreference []string) (PriorityMapFunction, PriorityReduceFunction) {
3636
labelPrioritizer := &NodeLabelPrioritizer{
37-
label: label,
38-
presence: presence,
37+
presentLabelsPreference: presentLabelsPreference,
38+
absentLabelsPreference: absentLabelsPreference,
3939
}
4040
return labelPrioritizer.CalculateNodeLabelPriorityMap, nil
4141
}
@@ -49,11 +49,20 @@ func (n *NodeLabelPrioritizer) CalculateNodeLabelPriorityMap(pod *v1.Pod, meta i
4949
return framework.NodeScore{}, fmt.Errorf("node not found")
5050
}
5151

52-
exists := labels.Set(node.Labels).Has(n.label)
5352
score := int64(0)
54-
if (exists && n.presence) || (!exists && !n.presence) {
55-
score = framework.MaxNodeScore
53+
for _, label := range n.presentLabelsPreference {
54+
if labels.Set(node.Labels).Has(label) {
55+
score += framework.MaxNodeScore
56+
}
5657
}
58+
for _, label := range n.absentLabelsPreference {
59+
if !labels.Set(node.Labels).Has(label) {
60+
score += framework.MaxNodeScore
61+
}
62+
}
63+
// Take average score for each label to ensure the score doesn't exceed MaxNodeScore.
64+
score /= int64(len(n.presentLabelsPreference) + len(n.absentLabelsPreference))
65+
5766
return framework.NodeScore{
5867
Name: node.Name,
5968
Score: score,

pkg/scheduler/algorithm/priorities/node_label_test.go

Lines changed: 0 additions & 127 deletions
This file was deleted.

pkg/scheduler/algorithm_factory.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,15 +400,35 @@ func RegisterCustomPriorityFunction(policy schedulerapi.PriorityPolicy, args *pl
400400
Weight: policy.Weight,
401401
}
402402
} else if policy.Argument.LabelPreference != nil {
403+
// We use the NodeLabel plugin name for all NodeLabel custom priorities.
404+
// It may get called multiple times but we essentially only register one instance of NodeLabel priority.
405+
// This name is then used to find the registered plugin and run the plugin instead of the priority.
406+
name = nodelabel.Name
407+
if args.NodeLabelArgs == nil {
408+
args.NodeLabelArgs = &nodelabel.Args{}
409+
}
410+
if policy.Argument.LabelPreference.Presence {
411+
args.NodeLabelArgs.PresentLabelsPreference = append(args.NodeLabelArgs.PresentLabelsPreference, policy.Argument.LabelPreference.Label)
412+
} else {
413+
args.NodeLabelArgs.AbsentLabelsPreference = append(args.NodeLabelArgs.AbsentLabelsPreference, policy.Argument.LabelPreference.Label)
414+
}
415+
schedulerFactoryMutex.RLock()
416+
weight := policy.Weight
417+
if existing, ok := priorityFunctionMap[name]; ok {
418+
// If there are n NodeLabel priority configured in the policy, the weight for the corresponding
419+
// priority is n*(weight of each priority in policy).
420+
weight += existing.Weight
421+
}
403422
pcf = &PriorityConfigFactory{
404-
MapReduceFunction: func(args PluginFactoryArgs) (priorities.PriorityMapFunction, priorities.PriorityReduceFunction) {
423+
MapReduceFunction: func(_ PluginFactoryArgs) (priorities.PriorityMapFunction, priorities.PriorityReduceFunction) {
405424
return priorities.NewNodeLabelPriority(
406-
policy.Argument.LabelPreference.Label,
407-
policy.Argument.LabelPreference.Presence,
425+
args.NodeLabelArgs.PresentLabelsPreference,
426+
args.NodeLabelArgs.AbsentLabelsPreference,
408427
)
409428
},
410-
Weight: policy.Weight,
429+
Weight: weight,
411430
}
431+
schedulerFactoryMutex.RUnlock()
412432
} else if policy.Argument.RequestedToCapacityRatioArguments != nil {
413433
scoringFunctionShape, resources := buildScoringFunctionShapeFromRequestedToCapacityRatioArguments(policy.Argument.RequestedToCapacityRatioArguments)
414434
args.RequestedToCapacityRatioArgs = &requestedtocapacityratio.Args{

pkg/scheduler/apis/config/testing/compatibility_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
103103
wantPrioritizers: sets.NewString(
104104
"ServiceSpreadingPriority",
105105
"TestServiceAntiAffinity",
106-
"TestLabelPreference",
107106
),
108107
wantPlugins: map[string][]config.Plugin{
109108
"FilterPlugin": {
@@ -116,6 +115,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
116115
},
117116
"ScorePlugin": {
118117
{Name: "NodeResourcesLeastAllocated", Weight: 1},
118+
{Name: "NodeLabel", Weight: 4},
119119
},
120120
},
121121
},
@@ -151,7 +151,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
151151
"EqualPriority",
152152
"SelectorSpreadPriority",
153153
"TestServiceAntiAffinity",
154-
"TestLabelPreference",
155154
),
156155
wantPlugins: map[string][]config.Plugin{
157156
"FilterPlugin": {
@@ -167,6 +166,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
167166
"ScorePlugin": {
168167
{Name: "NodeResourcesBalancedAllocation", Weight: 2},
169168
{Name: "NodeResourcesLeastAllocated", Weight: 2},
169+
{Name: "NodeLabel", Weight: 4},
170170
},
171171
},
172172
},
@@ -207,7 +207,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
207207
"EqualPriority",
208208
"SelectorSpreadPriority",
209209
"TestServiceAntiAffinity",
210-
"TestLabelPreference",
211210
),
212211
wantPlugins: map[string][]config.Plugin{
213212
"FilterPlugin": {
@@ -229,6 +228,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
229228
{Name: "ImageLocality", Weight: 2},
230229
{Name: "NodeResourcesLeastAllocated", Weight: 2},
231230
{Name: "NodeAffinity", Weight: 2},
231+
{Name: "NodeLabel", Weight: 4},
232232
},
233233
},
234234
},
@@ -1263,6 +1263,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
12631263
"NodeResourcesBalancedAllocation": "BalancedResourceAllocation",
12641264
"NodeResourcesMostAllocated": "MostRequestedPriority",
12651265
"RequestedToCapacityRatio": "RequestedToCapacityRatioPriority",
1266+
"NodeLabel": "TestLabelPreference",
12661267
}
12671268

12681269
for _, tc := range testcases {

pkg/scheduler/factory_test.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ func TestCreateFromConfig(t *testing.T) {
9898
],
9999
"priorities" : [
100100
{"name" : "RackSpread", "weight" : 3, "argument" : {"serviceAntiAffinity" : {"label" : "rack"}}},
101+
{"name" : "LabelPreference1", "weight" : 3, "argument" : {"labelPreference" : {"label" : "l1", "presence": true}}},
102+
{"name" : "LabelPreference2", "weight" : 3, "argument" : {"labelPreference" : {"label" : "l2", "presence": false}}},
101103
{"name" : "PriorityOne", "weight" : 2},
102104
{"name" : "PriorityTwo", "weight" : 1} ]
103105
}`)
@@ -114,29 +116,36 @@ func TestCreateFromConfig(t *testing.T) {
114116
t.Errorf("Wrong hardPodAffinitySymmetricWeight, ecpected: %d, got: %d", v1.DefaultHardPodAffinitySymmetricWeight, hpa)
115117
}
116118

117-
// Verify that custom predicates are converted to framework plugins.
118-
if !pluginExists(nodelabel.Name, "FilterPlugin", conf) {
119-
t.Error("NodeLabel plugin not exist in framework.")
119+
// Verify that node label predicate/priority are converted to framework plugins.
120+
if _, ok := findPlugin(nodelabel.Name, "FilterPlugin", conf); !ok {
121+
t.Fatalf("NodeLabel plugin not exist in framework.")
120122
}
121-
// Verify that the policy config is converted to plugin config for custom predicates.
123+
nodeLabelScorePlugin, ok := findPlugin(nodelabel.Name, "ScorePlugin", conf)
124+
if !ok {
125+
t.Fatalf("NodeLabel plugin not exist in framework.")
126+
}
127+
if nodeLabelScorePlugin.Weight != 6 {
128+
t.Errorf("Wrong weight. Got: %v, want: 6", nodeLabelScorePlugin.Weight)
129+
}
130+
// Verify that the policy config is converted to plugin config for node label predicate/priority.
122131
nodeLabelConfig := findPluginConfig(nodelabel.Name, conf)
123132
encoding, err := json.Marshal(nodeLabelConfig)
124133
if err != nil {
125134
t.Errorf("Failed to marshal %+v: %v", nodeLabelConfig, err)
126135
}
127-
want := `{"Name":"NodeLabel","Args":{"presentLabels":["zone"],"absentLabels":["foo"]}}`
136+
want := `{"Name":"NodeLabel","Args":{"presentLabels":["zone"],"absentLabels":["foo"],"presentLabelsPreference":["l1"],"absentLabelsPreference":["l2"]}}`
128137
if string(encoding) != want {
129138
t.Errorf("Config for NodeLabel plugin mismatch. got: %v, want: %v", string(encoding), want)
130139
}
131140
}
132141

133-
func pluginExists(name, extensionPoint string, schedConf *Config) bool {
142+
func findPlugin(name, extensionPoint string, schedConf *Config) (schedulerapi.Plugin, bool) {
134143
for _, pl := range schedConf.Framework.ListPlugins()[extensionPoint] {
135144
if pl.Name == name {
136-
return true
145+
return pl, true
137146
}
138147
}
139-
return false
148+
return schedulerapi.Plugin{}, false
140149
}
141150

142151
func findPluginConfig(name string, schedConf *Config) schedulerapi.PluginConfig {

pkg/scheduler/framework/plugins/default_registry.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,12 @@ func NewDefaultConfigProducerRegistry() *ConfigProducerRegistry {
256256
return
257257
})
258258

259+
registry.RegisterPriority(nodelabel.Name,
260+
func(args ConfigProducerArgs) (plugins config.Plugins, pluginConfig []config.PluginConfig) {
261+
plugins.Score = appendToPluginSet(plugins.Score, nodelabel.Name, &args.Weight)
262+
pluginConfig = append(pluginConfig, makePluginConfig(nodelabel.Name, args.NodeLabelArgs))
263+
return
264+
})
259265
return registry
260266
}
261267

pkg/scheduler/framework/plugins/nodelabel/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ go_library(
77
visibility = ["//visibility:public"],
88
deps = [
99
"//pkg/scheduler/algorithm/predicates:go_default_library",
10+
"//pkg/scheduler/algorithm/priorities:go_default_library",
1011
"//pkg/scheduler/framework/plugins/migration:go_default_library",
1112
"//pkg/scheduler/framework/v1alpha1:go_default_library",
1213
"//pkg/scheduler/nodeinfo:go_default_library",
@@ -22,6 +23,7 @@ go_test(
2223
deps = [
2324
"//pkg/scheduler/framework/v1alpha1:go_default_library",
2425
"//pkg/scheduler/nodeinfo:go_default_library",
26+
"//pkg/scheduler/nodeinfo/snapshot:go_default_library",
2527
"//staging/src/k8s.io/api/core/v1:go_default_library",
2628
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
2729
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",

0 commit comments

Comments
 (0)