mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 04:33:26 +00:00
Merge pull request #83849 from draveness/feature/node-locality-as-score-plugin
feat: implement imagelocality as a score plugin
This commit is contained in:
commit
dd5cb6426d
@ -171,7 +171,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"NodeAffinityPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -185,6 +184,9 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "NodeResources"},
|
||||
{Name: "VolumeRestrictions"},
|
||||
},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -235,7 +237,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -250,7 +251,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "VolumeRestrictions"},
|
||||
{Name: "TaintToleration"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -305,7 +309,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -322,7 +325,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "VolumeRestrictions"},
|
||||
{Name: "TaintToleration"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
},
|
||||
// Do not change this JSON after the corresponding release has been tagged.
|
||||
@ -386,7 +392,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -403,7 +408,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "VolumeRestrictions"},
|
||||
{Name: "TaintToleration"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
wantExtenders: []schedulerapi.ExtenderConfig{{
|
||||
URLPrefix: "/prefix",
|
||||
@ -480,7 +488,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -497,7 +504,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "VolumeRestrictions"},
|
||||
{Name: "TaintToleration"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
wantExtenders: []schedulerapi.ExtenderConfig{{
|
||||
URLPrefix: "/prefix",
|
||||
@ -575,7 +585,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -593,7 +602,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "TaintToleration"},
|
||||
{Name: "VolumeBinding"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
wantExtenders: []schedulerapi.ExtenderConfig{{
|
||||
URLPrefix: "/prefix",
|
||||
@ -676,7 +688,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -694,7 +705,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "TaintToleration"},
|
||||
{Name: "VolumeBinding"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
wantExtenders: []schedulerapi.ExtenderConfig{{
|
||||
URLPrefix: "/prefix",
|
||||
@ -789,7 +803,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -808,7 +821,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "TaintToleration"},
|
||||
{Name: "VolumeBinding"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
wantExtenders: []schedulerapi.ExtenderConfig{{
|
||||
URLPrefix: "/prefix",
|
||||
@ -905,7 +921,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -924,7 +939,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "TaintToleration"},
|
||||
{Name: "VolumeBinding"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
wantExtenders: []schedulerapi.ExtenderConfig{{
|
||||
URLPrefix: "/prefix",
|
||||
@ -1021,7 +1039,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -1040,7 +1057,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "TaintToleration"},
|
||||
{Name: "VolumeBinding"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
wantExtenders: []schedulerapi.ExtenderConfig{{
|
||||
URLPrefix: "/prefix",
|
||||
@ -1141,7 +1161,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
),
|
||||
wantPrioritizers: sets.NewString(
|
||||
"EqualPriority",
|
||||
"ImageLocalityPriority",
|
||||
"LeastRequestedPriority",
|
||||
"BalancedResourceAllocation",
|
||||
"SelectorSpreadPriority",
|
||||
@ -1160,7 +1179,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
{Name: "TaintToleration"},
|
||||
{Name: "VolumeBinding"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 2}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 2},
|
||||
{Name: "TaintToleration", Weight: 2},
|
||||
},
|
||||
},
|
||||
wantExtenders: []schedulerapi.ExtenderConfig{{
|
||||
URLPrefix: "/prefix",
|
||||
@ -1192,6 +1214,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
}
|
||||
scoreToPriorityMap := map[string]string{
|
||||
"TaintToleration": "TaintTolerationPriority",
|
||||
"ImageLocality": "ImageLocalityPriority",
|
||||
}
|
||||
|
||||
for v, tc := range schedulerFiles {
|
||||
@ -1245,7 +1268,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
||||
seenPredicates.Insert(filterToPredicateMap[p.Name])
|
||||
|
||||
}
|
||||
for _, p := range gotPlugins["FilterPlugin"] {
|
||||
for _, p := range gotPlugins["ScorePlugin"] {
|
||||
seenPriorities.Insert(scoreToPriorityMap[p.Name])
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ go_library(
|
||||
"//pkg/scheduler/algorithm/predicates:go_default_library",
|
||||
"//pkg/scheduler/algorithm/priorities:go_default_library",
|
||||
"//pkg/scheduler/apis/config:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/imagelocality:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/nodeaffinity:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/nodename:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/noderesources:go_default_library",
|
||||
@ -37,6 +38,7 @@ filegroup(
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/scheduler/framework/plugins/examples:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/imagelocality:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/migration:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/nodeaffinity:all-srcs",
|
||||
"//pkg/scheduler/framework/plugins/nodename:all-srcs",
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
|
||||
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources"
|
||||
@ -56,6 +57,7 @@ type RegistryArgs struct {
|
||||
// runs custom plugins, can pass a different Registry when initializing the scheduler.
|
||||
func NewDefaultRegistry(args *RegistryArgs) framework.Registry {
|
||||
return framework.Registry{
|
||||
imagelocality.Name: imagelocality.New,
|
||||
tainttoleration.Name: tainttoleration.New,
|
||||
noderesources.Name: noderesources.New,
|
||||
nodename.Name: nodename.New,
|
||||
@ -128,6 +130,12 @@ func NewDefaultConfigProducerRegistry() *ConfigProducerRegistry {
|
||||
return
|
||||
})
|
||||
|
||||
registry.RegisterPriority(priorities.ImageLocalityPriority,
|
||||
func(args ConfigProducerArgs) (plugins config.Plugins, pluginConfig []config.PluginConfig) {
|
||||
plugins.Score = appendToPluginSet(plugins.Score, imagelocality.Name, &args.Weight)
|
||||
return
|
||||
})
|
||||
|
||||
return registry
|
||||
}
|
||||
|
||||
|
46
pkg/scheduler/framework/plugins/imagelocality/BUILD
Normal file
46
pkg/scheduler/framework/plugins/imagelocality/BUILD
Normal file
@ -0,0 +1,46 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["image_locality.go"],
|
||||
importpath = "k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/scheduler/algorithm/priorities:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/migration:go_default_library",
|
||||
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["image_locality_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/scheduler/algorithm/priorities:go_default_library",
|
||||
"//pkg/scheduler/framework/plugins/migration:go_default_library",
|
||||
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
||||
"//pkg/scheduler/nodeinfo:go_default_library",
|
||||
"//pkg/scheduler/testing:go_default_library",
|
||||
"//pkg/util/parsers:go_default_library",
|
||||
"//staging/src/k8s.io/api/apps/v1:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package imagelocality
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/migration"
|
||||
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
|
||||
)
|
||||
|
||||
var mb int64 = 1024 * 1024
|
||||
|
||||
// ImageLocality is a plugin that checks if a pod tolerates a node's taints.
|
||||
type ImageLocality struct {
|
||||
handle framework.FrameworkHandle
|
||||
}
|
||||
|
||||
var _ = framework.ScorePlugin(&ImageLocality{})
|
||||
|
||||
// Name is the name of the plugin used in the plugin registry and configurations.
|
||||
const Name = "ImageLocality"
|
||||
|
||||
// Name returns name of the plugin. It is used in logs, etc.
|
||||
func (pl *ImageLocality) Name() string {
|
||||
return Name
|
||||
}
|
||||
|
||||
// Score invoked at the score extension point.
|
||||
func (pl *ImageLocality) Score(state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
|
||||
nodeInfo, exist := pl.handle.NodeInfoSnapshot().NodeInfoMap[nodeName]
|
||||
if !exist {
|
||||
return 0, framework.NewStatus(framework.Error, fmt.Sprintf("node %q does not exist in NodeInfoSnapshot", nodeName))
|
||||
}
|
||||
|
||||
meta := migration.PriorityMetadata(state)
|
||||
s, err := priorities.ImageLocalityPriorityMap(pod, meta, nodeInfo)
|
||||
return s.Score, migration.ErrorToFrameworkStatus(err)
|
||||
}
|
||||
|
||||
// ScoreExtensions of the Score plugin.
|
||||
func (pl *ImageLocality) ScoreExtensions() framework.ScoreExtensions {
|
||||
return nil
|
||||
}
|
||||
|
||||
// New initializes a new plugin and returns it.
|
||||
func New(_ *runtime.Unknown, h framework.FrameworkHandle) (framework.Plugin, error) {
|
||||
return &ImageLocality{handle: h}, nil
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package imagelocality
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
|
||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/migration"
|
||||
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
|
||||
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
|
||||
schedulertesting "k8s.io/kubernetes/pkg/scheduler/testing"
|
||||
"k8s.io/kubernetes/pkg/util/parsers"
|
||||
)
|
||||
|
||||
func TestImageLocalityPriority(t *testing.T) {
|
||||
test40250 := v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/40",
|
||||
},
|
||||
{
|
||||
Image: "gcr.io/250",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
test40300 := v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/40",
|
||||
},
|
||||
{
|
||||
Image: "gcr.io/300",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testMinMax := v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/10",
|
||||
},
|
||||
{
|
||||
Image: "gcr.io/2000",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
node403002000 := v1.NodeStatus{
|
||||
Images: []v1.ContainerImage{
|
||||
{
|
||||
Names: []string{
|
||||
"gcr.io/40:" + parsers.DefaultImageTag,
|
||||
"gcr.io/40:v1",
|
||||
"gcr.io/40:v1",
|
||||
},
|
||||
SizeBytes: int64(40 * mb),
|
||||
},
|
||||
{
|
||||
Names: []string{
|
||||
"gcr.io/300:" + parsers.DefaultImageTag,
|
||||
"gcr.io/300:v1",
|
||||
},
|
||||
SizeBytes: int64(300 * mb),
|
||||
},
|
||||
{
|
||||
Names: []string{
|
||||
"gcr.io/2000:" + parsers.DefaultImageTag,
|
||||
},
|
||||
SizeBytes: int64(2000 * mb),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
node25010 := v1.NodeStatus{
|
||||
Images: []v1.ContainerImage{
|
||||
{
|
||||
Names: []string{
|
||||
"gcr.io/250:" + parsers.DefaultImageTag,
|
||||
},
|
||||
SizeBytes: int64(250 * mb),
|
||||
},
|
||||
{
|
||||
Names: []string{
|
||||
"gcr.io/10:" + parsers.DefaultImageTag,
|
||||
"gcr.io/10:v1",
|
||||
},
|
||||
SizeBytes: int64(10 * mb),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
nodeWithNoImages := v1.NodeStatus{}
|
||||
|
||||
tests := []struct {
|
||||
pod *v1.Pod
|
||||
pods []*v1.Pod
|
||||
nodes []*v1.Node
|
||||
expectedList framework.NodeScoreList
|
||||
name string
|
||||
}{
|
||||
{
|
||||
// Pod: gcr.io/40 gcr.io/250
|
||||
|
||||
// Node1
|
||||
// Image: gcr.io/40:latest 40MB
|
||||
// Score: 0 (40M/2 < 23M, min-threshold)
|
||||
|
||||
// Node2
|
||||
// Image: gcr.io/250:latest 250MB
|
||||
// Score: 100 * (250M/2 - 23M)/(1000M - 23M) = 100
|
||||
pod: &v1.Pod{Spec: test40250},
|
||||
nodes: []*v1.Node{makeImageNode("machine1", node403002000), makeImageNode("machine2", node25010)},
|
||||
expectedList: []framework.NodeScore{{Name: "machine1", Score: 0}, {Name: "machine2", Score: 10}},
|
||||
name: "two images spread on two nodes, prefer the larger image one",
|
||||
},
|
||||
{
|
||||
// Pod: gcr.io/40 gcr.io/300
|
||||
|
||||
// Node1
|
||||
// Image: gcr.io/40:latest 40MB, gcr.io/300:latest 300MB
|
||||
// Score: 100 * ((40M + 300M)/2 - 23M)/(1000M - 23M) = 15
|
||||
|
||||
// Node2
|
||||
// Image: not present
|
||||
// Score: 0
|
||||
pod: &v1.Pod{Spec: test40300},
|
||||
nodes: []*v1.Node{makeImageNode("machine1", node403002000), makeImageNode("machine2", node25010)},
|
||||
expectedList: []framework.NodeScore{{Name: "machine1", Score: 15}, {Name: "machine2", Score: 0}},
|
||||
name: "two images on one node, prefer this node",
|
||||
},
|
||||
{
|
||||
// Pod: gcr.io/2000 gcr.io/10
|
||||
|
||||
// Node1
|
||||
// Image: gcr.io/2000:latest 2000MB
|
||||
// Score: 100 (2000M/2 >= 1000M, max-threshold)
|
||||
|
||||
// Node2
|
||||
// Image: gcr.io/10:latest 10MB
|
||||
// Score: 0 (10M/2 < 23M, min-threshold)
|
||||
pod: &v1.Pod{Spec: testMinMax},
|
||||
nodes: []*v1.Node{makeImageNode("machine1", node403002000), makeImageNode("machine2", node25010)},
|
||||
expectedList: []framework.NodeScore{{Name: "machine1", Score: framework.MaxNodeScore}, {Name: "machine2", Score: 0}},
|
||||
name: "if exceed limit, use limit",
|
||||
},
|
||||
{
|
||||
// Pod: gcr.io/2000 gcr.io/10
|
||||
|
||||
// Node1
|
||||
// Image: gcr.io/2000:latest 2000MB
|
||||
// Score: 100 * (2000M/3 - 23M)/(1000M - 23M) = 65
|
||||
|
||||
// Node2
|
||||
// Image: gcr.io/10:latest 10MB
|
||||
// Score: 0 (10M/2 < 23M, min-threshold)
|
||||
|
||||
// Node3
|
||||
// Image:
|
||||
// Score: 0
|
||||
pod: &v1.Pod{Spec: testMinMax},
|
||||
nodes: []*v1.Node{makeImageNode("machine1", node403002000), makeImageNode("machine2", node25010), makeImageNode("machine3", nodeWithNoImages)},
|
||||
expectedList: []framework.NodeScore{{Name: "machine1", Score: 65}, {Name: "machine2", Score: 0}, {Name: "machine3", Score: 0}},
|
||||
name: "if exceed limit, use limit (with node which has no images present)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
metaDataProducer := priorities.NewPriorityMetadataFactory(
|
||||
schedulertesting.FakeServiceLister([]*v1.Service{}),
|
||||
schedulertesting.FakeControllerLister([]*v1.ReplicationController{}),
|
||||
schedulertesting.FakeReplicaSetLister([]*apps.ReplicaSet{}),
|
||||
schedulertesting.FakeStatefulSetLister([]*apps.StatefulSet{}))
|
||||
|
||||
nodeNameToInfo := schedulernodeinfo.CreateNodeNameToInfoMap(nil, test.nodes)
|
||||
|
||||
meta := metaDataProducer(test.pod, nodeNameToInfo)
|
||||
|
||||
state := framework.NewCycleState()
|
||||
state.Write(migration.PrioritiesStateKey, &migration.PrioritiesStateData{Reference: meta})
|
||||
|
||||
fh, _ := framework.NewFramework(nil, nil, nil)
|
||||
snapshot := fh.NodeInfoSnapshot()
|
||||
snapshot.NodeInfoMap = schedulernodeinfo.CreateNodeNameToInfoMap(nil, test.nodes)
|
||||
|
||||
p, _ := New(nil, fh)
|
||||
var gotList framework.NodeScoreList
|
||||
for _, n := range test.nodes {
|
||||
nodeName := n.ObjectMeta.Name
|
||||
score, status := p.(framework.ScorePlugin).Score(state, test.pod, nodeName)
|
||||
if !status.IsSuccess() {
|
||||
t.Errorf("unexpected error: %v", status)
|
||||
}
|
||||
gotList = append(gotList, framework.NodeScore{Name: nodeName, Score: score})
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(test.expectedList, gotList) {
|
||||
t.Errorf("expected:\n\t%+v,\ngot:\n\t%+v", test.expectedList, gotList)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func makeImageNode(node string, status v1.NodeStatus) *v1.Node {
|
||||
return &v1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: node},
|
||||
Status: status,
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ package tainttoleration
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
|
||||
|
@ -144,7 +144,6 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
||||
"NodeAffinityPriority",
|
||||
"NodePreferAvoidPodsPriority",
|
||||
"SelectorSpreadPriority",
|
||||
"ImageLocalityPriority",
|
||||
),
|
||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
||||
"FilterPlugin": {
|
||||
@ -152,7 +151,10 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
||||
{Name: "TaintToleration"},
|
||||
{Name: "VolumeBinding"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 1}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 1},
|
||||
{Name: "TaintToleration", Weight: 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -213,7 +215,6 @@ kind: Policy
|
||||
"NodeAffinityPriority",
|
||||
"NodePreferAvoidPodsPriority",
|
||||
"SelectorSpreadPriority",
|
||||
"ImageLocalityPriority",
|
||||
),
|
||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
||||
"FilterPlugin": {
|
||||
@ -221,7 +222,10 @@ kind: Policy
|
||||
{Name: "TaintToleration"},
|
||||
{Name: "VolumeBinding"},
|
||||
},
|
||||
"ScorePlugin": {{Name: "TaintToleration", Weight: 1}},
|
||||
"ScorePlugin": {
|
||||
{Name: "ImageLocality", Weight: 1},
|
||||
{Name: "TaintToleration", Weight: 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user