diff --git a/pkg/scheduler/framework/plugins/defaultpodtopologyspread/default_pod_topology_spread.go b/pkg/scheduler/framework/plugins/defaultpodtopologyspread/default_pod_topology_spread.go index 0e6ca52cce8..d5137f3803d 100644 --- a/pkg/scheduler/framework/plugins/defaultpodtopologyspread/default_pod_topology_spread.go +++ b/pkg/scheduler/framework/plugins/defaultpodtopologyspread/default_pod_topology_spread.go @@ -67,10 +67,19 @@ func (s *postFilterState) Clone() framework.StateData { return s } +// skipDefaultPodTopologySpread returns true if the pod's TopologySpreadConstraints are specified. +func skipDefaultPodTopologySpread(pod *v1.Pod) bool { + return len(pod.Spec.TopologySpreadConstraints) != 0 +} + // Score invoked at the Score extension point. // The "score" returned in this function is the matching number of pods on the `nodeName`, // it is normalized later. func (pl *DefaultPodTopologySpread) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) { + if skipDefaultPodTopologySpread(pod) { + return 0, nil + } + c, err := state.Read(postFilterStateKey) if err != nil { return 0, framework.NewStatus(framework.Error, fmt.Sprintf("Error reading %q from cycleState: %v", postFilterStateKey, err)) @@ -96,6 +105,10 @@ func (pl *DefaultPodTopologySpread) Score(ctx context.Context, state *framework. // where zone information is included on the nodes, it favors nodes // in zones with fewer existing matching pods. func (pl *DefaultPodTopologySpread) NormalizeScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status { + if skipDefaultPodTopologySpread(pod) { + return nil + } + countsByZone := make(map[string]int64, 10) maxCountByZone := int64(0) maxCountByNodeName := int64(0) diff --git a/pkg/scheduler/framework/plugins/defaultpodtopologyspread/default_pod_topology_spread_test.go b/pkg/scheduler/framework/plugins/defaultpodtopologyspread/default_pod_topology_spread_test.go index 71e5cda6dc8..4faf0ead45b 100644 --- a/pkg/scheduler/framework/plugins/defaultpodtopologyspread/default_pod_topology_spread_test.go +++ b/pkg/scheduler/framework/plugins/defaultpodtopologyspread/default_pod_topology_spread_test.go @@ -338,6 +338,32 @@ func TestDefaultPodTopologySpreadScore(t *testing.T) { expectedList: []framework.NodeScore{{Name: "machine1", Score: 0}, {Name: "machine2", Score: 50}}, name: "Another stateful set with partial pod label matches", }, + { + pod: &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels1, + OwnerReferences: controllerRef("StatefulSet", "name", "abc123"), + }, + Spec: v1.PodSpec{ + TopologySpreadConstraints: []v1.TopologySpreadConstraint{ + { + MaxSkew: 1, + TopologyKey: "foo", + WhenUnsatisfiable: v1.DoNotSchedule, + }, + }, + }, + }, + pods: []*v1.Pod{ + {Spec: zone1Spec, ObjectMeta: metav1.ObjectMeta{Labels: labels2, OwnerReferences: controllerRef("StatefulSet", "name", "abc123")}}, + {Spec: zone1Spec, ObjectMeta: metav1.ObjectMeta{Labels: labels1, OwnerReferences: controllerRef("StatefulSet", "name", "abc123")}}, + {Spec: zone2Spec, ObjectMeta: metav1.ObjectMeta{Labels: labels1, OwnerReferences: controllerRef("StatefulSet", "name", "abc123")}}, + }, + nodes: []string{"machine1", "machine2"}, + sss: []*apps.StatefulSet{{Spec: apps.StatefulSetSpec{Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"baz": "blah"}}}}}, + expectedList: []framework.NodeScore{{Name: "machine1", Score: 0}, {Name: "machine2", Score: 0}}, + name: "Another stateful set with TopologySpreadConstraints set in pod", + }, } for _, test := range tests {