mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 05:27:21 +00:00
feat(scheduler): implement node affinity as score plugin
This commit is contained in:
parent
cedacc9cae
commit
3d74da4d53
@ -168,7 +168,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
),
|
),
|
||||||
wantPrioritizers: sets.NewString(
|
wantPrioritizers: sets.NewString(
|
||||||
"EqualPriority",
|
"EqualPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
@ -186,6 +185,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -238,7 +238,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
),
|
),
|
||||||
wantPlugins: map[string][]kubeschedulerconfig.Plugin{
|
wantPlugins: map[string][]kubeschedulerconfig.Plugin{
|
||||||
@ -253,6 +252,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -310,7 +310,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
),
|
),
|
||||||
@ -326,6 +325,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -393,7 +393,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
),
|
),
|
||||||
@ -409,6 +408,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -489,7 +489,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
),
|
),
|
||||||
@ -505,6 +504,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -586,7 +586,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
),
|
),
|
||||||
@ -603,6 +602,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -689,7 +689,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
),
|
),
|
||||||
@ -706,6 +705,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -804,7 +804,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
"RequestedToCapacityRatioPriority",
|
"RequestedToCapacityRatioPriority",
|
||||||
@ -822,6 +821,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -922,7 +922,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
"RequestedToCapacityRatioPriority",
|
"RequestedToCapacityRatioPriority",
|
||||||
@ -940,6 +939,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -1040,7 +1040,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
"RequestedToCapacityRatioPriority",
|
"RequestedToCapacityRatioPriority",
|
||||||
@ -1058,6 +1057,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -1162,7 +1162,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"MostRequestedPriority",
|
"MostRequestedPriority",
|
||||||
"RequestedToCapacityRatioPriority",
|
"RequestedToCapacityRatioPriority",
|
||||||
@ -1180,6 +1179,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 2},
|
{Name: "ImageLocality", Weight: 2},
|
||||||
|
{Name: "NodeAffinity", Weight: 2},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 2},
|
{Name: "NodePreferAvoidPods", Weight: 2},
|
||||||
{Name: "TaintToleration", Weight: 2},
|
{Name: "TaintToleration", Weight: 2},
|
||||||
},
|
},
|
||||||
@ -1216,6 +1216,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
}
|
}
|
||||||
scoreToPriorityMap := map[string]string{
|
scoreToPriorityMap := map[string]string{
|
||||||
"ImageLocality": "ImageLocalityPriority",
|
"ImageLocality": "ImageLocalityPriority",
|
||||||
|
"NodeAffinity": "NodeAffinityPriority",
|
||||||
"NodePreferAvoidPods": "NodePreferAvoidPodsPriority",
|
"NodePreferAvoidPods": "NodePreferAvoidPodsPriority",
|
||||||
"TaintToleration": "TaintTolerationPriority",
|
"TaintToleration": "TaintTolerationPriority",
|
||||||
}
|
}
|
||||||
|
@ -152,6 +152,12 @@ func NewDefaultConfigProducerRegistry() *ConfigProducerRegistry {
|
|||||||
return
|
return
|
||||||
})
|
})
|
||||||
|
|
||||||
|
registry.RegisterPriority(priorities.NodeAffinityPriority,
|
||||||
|
func(args ConfigProducerArgs) (plugins config.Plugins, pluginConfig []config.PluginConfig) {
|
||||||
|
plugins.Score = appendToPluginSet(plugins.Score, nodeaffinity.Name, &args.Weight)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
registry.RegisterPriority(priorities.ImageLocalityPriority,
|
registry.RegisterPriority(priorities.ImageLocalityPriority,
|
||||||
func(args ConfigProducerArgs) (plugins config.Plugins, pluginConfig []config.PluginConfig) {
|
func(args ConfigProducerArgs) (plugins config.Plugins, pluginConfig []config.PluginConfig) {
|
||||||
plugins.Score = appendToPluginSet(plugins.Score, imagelocality.Name, &args.Weight)
|
plugins.Score = appendToPluginSet(plugins.Score, imagelocality.Name, &args.Weight)
|
||||||
|
@ -7,6 +7,7 @@ go_library(
|
|||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/scheduler/algorithm/predicates:go_default_library",
|
"//pkg/scheduler/algorithm/predicates:go_default_library",
|
||||||
|
"//pkg/scheduler/algorithm/priorities:go_default_library",
|
||||||
"//pkg/scheduler/framework/plugins/migration:go_default_library",
|
"//pkg/scheduler/framework/plugins/migration:go_default_library",
|
||||||
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
||||||
"//pkg/scheduler/nodeinfo:go_default_library",
|
"//pkg/scheduler/nodeinfo:go_default_library",
|
||||||
|
@ -18,19 +18,24 @@ package nodeaffinity
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/migration"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/migration"
|
||||||
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
|
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/nodeinfo"
|
"k8s.io/kubernetes/pkg/scheduler/nodeinfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeAffinity is a plugin that checks if a pod node selector matches the node label.
|
// NodeAffinity is a plugin that checks if a pod node selector matches the node label.
|
||||||
type NodeAffinity struct{}
|
type NodeAffinity struct {
|
||||||
|
handle framework.FrameworkHandle
|
||||||
|
}
|
||||||
|
|
||||||
var _ = framework.FilterPlugin(&NodeAffinity{})
|
var _ framework.FilterPlugin = &NodeAffinity{}
|
||||||
|
var _ framework.ScorePlugin = &NodeAffinity{}
|
||||||
|
|
||||||
// Name is the name of the plugin used in the plugin registry and configurations.
|
// Name is the name of the plugin used in the plugin registry and configurations.
|
||||||
const Name = "NodeAffinity"
|
const Name = "NodeAffinity"
|
||||||
@ -41,12 +46,36 @@ func (pl *NodeAffinity) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter invoked at the filter extension point.
|
// Filter invoked at the filter extension point.
|
||||||
func (pl *NodeAffinity) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *nodeinfo.NodeInfo) *framework.Status {
|
func (pl *NodeAffinity) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *nodeinfo.NodeInfo) *framework.Status {
|
||||||
_, reasons, err := predicates.PodMatchNodeSelector(pod, nil, nodeInfo)
|
_, reasons, err := predicates.PodMatchNodeSelector(pod, nil, nodeInfo)
|
||||||
return migration.PredicateResultToFrameworkStatus(reasons, err)
|
return migration.PredicateResultToFrameworkStatus(reasons, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// New initializes a new plugin and returns it.
|
// Score invoked at the Score extension point.
|
||||||
func New(_ *runtime.Unknown, _ framework.FrameworkHandle) (framework.Plugin, error) {
|
func (pl *NodeAffinity) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
|
||||||
return &NodeAffinity{}, nil
|
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.CalculateNodeAffinityPriorityMap(pod, meta, nodeInfo)
|
||||||
|
return s.Score, migration.ErrorToFrameworkStatus(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NormalizeScore invoked after scoring all nodes.
|
||||||
|
func (pl *NodeAffinity) NormalizeScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status {
|
||||||
|
// Note that CalculateNodeAffinityPriorityReduce doesn't use priority metadata, hence passing nil here.
|
||||||
|
err := priorities.CalculateNodeAffinityPriorityReduce(pod, nil, pl.handle.NodeInfoSnapshot().NodeInfoMap, scores)
|
||||||
|
return migration.ErrorToFrameworkStatus(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScoreExtensions of the Score plugin.
|
||||||
|
func (pl *NodeAffinity) ScoreExtensions() framework.ScoreExtensions {
|
||||||
|
return pl
|
||||||
|
}
|
||||||
|
|
||||||
|
// New initializes a new plugin and returns it.
|
||||||
|
func New(_ *runtime.Unknown, h framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
|
return &NodeAffinity{handle: h}, nil
|
||||||
}
|
}
|
||||||
|
@ -705,3 +705,173 @@ func TestNodeAffinity(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNodeAffinityPriority(t *testing.T) {
|
||||||
|
label1 := map[string]string{"foo": "bar"}
|
||||||
|
label2 := map[string]string{"key": "value"}
|
||||||
|
label3 := map[string]string{"az": "az1"}
|
||||||
|
label4 := map[string]string{"abc": "az11", "def": "az22"}
|
||||||
|
label5 := map[string]string{"foo": "bar", "key": "value", "az": "az1"}
|
||||||
|
|
||||||
|
affinity1 := &v1.Affinity{
|
||||||
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.PreferredSchedulingTerm{{
|
||||||
|
Weight: 2,
|
||||||
|
Preference: v1.NodeSelectorTerm{
|
||||||
|
MatchExpressions: []v1.NodeSelectorRequirement{{
|
||||||
|
Key: "foo",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"bar"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
affinity2 := &v1.Affinity{
|
||||||
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
|
PreferredDuringSchedulingIgnoredDuringExecution: []v1.PreferredSchedulingTerm{
|
||||||
|
{
|
||||||
|
Weight: 2,
|
||||||
|
Preference: v1.NodeSelectorTerm{
|
||||||
|
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "foo",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Weight: 4,
|
||||||
|
Preference: v1.NodeSelectorTerm{
|
||||||
|
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "key",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"value"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Weight: 5,
|
||||||
|
Preference: v1.NodeSelectorTerm{
|
||||||
|
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "foo",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "key",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"value"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "az",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"az1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
pod *v1.Pod
|
||||||
|
nodes []*v1.Node
|
||||||
|
expectedList framework.NodeScoreList
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Annotations: map[string]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodes: []*v1.Node{
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine1", Labels: label1}},
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine2", Labels: label2}},
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine3", Labels: label3}},
|
||||||
|
},
|
||||||
|
expectedList: []framework.NodeScore{{Name: "machine1", Score: 0}, {Name: "machine2", Score: 0}, {Name: "machine3", Score: 0}},
|
||||||
|
name: "all machines are same priority as NodeAffinity is nil",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Affinity: affinity1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodes: []*v1.Node{
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine1", Labels: label4}},
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine2", Labels: label2}},
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine3", Labels: label3}},
|
||||||
|
},
|
||||||
|
expectedList: []framework.NodeScore{{Name: "machine1", Score: 0}, {Name: "machine2", Score: 0}, {Name: "machine3", Score: 0}},
|
||||||
|
name: "no machine macthes preferred scheduling requirements in NodeAffinity of pod so all machines' priority is zero",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Affinity: affinity1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodes: []*v1.Node{
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine1", Labels: label1}},
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine2", Labels: label2}},
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine3", Labels: label3}},
|
||||||
|
},
|
||||||
|
expectedList: []framework.NodeScore{{Name: "machine1", Score: framework.MaxNodeScore}, {Name: "machine2", Score: 0}, {Name: "machine3", Score: 0}},
|
||||||
|
name: "only machine1 matches the preferred scheduling requirements of pod",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pod: &v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Affinity: affinity2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodes: []*v1.Node{
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine1", Labels: label1}},
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine5", Labels: label5}},
|
||||||
|
{ObjectMeta: metav1.ObjectMeta{Name: "machine2", Labels: label2}},
|
||||||
|
},
|
||||||
|
expectedList: []framework.NodeScore{{Name: "machine1", Score: 18}, {Name: "machine5", Score: framework.MaxNodeScore}, {Name: "machine2", Score: 36}},
|
||||||
|
name: "all machines matches the preferred scheduling requirements of pod but with different priorities ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
state := framework.NewCycleState()
|
||||||
|
|
||||||
|
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(context.Background(), state, test.pod, nodeName)
|
||||||
|
if !status.IsSuccess() {
|
||||||
|
t.Errorf("unexpected error: %v", status)
|
||||||
|
}
|
||||||
|
gotList = append(gotList, framework.NodeScore{Name: nodeName, Score: score})
|
||||||
|
}
|
||||||
|
|
||||||
|
status := p.(framework.ScorePlugin).ScoreExtensions().NormalizeScore(context.Background(), state, test.pod, gotList)
|
||||||
|
if !status.IsSuccess() {
|
||||||
|
t.Errorf("unexpected error: %v", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(test.expectedList, gotList) {
|
||||||
|
t.Errorf("expected:\n\t%+v,\ngot:\n\t%+v", test.expectedList, gotList)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -140,7 +140,6 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
),
|
),
|
||||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
||||||
@ -152,6 +151,7 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 1},
|
{Name: "ImageLocality", Weight: 1},
|
||||||
|
{Name: "NodeAffinity", Weight: 1},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 10000},
|
{Name: "NodePreferAvoidPods", Weight: 10000},
|
||||||
{Name: "TaintToleration", Weight: 1},
|
{Name: "TaintToleration", Weight: 1},
|
||||||
},
|
},
|
||||||
@ -211,7 +211,6 @@ kind: Policy
|
|||||||
"BalancedResourceAllocation",
|
"BalancedResourceAllocation",
|
||||||
"InterPodAffinityPriority",
|
"InterPodAffinityPriority",
|
||||||
"LeastRequestedPriority",
|
"LeastRequestedPriority",
|
||||||
"NodeAffinityPriority",
|
|
||||||
"SelectorSpreadPriority",
|
"SelectorSpreadPriority",
|
||||||
),
|
),
|
||||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
||||||
@ -223,6 +222,7 @@ kind: Policy
|
|||||||
},
|
},
|
||||||
"ScorePlugin": {
|
"ScorePlugin": {
|
||||||
{Name: "ImageLocality", Weight: 1},
|
{Name: "ImageLocality", Weight: 1},
|
||||||
|
{Name: "NodeAffinity", Weight: 1},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 10000},
|
{Name: "NodePreferAvoidPods", Weight: 10000},
|
||||||
{Name: "TaintToleration", Weight: 1},
|
{Name: "TaintToleration", Weight: 1},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user