diff --git a/pkg/scheduler/framework/plugins/podtopologyspread/common.go b/pkg/scheduler/framework/plugins/podtopologyspread/common.go index 55f8d1e42b3..5ca7f320ab9 100644 --- a/pkg/scheduler/framework/plugins/podtopologyspread/common.go +++ b/pkg/scheduler/framework/plugins/podtopologyspread/common.go @@ -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). diff --git a/pkg/scheduler/framework/plugins/podtopologyspread/filtering_test.go b/pkg/scheduler/framework/plugins/podtopologyspread/filtering_test.go index c4ce832494d..1acbf29d403 100644 --- a/pkg/scheduler/framework/plugins/podtopologyspread/filtering_test.go +++ b/pkg/scheduler/framework/plugins/podtopologyspread/filtering_test.go @@ -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", ""). diff --git a/pkg/scheduler/framework/plugins/podtopologyspread/scoring_test.go b/pkg/scheduler/framework/plugins/podtopologyspread/scoring_test.go index f60552f8448..2e9bf046c95 100644 --- a/pkg/scheduler/framework/plugins/podtopologyspread/scoring_test.go +++ b/pkg/scheduler/framework/plugins/podtopologyspread/scoring_test.go @@ -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)