diff --git a/pkg/scheduler/core/generic_scheduler.go b/pkg/scheduler/core/generic_scheduler.go index 1557d01fea5..42a8b9c0ef0 100644 --- a/pkg/scheduler/core/generic_scheduler.go +++ b/pkg/scheduler/core/generic_scheduler.go @@ -804,11 +804,9 @@ func PrioritizeNodes( for j := range priorityConfigs { result[i].Score += results[j][i].Score * priorityConfigs[j].Weight } - } - for _, scoreList := range scoresMap { - for i := range nodes { - result[i].Score += scoreList[i] + for j := range scoresMap { + result[i].Score += scoresMap[j][i].Score } } diff --git a/pkg/scheduler/framework/v1alpha1/framework.go b/pkg/scheduler/framework/v1alpha1/framework.go index 351b2baf069..c1b03688590 100644 --- a/pkg/scheduler/framework/v1alpha1/framework.go +++ b/pkg/scheduler/framework/v1alpha1/framework.go @@ -349,25 +349,29 @@ func (f *framework) RunPostFilterPlugins( return nil } -// RunScorePlugins runs the set of configured scoring plugins. It returns a map that +// RunScorePlugins runs the set of configured scoring plugins. It returns a list that // stores for each scoring plugin name the corresponding NodeScoreList(s). // It also returns *Status, which is set to non-success if any of the plugins returns // a non-success status. -func (f *framework) RunScorePlugins(pc *PluginContext, pod *v1.Pod, nodes []*v1.Node) (PluginToNodeScoreMap, *Status) { - pluginToNodeScoreMap := make(PluginToNodeScoreMap, len(f.scorePlugins)) +func (f *framework) RunScorePlugins(pc *PluginContext, pod *v1.Pod, nodes []*v1.Node) (PluginToNodeScores, *Status) { + pluginToNodeScores := make(PluginToNodeScores, len(f.scorePlugins)) for _, pl := range f.scorePlugins { - pluginToNodeScoreMap[pl.Name()] = make(NodeScoreList, len(nodes)) + pluginToNodeScores[pl.Name()] = make(NodeScoreList, len(nodes)) } ctx, cancel := context.WithCancel(context.Background()) errCh := schedutil.NewErrorChannel() workqueue.ParallelizeUntil(ctx, 16, len(nodes), func(index int) { for _, pl := range f.scorePlugins { - score, status := pl.Score(pc, pod, nodes[index].Name) + nodeName := nodes[index].Name + score, status := pl.Score(pc, pod, nodeName) if !status.IsSuccess() { errCh.SendErrorWithCancel(fmt.Errorf(status.Message()), cancel) return } - pluginToNodeScoreMap[pl.Name()][index] = score + pluginToNodeScores[pl.Name()][index] = NodeScore{ + Name: nodeName, + Score: score, + } } }) @@ -377,21 +381,21 @@ func (f *framework) RunScorePlugins(pc *PluginContext, pod *v1.Pod, nodes []*v1. return nil, NewStatus(Error, msg) } - return pluginToNodeScoreMap, nil + return pluginToNodeScores, nil } // RunNormalizeScorePlugins runs the NormalizeScore function of Score plugins. -// It should be called after RunScorePlugins with the PluginToNodeScoreMap result. -// It then modifies the map with normalized scores. It returns a non-success Status +// It should be called after RunScorePlugins with the PluginToNodeScores result. +// It then modifies the list with normalized scores. It returns a non-success Status // if any of the NormalizeScore functions returns a non-success status. -func (f *framework) RunNormalizeScorePlugins(pc *PluginContext, pod *v1.Pod, scores PluginToNodeScoreMap) *Status { +func (f *framework) RunNormalizeScorePlugins(pc *PluginContext, pod *v1.Pod, scores PluginToNodeScores) *Status { ctx, cancel := context.WithCancel(context.Background()) errCh := schedutil.NewErrorChannel() workqueue.ParallelizeUntil(ctx, 16, len(f.scoreWithNormalizePlugins), func(index int) { pl := f.scoreWithNormalizePlugins[index] nodeScoreList, ok := scores[pl.Name()] if !ok { - err := fmt.Errorf("normalize score plugin %q has no corresponding scores in the PluginToNodeScoreMap", pl.Name()) + err := fmt.Errorf("normalize score plugin %q has no corresponding scores in the PluginToNodeScores", pl.Name()) errCh.SendErrorWithCancel(err, cancel) return } @@ -414,7 +418,7 @@ func (f *framework) RunNormalizeScorePlugins(pc *PluginContext, pod *v1.Pod, sco // ApplyScoreWeights applies weights to the score results. It should be called after // RunNormalizeScorePlugins. -func (f *framework) ApplyScoreWeights(pc *PluginContext, pod *v1.Pod, scores PluginToNodeScoreMap) *Status { +func (f *framework) ApplyScoreWeights(pc *PluginContext, pod *v1.Pod, scores PluginToNodeScores) *Status { ctx, cancel := context.WithCancel(context.Background()) errCh := schedutil.NewErrorChannel() workqueue.ParallelizeUntil(ctx, 16, len(f.scorePlugins), func(index int) { @@ -423,12 +427,12 @@ func (f *framework) ApplyScoreWeights(pc *PluginContext, pod *v1.Pod, scores Plu weight := f.pluginNameToWeightMap[pl.Name()] nodeScoreList, ok := scores[pl.Name()] if !ok { - err := fmt.Errorf("score plugin %q has no corresponding scores in the PluginToNodeScoreMap", pl.Name()) + err := fmt.Errorf("score plugin %q has no corresponding scores in the PluginToNodeScores", pl.Name()) errCh.SendErrorWithCancel(err, cancel) return } for i := range nodeScoreList { - nodeScoreList[i] = nodeScoreList[i] * weight + nodeScoreList[i].Score = nodeScoreList[i].Score * weight } }) diff --git a/pkg/scheduler/framework/v1alpha1/framework_test.go b/pkg/scheduler/framework/v1alpha1/framework_test.go index 052f37b093b..682110e407f 100644 --- a/pkg/scheduler/framework/v1alpha1/framework_test.go +++ b/pkg/scheduler/framework/v1alpha1/framework_test.go @@ -20,7 +20,7 @@ import ( "reflect" "testing" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/kubernetes/pkg/scheduler/apis/config" ) @@ -67,7 +67,7 @@ func (pl *TestScorePlugin1) NormalizeScore(pc *PluginContext, pod *v1.Pod, score } // Simply decrease each node score by 1. for i := range scores { - scores[i] = scores[i] - 1 + scores[i].Score = scores[i].Score - 1 } return nil } @@ -91,7 +91,7 @@ func (pl *TestScorePlugin2) Name() string { func (pl *TestScorePlugin2) NormalizeScore(pc *PluginContext, pod *v1.Pod, scores NodeScoreList) *Status { // Simply force each node score to 5. for i := range scores { - scores[i] = 5 + scores[i].Score = 5 } return nil } @@ -256,8 +256,8 @@ func TestRunNormalizeScorePlugins(t *testing.T) { name string registry Registry plugins *config.Plugins - input PluginToNodeScoreMap - want PluginToNodeScoreMap + input PluginToNodeScores + want PluginToNodeScores // If err is true, we expect RunNormalizeScorePlugin to fail. err bool }{ @@ -265,54 +265,162 @@ func TestRunNormalizeScorePlugins(t *testing.T) { name: "no NormalizeScore plugins", plugins: plugin3, registry: registry, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, }, // No NormalizeScore plugin, map should be untouched. - want: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, + want: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, }, }, { name: "single Score plugin, single NormalizeScore plugin", registry: registry, plugins: plugin1, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, }, - want: PluginToNodeScoreMap{ + want: PluginToNodeScores{ // For plugin1, want=input-1. - scorePlugin1: {1, 2}, + scorePlugin1: { + { + Name: "node1", + Score: 1, + }, + { + Name: "node2", + Score: 2, + }, + }, }, }, { name: "2 Score plugins, 2 NormalizeScore plugins", registry: registry, plugins: plugin1And2, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, - scorePlugin2: {2, 4}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, + scorePlugin2: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 4, + }, + }, }, - want: PluginToNodeScoreMap{ + want: PluginToNodeScores{ // For plugin1, want=input-1. - scorePlugin1: {1, 2}, + scorePlugin1: { + { + Name: "node1", + Score: 1, + }, + { + Name: "node2", + Score: 2, + }, + }, // For plugin2, want=5. - scorePlugin2: {5, 5}, + scorePlugin2: { + { + Name: "node1", + Score: 5, + }, + { + Name: "node2", + Score: 5, + }, + }, }, }, { name: "2 Score plugins, 1 NormalizeScore plugin", registry: registry, plugins: plugin1And3, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, - scorePlugin3: {2, 4}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, + scorePlugin2: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 4, + }, + }, }, - want: PluginToNodeScoreMap{ + want: PluginToNodeScores{ // For plugin1, want=input-1. - scorePlugin1: {1, 2}, + scorePlugin1: { + { + Name: "node1", + Score: 1, + }, + { + Name: "node2", + Score: 2, + }, + }, // No NormalizeScore for plugin 3. The node scores are untouched. - scorePlugin3: {2, 4}, + scorePlugin2: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 4, + }, + }, }, }, { @@ -322,9 +430,27 @@ func TestRunNormalizeScorePlugins(t *testing.T) { scorePlugin2: NewScorePlugin2, }, plugins: plugin1And2, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, - scorePlugin2: {2, 4}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, + scorePlugin2: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 4, + }, + }, }, err: true, }, @@ -332,8 +458,17 @@ func TestRunNormalizeScorePlugins(t *testing.T) { name: "2 plugins but score map only contains plugin1", registry: registry, plugins: plugin1And2, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, }, err: true, }, @@ -368,41 +503,104 @@ func TestApplyScoreWeights(t *testing.T) { tests := []struct { name string plugins *config.Plugins - input PluginToNodeScoreMap - want PluginToNodeScoreMap + input PluginToNodeScores + want PluginToNodeScores // If err is true, we expect ApplyScoreWeights to fail. err bool }{ { name: "single Score plugin, single nodeScoreList", plugins: plugin1, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, }, - want: PluginToNodeScoreMap{ + want: PluginToNodeScores{ // For plugin1, want=input*weight1. - scorePlugin1: {4, 6}, + scorePlugin1: { + { + Name: "node1", + Score: 4, + }, + { + Name: "node2", + Score: 6, + }, + }, }, }, { name: "2 Score plugins, 2 nodeScoreLists in scoreMap", plugins: plugin1And2, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, - scorePlugin2: {2, 4}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, + scorePlugin2: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 4, + }, + }, }, - want: PluginToNodeScoreMap{ + want: PluginToNodeScores{ // For plugin1, want=input*weight1. - scorePlugin1: {4, 6}, + scorePlugin1: { + { + Name: "node1", + Score: 4, + }, + { + Name: "node2", + Score: 6, + }, + }, // For plugin2, want=input*weight2. - scorePlugin2: {6, 12}, + scorePlugin2: { + { + Name: "node1", + Score: 6, + }, + { + Name: "node2", + Score: 12, + }, + }, }, }, { name: "2 Score plugins, 1 without corresponding nodeScoreList in the score map", plugins: plugin1And2, - input: PluginToNodeScoreMap{ - scorePlugin1: {2, 3}, + input: PluginToNodeScores{ + scorePlugin1: { + { + Name: "node1", + Score: 2, + }, + { + Name: "node2", + Score: 3, + }, + }, }, err: true, }, diff --git a/pkg/scheduler/framework/v1alpha1/interface.go b/pkg/scheduler/framework/v1alpha1/interface.go index c92e6fb1323..1044631b143 100644 --- a/pkg/scheduler/framework/v1alpha1/interface.go +++ b/pkg/scheduler/framework/v1alpha1/interface.go @@ -31,10 +31,16 @@ import ( type Code int // NodeScoreList declares a list of nodes and their scores. -type NodeScoreList []int +type NodeScoreList []NodeScore -// PluginToNodeScoreMap declares a map from plugin name to its NodeScoreList. -type PluginToNodeScoreMap map[string]NodeScoreList +// NodeScore is a struct with node name and score. +type NodeScore struct { + Name string + Score int +} + +// PluginToNodeScores declares a map from plugin name to its NodeScoreList. +type PluginToNodeScores map[string]NodeScoreList // NodeToStatusMap declares map from node name to its status. type NodeToStatusMap map[string]*Status @@ -294,17 +300,17 @@ type Framework interface { // stores for each scoring plugin name the corresponding NodeScoreList(s). // It also returns *Status, which is set to non-success if any of the plugins returns // a non-success status. - RunScorePlugins(pc *PluginContext, pod *v1.Pod, nodes []*v1.Node) (PluginToNodeScoreMap, *Status) + RunScorePlugins(pc *PluginContext, pod *v1.Pod, nodes []*v1.Node) (PluginToNodeScores, *Status) // RunNormalizeScorePlugins runs the normalize score plugins. It should be called after - // RunScorePlugins with the PluginToNodeScoreMap result. It then modifies the map with + // RunScorePlugins with the PluginToNodeScores result. It then modifies the map with // normalized scores. It returns a non-success Status if any of the normalize score plugins // returns a non-success status. - RunNormalizeScorePlugins(pc *PluginContext, pod *v1.Pod, scores PluginToNodeScoreMap) *Status + RunNormalizeScorePlugins(pc *PluginContext, pod *v1.Pod, scores PluginToNodeScores) *Status // ApplyScoreWeights applies weights to the score results. It should be called after // RunNormalizeScorePlugins. - ApplyScoreWeights(pc *PluginContext, pod *v1.Pod, scores PluginToNodeScoreMap) *Status + ApplyScoreWeights(pc *PluginContext, pod *v1.Pod, scores PluginToNodeScores) *Status // RunPrebindPlugins runs the set of configured prebind plugins. It returns // *Status and its code is set to non-success if any of the plugins returns diff --git a/pkg/scheduler/internal/queue/scheduling_queue_test.go b/pkg/scheduler/internal/queue/scheduling_queue_test.go index 51fb29ebc57..0f5d05d56fd 100644 --- a/pkg/scheduler/internal/queue/scheduling_queue_test.go +++ b/pkg/scheduler/internal/queue/scheduling_queue_test.go @@ -175,15 +175,15 @@ func (*fakeFramework) RunFilterPlugins(pc *framework.PluginContext, pod *v1.Pod, return nil } -func (*fakeFramework) RunScorePlugins(pc *framework.PluginContext, pod *v1.Pod, nodes []*v1.Node) (framework.PluginToNodeScoreMap, *framework.Status) { +func (*fakeFramework) RunScorePlugins(pc *framework.PluginContext, pod *v1.Pod, nodes []*v1.Node) (framework.PluginToNodeScores, *framework.Status) { return nil, nil } -func (*fakeFramework) RunNormalizeScorePlugins(pc *framework.PluginContext, pod *v1.Pod, scores framework.PluginToNodeScoreMap) *framework.Status { +func (*fakeFramework) RunNormalizeScorePlugins(pc *framework.PluginContext, pod *v1.Pod, scores framework.PluginToNodeScores) *framework.Status { return nil } -func (*fakeFramework) ApplyScoreWeights(pc *framework.PluginContext, pod *v1.Pod, scores framework.PluginToNodeScoreMap) *framework.Status { +func (*fakeFramework) ApplyScoreWeights(pc *framework.PluginContext, pod *v1.Pod, scores framework.PluginToNodeScores) *framework.Status { return nil }