diff --git a/plugin/pkg/scheduler/algorithm/predicates/error.go b/plugin/pkg/scheduler/algorithm/predicates/error.go index 155fe18f431..b4cbc0bb59d 100644 --- a/plugin/pkg/scheduler/algorithm/predicates/error.go +++ b/plugin/pkg/scheduler/algorithm/predicates/error.go @@ -30,24 +30,27 @@ var ( // be made to pass by removing pods, or you change an existing predicate so that // it can never be made to pass by removing pods, you need to add the predicate // failure error in nodesWherePreemptionMightHelp() in scheduler/core/generic_scheduler.go - ErrDiskConflict = newPredicateFailureError("NoDiskConflict") - ErrVolumeZoneConflict = newPredicateFailureError("NoVolumeZoneConflict") - ErrNodeSelectorNotMatch = newPredicateFailureError("MatchNodeSelector") - ErrPodAffinityNotMatch = newPredicateFailureError("MatchInterPodAffinity") - ErrTaintsTolerationsNotMatch = newPredicateFailureError("PodToleratesNodeTaints") - ErrPodNotMatchHostName = newPredicateFailureError("HostName") - ErrPodNotFitsHostPorts = newPredicateFailureError("PodFitsHostPorts") - ErrNodeLabelPresenceViolated = newPredicateFailureError("CheckNodeLabelPresence") - ErrServiceAffinityViolated = newPredicateFailureError("CheckServiceAffinity") - ErrMaxVolumeCountExceeded = newPredicateFailureError("MaxVolumeCount") - ErrNodeUnderMemoryPressure = newPredicateFailureError("NodeUnderMemoryPressure") - ErrNodeUnderDiskPressure = newPredicateFailureError("NodeUnderDiskPressure") - ErrNodeOutOfDisk = newPredicateFailureError("NodeOutOfDisk") - ErrNodeNotReady = newPredicateFailureError("NodeNotReady") - ErrNodeNetworkUnavailable = newPredicateFailureError("NodeNetworkUnavailable") - ErrNodeUnschedulable = newPredicateFailureError("NodeUnschedulable") - ErrNodeUnknownCondition = newPredicateFailureError("NodeUnknownCondition") - ErrVolumeNodeConflict = newPredicateFailureError("NoVolumeNodeConflict") + ErrDiskConflict = newPredicateFailureError("NoDiskConflict") + ErrVolumeZoneConflict = newPredicateFailureError("NoVolumeZoneConflict") + ErrNodeSelectorNotMatch = newPredicateFailureError("MatchNodeSelector") + ErrPodAffinityNotMatch = newPredicateFailureError("MatchInterPodAffinity") + ErrPodAffinityRulesNotMatch = newPredicateFailureError("PodAffinityRulesNotMatch") + ErrPodAntiAffinityRulesNotMatch = newPredicateFailureError("PodAntiAffinityRulesNotMatch") + ErrExistingPodsAntiAffinityRulesNotMatch = newPredicateFailureError("ExistingPodsAntiAffinityRulesNotMatch") + ErrTaintsTolerationsNotMatch = newPredicateFailureError("PodToleratesNodeTaints") + ErrPodNotMatchHostName = newPredicateFailureError("HostName") + ErrPodNotFitsHostPorts = newPredicateFailureError("PodFitsHostPorts") + ErrNodeLabelPresenceViolated = newPredicateFailureError("CheckNodeLabelPresence") + ErrServiceAffinityViolated = newPredicateFailureError("CheckServiceAffinity") + ErrMaxVolumeCountExceeded = newPredicateFailureError("MaxVolumeCount") + ErrNodeUnderMemoryPressure = newPredicateFailureError("NodeUnderMemoryPressure") + ErrNodeUnderDiskPressure = newPredicateFailureError("NodeUnderDiskPressure") + ErrNodeOutOfDisk = newPredicateFailureError("NodeOutOfDisk") + ErrNodeNotReady = newPredicateFailureError("NodeNotReady") + ErrNodeNetworkUnavailable = newPredicateFailureError("NodeNetworkUnavailable") + ErrNodeUnschedulable = newPredicateFailureError("NodeUnschedulable") + ErrNodeUnknownCondition = newPredicateFailureError("NodeUnknownCondition") + ErrVolumeNodeConflict = newPredicateFailureError("NoVolumeNodeConflict") // ErrFakePredicate is used for test only. The fake predicates returning false also returns error // as ErrFakePredicate. ErrFakePredicate = newPredicateFailureError("FakePredicateError") diff --git a/plugin/pkg/scheduler/algorithm/predicates/predicates.go b/plugin/pkg/scheduler/algorithm/predicates/predicates.go index a2fef1bd0c5..1b6a7062016 100644 --- a/plugin/pkg/scheduler/algorithm/predicates/predicates.go +++ b/plugin/pkg/scheduler/algorithm/predicates/predicates.go @@ -17,6 +17,7 @@ limitations under the License. package predicates import ( + "errors" "fmt" "math/rand" "strconv" @@ -963,8 +964,9 @@ func (c *PodAffinityChecker) InterPodAffinityMatches(pod *v1.Pod, meta algorithm if node == nil { return false, nil, fmt.Errorf("node not found") } - if !c.satisfiesExistingPodsAntiAffinity(pod, meta, nodeInfo) { - return false, []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}, nil + if failedPredicates, error := c.satisfiesExistingPodsAntiAffinity(pod, meta, nodeInfo); failedPredicates != nil { + failedPredicates := append([]algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}, failedPredicates) + return false, failedPredicates, error } // Now check if requirements will be satisfied on this node. @@ -972,8 +974,9 @@ func (c *PodAffinityChecker) InterPodAffinityMatches(pod *v1.Pod, meta algorithm if affinity == nil || (affinity.PodAffinity == nil && affinity.PodAntiAffinity == nil) { return true, nil, nil } - if !c.satisfiesPodsAffinityAntiAffinity(pod, nodeInfo, affinity) { - return false, []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}, nil + if failedPredicates, error := c.satisfiesPodsAffinityAntiAffinity(pod, nodeInfo, affinity); failedPredicates != nil { + failedPredicates := append([]algorithm.PredicateFailureReason{ErrPodAffinityNotMatch}, failedPredicates) + return false, failedPredicates, error } if glog.V(10) { @@ -1143,10 +1146,10 @@ func (c *PodAffinityChecker) getMatchingAntiAffinityTerms(pod *v1.Pod, allPods [ // Checks if scheduling the pod onto this node would break any anti-affinity // rules indicated by the existing pods. -func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta algorithm.PredicateMetadata, nodeInfo *schedulercache.NodeInfo) bool { +func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta algorithm.PredicateMetadata, nodeInfo *schedulercache.NodeInfo) (algorithm.PredicateFailureReason, error) { node := nodeInfo.Node() if node == nil { - return false + return ErrExistingPodsAntiAffinityRulesNotMatch, fmt.Errorf("Node is nil") } var matchingTerms map[string][]matchingPodAntiAffinityTerm if predicateMeta, ok := meta.(*predicateMetadata); ok { @@ -1156,25 +1159,28 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta // present in nodeInfo. Pods on other nodes pass the filter. filteredPods, err := c.podLister.FilteredList(nodeInfo.Filter, labels.Everything()) if err != nil { - glog.Errorf("Failed to get all pods, %+v", err) - return false + errMessage := fmt.Sprintf("Failed to get all pods, %+v", err) + glog.Error(errMessage) + return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage) } if matchingTerms, err = c.getMatchingAntiAffinityTerms(pod, filteredPods); err != nil { - glog.Errorf("Failed to get all terms that pod %+v matches, err: %+v", podName(pod), err) - return false + errMessage := fmt.Sprintf("Failed to get all terms that pod %+v matches, err: %+v", podName(pod), err) + glog.Error(errMessage) + return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage) } } for _, terms := range matchingTerms { for i := range terms { term := &terms[i] if len(term.term.TopologyKey) == 0 { - glog.Error("Empty topologyKey is not allowed except for PreferredDuringScheduling pod anti-affinity") - return false + errMessage := fmt.Sprintf("Empty topologyKey is not allowed except for PreferredDuringScheduling pod anti-affinity") + glog.Error(errMessage) + return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage) } if priorityutil.NodesHaveSameTopologyKey(node, term.node, term.term.TopologyKey) { glog.V(10).Infof("Cannot schedule pod %+v onto node %v,because of PodAntiAffinityTerm %v", podName(pod), node.Name, term.term) - return false + return ErrExistingPodsAntiAffinityRulesNotMatch, nil } } } @@ -1184,27 +1190,27 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta glog.Infof("Schedule Pod %+v on Node %+v is allowed, existing pods anti-affinity rules satisfied.", podName(pod), node.Name) } - return true + return nil, nil } // Checks if scheduling the pod onto this node would break any rules of this pod. -func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, nodeInfo *schedulercache.NodeInfo, affinity *v1.Affinity) bool { +func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, nodeInfo *schedulercache.NodeInfo, affinity *v1.Affinity) (algorithm.PredicateFailureReason, error) { node := nodeInfo.Node() if node == nil { - return false + return ErrPodAffinityRulesNotMatch, fmt.Errorf("Node is nil") } filteredPods, err := c.podLister.FilteredList(nodeInfo.Filter, labels.Everything()) if err != nil { - return false + return ErrPodAffinityRulesNotMatch, err } // Check all affinity terms. for _, term := range getPodAffinityTerms(affinity.PodAffinity) { termMatches, matchingPodExists, err := c.anyPodMatchesPodAffinityTerm(pod, filteredPods, node, &term) if err != nil { - glog.Errorf("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v, err: %v", - podName(pod), node.Name, term, err) - return false + errMessage := fmt.Sprintf("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v, err: %v", podName(pod), node.Name, term, err) + glog.Error(errMessage) + return ErrPodAffinityRulesNotMatch, errors.New(errMessage) } if !termMatches { // If the requirement matches a pod's own labels are namespace, and there are @@ -1213,20 +1219,20 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, node if matchingPodExists { glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v", podName(pod), node.Name, term) - return false + return ErrPodAffinityRulesNotMatch, nil } namespaces := priorityutil.GetNamespacesFromPodAffinityTerm(pod, &term) selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector) if err != nil { - glog.Errorf("Cannot parse selector on term %v for pod %v. Details %v", - term, podName(pod), err) - return false + errMessage := fmt.Sprintf("Cannot parse selector on term %v for pod %v. Details %v", term, podName(pod), err) + glog.Error(errMessage) + return ErrPodAffinityRulesNotMatch, errors.New(errMessage) } match := priorityutil.PodMatchesTermsNamespaceAndSelector(pod, namespaces, selector) if !match { glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinityTerm %v", podName(pod), node.Name, term) - return false + return ErrPodAffinityRulesNotMatch, nil } } } @@ -1237,7 +1243,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, node if err != nil || termMatches { glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAntiAffinityTerm %v, err: %v", podName(pod), node.Name, term, err) - return false + return ErrPodAntiAffinityRulesNotMatch, nil } } @@ -1247,7 +1253,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, node glog.Infof("Schedule Pod %+v on Node %+v is allowed, pod affinity/anti-affinity constraints satisfied.", podName(pod), node.Name) } - return true + return nil, nil } // PodToleratesNodeTaints checks if a pod tolerations can tolerate the node taints diff --git a/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go b/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go index d085d9d6f6e..0d20a309184 100644 --- a/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go +++ b/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go @@ -2024,11 +2024,12 @@ func TestInterPodAffinity(t *testing.T) { podLabel2 := map[string]string{"security": "S1"} node1 := v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "machine1", Labels: labels1}} tests := []struct { - pod *v1.Pod - pods []*v1.Pod - node *v1.Node - fits bool - test string + pod *v1.Pod + pods []*v1.Pod + node *v1.Node + fits bool + test string + expectFailureReasons []algorithm.PredicateFailureReason }{ { pod: new(v1.Pod), @@ -2124,10 +2125,11 @@ func TestInterPodAffinity(t *testing.T) { }, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel, Namespace: "ns"}}}, - node: &node1, - fits: false, - test: "Does not satisfy the PodAffinity with labelSelector because of diff Namespace", + pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel, Namespace: "ns"}}}, + node: &node1, + fits: false, + test: "Does not satisfy the PodAffinity with labelSelector because of diff Namespace", + expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch}, }, { pod: &v1.Pod{ @@ -2154,10 +2156,11 @@ func TestInterPodAffinity(t *testing.T) { }, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}}, - node: &node1, - fits: false, - test: "Doesn't satisfy the PodAffinity because of unmatching labelSelector with the existing pod", + pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}}, + node: &node1, + fits: false, + test: "Doesn't satisfy the PodAffinity because of unmatching labelSelector with the existing pod", + expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch}, }, { pod: &v1.Pod{ @@ -2250,10 +2253,11 @@ func TestInterPodAffinity(t *testing.T) { }, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}}, - node: &node1, - fits: false, - test: "The labelSelector requirements(items of matchExpressions) are ANDed, the pod cannot schedule onto the node because one of the matchExpression item don't match.", + pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}}, + node: &node1, + fits: false, + test: "The labelSelector requirements(items of matchExpressions) are ANDed, the pod cannot schedule onto the node because one of the matchExpression item don't match.", + expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch}, }, { pod: &v1.Pod{ @@ -2416,10 +2420,11 @@ func TestInterPodAffinity(t *testing.T) { }, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}}, - node: &node1, - fits: false, - test: "satisfies the PodAffinity but doesn't satisfies the PodAntiAffinity with the existing pod", + pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}}, + node: &node1, + fits: false, + test: "satisfies the PodAffinity but doesn't satisfies the PodAntiAffinity with the existing pod", + expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, }, { pod: &v1.Pod{ @@ -2489,9 +2494,10 @@ func TestInterPodAffinity(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Labels: podLabel}, }, }, - node: &node1, - fits: false, - test: "satisfies the PodAffinity and PodAntiAffinity but doesn't satisfies PodAntiAffinity symmetry with the existing pod", + node: &node1, + fits: false, + test: "satisfies the PodAffinity and PodAntiAffinity but doesn't satisfies PodAntiAffinity symmetry with the existing pod", + expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrExistingPodsAntiAffinityRulesNotMatch}, }, { pod: &v1.Pod{ @@ -2519,10 +2525,11 @@ func TestInterPodAffinity(t *testing.T) { }, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}}, - node: &node1, - fits: false, - test: "pod matches its own Label in PodAffinity and that matches the existing pod Labels", + pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: metav1.ObjectMeta{Labels: podLabel}}}, + node: &node1, + fits: false, + test: "pod matches its own Label in PodAffinity and that matches the existing pod Labels", + expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch}, }, { pod: &v1.Pod{ @@ -2555,9 +2562,10 @@ func TestInterPodAffinity(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Labels: podLabel}, }, }, - node: &node1, - fits: false, - test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. doesn't satisfy PodAntiAffinity symmetry with the existing pod", + node: &node1, + fits: false, + test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. doesn't satisfy PodAntiAffinity symmetry with the existing pod", + expectFailureReasons: []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch, ErrExistingPodsAntiAffinityRulesNotMatch}, }, { pod: &v1.Pod{ @@ -2595,7 +2603,6 @@ func TestInterPodAffinity(t *testing.T) { test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. satisfy PodAntiAffinity symmetry with the existing pod", }, } - expectedFailureReasons := []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch} for _, test := range tests { node := test.node @@ -2613,12 +2620,9 @@ func TestInterPodAffinity(t *testing.T) { nodeInfo := schedulercache.NewNodeInfo(podsOnNode...) nodeInfo.SetNode(test.node) nodeInfoMap := map[string]*schedulercache.NodeInfo{test.node.Name: nodeInfo} - fits, reasons, err := fit.InterPodAffinityMatches(test.pod, PredicateMetadata(test.pod, nodeInfoMap), nodeInfo) - if err != nil { - t.Errorf("%s: unexpected error %v", test.test, err) - } - if !fits && !reflect.DeepEqual(reasons, expectedFailureReasons) { - t.Errorf("%s: unexpected failure reasons: %v, want: %v", test.test, reasons, expectedFailureReasons) + fits, reasons, _ := fit.InterPodAffinityMatches(test.pod, PredicateMetadata(test.pod, nodeInfoMap), nodeInfo) + if !fits && !reflect.DeepEqual(reasons, test.expectFailureReasons) { + t.Errorf("%s: unexpected failure reasons: %v, want: %v", test.test, reasons, test.expectFailureReasons) } if fits != test.fits { t.Errorf("%s: expected %v got %v", test.test, test.fits, fits) @@ -2645,12 +2649,13 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { } tests := []struct { - pod *v1.Pod - pods []*v1.Pod - nodes []v1.Node - fits map[string]bool - test string - nometa bool + pod *v1.Pod + pods []*v1.Pod + nodes []v1.Node + nodesExpectAffinityFailureReasons [][]algorithm.PredicateFailureReason + fits map[string]bool + test string + nometa bool }{ { pod: &v1.Pod{ @@ -2688,6 +2693,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { "machine2": true, "machine3": false, }, + nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{nil, nil, {ErrPodAffinityNotMatch, ErrPodAffinityRulesNotMatch}}, test: "A pod can be scheduled onto all the nodes that have the same topology key & label value with one of them has an existing pod that match the affinity rules", }, { @@ -2736,6 +2742,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { {ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"region": "r1", "hostname": "h1"}}}, {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"region": "r1", "hostname": "h2"}}}, }, + nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{nil, nil}, fits: map[string]bool{ "nodeA": false, "nodeB": true, @@ -2775,6 +2782,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { {ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"zone": "az1", "hostname": "h1"}}}, {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"zone": "az2", "hostname": "h2"}}}, }, + nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{nil, nil}, fits: map[string]bool{ "nodeA": true, "nodeB": true, @@ -2812,6 +2820,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { {ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"region": "r1", "hostname": "nodeA"}}}, {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: map[string]string{"region": "r1", "hostname": "nodeB"}}}, }, + nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, {ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}}, fits: map[string]bool{ "nodeA": false, "nodeB": false, @@ -2849,6 +2858,7 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: labelRgChinaAzAz1}}, {ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}}, }, + nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{{ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, {ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, nil}, fits: map[string]bool{ "nodeA": false, "nodeB": false, @@ -2912,6 +2922,12 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { {ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}}, {ObjectMeta: metav1.ObjectMeta{Name: "nodeD", Labels: labelRgUS}}, }, + nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{ + {ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, + {ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, + {ErrPodAffinityNotMatch, ErrExistingPodsAntiAffinityRulesNotMatch}, + nil, + }, fits: map[string]bool{ "nodeA": false, "nodeB": false, @@ -2986,6 +3002,11 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: labelRgChinaAzAz1}}, {ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: labelRgIndia}}, }, + nodesExpectAffinityFailureReasons: [][]algorithm.PredicateFailureReason{ + {ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, + {ErrPodAffinityNotMatch, ErrPodAntiAffinityRulesNotMatch}, + nil, + }, fits: map[string]bool{ "nodeA": false, "nodeB": false, @@ -2994,12 +3015,12 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { test: "NodeA and nodeB have same topologyKey and label value. NodeA has an existing pod that match the inter pod affinity rule. The pod can not be scheduled onto nodeA, nodeB, but can be schedulerd onto nodeC (NodeC has an existing pod that match the inter pod affinity rule but in different namespace)", }, } - affinityExpectedFailureReasons := []algorithm.PredicateFailureReason{ErrPodAffinityNotMatch} + selectorExpectedFailureReasons := []algorithm.PredicateFailureReason{ErrNodeSelectorNotMatch} - for _, test := range tests { + for indexTest, test := range tests { nodeListInfo := FakeNodeListInfo(test.nodes) - for _, node := range test.nodes { + for indexNode, node := range test.nodes { var podsOnNode []*v1.Pod for _, pod := range test.pods { if pod.Spec.NodeName == node.Name { @@ -3021,12 +3042,9 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { meta = PredicateMetadata(test.pod, nodeInfoMap) } - fits, reasons, err := testFit.InterPodAffinityMatches(test.pod, meta, nodeInfo) - if err != nil { - t.Errorf("%s: unexpected error %v", test.test, err) - } - if !fits && !reflect.DeepEqual(reasons, affinityExpectedFailureReasons) { - t.Errorf("%s: unexpected failure reasons: %v", test.test, reasons) + fits, reasons, _ := testFit.InterPodAffinityMatches(test.pod, meta, nodeInfo) + if !fits && !reflect.DeepEqual(reasons, test.nodesExpectAffinityFailureReasons[indexNode]) { + t.Errorf("index: %d test: %s unexpected failure reasons: %v expect: %v", indexTest, test.test, reasons, test.nodesExpectAffinityFailureReasons[indexNode]) } affinity := test.pod.Spec.Affinity if affinity != nil && affinity.NodeAffinity != nil {