Optimize topology spreading for null selector

Change-Id: I28f031a040b143fa9452b4400cc3ae85d58e572c
This commit is contained in:
Aldo Culquicondor 2023-03-14 14:52:46 -04:00
parent 1cb334960c
commit 3dae9ba6d6
No known key found for this signature in database
GPG Key ID: 51D903912270D4EE
3 changed files with 122 additions and 3 deletions

View File

@ -145,6 +145,9 @@ func mergeLabelSetWithSelector(matchLabels labels.Set, s labels.Selector) labels
}
func countPodsMatchSelector(podInfos []*framework.PodInfo, selector labels.Selector, ns string) int {
if selector.Empty() {
return 0
}
count := 0
for _, p := range podInfos {
// Bypass terminating Pod (see #87621).

View File

@ -149,6 +149,44 @@ func TestPreFilterState(t *testing.T) {
},
},
},
{
name: "normal case with null label selector",
pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, nil, nil, nil, nil, nil).
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(),
},
existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
},
want: &preFilterState{
Constraints: []topologySpreadConstraint{
{
MaxSkew: 1,
TopologyKey: "zone",
Selector: labels.Nothing(),
MinDomains: 1,
NodeAffinityPolicy: v1.NodeInclusionPolicyHonor,
NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore,
},
},
TpKeyToCriticalPaths: map[string]*criticalPaths{
"zone": {{"zone2", 0}, {"zone1", 0}},
},
TpPairToMatchNum: map[topologyPair]int{
{key: "zone", value: "zone1"}: 0,
{key: "zone", value: "zone2"}: 0,
},
},
},
{
name: "normal case with one spreadConstraint, on a 3-zone cluster",
pod: st.MakePod().Name("p").Label("foo", "").
@ -2347,6 +2385,28 @@ func TestSingleConstraint(t *testing.T) {
"node-y": framework.Unschedulable,
},
},
{
name: "existing pods do not match null selector",
pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, nil, nil, nil, nil, nil).
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(),
},
existingPods: []*v1.Pod{
st.MakePod().Name("p-x1").Node("node-x").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
},
wantStatusCode: map[string]framework.Code{
"node-a": framework.Success,
"node-b": framework.Success,
"node-x": framework.Success,
"node-y": framework.Success,
},
},
{
name: "pods spread across zones as 3/3, all nodes fit",
pod: st.MakePod().Name("p").Label("foo", "").

View File

@ -18,13 +18,13 @@ package podtopologyspread
import (
"context"
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/informers"
@ -92,6 +92,38 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
TopologyNormalizingWeight: []float64{topologyNormalizingWeight(2), topologyNormalizingWeight(3)},
},
},
{
name: "null selector",
pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, nil, nil, nil, nil, nil).
Obj(),
nodes: []*v1.Node{
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(),
},
config: config.PodTopologySpreadArgs{
DefaultingType: config.ListDefaulting,
},
want: &preScoreState{
Constraints: []topologySpreadConstraint{
{
MaxSkew: 1,
TopologyKey: "zone",
Selector: labels.Nothing(),
MinDomains: 1,
NodeAffinityPolicy: v1.NodeInclusionPolicyHonor,
NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore,
},
},
IgnoredNodes: sets.NewString(),
TopologyPairToPodCounts: map[topologyPair]*int64{
{key: "zone", value: "zone1"}: pointer.Int64(0),
{key: "zone", value: "zone2"}: pointer.Int64(0),
},
TopologyNormalizingWeight: []float64{topologyNormalizingWeight(2)},
},
},
{
name: "node-x doesn't have label zone",
pod: st.MakePod().Name("p").Label("foo", "").
@ -625,6 +657,32 @@ func TestPodTopologySpreadScore(t *testing.T) {
{Name: "node-d", Score: 0},
},
},
{
name: "one constraint on node, null selector",
pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, nil, nil, nil, nil, nil).
Obj(),
existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-d1").Node("node-d").Label("foo", "").Obj(),
st.MakePod().Name("p-d2").Node("node-d").Label("foo", "").Obj(),
st.MakePod().Name("p-d3").Node("node-d").Label("foo", "").Obj(),
},
nodes: []*v1.Node{
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(),
},
want: []framework.NodeScore{
{Name: "node-a", Score: 100},
{Name: "node-b", Score: 100},
{Name: "node-c", Score: 100},
{Name: "node-d", Score: 100},
},
},
{
name: "one constraint on node, all 4 nodes are candidates, maxSkew=2",
pod: st.MakePod().Name("p").Label("foo", "").
@ -1250,14 +1308,12 @@ func TestPodTopologySpreadScore(t *testing.T) {
for _, n := range tt.nodes {
nodeName := n.Name
score, status := p.Score(ctx, state, tt.pod, nodeName)
fmt.Println("get score", score)
if !status.IsSuccess() {
t.Errorf("unexpected error: %v", status)
}
gotList = append(gotList, framework.NodeScore{Name: nodeName, Score: score})
}
fmt.Println(gotList)
status = p.NormalizeScore(ctx, state, tt.pod, gotList)
if !status.IsSuccess() {
t.Errorf("unexpected error: %v", status)