Commit ac4a082b authored by Ahmad Diaa's avatar Ahmad Diaa

use topologyPairsMaps for inter pod affinity/anti-affinity maps

parent e41d9f15
...@@ -52,13 +52,6 @@ func (s sortableServices) Swap(i, j int) { s[i], s[j] = s[j], s[i] } ...@@ -52,13 +52,6 @@ func (s sortableServices) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
var _ = sort.Interface(&sortableServices{}) var _ = sort.Interface(&sortableServices{})
func sortNodePodMap(np map[string][]*v1.Pod) {
for _, pl := range np {
sortablePods := sortablePods(pl)
sort.Sort(sortablePods)
}
}
// predicateMetadataEquivalent returns true if the two metadata are equivalent. // predicateMetadataEquivalent returns true if the two metadata are equivalent.
// Note: this function does not compare podRequest. // Note: this function does not compare podRequest.
func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error { func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error {
...@@ -77,15 +70,11 @@ func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error { ...@@ -77,15 +70,11 @@ func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error {
for !reflect.DeepEqual(meta1.podPorts, meta2.podPorts) { for !reflect.DeepEqual(meta1.podPorts, meta2.podPorts) {
return fmt.Errorf("podPorts are not equal") return fmt.Errorf("podPorts are not equal")
} }
sortNodePodMap(meta1.nodeNameToMatchingAffinityPods) if !reflect.DeepEqual(meta1.topologyPairsPotentialAffinityPods, meta2.topologyPairsPotentialAffinityPods) {
sortNodePodMap(meta2.nodeNameToMatchingAffinityPods) return fmt.Errorf("topologyPairsPotentialAffinityPods are not equal")
if !reflect.DeepEqual(meta1.nodeNameToMatchingAffinityPods, meta2.nodeNameToMatchingAffinityPods) {
return fmt.Errorf("nodeNameToMatchingAffinityPods are not euqal")
} }
sortNodePodMap(meta1.nodeNameToMatchingAntiAffinityPods) if !reflect.DeepEqual(meta1.topologyPairsPotentialAntiAffinityPods, meta2.topologyPairsPotentialAntiAffinityPods) {
sortNodePodMap(meta2.nodeNameToMatchingAntiAffinityPods) return fmt.Errorf("topologyPairsPotentialAntiAffinityPods are not equal")
if !reflect.DeepEqual(meta1.nodeNameToMatchingAntiAffinityPods, meta2.nodeNameToMatchingAntiAffinityPods) {
return fmt.Errorf("nodeNameToMatchingAntiAffinityPods are not euqal")
} }
if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.podToTopologyPairs, if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.podToTopologyPairs,
meta2.topologyPairsAntiAffinityPodsMap.podToTopologyPairs) { meta2.topologyPairsAntiAffinityPodsMap.podToTopologyPairs) {
...@@ -454,42 +443,71 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) { ...@@ -454,42 +443,71 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) {
}, },
}, },
}, },
nodeNameToMatchingAffinityPods: map[string][]*v1.Pod{ topologyPairsPotentialAffinityPods: &topologyPairsMaps{
"nodeA": { topologyPairToPods: map[topologyPair]podSet{
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1}, {key: "name", value: "nodeA"}: {
Spec: v1.PodSpec{NodeName: "nodeA"}, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
Spec: v1.PodSpec{NodeName: "nodeA"},
}: struct{}{},
},
{key: "name", value: "nodeC"}: {
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2"},
Spec: v1.PodSpec{
NodeName: "nodeC",
},
}: struct{}{},
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p6", Labels: selector1},
Spec: v1.PodSpec{NodeName: "nodeC"},
}: struct{}{},
}, },
}, },
"nodeC": { podToTopologyPairs: map[string]topologyPairSet{
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2"}, "p1_": {
Spec: v1.PodSpec{ topologyPair{key: "name", value: "nodeA"}: struct{}{},
NodeName: "nodeC",
},
}, },
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p6", Labels: selector1}, "p2_": {
Spec: v1.PodSpec{NodeName: "nodeC"}, topologyPair{key: "name", value: "nodeC"}: struct{}{},
},
"p6_": {
topologyPair{key: "name", value: "nodeC"}: struct{}{},
}, },
}, },
}, },
nodeNameToMatchingAntiAffinityPods: map[string][]*v1.Pod{ topologyPairsPotentialAntiAffinityPods: &topologyPairsMaps{
"nodeN": { topologyPairToPods: map[topologyPair]podSet{
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1}, {key: "name", value: "nodeN"}: {
Spec: v1.PodSpec{NodeName: "nodeN"}, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
}, Spec: v1.PodSpec{NodeName: "nodeN"},
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2"}, }: struct{}{},
Spec: v1.PodSpec{ &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2"},
NodeName: "nodeM", Spec: v1.PodSpec{
}, NodeName: "nodeM",
},
}: struct{}{},
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p3"},
Spec: v1.PodSpec{
NodeName: "nodeM",
},
}: struct{}{},
}, },
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p3"}, {key: "name", value: "nodeM"}: {
Spec: v1.PodSpec{ &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p6", Labels: selector1},
NodeName: "nodeM", Spec: v1.PodSpec{NodeName: "nodeM"},
}, }: struct{}{},
}, },
}, },
"nodeM": { podToTopologyPairs: map[string]topologyPairSet{
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p6", Labels: selector1}, "p1_": {
Spec: v1.PodSpec{NodeName: "nodeM"}, topologyPair{key: "name", value: "nodeN"}: struct{}{},
},
"p2_": {
topologyPair{key: "name", value: "nodeN"}: struct{}{},
},
"p3_": {
topologyPair{key: "name", value: "nodeN"}: struct{}{},
},
"p6_": {
topologyPair{key: "name", value: "nodeM"}: struct{}{},
}, },
}, },
}, },
......
...@@ -1395,23 +1395,16 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta ...@@ -1395,23 +1395,16 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
// anyPodsMatchingTopologyTerms checks whether any of the nodes given via // anyPodsMatchingTopologyTerms checks whether any of the nodes given via
// "targetPods" matches topology of all the "terms" for the give "pod" and "nodeInfo". // "targetPods" matches topology of all the "terms" for the give "pod" and "nodeInfo".
func (c *PodAffinityChecker) anyPodsMatchingTopologyTerms(pod *v1.Pod, targetPods map[string][]*v1.Pod, nodeInfo *schedulercache.NodeInfo, terms []v1.PodAffinityTerm) (bool, error) { func (c *PodAffinityChecker) anyPodsMatchingTopologyTerms(pod *v1.Pod, targetPods *topologyPairsMaps, nodeInfo *schedulercache.NodeInfo, terms []v1.PodAffinityTerm) (bool, error) {
for nodeName, targetPods := range targetPods { podNameToMatchingTermsCount := make(map[string]int)
targetPodNodeInfo, err := c.info.GetNodeInfo(nodeName) node := nodeInfo.Node()
if err != nil { podTermsCount := len(terms)
return false, err for _, term := range terms {
} pair := topologyPair{key: term.TopologyKey, value: node.Labels[term.TopologyKey]}
if len(targetPods) > 0 { for existingPod := range targetPods.topologyPairToPods[pair] {
allTermsMatched := true existingPodFullName := schedutil.GetPodFullName(existingPod)
for _, term := range terms { podNameToMatchingTermsCount[existingPodFullName] = podNameToMatchingTermsCount[existingPodFullName] + 1
if !priorityutil.NodesHaveSameTopologyKey(nodeInfo.Node(), targetPodNodeInfo, term.TopologyKey) { if podNameToMatchingTermsCount[existingPodFullName] == podTermsCount {
allTermsMatched = false
break
}
}
if allTermsMatched {
// We have 1 or more pods on the target node that have already matched namespace and selector
// and all of the terms topologies matched the target node. So, there is at least 1 matching pod on the node.
return true, nil return true, nil
} }
} }
...@@ -1429,7 +1422,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, ...@@ -1429,7 +1422,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod,
} }
if predicateMeta, ok := meta.(*predicateMetadata); ok { if predicateMeta, ok := meta.(*predicateMetadata); ok {
// Check all affinity terms. // Check all affinity terms.
matchingPods := predicateMeta.nodeNameToMatchingAffinityPods matchingPods := predicateMeta.topologyPairsPotentialAffinityPods
if affinityTerms := GetPodAffinityTerms(affinity.PodAffinity); len(affinityTerms) > 0 { if affinityTerms := GetPodAffinityTerms(affinity.PodAffinity); len(affinityTerms) > 0 {
matchExists, err := c.anyPodsMatchingTopologyTerms(pod, matchingPods, nodeInfo, affinityTerms) matchExists, err := c.anyPodsMatchingTopologyTerms(pod, matchingPods, nodeInfo, affinityTerms)
if err != nil { if err != nil {
...@@ -1442,7 +1435,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, ...@@ -1442,7 +1435,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod,
// to not leave such pods in pending state forever, we check that if no other pod // to not leave such pods in pending state forever, we check that if no other pod
// in the cluster matches the namespace and selector of this pod and the pod matches // in the cluster matches the namespace and selector of this pod and the pod matches
// its own terms, then we allow the pod to pass the affinity check. // its own terms, then we allow the pod to pass the affinity check.
if !(len(matchingPods) == 0 && targetPodMatchesAffinityOfPod(pod, pod)) { if !(len(matchingPods.topologyPairToPods) == 0 && targetPodMatchesAffinityOfPod(pod, pod)) {
glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinity", glog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinity",
podName(pod), node.Name) podName(pod), node.Name)
return ErrPodAffinityRulesNotMatch, nil return ErrPodAffinityRulesNotMatch, nil
...@@ -1451,7 +1444,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod, ...@@ -1451,7 +1444,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod,
} }
// Check all anti-affinity terms. // Check all anti-affinity terms.
matchingPods = predicateMeta.nodeNameToMatchingAntiAffinityPods matchingPods = predicateMeta.topologyPairsPotentialAntiAffinityPods
if antiAffinityTerms := GetPodAntiAffinityTerms(affinity.PodAntiAffinity); len(antiAffinityTerms) > 0 { if antiAffinityTerms := GetPodAntiAffinityTerms(affinity.PodAntiAffinity); len(antiAffinityTerms) > 0 {
matchExists, err := c.anyPodsMatchingTopologyTerms(pod, matchingPods, nodeInfo, antiAffinityTerms) matchExists, err := c.anyPodsMatchingTopologyTerms(pod, matchingPods, nodeInfo, antiAffinityTerms)
if err != nil || matchExists { if err != nil || matchExists {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment