implementation for MatchLabelKeys in TopologySpreadConstraint

Signed-off-by: Alex Wang <wangqingcan1990@gmail.com>
This commit is contained in:
Alex Wang 2022-07-30 13:23:49 +08:00
parent e6c2bf8516
commit f4bc904376
14 changed files with 576 additions and 188 deletions

View File

@ -515,6 +515,13 @@ const (
// Enables scaling down replicas via logarithmic comparison of creation/ready timestamps // Enables scaling down replicas via logarithmic comparison of creation/ready timestamps
LogarithmicScaleDown featuregate.Feature = "LogarithmicScaleDown" LogarithmicScaleDown featuregate.Feature = "LogarithmicScaleDown"
// owner: @denkensk
// kep: http://kep.k8s.io/3243
// alpha: v1.25
//
// Enable MatchLabelKeys in PodTopologySpread.
MatchLabelKeysInPodTopologySpread featuregate.Feature = "MatchLabelKeysInPodTopologySpread"
// owner: @krmayankk // owner: @krmayankk
// alpha: v1.24 // alpha: v1.24
// //
@ -948,6 +955,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
LogarithmicScaleDown: {Default: true, PreRelease: featuregate.Beta}, LogarithmicScaleDown: {Default: true, PreRelease: featuregate.Beta},
MatchLabelKeysInPodTopologySpread: {Default: false, PreRelease: featuregate.Alpha},
MaxUnavailableStatefulSet: {Default: false, PreRelease: featuregate.Alpha}, MaxUnavailableStatefulSet: {Default: false, PreRelease: featuregate.Alpha},
MemoryManager: {Default: true, PreRelease: featuregate.Beta}, MemoryManager: {Default: true, PreRelease: featuregate.Beta},

View File

@ -644,8 +644,8 @@ func TestDryRunPreemption(t *testing.T) {
nodeNames: []string{"node-a/zone1", "node-b/zone1", "node-x/zone2"}, nodeNames: []string{"node-a/zone1", "node-b/zone1", "node-x/zone2"},
testPods: []*v1.Pod{ testPods: []*v1.Pod{
st.MakePod().Name("p").UID("p").Label("foo", "").Priority(highPriority). st.MakePod().Name("p").UID("p").Label("foo", "").Priority(highPriority).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "hostname", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "hostname", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
}, },
initPods: []*v1.Pod{ initPods: []*v1.Pod{
@ -1486,8 +1486,8 @@ func TestPreempt(t *testing.T) {
{ {
name: "preemption for topology spread constraints", name: "preemption for topology spread constraints",
pod: st.MakePod().Name("p").UID("p").Namespace(v1.NamespaceDefault).Label("foo", "").Priority(highPriority). pod: st.MakePod().Name("p").UID("p").Namespace(v1.NamespaceDefault).Label("foo", "").Priority(highPriority).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "hostname", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "hostname", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
pods: []*v1.Pod{ pods: []*v1.Pod{
st.MakePod().Name("p-a1").UID("p-a1").Namespace(v1.NamespaceDefault).Node("node-a").Label("foo", "").Priority(highPriority).Obj(), st.MakePod().Name("p-a1").UID("p-a1").Namespace(v1.NamespaceDefault).Node("node-a").Label("foo", "").Priority(highPriority).Obj(),

View File

@ -24,4 +24,5 @@ type Features struct {
EnableVolumeCapacityPriority bool EnableVolumeCapacityPriority bool
EnableMinDomainsInPodTopologySpread bool EnableMinDomainsInPodTopologySpread bool
EnableNodeInclusionPolicyInPodTopologySpread bool EnableNodeInclusionPolicyInPodTopologySpread bool
EnableMatchLabelKeysInPodTopologySpread bool
} }

View File

@ -63,7 +63,7 @@ func (tsc *topologySpreadConstraint) matchNodeInclusionPolicies(pod *v1.Pod, nod
// .DefaultConstraints and the selectors from the services, replication // .DefaultConstraints and the selectors from the services, replication
// controllers, replica sets and stateful sets that match the pod. // controllers, replica sets and stateful sets that match the pod.
func (pl *PodTopologySpread) buildDefaultConstraints(p *v1.Pod, action v1.UnsatisfiableConstraintAction) ([]topologySpreadConstraint, error) { func (pl *PodTopologySpread) buildDefaultConstraints(p *v1.Pod, action v1.UnsatisfiableConstraintAction) ([]topologySpreadConstraint, error) {
constraints, err := filterTopologySpreadConstraints(pl.defaultConstraints, action, pl.enableMinDomainsInPodTopologySpread, pl.enableNodeInclusionPolicyInPodTopologySpread) constraints, err := pl.filterTopologySpreadConstraints(pl.defaultConstraints, p.Labels, action)
if err != nil || len(constraints) == 0 { if err != nil || len(constraints) == 0 {
return nil, err return nil, err
} }
@ -87,7 +87,7 @@ func nodeLabelsMatchSpreadConstraints(nodeLabels map[string]string, constraints
return true return true
} }
func filterTopologySpreadConstraints(constraints []v1.TopologySpreadConstraint, action v1.UnsatisfiableConstraintAction, enableMinDomainsInPodTopologySpread, enableNodeInclusionPolicyInPodTopologySpread bool) ([]topologySpreadConstraint, error) { func (pl *PodTopologySpread) filterTopologySpreadConstraints(constraints []v1.TopologySpreadConstraint, podLabels map[string]string, action v1.UnsatisfiableConstraintAction) ([]topologySpreadConstraint, error) {
var result []topologySpreadConstraint var result []topologySpreadConstraint
for _, c := range constraints { for _, c := range constraints {
if c.WhenUnsatisfiable == action { if c.WhenUnsatisfiable == action {
@ -95,6 +95,19 @@ func filterTopologySpreadConstraints(constraints []v1.TopologySpreadConstraint,
if err != nil { if err != nil {
return nil, err return nil, err
} }
if pl.enableMatchLabelKeysInPodTopologySpread && len(c.MatchLabelKeys) > 0 {
matchLabels := make(labels.Set)
for _, labelKey := range c.MatchLabelKeys {
if value, ok := podLabels[labelKey]; ok {
matchLabels[labelKey] = value
}
}
if len(matchLabels) > 0 {
selector = mergeLabelSetWithSelector(matchLabels, selector)
}
}
tsc := topologySpreadConstraint{ tsc := topologySpreadConstraint{
MaxSkew: c.MaxSkew, MaxSkew: c.MaxSkew,
TopologyKey: c.TopologyKey, TopologyKey: c.TopologyKey,
@ -103,10 +116,10 @@ func filterTopologySpreadConstraints(constraints []v1.TopologySpreadConstraint,
NodeAffinityPolicy: v1.NodeInclusionPolicyHonor, // If NodeAffinityPolicy is nil, we treat NodeAffinityPolicy as "Honor". NodeAffinityPolicy: v1.NodeInclusionPolicyHonor, // If NodeAffinityPolicy is nil, we treat NodeAffinityPolicy as "Honor".
NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore, // If NodeTaintsPolicy is nil, we treat NodeTaintsPolicy as "Ignore". NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore, // If NodeTaintsPolicy is nil, we treat NodeTaintsPolicy as "Ignore".
} }
if enableMinDomainsInPodTopologySpread && c.MinDomains != nil { if pl.enableMinDomainsInPodTopologySpread && c.MinDomains != nil {
tsc.MinDomains = *c.MinDomains tsc.MinDomains = *c.MinDomains
} }
if enableNodeInclusionPolicyInPodTopologySpread { if pl.enableNodeInclusionPolicyInPodTopologySpread {
if c.NodeAffinityPolicy != nil { if c.NodeAffinityPolicy != nil {
tsc.NodeAffinityPolicy = *c.NodeAffinityPolicy tsc.NodeAffinityPolicy = *c.NodeAffinityPolicy
} }
@ -120,6 +133,17 @@ func filterTopologySpreadConstraints(constraints []v1.TopologySpreadConstraint,
return result, nil return result, nil
} }
func mergeLabelSetWithSelector(matchLabels labels.Set, s labels.Selector) labels.Selector {
mergedSelector := labels.SelectorFromSet(matchLabels)
if requirements, ok := s.Requirements(); ok {
for _, r := range requirements {
mergedSelector = mergedSelector.Add(r)
}
}
return mergedSelector
}
func countPodsMatchSelector(podInfos []*framework.PodInfo, selector labels.Selector, ns string) int { func countPodsMatchSelector(podInfos []*framework.PodInfo, selector labels.Selector, ns string) int {
count := 0 count := 0
for _, p := range podInfos { for _, p := range podInfos {

View File

@ -244,11 +244,10 @@ func (pl *PodTopologySpread) calPreFilterState(ctx context.Context, pod *v1.Pod)
if len(pod.Spec.TopologySpreadConstraints) > 0 { if len(pod.Spec.TopologySpreadConstraints) > 0 {
// We have feature gating in APIServer to strip the spec // We have feature gating in APIServer to strip the spec
// so don't need to re-check feature gate, just check length of Constraints. // so don't need to re-check feature gate, just check length of Constraints.
constraints, err = filterTopologySpreadConstraints( constraints, err = pl.filterTopologySpreadConstraints(
pod.Spec.TopologySpreadConstraints, pod.Spec.TopologySpreadConstraints,
pod.Labels,
v1.DoNotSchedule, v1.DoNotSchedule,
pl.enableMinDomainsInPodTopologySpread,
pl.enableNodeInclusionPolicyInPodTopologySpread,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("obtaining pod's hard topology spread constraints: %w", err) return nil, fmt.Errorf("obtaining pod's hard topology spread constraints: %w", err)

View File

@ -55,7 +55,8 @@ var (
honorPolicy = v1.NodeInclusionPolicyHonor honorPolicy = v1.NodeInclusionPolicyHonor
fooSelector = st.MakeLabelSelector().Exists("foo").Obj() fooSelector = st.MakeLabelSelector().Exists("foo").Obj()
barSelector = st.MakeLabelSelector().Exists("bar").Obj() barSelector = st.MakeLabelSelector().Exists("bar").Obj()
taints = []v1.Taint{{Key: v1.TaintNodeUnschedulable, Value: "", Effect: v1.TaintEffectPreferNoSchedule}}
taints = []v1.Taint{{Key: v1.TaintNodeUnschedulable, Value: "", Effect: v1.TaintEffectPreferNoSchedule}}
) )
func (p *criticalPaths) sort() { func (p *criticalPaths) sort() {
@ -77,11 +78,12 @@ func TestPreFilterState(t *testing.T) {
want *preFilterState want *preFilterState
enableMinDomains bool enableMinDomains bool
enableNodeInclustionPolicy bool enableNodeInclustionPolicy bool
enableMatchLabelKeys bool
}{ }{
{ {
name: "clean cluster with one spreadConstraint", name: "clean cluster with one spreadConstraint",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(5, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Label("foo", "bar").Obj(), nil, nil, nil). SpreadConstraint(5, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Label("foo", "bar").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -112,7 +114,7 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "normal case with one spreadConstraint", name: "normal case with one spreadConstraint",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -150,7 +152,7 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "normal case with one spreadConstraint, on a 3-zone cluster", name: "normal case with one spreadConstraint, on a 3-zone cluster",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -191,7 +193,7 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "namespace mismatch doesn't count", name: "namespace mismatch doesn't count",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -229,8 +231,8 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "normal case with two spreadConstraints", name: "normal case with two spreadConstraints",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -283,10 +285,10 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "soft spreadConstraints should be bypassed", name: "soft spreadConstraints should be bypassed",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -337,8 +339,8 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "different labelSelectors - simple version", name: "different labelSelectors - simple version",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -384,8 +386,8 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "different labelSelectors - complex pods", name: "different labelSelectors - complex pods",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -437,8 +439,8 @@ func TestPreFilterState(t *testing.T) {
name: "two spreadConstraints, and with podAffinity", name: "two spreadConstraints, and with podAffinity",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityNotIn("node", []string{"node-x"}). // exclude node-x NodeAffinityNotIn("node", []string{"node-x"}). // exclude node-x
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -538,8 +540,8 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "default constraints and a service, but pod has constraints", name: "default constraints and a service, but pod has constraints",
pod: st.MakePod().Name("p").Label("foo", "bar").Label("baz", "tar"). pod: st.MakePod().Name("p").Label("foo", "bar").Label("baz", "tar").
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Label("baz", "tar").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Label("baz", "tar").Obj(), nil, nil, nil, nil).
SpreadConstraint(2, "planet", v1.ScheduleAnyway, st.MakeLabelSelector().Label("fot", "rok").Obj(), nil, nil, nil). SpreadConstraint(2, "planet", v1.ScheduleAnyway, st.MakeLabelSelector().Label("fot", "rok").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
defaultConstraints: []v1.TopologySpreadConstraint{ defaultConstraints: []v1.TopologySpreadConstraint{
{MaxSkew: 2, TopologyKey: "node", WhenUnsatisfiable: v1.DoNotSchedule}, {MaxSkew: 2, TopologyKey: "node", WhenUnsatisfiable: v1.DoNotSchedule},
@ -578,8 +580,8 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "TpKeyToDomainsNum is calculated when MinDomains is enabled", name: "TpKeyToDomainsNum is calculated when MinDomains is enabled",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -638,7 +640,7 @@ func TestPreFilterState(t *testing.T) {
name: "feature gate disabled with NodeAffinityPolicy", name: "feature gate disabled with NodeAffinityPolicy",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -676,7 +678,7 @@ func TestPreFilterState(t *testing.T) {
name: "NodeAffinityPolicy honored with labelSelectors", name: "NodeAffinityPolicy honored with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -714,7 +716,7 @@ func TestPreFilterState(t *testing.T) {
name: "NodeAffinityPolicy ignored with labelSelectors", name: "NodeAffinityPolicy ignored with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -753,7 +755,7 @@ func TestPreFilterState(t *testing.T) {
name: "NodeAffinityPolicy honored with nodeAffinity", name: "NodeAffinityPolicy honored with nodeAffinity",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -791,7 +793,7 @@ func TestPreFilterState(t *testing.T) {
name: "NodeAffinityPolicy ignored with nodeAffinity", name: "NodeAffinityPolicy ignored with nodeAffinity",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -829,7 +831,7 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "feature gate disabled with NodeTaintsPolicy", name: "feature gate disabled with NodeTaintsPolicy",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -867,7 +869,7 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "NodeTaintsPolicy ignored", name: "NodeTaintsPolicy ignored",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -905,7 +907,7 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "NodeTaintsPolicy honored", name: "NodeTaintsPolicy honored",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, &honorPolicy, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -943,7 +945,7 @@ func TestPreFilterState(t *testing.T) {
name: "NodeTaintsPolicy honored with tolerated taints", name: "NodeTaintsPolicy honored with tolerated taints",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
Toleration(v1.TaintNodeUnschedulable). Toleration(v1.TaintNodeUnschedulable).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, &honorPolicy, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -982,8 +984,8 @@ func TestPreFilterState(t *testing.T) {
name: "two node inclusion Constraints, zone: honor/ignore, node: ignore/ignore", name: "two node inclusion Constraints, zone: honor/ignore, node: ignore/ignore",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(),
@ -1031,8 +1033,8 @@ func TestPreFilterState(t *testing.T) {
{ {
name: "two node inclusion Constraints, zone: honor/honor, node: honor/ignore", name: "two node inclusion Constraints, zone: honor/honor, node: honor/ignore",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(),
@ -1081,8 +1083,8 @@ func TestPreFilterState(t *testing.T) {
name: "two node inclusion Constraints, zone: honor/ignore, node: honor/ignore", name: "two node inclusion Constraints, zone: honor/ignore, node: honor/ignore",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1132,8 +1134,8 @@ func TestPreFilterState(t *testing.T) {
name: "two node inclusion Constraints, zone: ignore/ignore, node: honor/honor", name: "two node inclusion Constraints, zone: ignore/ignore, node: honor/honor",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1180,6 +1182,162 @@ func TestPreFilterState(t *testing.T) {
}, },
enableNodeInclustionPolicy: true, enableNodeInclustionPolicy: true,
}, },
{
name: "matchLabelKeys ignored when feature gate disabled",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, []string{"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(),
},
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: mustConvertLabelSelectorAsSelector(t, fooSelector),
MinDomains: 1,
NodeAffinityPolicy: v1.NodeInclusionPolicyHonor,
NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore,
},
},
TpKeyToCriticalPaths: map[string]*criticalPaths{
"zone": {{"zone2", 2}, {"zone1", 3}},
},
TpPairToMatchNum: map[topologyPair]int{
{key: "zone", value: "zone1"}: 3,
{key: "zone", value: "zone2"}: 2,
},
},
enableMatchLabelKeys: false,
},
{
name: "matchLabelKeys ANDed with LabelSelector when LabelSelector isn't empty",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "a").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, []string{"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(),
},
existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "").Label("bar", "a").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Label("bar", "a").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("bar", "").Obj(),
},
want: &preFilterState{
Constraints: []topologySpreadConstraint{
{
MaxSkew: 1,
TopologyKey: "zone",
Selector: mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Exists("foo").Label("bar", "a").Obj()),
MinDomains: 1,
NodeAffinityPolicy: v1.NodeInclusionPolicyHonor,
NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore,
},
},
TpKeyToCriticalPaths: map[string]*criticalPaths{
"zone": {{"zone2", 1}, {"zone1", 1}},
},
TpPairToMatchNum: map[topologyPair]int{
{key: "zone", value: "zone1"}: 1,
{key: "zone", value: "zone2"}: 1,
},
},
enableMatchLabelKeys: true,
},
{
name: "matchLabelKeys ANDed with LabelSelector when LabelSelector is empty",
pod: st.MakePod().Name("p").Label("foo", "a").
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Obj(), nil, nil, nil, []string{"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-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
},
existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "a").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "a").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "a").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "a").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "a").Obj(),
},
want: &preFilterState{
Constraints: []topologySpreadConstraint{
{
MaxSkew: 1,
TopologyKey: "zone",
Selector: mustConvertLabelSelectorAsSelector(t, st.MakeLabelSelector().Label("foo", "a").Obj()),
MinDomains: 1,
NodeAffinityPolicy: v1.NodeInclusionPolicyHonor,
NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore,
},
},
TpKeyToCriticalPaths: map[string]*criticalPaths{
"zone": {{"zone2", 2}, {"zone1", 3}},
},
TpPairToMatchNum: map[topologyPair]int{
{key: "zone", value: "zone1"}: 3,
{key: "zone", value: "zone2"}: 2,
},
},
enableMatchLabelKeys: true,
},
{
name: "key in matchLabelKeys is ignored when it isn't exist in pod.labels",
pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, []string{"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(),
},
existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "a").Obj(),
st.MakePod().Name("p-a2").Node("node-a").Label("foo", "a").Obj(),
st.MakePod().Name("p-b1").Node("node-b").Label("foo", "a").Obj(),
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "a").Obj(),
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "a").Obj(),
},
want: &preFilterState{
Constraints: []topologySpreadConstraint{
{
MaxSkew: 1,
TopologyKey: "zone",
Selector: mustConvertLabelSelectorAsSelector(t, fooSelector),
MinDomains: 1,
NodeAffinityPolicy: v1.NodeInclusionPolicyHonor,
NodeTaintsPolicy: v1.NodeInclusionPolicyIgnore,
},
},
TpKeyToCriticalPaths: map[string]*criticalPaths{
"zone": {{"zone2", 2}, {"zone1", 3}},
},
TpPairToMatchNum: map[topologyPair]int{
{key: "zone", value: "zone1"}: 3,
{key: "zone", value: "zone2"}: 2,
},
},
enableMatchLabelKeys: true,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -1193,6 +1351,7 @@ func TestPreFilterState(t *testing.T) {
p := plugintesting.SetupPluginWithInformers(ctx, t, topologySpreadFunc, args, cache.NewSnapshot(tt.existingPods, tt.nodes), tt.objs) p := plugintesting.SetupPluginWithInformers(ctx, t, topologySpreadFunc, args, cache.NewSnapshot(tt.existingPods, tt.nodes), tt.objs)
p.(*PodTopologySpread).enableMinDomainsInPodTopologySpread = tt.enableMinDomains p.(*PodTopologySpread).enableMinDomainsInPodTopologySpread = tt.enableMinDomains
p.(*PodTopologySpread).enableNodeInclusionPolicyInPodTopologySpread = tt.enableNodeInclustionPolicy p.(*PodTopologySpread).enableNodeInclusionPolicyInPodTopologySpread = tt.enableNodeInclustionPolicy
p.(*PodTopologySpread).enableMatchLabelKeysInPodTopologySpread = tt.enableMatchLabelKeys
cs := framework.NewCycleState() cs := framework.NewCycleState()
if _, s := p.(*PodTopologySpread).PreFilter(ctx, cs, tt.pod); !s.IsSuccess() { if _, s := p.(*PodTopologySpread).PreFilter(ctx, cs, tt.pod); !s.IsSuccess() {
@ -1233,7 +1392,7 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "node a and b both impact current min match", name: "node a and b both impact current min match",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
existingPods: nil, // it's an empty cluster existingPods: nil, // it's an empty cluster
@ -1256,7 +1415,7 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "only node a impacts current min match", name: "only node a impacts current min match",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1281,7 +1440,7 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "add a pod in a different namespace doesn't change topologyKeyToMinPodsMap", name: "add a pod in a different namespace doesn't change topologyKeyToMinPodsMap",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-a1").Namespace("ns1").Node("node-a").Label("foo", "").Obj(), addedPod: st.MakePod().Name("p-a1").Namespace("ns1").Node("node-a").Label("foo", "").Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1306,7 +1465,7 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "add pod on non-critical node won't trigger re-calculation", name: "add pod on non-critical node won't trigger re-calculation",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-b2").Node("node-b").Label("foo", "").Obj(), addedPod: st.MakePod().Name("p-b2").Node("node-b").Label("foo", "").Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1331,8 +1490,8 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "node a and x both impact topologyKeyToMinPodsMap on zone and node", name: "node a and x both impact topologyKeyToMinPodsMap on zone and node",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
existingPods: nil, // it's an empty cluster existingPods: nil, // it's an empty cluster
@ -1358,8 +1517,8 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "only node a impacts topologyKeyToMinPodsMap on zone and node", name: "only node a impacts topologyKeyToMinPodsMap on zone and node",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1387,8 +1546,8 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "node a impacts topologyKeyToMinPodsMap on node, node x impacts topologyKeyToMinPodsMap on zone", name: "node a impacts topologyKeyToMinPodsMap on node, node x impacts topologyKeyToMinPodsMap on zone",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1420,8 +1579,8 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "Constraints hold different labelSelectors, node a impacts topologyKeyToMinPodsMap on zone", name: "Constraints hold different labelSelectors, node a impacts topologyKeyToMinPodsMap on zone",
preemptor: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). preemptor: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1463,8 +1622,8 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "Constraints hold different labelSelectors, node a impacts topologyKeyToMinPodsMap on both zone and node", name: "Constraints hold different labelSelectors, node a impacts topologyKeyToMinPodsMap on both zone and node",
preemptor: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). preemptor: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Label("bar", "").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Label("bar", "").Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1506,7 +1665,7 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "add a pod that doesn't match node affinity when NodeInclustionPolicy disabled", name: "add a pod that doesn't match node affinity when NodeInclustionPolicy disabled",
preemptor: st.MakePod().Name("p").Label("foo", "").NodeAffinityNotIn("foo", []string{"bar"}). preemptor: st.MakePod().Name("p").Label("foo", "").NodeAffinityNotIn("foo", []string{"bar"}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodeIdx: 0, nodeIdx: 0,
addedPod: st.MakePod().Name("p-a1").Node("node-b").Label("foo", "").Label("zone", "zone2").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-b").Label("foo", "").Label("zone", "zone2").Obj(),
@ -1532,7 +1691,7 @@ func TestPreFilterStateAddPod(t *testing.T) {
{ {
name: "add a pod that doesn't match node affinity when NodeInclustionPolicy enabled", name: "add a pod that doesn't match node affinity when NodeInclustionPolicy enabled",
preemptor: st.MakePod().Name("p").Label("foo", "").NodeAffinityNotIn("foo", []string{"bar"}). preemptor: st.MakePod().Name("p").Label("foo", "").NodeAffinityNotIn("foo", []string{"bar"}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodeIdx: 0, nodeIdx: 0,
addedPod: st.MakePod().Name("p-a1").Node("node-b").Label("foo", "").Label("zone", "zone2").Obj(), addedPod: st.MakePod().Name("p-a1").Node("node-b").Label("foo", "").Label("zone", "zone2").Obj(),
@ -1612,7 +1771,7 @@ func TestPreFilterStateRemovePod(t *testing.T) {
// So preemption is triggered. // So preemption is triggered.
name: "one spreadConstraint on zone, topologyKeyToMinPodsMap unchanged", name: "one spreadConstraint on zone, topologyKeyToMinPodsMap unchanged",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1640,7 +1799,7 @@ func TestPreFilterStateRemovePod(t *testing.T) {
{ {
name: "one spreadConstraint on node, topologyKeyToMinPodsMap changed", name: "one spreadConstraint on node, topologyKeyToMinPodsMap changed",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1670,7 +1829,7 @@ func TestPreFilterStateRemovePod(t *testing.T) {
{ {
name: "delete an irrelevant pod won't help", name: "delete an irrelevant pod won't help",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1701,7 +1860,7 @@ func TestPreFilterStateRemovePod(t *testing.T) {
{ {
name: "delete a non-existing pod won't help", name: "delete a non-existing pod won't help",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1732,8 +1891,8 @@ func TestPreFilterStateRemovePod(t *testing.T) {
{ {
name: "two spreadConstraints", name: "two spreadConstraints",
preemptor: st.MakePod().Name("p").Label("foo", ""). preemptor: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1811,7 +1970,7 @@ func BenchmarkFilter(b *testing.B) {
{ {
name: "1000nodes/single-constraint-zone", name: "1000nodes/single-constraint-zone",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelTopologyZone, v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelTopologyZone, v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPodsNum: 10000, existingPodsNum: 10000,
allNodesNum: 1000, allNodesNum: 1000,
@ -1820,7 +1979,7 @@ func BenchmarkFilter(b *testing.B) {
{ {
name: "1000nodes/single-constraint-node", name: "1000nodes/single-constraint-node",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPodsNum: 10000, existingPodsNum: 10000,
allNodesNum: 1000, allNodesNum: 1000,
@ -1829,8 +1988,8 @@ func BenchmarkFilter(b *testing.B) {
{ {
name: "1000nodes/two-Constraints-zone-node", name: "1000nodes/two-Constraints-zone-node",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, v1.LabelTopologyZone, v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelTopologyZone, v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPodsNum: 10000, existingPodsNum: 10000,
allNodesNum: 1000, allNodesNum: 1000,
@ -1887,7 +2046,7 @@ func TestSingleConstraint(t *testing.T) {
{ {
name: "no existing pods", name: "no existing pods",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1905,7 +2064,7 @@ func TestSingleConstraint(t *testing.T) {
{ {
name: "no existing pods, incoming pod doesn't match itself", name: "no existing pods, incoming pod doesn't match itself",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1923,7 +2082,7 @@ func TestSingleConstraint(t *testing.T) {
{ {
name: "existing pods in a different namespace do not count", name: "existing pods in a different namespace do not count",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1947,7 +2106,7 @@ func TestSingleConstraint(t *testing.T) {
{ {
name: "pods spread across zones as 3/3, all nodes fit", name: "pods spread across zones as 3/3, all nodes fit",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1975,7 +2134,7 @@ func TestSingleConstraint(t *testing.T) {
// can cause unexpected behavior // can cause unexpected behavior
name: "pods spread across zones as 1/2 due to absence of label 'zone' on node-b", name: "pods spread across zones as 1/2 due to absence of label 'zone' on node-b",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -1999,7 +2158,7 @@ func TestSingleConstraint(t *testing.T) {
{ {
name: "pod cannot be scheduled as all nodes don't have label 'rack'", name: "pod cannot be scheduled as all nodes don't have label 'rack'",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "rack", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "rack", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2013,7 +2172,7 @@ func TestSingleConstraint(t *testing.T) {
{ {
name: "pods spread across nodes as 2/1/0/3, only node-x fits", name: "pods spread across nodes as 2/1/0/3, only node-x fits",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2039,7 +2198,7 @@ func TestSingleConstraint(t *testing.T) {
{ {
name: "pods spread across nodes as 2/1/0/3, maxSkew is 2, node-b and node-x fit", name: "pods spread across nodes as 2/1/0/3, maxSkew is 2, node-b and node-x fit",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(2, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(2, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2069,7 +2228,7 @@ func TestSingleConstraint(t *testing.T) {
// as the incoming pod doesn't have label "foo" // as the incoming pod doesn't have label "foo"
name: "pods spread across nodes as 2/1/0/3, but pod doesn't match itself", name: "pods spread across nodes as 2/1/0/3, but pod doesn't match itself",
pod: st.MakePod().Name("p").Label("bar", ""). pod: st.MakePod().Name("p").Label("bar", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2101,7 +2260,7 @@ func TestSingleConstraint(t *testing.T) {
name: "incoming pod has nodeAffinity, pods spread as 2/~1~/~0~/3, hence node-a fits", name: "incoming pod has nodeAffinity, pods spread as 2/~1~/~0~/3, hence node-a fits",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("node", []string{"node-a", "node-y"}). NodeAffinityIn("node", []string{"node-a", "node-y"}).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2127,7 +2286,7 @@ func TestSingleConstraint(t *testing.T) {
{ {
name: "terminating Pods should be excluded", name: "terminating Pods should be excluded",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -2147,7 +2306,7 @@ func TestSingleConstraint(t *testing.T) {
name: "incoming pod has nodeAffinity, pods spread as 0/~2~/0/1, hence node-a fits", name: "incoming pod has nodeAffinity, pods spread as 0/~2~/0/1, hence node-a fits",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityNotIn("node", []string{"node-b"}). NodeAffinityNotIn("node", []string{"node-b"}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2177,6 +2336,7 @@ func TestSingleConstraint(t *testing.T) {
pointer.Int32(4), // larger than the number of domains(3) pointer.Int32(4), // larger than the number of domains(3)
nil, nil,
nil, nil,
nil,
).Obj(), ).Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -2207,6 +2367,7 @@ func TestSingleConstraint(t *testing.T) {
pointer.Int32(2), // smaller than the number of domains(3) pointer.Int32(2), // smaller than the number of domains(3)
nil, nil,
nil, nil,
nil,
).Obj(), ).Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -2237,6 +2398,7 @@ func TestSingleConstraint(t *testing.T) {
pointer.Int32(3), // larger than the number of domains(2) pointer.Int32(3), // larger than the number of domains(2)
nil, nil,
nil, nil,
nil,
).Obj(), ).Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2267,6 +2429,7 @@ func TestSingleConstraint(t *testing.T) {
pointer.Int32(1), // smaller than the number of domains(2) pointer.Int32(1), // smaller than the number of domains(2)
nil, nil,
nil, nil,
nil,
).Obj(), ).Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2292,7 +2455,7 @@ func TestSingleConstraint(t *testing.T) {
name: "NodeAffinityPolicy honored with labelSelectors", name: "NodeAffinityPolicy honored with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -2318,7 +2481,7 @@ func TestSingleConstraint(t *testing.T) {
name: "NodeAffinityPolicy ignored with labelSelectors", name: "NodeAffinityPolicy ignored with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -2344,7 +2507,7 @@ func TestSingleConstraint(t *testing.T) {
name: "NodeAffinityPolicy honored with nodeAffinity", name: "NodeAffinityPolicy honored with nodeAffinity",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -2370,7 +2533,7 @@ func TestSingleConstraint(t *testing.T) {
name: "NodeAffinityPolicy ignored with labelSelectors", name: "NodeAffinityPolicy ignored with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -2395,7 +2558,7 @@ func TestSingleConstraint(t *testing.T) {
// pods spread across node as 1/1/0/~0~ // pods spread across node as 1/1/0/~0~
name: "NodeTaintsPolicy honored", name: "NodeTaintsPolicy honored",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -2420,7 +2583,7 @@ func TestSingleConstraint(t *testing.T) {
// pods spread across node as 1/1/0/~1~ // pods spread across node as 1/1/0/~1~
name: "NodeTaintsPolicy ignored", name: "NodeTaintsPolicy ignored",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -2480,8 +2643,8 @@ func TestMultipleConstraints(t *testing.T) {
// intersection of (1) and (2) returns node-x // intersection of (1) and (2) returns node-x
name: "two Constraints on zone and node, spreads = [3/3, 2/1/0/3]", name: "two Constraints on zone and node, spreads = [3/3, 2/1/0/3]",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2510,8 +2673,8 @@ func TestMultipleConstraints(t *testing.T) {
// intersection of (1) and (2) returns no node // intersection of (1) and (2) returns no node
name: "two Constraints on zone and node, spreads = [3/4, 2/1/0/4]", name: "two Constraints on zone and node, spreads = [3/4, 2/1/0/4]",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2541,8 +2704,8 @@ func TestMultipleConstraints(t *testing.T) {
// intersection of (1) and (2) returns node-x // intersection of (1) and (2) returns node-x
name: "Constraints hold different labelSelectors, spreads = [1/0, 1/0/0/1]", name: "Constraints hold different labelSelectors, spreads = [1/0, 1/0/0/1]",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2567,8 +2730,8 @@ func TestMultipleConstraints(t *testing.T) {
// intersection of (1) and (2) returns no node // intersection of (1) and (2) returns no node
name: "Constraints hold different labelSelectors, spreads = [1/0, 0/0/1/1]", name: "Constraints hold different labelSelectors, spreads = [1/0, 0/0/1/1]",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2594,8 +2757,8 @@ func TestMultipleConstraints(t *testing.T) {
// intersection of (1) and (2) returns node-b // intersection of (1) and (2) returns node-b
name: "Constraints hold different labelSelectors, spreads = [2/3, 1/0/0/1]", name: "Constraints hold different labelSelectors, spreads = [2/3, 1/0/0/1]",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2623,8 +2786,8 @@ func TestMultipleConstraints(t *testing.T) {
// intersection of (1) and (2) returns node-a and node-b // intersection of (1) and (2) returns node-a and node-b
name: "Constraints hold different labelSelectors but pod doesn't match itself on 'zone' constraint", name: "Constraints hold different labelSelectors but pod doesn't match itself on 'zone' constraint",
pod: st.MakePod().Name("p").Label("bar", ""). pod: st.MakePod().Name("p").Label("bar", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2650,8 +2813,8 @@ func TestMultipleConstraints(t *testing.T) {
// intersection of (1) and (2) returns node-b // intersection of (1) and (2) returns node-b
name: "two Constraints on zone and node, absence of label 'node' on node-x, spreads = [1/1, 1/0/0/1]", name: "two Constraints on zone and node, absence of label 'node' on node-x, spreads = [1/1, 1/0/0/1]",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
@ -2677,8 +2840,8 @@ func TestMultipleConstraints(t *testing.T) {
name: "two node inclusion Constraints, zone: honor/ignore, node: ignore/ignore", name: "two node inclusion Constraints, zone: honor/ignore, node: ignore/ignore",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(),
@ -2705,8 +2868,8 @@ func TestMultipleConstraints(t *testing.T) {
// intersection of (1) and (2) returns node-x // intersection of (1) and (2) returns node-x
name: "two node inclusion Constraints, zone: honor/honor, node: honor/ignore", name: "two node inclusion Constraints, zone: honor/honor, node: honor/ignore",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(),
@ -2734,8 +2897,8 @@ func TestMultipleConstraints(t *testing.T) {
name: "two node inclusion Constraints, zone: honor/ignore, node: honor/ignore", name: "two node inclusion Constraints, zone: honor/ignore, node: honor/ignore",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(),
@ -2763,8 +2926,8 @@ func TestMultipleConstraints(t *testing.T) {
name: "two node inclusion Constraints, zone: honor/honor, node: ignore/ignore", name: "two node inclusion Constraints, zone: honor/honor, node: ignore/ignore",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "zone", v1.DoNotSchedule, fooSelector, nil, nil, &honorPolicy, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, fooSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Label("foo", "").Obj(),

View File

@ -64,6 +64,7 @@ type PodTopologySpread struct {
statefulSets appslisters.StatefulSetLister statefulSets appslisters.StatefulSetLister
enableMinDomainsInPodTopologySpread bool enableMinDomainsInPodTopologySpread bool
enableNodeInclusionPolicyInPodTopologySpread bool enableNodeInclusionPolicyInPodTopologySpread bool
enableMatchLabelKeysInPodTopologySpread bool
} }
var _ framework.PreFilterPlugin = &PodTopologySpread{} var _ framework.PreFilterPlugin = &PodTopologySpread{}
@ -98,6 +99,7 @@ func New(plArgs runtime.Object, h framework.Handle, fts feature.Features) (frame
defaultConstraints: args.DefaultConstraints, defaultConstraints: args.DefaultConstraints,
enableMinDomainsInPodTopologySpread: fts.EnableMinDomainsInPodTopologySpread, enableMinDomainsInPodTopologySpread: fts.EnableMinDomainsInPodTopologySpread,
enableNodeInclusionPolicyInPodTopologySpread: fts.EnableNodeInclusionPolicyInPodTopologySpread, enableNodeInclusionPolicyInPodTopologySpread: fts.EnableNodeInclusionPolicyInPodTopologySpread,
enableMatchLabelKeysInPodTopologySpread: fts.EnableMatchLabelKeysInPodTopologySpread,
} }
if args.DefaultingType == config.SystemDefaulting { if args.DefaultingType == config.SystemDefaulting {
pl.defaultConstraints = systemDefaultConstraints pl.defaultConstraints = systemDefaultConstraints

View File

@ -59,11 +59,10 @@ func (s *preScoreState) Clone() framework.StateData {
func (pl *PodTopologySpread) initPreScoreState(s *preScoreState, pod *v1.Pod, filteredNodes []*v1.Node, requireAllTopologies bool) error { func (pl *PodTopologySpread) initPreScoreState(s *preScoreState, pod *v1.Pod, filteredNodes []*v1.Node, requireAllTopologies bool) error {
var err error var err error
if len(pod.Spec.TopologySpreadConstraints) > 0 { if len(pod.Spec.TopologySpreadConstraints) > 0 {
s.Constraints, err = filterTopologySpreadConstraints( s.Constraints, err = pl.filterTopologySpreadConstraints(
pod.Spec.TopologySpreadConstraints, pod.Spec.TopologySpreadConstraints,
pod.Labels,
v1.ScheduleAnyway, v1.ScheduleAnyway,
pl.enableMinDomainsInPodTopologySpread,
pl.enableNodeInclusionPolicyInPodTopologySpread,
) )
if err != nil { if err != nil {
return fmt.Errorf("obtaining pod's soft topology spread constraints: %w", err) return fmt.Errorf("obtaining pod's soft topology spread constraints: %w", err)

View File

@ -55,8 +55,8 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
{ {
name: "normal case", name: "normal case",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
@ -96,8 +96,8 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
{ {
name: "node-x doesn't have label zone", name: "node-x doesn't have label zone",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label(v1.LabelHostname, "node-a").Obj(),
@ -253,8 +253,8 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
name: "default constraints and a replicaset, but pod has constraints", name: "default constraints and a replicaset, but pod has constraints",
pod: st.MakePod().Name("p").Namespace("default").Label("foo", "bar").Label("baz", "sup"). pod: st.MakePod().Name("p").Namespace("default").Label("foo", "bar").Label("baz", "sup").
OwnerReference("rs1", appsv1.SchemeGroupVersion.WithKind("ReplicaSet")). OwnerReference("rs1", appsv1.SchemeGroupVersion.WithKind("ReplicaSet")).
SpreadConstraint(1, "zone", v1.DoNotSchedule, barSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, barSelector, nil, nil, nil, nil).
SpreadConstraint(2, "planet", v1.ScheduleAnyway, st.MakeLabelSelector().Label("baz", "sup").Obj(), nil, nil, nil). SpreadConstraint(2, "planet", v1.ScheduleAnyway, st.MakeLabelSelector().Label("baz", "sup").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
config: config.PodTopologySpreadArgs{ config: config.PodTopologySpreadArgs{
DefaultConstraints: []v1.TopologySpreadConstraint{ DefaultConstraints: []v1.TopologySpreadConstraint{
@ -294,7 +294,7 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
name: "NodeAffinityPolicy honored with labelSelectors", name: "NodeAffinityPolicy honored with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(),
@ -328,7 +328,7 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
name: "NodeAffinityPolicy ignored with labelSelectors", name: "NodeAffinityPolicy ignored with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(),
@ -362,7 +362,7 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
name: "NodeAffinityPolicy honored with nodeAffinity", name: "NodeAffinityPolicy honored with nodeAffinity",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(),
@ -396,7 +396,7 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
name: "NodeAffinityPolicy ignored with nodeAffinity", name: "NodeAffinityPolicy ignored with nodeAffinity",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(),
@ -429,7 +429,7 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
{ {
name: "NodeTaintsPolicy honored", name: "NodeTaintsPolicy honored",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, nil, &honorPolicy, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(),
@ -462,7 +462,7 @@ func TestPreScoreStateEmptyNodes(t *testing.T) {
{ {
name: "NodeTaintsPolicy ignored", name: "NodeTaintsPolicy ignored",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label("zone", "zone1").Label("foo", "").Label(v1.LabelHostname, "node-a").Obj(),
@ -537,6 +537,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
objs []runtime.Object objs []runtime.Object
want framework.NodeScoreList want framework.NodeScoreList
enableNodeInclustionPolicy bool enableNodeInclustionPolicy bool
enableMatchLabelKeys bool
}{ }{
// Explanation on the Legend: // Explanation on the Legend:
// a) X/Y means there are X matching pods on node1 and Y on node2, both nodes are candidates // a) X/Y means there are X matching pods on node1 and Y on node2, both nodes are candidates
@ -547,7 +548,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
{ {
name: "one constraint on node, no existing pods", name: "one constraint on node, no existing pods",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
@ -562,7 +563,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
// if there is only one candidate node, it should be scored to 100 // if there is only one candidate node, it should be scored to 100
name: "one constraint on node, only one node is candidate", name: "one constraint on node, only one node is candidate",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -582,7 +583,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
{ {
name: "one constraint on node, all nodes have the same number of matching pods", name: "one constraint on node, all nodes have the same number of matching pods",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -601,7 +602,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
// matching pods spread as 2/1/0/3. // matching pods spread as 2/1/0/3.
name: "one constraint on node, all 4 nodes are candidates", name: "one constraint on node, all 4 nodes are candidates",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -628,7 +629,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
{ {
name: "one constraint on node, all 4 nodes are candidates, maxSkew=2", name: "one constraint on node, all 4 nodes are candidates, maxSkew=2",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(2, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(2, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
// matching pods spread as 2/1/0/3. // matching pods spread as 2/1/0/3.
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -656,7 +657,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
{ {
name: "one constraint on node, all 4 nodes are candidates, maxSkew=3", name: "one constraint on node, all 4 nodes are candidates, maxSkew=3",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(3, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(3, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
// matching pods spread as 4/3/2/1. // matching pods spread as 4/3/2/1.
@ -723,7 +724,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
// matching pods spread as 4/2/1/~3~ (node4 is not a candidate) // 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", name: "one constraint on node, 3 out of 4 nodes are candidates",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -755,7 +756,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
// matching pods spread as 4/?2?/1/~3~, total = 4+?+1 = 5 (as node2 is problematic) // matching pods spread as 4/?2?/1/~3~, total = 4+?+1 = 5 (as node2 is problematic)
name: "one constraint on node, 3 out of 4 nodes are candidates, one node doesn't match topology key", 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", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -787,7 +788,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
// matching pods spread as 4/2/1/~3~ // matching pods spread as 4/2/1/~3~
name: "one constraint on zone, 3 out of 4 nodes are candidates", name: "one constraint on zone, 3 out of 4 nodes are candidates",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -819,8 +820,8 @@ func TestPodTopologySpreadScore(t *testing.T) {
// matching pods spread as 2/~1~/2/~4~. // matching pods spread as 2/~1~/2/~4~.
name: "two Constraints on zone and node, 2 out of 4 nodes are candidates", name: "two Constraints on zone and node, 2 out of 4 nodes are candidates",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -859,8 +860,8 @@ func TestPodTopologySpreadScore(t *testing.T) {
// For the second constraint (node): the matching pods spread as 0/1/0/1 // For the second constraint (node): the matching pods spread as 0/1/0/1
name: "two Constraints on zone and node, with different labelSelectors", name: "two Constraints on zone and node, with different labelSelectors",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -887,8 +888,8 @@ func TestPodTopologySpreadScore(t *testing.T) {
// For the second constraint (node): the matching pods spread as 0/1/0/1 // For the second constraint (node): the matching pods spread as 0/1/0/1
name: "two Constraints on zone and node, with different labelSelectors, some nodes have 0 pods", name: "two Constraints on zone and node, with different labelSelectors, some nodes have 0 pods",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-b1").Node("node-b").Label("bar", "").Obj(), st.MakePod().Name("p-b1").Node("node-b").Label("bar", "").Obj(),
@ -914,8 +915,8 @@ func TestPodTopologySpreadScore(t *testing.T) {
// For the second constraint (node): the matching pods spread as 0/1/0/~1~ // For the second constraint (node): the matching pods spread as 0/1/0/~1~
name: "two Constraints on zone and node, with different labelSelectors, 3 out of 4 nodes are candidates", 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", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Node("node-a").Label("foo", "").Obj(),
@ -940,7 +941,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
{ {
name: "existing pods in a different namespace do not count", name: "existing pods in a different namespace do not count",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p-a1").Namespace("ns1").Node("node-a").Label("foo", "").Obj(), st.MakePod().Name("p-a1").Namespace("ns1").Node("node-a").Label("foo", "").Obj(),
@ -960,7 +961,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
{ {
name: "terminating Pods should be excluded", name: "terminating Pods should be excluded",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(), st.MakeNode().Name("node-a").Label(v1.LabelHostname, "node-a").Obj(),
@ -987,6 +988,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
pointer.Int32(10), // larger than the number of domains(3) pointer.Int32(10), // larger than the number of domains(3)
nil, nil,
nil, nil,
nil,
).Obj(), ).Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -1010,7 +1012,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
name: "NodeAffinityPolicy honoed with labelSelectors", name: "NodeAffinityPolicy honoed with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -1034,7 +1036,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
name: "NodeAffinityPolicy ignored with labelSelectors", name: "NodeAffinityPolicy ignored with labelSelectors",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -1058,7 +1060,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
name: "NodeAffinityPolicy honoed with nodeAffinity", name: "NodeAffinityPolicy honoed with nodeAffinity",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -1082,7 +1084,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
name: "NodeAffinityPolicy ignored with nodeAffinity", name: "NodeAffinityPolicy ignored with nodeAffinity",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, &ignorePolicy, nil). SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Label("foo", "").Obj(),
@ -1105,7 +1107,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
{ {
name: "NodeTaintsPolicy honored", name: "NodeTaintsPolicy honored",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, &honorPolicy). SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, &honorPolicy, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -1128,7 +1130,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
{ {
name: "NodeTaintsPolicy ignored", name: "NodeTaintsPolicy ignored",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, "node", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
nodes: []*v1.Node{ nodes: []*v1.Node{
st.MakeNode().Name("node-a").Label("node", "node-a").Obj(), st.MakeNode().Name("node-a").Label("node", "node-a").Obj(),
@ -1148,6 +1150,85 @@ func TestPodTopologySpreadScore(t *testing.T) {
}, },
enableNodeInclustionPolicy: true, enableNodeInclustionPolicy: true,
}, },
{
name: "matchLabelKeys ignored when feature gate disabled",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").Label("baz", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, []string{"baz"}).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil, []string{"baz"}).
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", "").Label("bar", "").Obj(),
st.MakePod().Name("p-y1").Node("node-c").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-c").Label("bar", "").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-c").Label("zone", "zone2").Label(v1.LabelHostname, "node-c").Obj(),
st.MakeNode().Name("node-d").Label("zone", "zone2").Label(v1.LabelHostname, "node-d").Obj(),
},
want: []framework.NodeScore{
{Name: "node-a", Score: 60},
{Name: "node-b", Score: 20},
{Name: "node-c", Score: 60},
{Name: "node-d", Score: 100},
},
enableMatchLabelKeys: false,
},
{
name: "matchLabelKeys ANDed with LabelSelector when LabelSelector is empty",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, st.MakeLabelSelector().Obj(), nil, nil, nil, []string{"foo"}).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, st.MakeLabelSelector().Obj(), nil, nil, nil, []string{"bar"}).
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", "").Label("bar", "").Obj(),
st.MakePod().Name("p-y1").Node("node-c").Label("foo", "").Obj(),
st.MakePod().Name("p-y2").Node("node-c").Label("bar", "").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-c").Label("zone", "zone2").Label(v1.LabelHostname, "node-c").Obj(),
st.MakeNode().Name("node-d").Label("zone", "zone2").Label(v1.LabelHostname, "node-d").Obj(),
},
want: []framework.NodeScore{
{Name: "node-a", Score: 60},
{Name: "node-b", Score: 20},
{Name: "node-c", Score: 60},
{Name: "node-d", Score: 100},
},
enableMatchLabelKeys: true,
},
{
name: "matchLabelKeys ANDed with LabelSelector when LabelSelector isn't empty",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").Label("baz", "").
SpreadConstraint(1, "zone", v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil, []string{"baz"}).
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", "").Label("bar", "").Label("baz", "").Obj(),
st.MakePod().Name("p-c1").Node("node-c").Label("foo", "").Obj(),
st.MakePod().Name("p-c2").Node("node-c").Label("bar", "").Obj(),
st.MakePod().Name("p-d3").Node("node-c").Label("bar", "").Label("baz", "").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-c").Label("zone", "zone2").Label(v1.LabelHostname, "node-c").Obj(),
st.MakeNode().Name("node-d").Label("zone", "zone2").Label(v1.LabelHostname, "node-d").Obj(),
},
want: []framework.NodeScore{
{Name: "node-a", Score: 60},
{Name: "node-b", Score: 20},
{Name: "node-c", Score: 60},
{Name: "node-d", Score: 100},
},
enableMatchLabelKeys: true,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -1159,6 +1240,7 @@ func TestPodTopologySpreadScore(t *testing.T) {
pl := plugintesting.SetupPluginWithInformers(ctx, t, podTopologySpreadFunc, &config.PodTopologySpreadArgs{DefaultingType: config.SystemDefaulting}, cache.NewSnapshot(tt.existingPods, allNodes), tt.objs) pl := plugintesting.SetupPluginWithInformers(ctx, t, podTopologySpreadFunc, &config.PodTopologySpreadArgs{DefaultingType: config.SystemDefaulting}, cache.NewSnapshot(tt.existingPods, allNodes), tt.objs)
p := pl.(*PodTopologySpread) p := pl.(*PodTopologySpread)
p.enableNodeInclusionPolicyInPodTopologySpread = tt.enableNodeInclustionPolicy p.enableNodeInclusionPolicyInPodTopologySpread = tt.enableNodeInclustionPolicy
p.enableMatchLabelKeysInPodTopologySpread = tt.enableMatchLabelKeys
status := p.PreScore(context.Background(), state, tt.pod, tt.nodes) status := p.PreScore(context.Background(), state, tt.pod, tt.nodes)
if !status.IsSuccess() { if !status.IsSuccess() {
@ -1199,7 +1281,7 @@ func BenchmarkTestPodTopologySpreadScore(b *testing.B) {
{ {
name: "1000nodes/single-constraint-zone", name: "1000nodes/single-constraint-zone",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelTopologyZone, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelTopologyZone, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPodsNum: 10000, existingPodsNum: 10000,
allNodesNum: 1000, allNodesNum: 1000,
@ -1208,7 +1290,7 @@ func BenchmarkTestPodTopologySpreadScore(b *testing.B) {
{ {
name: "1000nodes/single-constraint-node", name: "1000nodes/single-constraint-node",
pod: st.MakePod().Name("p").Label("foo", ""). pod: st.MakePod().Name("p").Label("foo", "").
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPodsNum: 10000, existingPodsNum: 10000,
allNodesNum: 1000, allNodesNum: 1000,
@ -1217,8 +1299,8 @@ func BenchmarkTestPodTopologySpreadScore(b *testing.B) {
{ {
name: "1000nodes/two-Constraints-zone-node", name: "1000nodes/two-Constraints-zone-node",
pod: st.MakePod().Name("p").Label("foo", "").Label("bar", ""). pod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").
SpreadConstraint(1, v1.LabelTopologyZone, v1.ScheduleAnyway, fooSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelTopologyZone, v1.ScheduleAnyway, fooSelector, nil, nil, nil, nil).
SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil). SpreadConstraint(1, v1.LabelHostname, v1.ScheduleAnyway, barSelector, nil, nil, nil, nil).
Obj(), Obj(),
existingPodsNum: 10000, existingPodsNum: 10000,
allNodesNum: 1000, allNodesNum: 1000,

View File

@ -49,6 +49,7 @@ func NewInTreeRegistry() runtime.Registry {
EnableVolumeCapacityPriority: feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority), EnableVolumeCapacityPriority: feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority),
EnableMinDomainsInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread), EnableMinDomainsInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread),
EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread), EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread),
EnableMatchLabelKeysInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MatchLabelKeysInPodTopologySpread),
} }
return runtime.Registry{ return runtime.Registry{

View File

@ -1759,7 +1759,7 @@ func TestSchedulerSchedulePod(t *testing.T) {
Operator: metav1.LabelSelectorOpExists, Operator: metav1.LabelSelectorOpExists,
}, },
}, },
}, nil, nil, nil).Obj(), }, nil, nil, nil, nil).Obj(),
pods: []*v1.Pod{ pods: []*v1.Pod{
st.MakePod().Name("pod1").UID("pod1").Label("foo", "").Node("node1").Phase(v1.PodRunning).Obj(), st.MakePod().Name("pod1").UID("pod1").Label("foo", "").Node("node1").Phase(v1.PodRunning).Obj(),
}, },
@ -1786,7 +1786,7 @@ func TestSchedulerSchedulePod(t *testing.T) {
Operator: metav1.LabelSelectorOpExists, Operator: metav1.LabelSelectorOpExists,
}, },
}, },
}, nil, nil, nil).Obj(), }, nil, nil, nil, nil).Obj(),
pods: []*v1.Pod{ pods: []*v1.Pod{
st.MakePod().Name("pod1a").UID("pod1a").Label("foo", "").Node("node1").Phase(v1.PodRunning).Obj(), st.MakePod().Name("pod1a").UID("pod1a").Label("foo", "").Node("node1").Phase(v1.PodRunning).Obj(),
st.MakePod().Name("pod1b").UID("pod1b").Label("foo", "").Node("node1").Phase(v1.PodRunning).Obj(), st.MakePod().Name("pod1b").UID("pod1b").Label("foo", "").Node("node1").Phase(v1.PodRunning).Obj(),

View File

@ -547,7 +547,7 @@ func (p *PodWrapper) PodAntiAffinityNotIn(labelKey, topologyKey string, vals []s
// SpreadConstraint constructs a TopologySpreadConstraint object and injects // SpreadConstraint constructs a TopologySpreadConstraint object and injects
// into the inner pod. // into the inner pod.
func (p *PodWrapper) SpreadConstraint(maxSkew int, tpKey string, mode v1.UnsatisfiableConstraintAction, selector *metav1.LabelSelector, minDomains *int32, nodeAffinityPolicy, nodeTaintsPolicy *v1.NodeInclusionPolicy) *PodWrapper { func (p *PodWrapper) SpreadConstraint(maxSkew int, tpKey string, mode v1.UnsatisfiableConstraintAction, selector *metav1.LabelSelector, minDomains *int32, nodeAffinityPolicy, nodeTaintsPolicy *v1.NodeInclusionPolicy, matchLabelKeys []string) *PodWrapper {
c := v1.TopologySpreadConstraint{ c := v1.TopologySpreadConstraint{
MaxSkew: int32(maxSkew), MaxSkew: int32(maxSkew),
TopologyKey: tpKey, TopologyKey: tpKey,
@ -556,6 +556,7 @@ func (p *PodWrapper) SpreadConstraint(maxSkew int, tpKey string, mode v1.Unsatis
MinDomains: minDomains, MinDomains: minDomains,
NodeAffinityPolicy: nodeAffinityPolicy, NodeAffinityPolicy: nodeAffinityPolicy,
NodeTaintsPolicy: nodeTaintsPolicy, NodeTaintsPolicy: nodeTaintsPolicy,
MatchLabelKeys: matchLabelKeys,
} }
p.Spec.TopologySpreadConstraints = append(p.Spec.TopologySpreadConstraints, c) p.Spec.TopologySpreadConstraints = append(p.Spec.TopologySpreadConstraints, c)
return p return p

View File

@ -1076,12 +1076,13 @@ func TestPodTopologySpreadFilter(t *testing.T) {
candidateNodes []string // nodes expected to schedule onto candidateNodes []string // nodes expected to schedule onto
enableMinDomains bool enableMinDomains bool
enableNodeInclustionPolicy bool enableNodeInclustionPolicy bool
enableMatchLabelKeys bool
}{ }{
// note: naming starts at index 0 // note: naming starts at index 0
{ {
name: "place pod on a 1/1/0/1 cluster with MaxSkew=1, node-2 is the only fit", name: "place pod on a 1/1/0/1 cluster with MaxSkew=1, node-2 is the only fit",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p0").Node("node-0").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p0").Node("node-0").Label("foo", "").Container(pause).Obj(),
@ -1095,7 +1096,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
{ {
name: "place pod on a 2/0/0/1 cluster with MaxSkew=2, node-{1,2,3} are good fits", name: "place pod on a 2/0/0/1 cluster with MaxSkew=2, node-{1,2,3} are good fits",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(2, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(2, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p0a").Node("node-0").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p0a").Node("node-0").Label("foo", "").Container(pause).Obj(),
@ -1110,7 +1111,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
name: "pod is required to be placed on zone0, so only node-1 fits", name: "pod is required to be placed on zone0, so only node-1 fits",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeAffinityIn("zone", []string{"zone-0"}). NodeAffinityIn("zone", []string{"zone-0"}).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p0").Node("node-0").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p0").Node("node-0").Label("foo", "").Container(pause).Obj(),
@ -1123,8 +1124,8 @@ func TestPodTopologySpreadFilter(t *testing.T) {
{ {
name: "two constraints: pod can only be placed to zone-1/node-2", name: "two constraints: pod can only be placed to zone-1/node-2",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p0").Node("node-0").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p0").Node("node-0").Label("foo", "").Container(pause).Obj(),
@ -1140,8 +1141,8 @@ func TestPodTopologySpreadFilter(t *testing.T) {
name: "pod cannot be placed onto any node", name: "pod cannot be placed onto any node",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeAffinityNotIn("node", []string{"node-0"}). // mock a 3-node cluster NodeAffinityNotIn("node", []string{"node-0"}). // mock a 3-node cluster
SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1157,8 +1158,8 @@ func TestPodTopologySpreadFilter(t *testing.T) {
name: "high priority pod can preempt others", name: "high priority pod can preempt others",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).Priority(100). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).Priority(100).
NodeAffinityNotIn("node", []string{"node-0"}). // mock a 3-node cluster NodeAffinityNotIn("node", []string{"node-0"}). // mock a 3-node cluster
SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().ZeroTerminationGracePeriod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().ZeroTerminationGracePeriod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1183,6 +1184,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
pointer.Int32(4), // larger than the number of domains (= 3) pointer.Int32(4), // larger than the number of domains (= 3)
nil, nil,
nil, nil,
nil,
). ).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1209,6 +1211,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
pointer.Int32(2), // smaller than the number of domains (= 3) pointer.Int32(2), // smaller than the number of domains (= 3)
nil, nil,
nil, nil,
nil,
). ).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
@ -1234,6 +1237,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
pointer.Int32(3), // larger than the number of domains(2) pointer.Int32(3), // larger than the number of domains(2)
nil, nil,
nil, nil,
nil,
).Obj(), ).Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-0").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-0").Label("foo", "").Container(pause).Obj(),
@ -1256,6 +1260,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
pointer.Int32(1), // smaller than the number of domains(2) pointer.Int32(1), // smaller than the number of domains(2)
nil, nil,
nil, nil,
nil,
).Obj(), ).Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1271,7 +1276,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
name: "NodeAffinityPolicy honored with labelSelectors, pods spread across zone as 2/1", name: "NodeAffinityPolicy honored with labelSelectors, pods spread across zone as 2/1",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1293,7 +1298,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
name: "NodeAffinityPolicy ignored with nodeAffinity, pods spread across zone as 1/~2~", name: "NodeAffinityPolicy ignored with nodeAffinity, pods spread across zone as 1/~2~",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeAffinityIn("foo", []string{""}). NodeAffinityIn("foo", []string{""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, &ignorePolicy, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, &ignorePolicy, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1313,7 +1318,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
{ {
name: "NodeTaintsPolicy honored, pods spread across zone as 2/1", name: "NodeTaintsPolicy honored, pods spread across zone as 2/1",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, &honorPolicy). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, &honorPolicy, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1334,7 +1339,7 @@ func TestPodTopologySpreadFilter(t *testing.T) {
{ {
name: "NodeTaintsPolicy ignored, pods spread across zone as 2/2", name: "NodeTaintsPolicy ignored, pods spread across zone as 2/2",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1359,8 +1364,8 @@ func TestPodTopologySpreadFilter(t *testing.T) {
name: "two node inclusion Constraints, zone: honor/ignore, node: honor/ignore", name: "two node inclusion Constraints, zone: honor/ignore, node: honor/ignore",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1385,8 +1390,8 @@ func TestPodTopologySpreadFilter(t *testing.T) {
name: "feature gate disabled, two node inclusion Constraints, zone: honor/ignore, node: honor/ignore", name: "feature gate disabled, two node inclusion Constraints, zone: honor/ignore, node: honor/ignore",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1411,8 +1416,8 @@ func TestPodTopologySpreadFilter(t *testing.T) {
name: "two node inclusion Constraints, zone: ignore/ignore, node: honor/honor", name: "two node inclusion Constraints, zone: ignore/ignore, node: honor/honor",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, &ignorePolicy, nil). SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, &ignorePolicy, nil, nil).
SpreadConstraint(1, "node", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, &honorPolicy). SpreadConstraint(1, "node", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, &honorPolicy, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -1430,11 +1435,57 @@ func TestPodTopologySpreadFilter(t *testing.T) {
candidateNodes: []string{"node-1", "node-4"}, candidateNodes: []string{"node-1", "node-4"},
enableNodeInclustionPolicy: true, enableNodeInclustionPolicy: true,
}, },
{
name: "matchLabelKeys ignored when feature gate disabled, pods spread across zone as 2/1",
incomingPod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").Container(pause).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, []string{"bar"}).
Obj(),
existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-0").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p2a").Node("node-1").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p3a").Node("node-2").Label("foo", "").Label("bar", "").Container(pause).Obj(),
},
fits: true,
nodes: defaultNodes,
candidateNodes: []string{"node-2", "node-3"},
enableMatchLabelKeys: false,
},
{
name: "matchLabelKeys ANDed with LabelSelector when LabelSelector isn't empty, pods spread across zone as 0/1",
incomingPod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").Container(pause).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, []string{"bar"}).
Obj(),
existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-0").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p2a").Node("node-1").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p3a").Node("node-2").Label("foo", "").Label("bar", "").Container(pause).Obj(),
},
fits: true,
nodes: defaultNodes,
candidateNodes: []string{"node-0", "node-1"},
enableMatchLabelKeys: true,
},
{
name: "matchLabelKeys ANDed with LabelSelector when LabelSelector is empty, pods spread across zone as 2/1",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(1, "zone", v1.DoNotSchedule, st.MakeLabelSelector().Obj(), nil, nil, nil, []string{"foo"}).
Obj(),
existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-0").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p2a").Node("node-1").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p3a").Node("node-2").Label("foo", "").Container(pause).Obj(),
},
fits: true,
nodes: defaultNodes,
candidateNodes: []string{"node-2", "node-3"},
enableMatchLabelKeys: true,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MinDomainsInPodTopologySpread, tt.enableMinDomains)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MinDomainsInPodTopologySpread, tt.enableMinDomains)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeInclusionPolicyInPodTopologySpread, tt.enableNodeInclustionPolicy)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeInclusionPolicyInPodTopologySpread, tt.enableNodeInclustionPolicy)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MatchLabelKeysInPodTopologySpread, tt.enableMatchLabelKeys)()
testCtx := initTest(t, "pts-predicate") testCtx := initTest(t, "pts-predicate")
cs := testCtx.ClientSet cs := testCtx.ClientSet

View File

@ -449,13 +449,14 @@ func TestPodTopologySpreadScoring(t *testing.T) {
nodes []*v1.Node nodes []*v1.Node
want []string // nodes expected to schedule onto want []string // nodes expected to schedule onto
enableNodeInclustionPolicy bool enableNodeInclustionPolicy bool
enableMatchLabelKeys bool
}{ }{
// note: naming starts at index 0 // note: naming starts at index 0
// the symbol ~X~ means that node is infeasible // the symbol ~X~ means that node is infeasible
{ {
name: "place pod on a ~0~/1/2/3 cluster with MaxSkew=1, node-1 is the preferred fit", name: "place pod on a ~0~/1/2/3 cluster with MaxSkew=1, node-1 is the preferred fit",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -472,8 +473,8 @@ func TestPodTopologySpreadScoring(t *testing.T) {
{ {
name: "combined with hardSpread constraint on a ~4~/0/1/2 cluster", name: "combined with hardSpread constraint on a ~4~/0/1/2 cluster",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", hardSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p0a").Node("node-0").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p0a").Node("node-0").Label("foo", "").Container(pause).Obj(),
@ -495,8 +496,8 @@ func TestPodTopologySpreadScoring(t *testing.T) {
name: "soft constraint with two node inclusion Constraints, zone: honor/ignore, node: honor/ignore", name: "soft constraint with two node inclusion Constraints, zone: honor/ignore, node: honor/ignore",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "zone", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil). SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -521,8 +522,8 @@ func TestPodTopologySpreadScoring(t *testing.T) {
name: "soft constraint with two node inclusion Constraints, zone: ignore/ignore, node: honor/honor", name: "soft constraint with two node inclusion Constraints, zone: ignore/ignore, node: honor/honor",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause). incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
NodeSelector(map[string]string{"foo": ""}). NodeSelector(map[string]string{"foo": ""}).
SpreadConstraint(1, "zone", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, &ignorePolicy, nil). SpreadConstraint(1, "zone", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, &ignorePolicy, nil, nil).
SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, &honorPolicy). SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, &honorPolicy, nil).
Obj(), Obj(),
existingPods: []*v1.Pod{ existingPods: []*v1.Pod{
st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(), st.MakePod().Name("p1a").Node("node-1").Label("foo", "").Container(pause).Obj(),
@ -540,10 +541,65 @@ func TestPodTopologySpreadScoring(t *testing.T) {
want: []string{"node-3"}, want: []string{"node-3"},
enableNodeInclustionPolicy: true, enableNodeInclustionPolicy: true,
}, },
{
name: "matchLabelKeys ignored when feature gate disabled, node-1 is the preferred fit",
incomingPod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").Container(pause).
SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, []string{"bar"}).
Obj(),
existingPods: []*v1.Pod{
st.MakePod().Name("p1").Node("node-1").Label("foo", "").Label("bar", "").Container(pause).Obj(),
st.MakePod().Name("p2a").Node("node-2").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p2b").Node("node-2").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p3a").Node("node-3").Label("foo", "").Label("bar", "").Container(pause).Obj(),
st.MakePod().Name("p3b").Node("node-3").Label("foo", "").Label("bar", "").Container(pause).Obj(),
st.MakePod().Name("p3c").Node("node-3").Label("foo", "").Container(pause).Obj(),
},
fits: true,
nodes: defaultNodes,
want: []string{"node-1"},
enableMatchLabelKeys: false,
},
{
name: "matchLabelKeys ANDed with LabelSelector when LabelSelector isn't empty, node-2 is the preferred fit",
incomingPod: st.MakePod().Name("p").Label("foo", "").Label("bar", "").Container(pause).
SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Exists("foo").Obj(), nil, nil, nil, []string{"bar"}).
Obj(),
existingPods: []*v1.Pod{
st.MakePod().Name("p1").Node("node-1").Label("foo", "").Label("bar", "").Container(pause).Obj(),
st.MakePod().Name("p2a").Node("node-2").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p2b").Node("node-2").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p3a").Node("node-3").Label("foo", "").Label("bar", "").Container(pause).Obj(),
st.MakePod().Name("p3b").Node("node-3").Label("foo", "").Label("bar", "").Container(pause).Obj(),
st.MakePod().Name("p3c").Node("node-3").Label("foo", "").Container(pause).Obj(),
},
fits: true,
nodes: defaultNodes,
want: []string{"node-2"},
enableMatchLabelKeys: true,
},
{
name: "matchLabelKeys ANDed with LabelSelector when LabelSelector is empty, node-1 is the preferred fit",
incomingPod: st.MakePod().Name("p").Label("foo", "").Container(pause).
SpreadConstraint(1, "node", softSpread, st.MakeLabelSelector().Obj(), nil, nil, nil, []string{"foo"}).
Obj(),
existingPods: []*v1.Pod{
st.MakePod().Name("p1").Node("node-1").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p2a").Node("node-2").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p2b").Node("node-2").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p3a").Node("node-3").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p3b").Node("node-3").Label("foo", "").Container(pause).Obj(),
st.MakePod().Name("p3c").Node("node-3").Label("foo", "").Container(pause).Obj(),
},
fits: true,
nodes: defaultNodes,
want: []string{"node-1"},
enableMatchLabelKeys: true,
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeInclusionPolicyInPodTopologySpread, tt.enableNodeInclustionPolicy)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeInclusionPolicyInPodTopologySpread, tt.enableNodeInclustionPolicy)()
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MatchLabelKeysInPodTopologySpread, tt.enableMatchLabelKeys)()
testCtx := initTestSchedulerForPriorityTest(t, podtopologyspread.Name) testCtx := initTestSchedulerForPriorityTest(t, podtopologyspread.Name)
defer testutils.CleanupTest(t, testCtx) defer testutils.CleanupTest(t, testCtx)