diff --git a/pkg/scheduler/algorithm/predicates/predicates.go b/pkg/scheduler/algorithm/predicates/predicates.go index e365583560..b1bace2fe3 100644 --- a/pkg/scheduler/algorithm/predicates/predicates.go +++ b/pkg/scheduler/algorithm/predicates/predicates.go @@ -1470,7 +1470,14 @@ func CheckNodeUnschedulablePredicate(pod *v1.Pod, meta algorithm.PredicateMetada return false, []algorithm.PredicateFailureReason{ErrNodeUnknownCondition}, nil } - if nodeInfo.Node().Spec.Unschedulable { + // If pod tolerate unschedulable taint, it's also tolerate `node.Spec.Unschedulable`. + podToleratesUnschedulable := v1helper.TolerationsTolerateTaint(pod.Spec.Tolerations, &v1.Taint{ + Key: algorithm.TaintNodeUnschedulable, + Effect: v1.TaintEffectNoSchedule, + }) + + // TODO (k82cn): deprecates `node.Spec.Unschedulable` in 1.13. + if nodeInfo.Node().Spec.Unschedulable && !podToleratesUnschedulable { return false, []algorithm.PredicateFailureReason{ErrNodeUnschedulable}, nil } diff --git a/pkg/scheduler/algorithm/predicates/predicates_test.go b/pkg/scheduler/algorithm/predicates/predicates_test.go index 8fe90add78..42d795819e 100644 --- a/pkg/scheduler/algorithm/predicates/predicates_test.go +++ b/pkg/scheduler/algorithm/predicates/predicates_test.go @@ -4982,3 +4982,65 @@ func TestGetMaxVols(t *testing.T) { os.Setenv(KubeMaxPDVols, previousValue) } } + +func TestCheckNodeUnschedulablePredicate(t *testing.T) { + testCases := []struct { + name string + pod *v1.Pod + node *v1.Node + fit bool + }{ + { + name: "Does not schedule pod to unschedulable node (node.Spec.Unschedulable==true)", + pod: &v1.Pod{}, + node: &v1.Node{ + Spec: v1.NodeSpec{ + Unschedulable: true, + }, + }, + fit: false, + }, + { + name: "Schedule pod to normal node", + pod: &v1.Pod{}, + node: &v1.Node{ + Spec: v1.NodeSpec{ + Unschedulable: false, + }, + }, + fit: true, + }, + { + name: "Schedule pod with toleration to unschedulable node (node.Spec.Unschedulable==true)", + pod: &v1.Pod{ + Spec: v1.PodSpec{ + Tolerations: []v1.Toleration{ + { + Key: algorithm.TaintNodeUnschedulable, + Effect: v1.TaintEffectNoSchedule, + }, + }, + }, + }, + node: &v1.Node{ + Spec: v1.NodeSpec{ + Unschedulable: true, + }, + }, + fit: true, + }, + } + + for _, test := range testCases { + nodeInfo := schedulercache.NewNodeInfo() + nodeInfo.SetNode(test.node) + fit, _, err := CheckNodeUnschedulablePredicate(test.pod, nil, nodeInfo) + if err != nil { + t.Fatalf("Failed to check node unschedulable: %v", err) + } + + if fit != test.fit { + t.Errorf("Unexpected fit: expected %v, got %v", test.fit, fit) + } + } +} diff --git a/pkg/scheduler/algorithmprovider/defaults/defaults.go b/pkg/scheduler/algorithmprovider/defaults/defaults.go index 6b18c4fa9f..ce1093cb5a 100644 --- a/pkg/scheduler/algorithmprovider/defaults/defaults.go +++ b/pkg/scheduler/algorithmprovider/defaults/defaults.go @@ -199,10 +199,13 @@ func ApplyFeatureGates() { // Fit is determined based on whether a pod can tolerate all of the node's taints factory.RegisterMandatoryFitPredicate(predicates.PodToleratesNodeTaintsPred, predicates.PodToleratesNodeTaints) + // Fit is determined based on whether a pod can tolerate unschedulable of node + factory.RegisterMandatoryFitPredicate(predicates.CheckNodeUnschedulablePred, predicates.CheckNodeUnschedulablePredicate) // Insert Key "PodToleratesNodeTaints" and "CheckNodeUnschedulable" To All Algorithm Provider // The key will insert to all providers which in algorithmProviderMap[] // if you just want insert to specific provider, call func InsertPredicateKeyToAlgoProvider() factory.InsertPredicateKeyToAlgorithmProviderMap(predicates.PodToleratesNodeTaintsPred) + factory.InsertPredicateKeyToAlgorithmProviderMap(predicates.CheckNodeUnschedulablePred) glog.Warningf("TaintNodesByCondition is enabled, PodToleratesNodeTaints predicate is mandatory") }