mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 02:41:25 +00:00
Merge pull request #90475 from alculquicondor/topology-scoring
Topology spreading scoring with automatically weighted topologies
This commit is contained in:
commit
ba43630708
@ -39,6 +39,10 @@ type preScoreState struct {
|
||||
IgnoredNodes sets.String
|
||||
// TopologyPairToPodCounts is keyed with topologyPair, and valued with the number of matching pods.
|
||||
TopologyPairToPodCounts map[topologyPair]*int64
|
||||
// TopologyNormalizingWeight is the weight we give to the counts per topology.
|
||||
// This allows the pod counts of smaller topologies to not be watered down by
|
||||
// bigger ones.
|
||||
TopologyNormalizingWeight []float64
|
||||
}
|
||||
|
||||
// Clone implements the mandatory Clone interface. We don't really copy the data since
|
||||
@ -51,6 +55,7 @@ func (s *preScoreState) Clone() framework.StateData {
|
||||
// don't have required topologyKey(s), and initialize:
|
||||
// 1) s.TopologyPairToPodCounts: keyed with both eligible topology pair and node names.
|
||||
// 2) s.IgnoredNodes: the set of nodes that shouldn't be scored.
|
||||
// 3) s.TopologyNormalizingWeight: The weight to be given to each constraint based on the number of values in a topology.
|
||||
func (pl *PodTopologySpread) initPreScoreState(s *preScoreState, pod *v1.Pod, filteredNodes []*v1.Node) error {
|
||||
var err error
|
||||
if len(pod.Spec.TopologySpreadConstraints) > 0 {
|
||||
@ -67,6 +72,7 @@ func (pl *PodTopologySpread) initPreScoreState(s *preScoreState, pod *v1.Pod, fi
|
||||
if len(s.Constraints) == 0 {
|
||||
return nil
|
||||
}
|
||||
topoSize := make([]int, len(s.Constraints))
|
||||
for _, node := range filteredNodes {
|
||||
if !nodeLabelsMatchSpreadConstraints(node.Labels, s.Constraints) {
|
||||
// Nodes which don't have all required topologyKeys present are ignored
|
||||
@ -74,7 +80,7 @@ func (pl *PodTopologySpread) initPreScoreState(s *preScoreState, pod *v1.Pod, fi
|
||||
s.IgnoredNodes.Insert(node.Name)
|
||||
continue
|
||||
}
|
||||
for _, constraint := range s.Constraints {
|
||||
for i, constraint := range s.Constraints {
|
||||
// per-node counts are calculated during Score.
|
||||
if constraint.TopologyKey == v1.LabelHostname {
|
||||
continue
|
||||
@ -82,9 +88,19 @@ func (pl *PodTopologySpread) initPreScoreState(s *preScoreState, pod *v1.Pod, fi
|
||||
pair := topologyPair{key: constraint.TopologyKey, value: node.Labels[constraint.TopologyKey]}
|
||||
if s.TopologyPairToPodCounts[pair] == nil {
|
||||
s.TopologyPairToPodCounts[pair] = new(int64)
|
||||
topoSize[i]++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.TopologyNormalizingWeight = make([]float64, len(s.Constraints))
|
||||
for i, c := range s.Constraints {
|
||||
sz := topoSize[i]
|
||||
if c.TopologyKey == v1.LabelHostname {
|
||||
sz = len(filteredNodes) - len(s.IgnoredNodes)
|
||||
}
|
||||
s.TopologyNormalizingWeight[i] = topologyNormalizingWeight(sz)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -174,20 +190,20 @@ func (pl *PodTopologySpread) Score(ctx context.Context, cycleState *framework.Cy
|
||||
|
||||
// For each present <pair>, current node gets a credit of <matchSum>.
|
||||
// And we sum up <matchSum> and return it as this node's score.
|
||||
var score int64
|
||||
for _, c := range s.Constraints {
|
||||
var score float64
|
||||
for i, c := range s.Constraints {
|
||||
if tpVal, ok := node.Labels[c.TopologyKey]; ok {
|
||||
var cnt int64
|
||||
if c.TopologyKey == v1.LabelHostname {
|
||||
count := countPodsMatchSelector(nodeInfo.Pods, c.Selector, pod.Namespace)
|
||||
score += int64(count)
|
||||
cnt = int64(countPodsMatchSelector(nodeInfo.Pods, c.Selector, pod.Namespace))
|
||||
} else {
|
||||
pair := topologyPair{key: c.TopologyKey, value: tpVal}
|
||||
matchSum := *s.TopologyPairToPodCounts[pair]
|
||||
score += matchSum
|
||||
cnt = *s.TopologyPairToPodCounts[pair]
|
||||
}
|
||||
score += float64(cnt) * s.TopologyNormalizingWeight[i]
|
||||
}
|
||||
}
|
||||
return score, nil
|
||||
return int64(score), nil
|
||||
}
|
||||
|
||||
// NormalizeScore invoked after scoring all nodes.
|
||||
@ -200,21 +216,22 @@ func (pl *PodTopologySpread) NormalizeScore(ctx context.Context, cycleState *fra
|
||||
return nil
|
||||
}
|
||||
|
||||
// Calculate the summed <total> score and <minScore>.
|
||||
// Calculate <minScore> and <maxScore>
|
||||
var minScore int64 = math.MaxInt64
|
||||
var total int64
|
||||
var maxScore int64
|
||||
for _, score := range scores {
|
||||
// it's mandatory to check if <score.Name> is present in m.IgnoredNodes
|
||||
if s.IgnoredNodes.Has(score.Name) {
|
||||
continue
|
||||
}
|
||||
total += score.Score
|
||||
if score.Score < minScore {
|
||||
minScore = score.Score
|
||||
}
|
||||
if score.Score > maxScore {
|
||||
maxScore = score.Score
|
||||
}
|
||||
}
|
||||
|
||||
maxMinDiff := total - minScore
|
||||
for i := range scores {
|
||||
nodeInfo, err := pl.sharedLister.NodeInfos().Get(scores[i].Name)
|
||||
if err != nil {
|
||||
@ -222,19 +239,18 @@ func (pl *PodTopologySpread) NormalizeScore(ctx context.Context, cycleState *fra
|
||||
}
|
||||
node := nodeInfo.Node()
|
||||
|
||||
if maxMinDiff == 0 {
|
||||
scores[i].Score = framework.MaxNodeScore
|
||||
continue
|
||||
}
|
||||
|
||||
if s.IgnoredNodes.Has(node.Name) {
|
||||
scores[i].Score = 0
|
||||
continue
|
||||
}
|
||||
|
||||
flippedScore := total - scores[i].Score
|
||||
fScore := float64(framework.MaxNodeScore) * (float64(flippedScore) / float64(maxMinDiff))
|
||||
scores[i].Score = int64(fScore)
|
||||
if maxScore == 0 {
|
||||
scores[i].Score = framework.MaxNodeScore
|
||||
continue
|
||||
}
|
||||
|
||||
s := scores[i].Score
|
||||
scores[i].Score = framework.MaxNodeScore * (maxScore + minScore - s) / maxScore
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -256,3 +272,16 @@ func getPreScoreState(cycleState *framework.CycleState) (*preScoreState, error)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// topologyNormalizingWeight calculates the weight for the topology, based on
|
||||
// the number of values that exist for a topology.
|
||||
// Since <size> is at least 1 (all nodes that passed the Filters are in the
|
||||
// same topology), and k8s supports 5k nodes, the result is in the interval
|
||||
// <1.09, 8.52>.
|
||||
//
|
||||
// Note: <size> could also be zero when no nodes have the required topologies,
|
||||
// however we don't care about topology weight in this case as we return a 0
|
||||
// score for all nodes.
|
||||
func topologyNormalizingWeight(size int) float64 {
|
||||
return math.Log(float64(size + 2))
|
||||
}
|
||||
|
@ -48,12 +48,12 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
|
||||
name: "normal case",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "zone", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
},
|
||||
want: &preScoreState{
|
||||
Constraints: []topologySpreadConstraint{
|
||||
@ -64,30 +64,28 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
|
||||
},
|
||||
{
|
||||
MaxSkew: 1,
|
||||
TopologyKey: "node",
|
||||
TopologyKey: v1.LabelHostname,
|
||||
Selector: mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Exists("foo").Obj()),
|
||||
},
|
||||
},
|
||||
IgnoredNodes: sets.NewString(),
|
||||
TopologyPairToPodCounts: map[topologyPair]*int64{
|
||||
{key: "zone", value: "zone1"}: pointer.Int64Ptr(0),
|
||||
{key: "zone", value: "zone2"}: pointer.Int64Ptr(0),
|
||||
{key: "node", value: "node-a"}: pointer.Int64Ptr(0),
|
||||
{key: "node", value: "node-b"}: pointer.Int64Ptr(0),
|
||||
{key: "node", value: "node-x"}: pointer.Int64Ptr(0),
|
||||
{key: "zone", value: "zone1"}: pointer.Int64Ptr(0),
|
||||
{key: "zone", value: "zone2"}: pointer.Int64Ptr(0),
|
||||
},
|
||||
TopologyNormalizingWeight: []float64{topologyNormalizingWeight(2), topologyNormalizingWeight(3)},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "node-x doesn't have label zone",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "zone", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("bar").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("bar").Obj()).
|
||||
Obj(),
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
},
|
||||
want: &preScoreState{
|
||||
Constraints: []topologySpreadConstraint{
|
||||
@ -98,28 +96,27 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
|
||||
},
|
||||
{
|
||||
MaxSkew: 1,
|
||||
TopologyKey: "node",
|
||||
TopologyKey: v1.LabelHostname,
|
||||
Selector: mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Exists("bar").Obj()),
|
||||
},
|
||||
},
|
||||
IgnoredNodes: sets.NewString("node-x"),
|
||||
TopologyPairToPodCounts: map[topologyPair]*int64{
|
||||
{key: "zone", value: "zone1"}: pointer.Int64Ptr(0),
|
||||
{key: "node", value: "node-a"}: pointer.Int64Ptr(0),
|
||||
{key: "node", value: "node-b"}: pointer.Int64Ptr(0),
|
||||
{key: "zone", value: "zone1"}: pointer.Int64Ptr(0),
|
||||
},
|
||||
TopologyNormalizingWeight: []float64{topologyNormalizingWeight(1), topologyNormalizingWeight(2)},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "defaults constraints and a replica set",
|
||||
pod: st.MakePod().Name("p").Label("foo", "tar").Label("baz", "sup").Obj(),
|
||||
defaultConstraints: []v1.TopologySpreadConstraint{
|
||||
{MaxSkew: 1, TopologyKey: "node", WhenUnsatisfiable: v1.ScheduleAnyway},
|
||||
{MaxSkew: 1, TopologyKey: v1.LabelHostname, WhenUnsatisfiable: v1.ScheduleAnyway},
|
||||
{MaxSkew: 2, TopologyKey: "rack", WhenUnsatisfiable: v1.DoNotSchedule},
|
||||
{MaxSkew: 2, TopologyKey: "planet", WhenUnsatisfiable: v1.ScheduleAnyway},
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("rack", "rack1").Label("node", "node-a").Label("planet", "mars").Obj(),
|
||||
st.MakeNode().Name("node-a").Label("rack", "rack1").Label(v1.LabelHostname, "node-a").Label("planet", "mars").Obj(),
|
||||
},
|
||||
objs: []runtime.Object{
|
||||
&appsv1.ReplicaSet{Spec: appsv1.ReplicaSetSpec{Selector: st.MakeLabelSelector().Exists("foo").Obj()}},
|
||||
@ -128,7 +125,7 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
|
||||
Constraints: []topologySpreadConstraint{
|
||||
{
|
||||
MaxSkew: 1,
|
||||
TopologyKey: "node",
|
||||
TopologyKey: v1.LabelHostname,
|
||||
Selector: mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Exists("foo").Obj()),
|
||||
},
|
||||
{
|
||||
@ -139,9 +136,9 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
|
||||
},
|
||||
IgnoredNodes: sets.NewString(),
|
||||
TopologyPairToPodCounts: map[topologyPair]*int64{
|
||||
{key: "node", value: "node-a"}: pointer.Int64Ptr(0),
|
||||
{key: "planet", value: "mars"}: pointer.Int64Ptr(0),
|
||||
},
|
||||
TopologyNormalizingWeight: []float64{topologyNormalizingWeight(1), topologyNormalizingWeight(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -186,6 +183,7 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
|
||||
TopologyPairToPodCounts: map[topologyPair]*int64{
|
||||
{"planet", "mars"}: pointer.Int64Ptr(0),
|
||||
},
|
||||
TopologyNormalizingWeight: []float64{topologyNormalizingWeight(1)},
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -238,11 +236,11 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
// if there is only one candidate node, it should be scored to 10
|
||||
name: "one constraint on node, no existing pods",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 100},
|
||||
@ -253,7 +251,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
// if there is only one candidate node, it should be scored to 10
|
||||
name: "one constraint on node, only one node is candidate",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
|
||||
@ -261,10 +259,10 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-b").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-b").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 100},
|
||||
@ -273,15 +271,15 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
{
|
||||
name: "one constraint on node, all nodes have the same number of matching pods",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
|
||||
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 100},
|
||||
@ -289,12 +287,10 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
// matching pods spread as 2/1/0/3, total = 6
|
||||
// after reversing, it's 4/5/6/3
|
||||
// so scores = 400/6, 500/6, 600/6, 300/6
|
||||
// matching pods spread as 2/1/0/3.
|
||||
name: "one constraint on node, all 4 nodes are candidates",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
|
||||
@ -305,26 +301,24 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-d3").Node("node-d").Label("foo", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-c").Label("node", "node-c").Obj(),
|
||||
st.MakeNode().Name("node-d").Label("node", "node-d").Obj(),
|
||||
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-c").Label(v1.LabelHostname, "node-c").Obj(),
|
||||
st.MakeNode().Name("node-d").Label(v1.LabelHostname, "node-d").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 66},
|
||||
{Name: "node-b", Score: 83},
|
||||
{Name: "node-a", Score: 40},
|
||||
{Name: "node-b", Score: 80},
|
||||
{Name: "node-c", Score: 100},
|
||||
{Name: "node-d", Score: 50},
|
||||
{Name: "node-d", Score: 0},
|
||||
},
|
||||
},
|
||||
{
|
||||
// matching pods spread as 4/2/1/~3~, total = 4+2+1 = 7 (as node4 is not a candidate)
|
||||
// after reversing, it's 3/5/6
|
||||
// so scores = 300/6, 500/6, 600/6
|
||||
// matching pods spread as 4/2/1/~3~ (node4 is not a candidate)
|
||||
name: "one constraint on node, 3 out of 4 nodes are candidates",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
|
||||
@ -339,26 +333,24 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-y").Label("node", "node-y").Obj(),
|
||||
st.MakeNode().Name("node-y").Label(v1.LabelHostname, "node-y").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 50},
|
||||
{Name: "node-b", Score: 83},
|
||||
{Name: "node-a", Score: 16},
|
||||
{Name: "node-b", Score: 66},
|
||||
{Name: "node-x", Score: 100},
|
||||
},
|
||||
},
|
||||
{
|
||||
// matching pods spread as 4/?2?/1/~3~, total = 4+?+1 = 5 (as node2 is problematic)
|
||||
// after reversing, it's 1/?/4
|
||||
// so scores = 100/4, 0, 400/4
|
||||
name: "one constraint on node, 3 out of 4 nodes are candidates",
|
||||
name: "one constraint on node, 3 out of 4 nodes are candidates, one node doesn't match topology key",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
|
||||
@ -373,23 +365,21 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("n", "node-b").Obj(), // label `n` doesn't match topologyKey
|
||||
st.MakeNode().Name("node-x").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-x").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-y").Label("node", "node-y").Obj(),
|
||||
st.MakeNode().Name("node-y").Label(v1.LabelHostname, "node-y").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 25},
|
||||
{Name: "node-a", Score: 20},
|
||||
{Name: "node-b", Score: 0},
|
||||
{Name: "node-x", Score: 100},
|
||||
},
|
||||
},
|
||||
{
|
||||
// matching pods spread as 4/2/1/~3~, total = 6+6+4 = 16 (as topologyKey is zone instead of node)
|
||||
// after reversing, it's 10/10/12
|
||||
// so scores = 1000/12, 1000/12, 1200/12
|
||||
// matching pods spread as 4/2/1/~3~
|
||||
name: "one constraint on zone, 3 out of 4 nodes are candidates",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "zone", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
@ -407,27 +397,25 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label(v1.LabelHostname, "node-y").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 83},
|
||||
{Name: "node-b", Score: 83},
|
||||
{Name: "node-a", Score: 62},
|
||||
{Name: "node-b", Score: 62},
|
||||
{Name: "node-x", Score: 100},
|
||||
},
|
||||
},
|
||||
{
|
||||
// matching pods spread as 2/~1~/2/~4~, total = 2+3 + 2+6 = 13 (zone and node should be both summed up)
|
||||
// after reversing, it's 8/5
|
||||
// so scores = 800/8, 500/8
|
||||
// matching pods spread as 2/~1~/2/~4~.
|
||||
name: "two Constraints on zone and node, 2 out of 4 nodes are candidates",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "zone", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
|
||||
@ -441,16 +429,16 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label(v1.LabelHostname, "node-y").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 100},
|
||||
{Name: "node-x", Score: 62},
|
||||
{Name: "node-x", Score: 54},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -464,13 +452,10 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
// +--------+-------------+--------+---------------+
|
||||
// For the first constraint (zone): the matching pods spread as 2/2/1/1
|
||||
// For the second constraint (node): the matching pods spread as 0/1/0/1
|
||||
// sum them up gets: 2/3/1/2, and total number is 8.
|
||||
// after reversing, it's 6/5/7/6
|
||||
// so scores = 600/7, 500/7, 700/7, 600/7
|
||||
name: "two Constraints on zone and node, with different labelSelectors",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
|
||||
SpreadConstraint(1, "zone", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("bar").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("bar").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
|
||||
@ -479,29 +464,26 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-y2").Node("node-y").Label("bar", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label(v1.LabelHostname, "node-y").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 85},
|
||||
{Name: "node-b", Score: 71},
|
||||
{Name: "node-a", Score: 75},
|
||||
{Name: "node-b", Score: 25},
|
||||
{Name: "node-x", Score: 100},
|
||||
{Name: "node-y", Score: 85},
|
||||
{Name: "node-y", Score: 50},
|
||||
},
|
||||
},
|
||||
{
|
||||
// For the first constraint (zone): the matching pods spread as 0/0/2/2
|
||||
// For the second constraint (node): the matching pods spread as 0/1/0/1
|
||||
// sum them up gets: 0/1/2/3, and total number is 6.
|
||||
// after reversing, it's 6/5/4/3.
|
||||
// so scores = 600/6, 500/6, 400/6, 300/6
|
||||
name: "two Constraints on zone and node, with different labelSelectors, some nodes have 0 pods",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
|
||||
SpreadConstraint(1, "zone", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("bar").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("bar").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-b1").Node("node-b").Label("bar", "").Obj(),
|
||||
@ -509,29 +491,26 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Label("bar", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label(v1.LabelHostname, "node-y").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 100},
|
||||
{Name: "node-b", Score: 83},
|
||||
{Name: "node-x", Score: 66},
|
||||
{Name: "node-y", Score: 50},
|
||||
{Name: "node-b", Score: 75},
|
||||
{Name: "node-x", Score: 50},
|
||||
{Name: "node-y", Score: 0},
|
||||
},
|
||||
},
|
||||
{
|
||||
// For the first constraint (zone): the matching pods spread as 2/2/1/~1~
|
||||
// For the second constraint (node): the matching pods spread as 0/1/0/~1~
|
||||
// sum them up gets: 2/3/1, and total number is 6.
|
||||
// after reversing, it's 4/3/5
|
||||
// so scores = 400/5, 300/5, 500/5
|
||||
name: "two Constraints on zone and node, with different labelSelectors, 3 out of 4 nodes are candidates",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
|
||||
SpreadConstraint(1, "zone", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("bar").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("bar").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
|
||||
@ -540,23 +519,23 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-y2").Node("node-y").Label("bar", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label(v1.LabelHostname, "node-x").Obj(),
|
||||
},
|
||||
failedNodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
|
||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label(v1.LabelHostname, "node-y").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 80},
|
||||
{Name: "node-b", Score: 60},
|
||||
{Name: "node-a", Score: 75},
|
||||
{Name: "node-b", Score: 25},
|
||||
{Name: "node-x", Score: 100},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "existing pods in a different namespace do not count",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").
|
||||
SpreadConstraint(1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj()).
|
||||
Obj(),
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a1").Namespace("ns1").Node("node-a").Label("foo", "").Obj(),
|
||||
@ -565,8 +544,8 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
st.MakePod().Name("p-b2").Node("node-b").Label("foo", "").Obj(),
|
||||
},
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
},
|
||||
want: []framework.NodeScore{
|
||||
{Name: "node-a", Score: 100},
|
||||
@ -576,11 +555,11 @@ func TestPodTopologySpreadScore(t *testing.T) {
|
||||
{
|
||||
name: "terminating Pods should be excluded",
|
||||
pod: st.MakePod().Name("p").Label("foo", "").SpreadConstraint(
|
||||
1, "node", v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj(),
|
||||
1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Exists("foo").Obj(),
|
||||
).Obj(),
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label("node", "node-b").Obj(),
|
||||
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
|
||||
st.MakeNode().Name("node-b").Label(v1.LabelHostname, "node-b").Obj(),
|
||||
},
|
||||
existingPods: []*v1.Pod{
|
||||
st.MakePod().Name("p-a").Node("node-a").Label("foo", "").Terminating().Obj(),
|
||||
|
Loading…
Reference in New Issue
Block a user