diff --git a/pkg/scheduler/algorithm/predicates/error.go b/pkg/scheduler/algorithm/predicates/error.go index 7f35c84f93e..372cfc8ddf9 100644 --- a/pkg/scheduler/algorithm/predicates/error.go +++ b/pkg/scheduler/algorithm/predicates/error.go @@ -75,6 +75,8 @@ var ( ErrVolumeNodeConflict = newPredicateFailureError("VolumeNodeAffinityConflict", "node(s) had volume node affinity conflict") // ErrVolumeBindConflict is used for VolumeBindingNoMatch predicate error. ErrVolumeBindConflict = newPredicateFailureError("VolumeBindingNoMatch", "node(s) didn't find available persistent volumes to bind") + // ErrSpreadConstraintsNotMatch is used for EvenPodsSpread predicate error. + ErrSpreadConstraintsNotMatch = newPredicateFailureError("EvenPodsSpread", "node(s) didn't match pod topology spread constraints") // ErrFakePredicate is used for test only. The fake predicates returning false also returns error // as ErrFakePredicate. ErrFakePredicate = newPredicateFailureError("FakePredicateError", "Nodes failed the fake predicate") diff --git a/pkg/scheduler/algorithm/predicates/predicates.go b/pkg/scheduler/algorithm/predicates/predicates.go index 9a5e43c4734..6487a6bcdec 100644 --- a/pkg/scheduler/algorithm/predicates/predicates.go +++ b/pkg/scheduler/algorithm/predicates/predicates.go @@ -106,6 +106,8 @@ const ( CheckNodeDiskPressurePred = "CheckNodeDiskPressure" // CheckNodePIDPressurePred defines the name of predicate CheckNodePIDPressure. CheckNodePIDPressurePred = "CheckNodePIDPressure" + // EvenPodsSpreadPred defines the name of predicate EvenPodsSpread + EvenPodsSpreadPred = "EvenPodsSpread" // DefaultMaxGCEPDVolumes defines the maximum number of PD Volumes for GCE // GCE instances can have up to 16 PD volumes attached. @@ -148,7 +150,7 @@ var ( PodToleratesNodeTaintsPred, PodToleratesNodeNoExecuteTaintsPred, CheckNodeLabelPresencePred, CheckServiceAffinityPred, MaxEBSVolumeCountPred, MaxGCEPDVolumeCountPred, MaxCSIVolumeCountPred, MaxAzureDiskVolumeCountPred, MaxCinderVolumeCountPred, CheckVolumeBindingPred, NoVolumeZoneConflictPred, - CheckNodeMemoryPressurePred, CheckNodePIDPressurePred, CheckNodeDiskPressurePred, MatchInterPodAffinityPred} + CheckNodeMemoryPressurePred, CheckNodePIDPressurePred, CheckNodeDiskPressurePred, EvenPodsSpreadPred, MatchInterPodAffinityPred} ) // FitPredicate is a function that indicates if a pod fits into an existing node. @@ -1712,3 +1714,17 @@ func (c *VolumeBindingChecker) predicate(pod *v1.Pod, meta PredicateMetadata, no klog.V(5).Infof("All PVCs found matches for pod %v/%v, node %q", pod.Namespace, pod.Name, node.Name) return true, nil, nil } + +// EvenPodsSpreadPredicate checks if a pod can be scheduled on a node which satisfies +// its topologySpreadConstraints. +func EvenPodsSpreadPredicate(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) { + node := nodeInfo.Node() + if node == nil { + return false, nil, fmt.Errorf("node not found") + } + constraints := getHardTopologySpreadConstraints(pod) + if len(constraints) == 0 { + return true, nil, nil + } + return true, nil, nil +} diff --git a/pkg/scheduler/algorithmprovider/defaults/defaults.go b/pkg/scheduler/algorithmprovider/defaults/defaults.go index 3a290c6b110..a77ee69e069 100644 --- a/pkg/scheduler/algorithmprovider/defaults/defaults.go +++ b/pkg/scheduler/algorithmprovider/defaults/defaults.go @@ -87,6 +87,12 @@ func ApplyFeatureGates() { klog.Infof("TaintNodesByCondition is enabled, PodToleratesNodeTaints predicate is mandatory") } + // Only register EvenPodsSpreadPredicate if the feature is enabled + if utilfeature.DefaultFeatureGate.Enabled(features.EvenPodsSpread) { + factory.InsertPredicateKeyToAlgorithmProviderMap(predicates.EvenPodsSpreadPred) + factory.RegisterFitPredicate(predicates.EvenPodsSpreadPred, predicates.EvenPodsSpreadPredicate) + } + // Prioritizes nodes that satisfy pod's resource limits if utilfeature.DefaultFeatureGate.Enabled(features.ResourceLimitsPriorityFunction) { klog.Infof("Registering resourcelimits priority function")