optimize required inter-pod affinity

This commit is contained in:
Abdullah Gharaibeh 2019-12-09 16:21:13 -05:00
parent 77a95dce68
commit 32dc70e0f1
3 changed files with 191 additions and 379 deletions

View File

@ -51,16 +51,10 @@ type topologyPair struct {
value string value string
} }
type podSet map[*v1.Pod]struct{} // TODO(Huang-Wei): It might be possible to use "make(map[topologyPair]*int64)" so that
// we can do atomic additions instead of using a global mutext, however we need to consider
type topologyPairSet map[topologyPair]struct{} // how to init each topologyToMatchedTermCount.
type topologyToMatchedTermCount map[topologyPair]int64
// topologyPairsMaps keeps topologyPairToAntiAffinityPods and antiAffinityPodToTopologyPairs in sync
// as they are the inverse of each others.
type topologyPairsMaps struct {
topologyPairToPods map[topologyPair]podSet
podToTopologyPairs map[string]topologyPairSet
}
type criticalPath struct { type criticalPath struct {
// topologyValue denotes the topology value mapping to topology key. // topologyValue denotes the topology value mapping to topology key.
@ -186,61 +180,89 @@ func (m *serviceAffinityMetadata) clone() *serviceAffinityMetadata {
} }
type podAffinityMetadata struct { type podAffinityMetadata struct {
topologyPairsAntiAffinityPodsMap *topologyPairsMaps // A map of topology pairs to the number of existing pods that has anti-affinity terms that match the "pod".
// A map of topology pairs to a list of Pods that can potentially match topologyToMatchedExistingAntiAffinityTerms topologyToMatchedTermCount
// the affinity terms of the "pod" and its inverse. // A map of topology pairs to the number of existing pods that match the affinity terms of the "pod".
topologyPairsPotentialAffinityPods *topologyPairsMaps topologyToMatchedAffinityTerms topologyToMatchedTermCount
// A map of topology pairs to a list of Pods that can potentially match // A map of topology pairs to the number of existing pods that match the anti-affinity terms of the "pod".
// the anti-affinity terms of the "pod" and its inverse. topologyToMatchedAntiAffinityTerms topologyToMatchedTermCount
topologyPairsPotentialAntiAffinityPods *topologyPairsMaps
} }
func (m *podAffinityMetadata) addPod(addedPod *v1.Pod, pod *v1.Pod, node *v1.Node) error { // updateWithAffinityTerms updates the topologyToMatchedTermCount map with the specified value
// Add matching anti-affinity terms of the addedPod to the map. // for each affinity term if "targetPod" matches ALL terms.
topologyPairsMaps, err := getMatchingAntiAffinityTopologyPairsOfPod(pod, addedPod, node) func (m topologyToMatchedTermCount) updateWithAffinityTerms(targetPod *v1.Pod, targetPodNode *v1.Node, affinityTerms []*affinityTermProperties, value int64) {
if err != nil { if podMatchesAllAffinityTermProperties(targetPod, affinityTerms) {
return err for _, t := range affinityTerms {
} if topologyValue, ok := targetPodNode.Labels[t.topologyKey]; ok {
m.topologyPairsAntiAffinityPodsMap.appendMaps(topologyPairsMaps) pair := topologyPair{key: t.topologyKey, value: topologyValue}
// Add the pod to nodeNameToMatchingAffinityPods and nodeNameToMatchingAntiAffinityPods if needed. m[pair] += value
affinity := pod.Spec.Affinity // value could be a negative value, hence we delete the entry if
podNodeName := addedPod.Spec.NodeName // the entry is down to zero.
if affinity != nil && len(podNodeName) > 0 { if m[pair] == 0 {
// It is assumed that when the added pod matches affinity of the pod, all the terms must match, delete(m, pair)
// this should be changed when the implementation of targetPodMatchesAffinityOfPod/podMatchesAffinityTermProperties
// is changed
if targetPodMatchesAffinityOfPod(pod, addedPod) {
affinityTerms := GetPodAffinityTerms(affinity.PodAffinity)
for _, term := range affinityTerms {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue}
m.topologyPairsPotentialAffinityPods.addTopologyPair(pair, addedPod)
}
}
}
if targetPodMatchesAntiAffinityOfPod(pod, addedPod) {
antiAffinityTerms := GetPodAntiAffinityTerms(affinity.PodAntiAffinity)
for _, term := range antiAffinityTerms {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue}
m.topologyPairsPotentialAntiAffinityPods.addTopologyPair(pair, addedPod)
} }
} }
} }
} }
return nil
} }
func (m *podAffinityMetadata) removePod(deletedPod *v1.Pod) { // updateAntiAffinityTerms updates the topologyToMatchedTermCount map with the specified value
// for each anti-affinity term matched the target pod.
func (m topologyToMatchedTermCount) updateWithAntiAffinityTerms(targetPod *v1.Pod, targetPodNode *v1.Node, antiAffinityTerms []*affinityTermProperties, value int64) {
// Check anti-affinity properties.
for _, a := range antiAffinityTerms {
if priorityutil.PodMatchesTermsNamespaceAndSelector(targetPod, a.namespaces, a.selector) {
if topologyValue, ok := targetPodNode.Labels[a.topologyKey]; ok {
pair := topologyPair{key: a.topologyKey, value: topologyValue}
m[pair] += value
// value could be a negative value, hence we delete the entry if
// the entry is down to zero.
if m[pair] == 0 {
delete(m, pair)
}
}
}
}
}
func (m *podAffinityMetadata) updatePod(updatedPod, pod *v1.Pod, node *v1.Node, multiplier int64) error {
if m == nil { if m == nil {
return return nil
} }
m.topologyPairsAntiAffinityPodsMap.removePod(deletedPod) // Update matching existing anti-affinity terms.
// Delete pod from the matching affinity or anti-affinity topology pairs maps. updatedPodAffinity := updatedPod.Spec.Affinity
m.topologyPairsPotentialAffinityPods.removePod(deletedPod) if updatedPodAffinity != nil && updatedPodAffinity.PodAntiAffinity != nil {
m.topologyPairsPotentialAntiAffinityPods.removePod(deletedPod) antiAffinityProperties, err := getAffinityTermProperties(pod, GetPodAntiAffinityTerms(updatedPodAffinity.PodAntiAffinity))
if err != nil {
klog.Errorf("error in getting anti-affinity properties of Pod %v", updatedPod.Name)
return err
}
m.topologyToMatchedExistingAntiAffinityTerms.updateWithAntiAffinityTerms(pod, node, antiAffinityProperties, multiplier)
}
// Update matching incoming pod (anti)affinity terms.
affinity := pod.Spec.Affinity
podNodeName := updatedPod.Spec.NodeName
if affinity != nil && len(podNodeName) > 0 {
if affinity.PodAffinity == nil {
affinityProperties, err := getAffinityTermProperties(pod, GetPodAffinityTerms(affinity.PodAffinity))
if err != nil {
klog.Errorf("error in getting affinity properties of Pod %v", pod.Name)
return err
}
m.topologyToMatchedAffinityTerms.updateWithAffinityTerms(updatedPod, node, affinityProperties, multiplier)
}
if affinity.PodAntiAffinity != nil {
antiAffinityProperties, err := getAffinityTermProperties(pod, GetPodAntiAffinityTerms(affinity.PodAntiAffinity))
if err != nil {
klog.Errorf("error in getting anti-affinity properties of Pod %v", pod.Name)
return err
}
m.topologyToMatchedAntiAffinityTerms.updateWithAntiAffinityTerms(updatedPod, node, antiAffinityProperties, multiplier)
}
}
return nil
} }
func (m *podAffinityMetadata) clone() *podAffinityMetadata { func (m *podAffinityMetadata) clone() *podAffinityMetadata {
@ -249,9 +271,9 @@ func (m *podAffinityMetadata) clone() *podAffinityMetadata {
} }
copy := podAffinityMetadata{} copy := podAffinityMetadata{}
copy.topologyPairsPotentialAffinityPods = m.topologyPairsPotentialAffinityPods.clone() copy.topologyToMatchedAffinityTerms = m.topologyToMatchedAffinityTerms.clone()
copy.topologyPairsPotentialAntiAffinityPods = m.topologyPairsPotentialAntiAffinityPods.clone() copy.topologyToMatchedAntiAffinityTerms = m.topologyToMatchedAntiAffinityTerms.clone()
copy.topologyPairsAntiAffinityPodsMap = m.topologyPairsAntiAffinityPodsMap.clone() copy.topologyToMatchedExistingAntiAffinityTerms = m.topologyToMatchedExistingAntiAffinityTerms.clone()
return &copy return &copy
} }
@ -421,9 +443,9 @@ func getPodAffinityMetadata(pod *v1.Pod, allNodes []*schedulernodeinfo.NodeInfo,
} }
return &podAffinityMetadata{ return &podAffinityMetadata{
topologyPairsPotentialAffinityPods: incomingPodAffinityMap, topologyToMatchedAffinityTerms: incomingPodAffinityMap,
topologyPairsPotentialAntiAffinityPods: incomingPodAntiAffinityMap, topologyToMatchedAntiAffinityTerms: incomingPodAntiAffinityMap,
topologyPairsAntiAffinityPodsMap: existingPodAntiAffinityMap, topologyToMatchedExistingAntiAffinityTerms: existingPodAntiAffinityMap,
}, nil }, nil
} }
@ -527,50 +549,14 @@ func NodeLabelsMatchSpreadConstraints(nodeLabels map[string]string, constraints
return true return true
} }
// returns a pointer to a new topologyPairsMaps func (m topologyToMatchedTermCount) appendMaps(toAppend topologyToMatchedTermCount) {
func newTopologyPairsMaps() *topologyPairsMaps { for pair := range toAppend {
return &topologyPairsMaps{ m[pair] += toAppend[pair]
topologyPairToPods: make(map[topologyPair]podSet),
podToTopologyPairs: make(map[string]topologyPairSet),
} }
} }
func (m *topologyPairsMaps) addTopologyPair(pair topologyPair, pod *v1.Pod) { func (m topologyToMatchedTermCount) clone() topologyToMatchedTermCount {
podFullName := schedutil.GetPodFullName(pod) copy := make(topologyToMatchedTermCount, len(m))
if m.topologyPairToPods[pair] == nil {
m.topologyPairToPods[pair] = make(map[*v1.Pod]struct{})
}
m.topologyPairToPods[pair][pod] = struct{}{}
if m.podToTopologyPairs[podFullName] == nil {
m.podToTopologyPairs[podFullName] = make(map[topologyPair]struct{})
}
m.podToTopologyPairs[podFullName][pair] = struct{}{}
}
func (m *topologyPairsMaps) removePod(deletedPod *v1.Pod) {
deletedPodFullName := schedutil.GetPodFullName(deletedPod)
for pair := range m.podToTopologyPairs[deletedPodFullName] {
delete(m.topologyPairToPods[pair], deletedPod)
if len(m.topologyPairToPods[pair]) == 0 {
delete(m.topologyPairToPods, pair)
}
}
delete(m.podToTopologyPairs, deletedPodFullName)
}
func (m *topologyPairsMaps) appendMaps(toAppend *topologyPairsMaps) {
if toAppend == nil {
return
}
for pair := range toAppend.topologyPairToPods {
for pod := range toAppend.topologyPairToPods[pair] {
m.addTopologyPair(pair, pod)
}
}
}
func (m *topologyPairsMaps) clone() *topologyPairsMaps {
copy := newTopologyPairsMaps()
copy.appendMaps(m) copy.appendMaps(m)
return copy return copy
} }
@ -633,7 +619,7 @@ func (meta *predicateMetadata) RemovePod(deletedPod *v1.Pod, node *v1.Node) erro
if deletedPodFullName == schedutil.GetPodFullName(meta.pod) { if deletedPodFullName == schedutil.GetPodFullName(meta.pod) {
return fmt.Errorf("deletedPod and meta.pod must not be the same") return fmt.Errorf("deletedPod and meta.pod must not be the same")
} }
meta.podAffinityMetadata.removePod(deletedPod) meta.podAffinityMetadata.updatePod(deletedPod, meta.pod, node, -1)
meta.evenPodsSpreadMetadata.removePod(deletedPod, meta.pod, node) meta.evenPodsSpreadMetadata.removePod(deletedPod, meta.pod, node)
meta.serviceAffinityMetadata.removePod(deletedPod, node) meta.serviceAffinityMetadata.removePod(deletedPod, node)
@ -651,7 +637,7 @@ func (meta *predicateMetadata) AddPod(addedPod *v1.Pod, node *v1.Node) error {
return fmt.Errorf("node not found") return fmt.Errorf("node not found")
} }
if err := meta.podAffinityMetadata.addPod(addedPod, meta.pod, node); err != nil { if err := meta.podAffinityMetadata.updatePod(addedPod, meta.pod, node, 1); err != nil {
return err return err
} }
// Update meta.evenPodsSpreadMetadata if meta.pod has hard spread constraints // Update meta.evenPodsSpreadMetadata if meta.pod has hard spread constraints
@ -678,9 +664,11 @@ func (meta *predicateMetadata) ShallowCopy() Metadata {
return (Metadata)(newPredMeta) return (Metadata)(newPredMeta)
} }
// A processed version of v1.PodAffinityTerm.
type affinityTermProperties struct { type affinityTermProperties struct {
namespaces sets.String namespaces sets.String
selector labels.Selector selector labels.Selector
topologyKey string
} }
// getAffinityTermProperties receives a Pod and affinity terms and returns the namespaces and // getAffinityTermProperties receives a Pod and affinity terms and returns the namespaces and
@ -696,7 +684,7 @@ func getAffinityTermProperties(pod *v1.Pod, terms []v1.PodAffinityTerm) (propert
if err != nil { if err != nil {
return nil, err return nil, err
} }
properties = append(properties, &affinityTermProperties{namespaces: namespaces, selector: selector}) properties = append(properties, &affinityTermProperties{namespaces: namespaces, selector: selector, topologyKey: term.TopologyKey})
} }
return properties, nil return properties, nil
} }
@ -714,31 +702,18 @@ func podMatchesAllAffinityTermProperties(pod *v1.Pod, properties []*affinityTerm
return true return true
} }
// podMatchesAnyAffinityTermProperties returns true if the given pod matches any given property.
func podMatchesAnyAffinityTermProperties(pod *v1.Pod, properties []*affinityTermProperties) bool {
if len(properties) == 0 {
return false
}
for _, property := range properties {
if priorityutil.PodMatchesTermsNamespaceAndSelector(pod, property.namespaces, property.selector) {
return true
}
}
return false
}
// getTPMapMatchingExistingAntiAffinity calculates the following for each existing pod on each node: // getTPMapMatchingExistingAntiAffinity calculates the following for each existing pod on each node:
// (1) Whether it has PodAntiAffinity // (1) Whether it has PodAntiAffinity
// (2) Whether any AffinityTerm matches the incoming pod // (2) Whether any AffinityTerm matches the incoming pod
func getTPMapMatchingExistingAntiAffinity(pod *v1.Pod, allNodes []*schedulernodeinfo.NodeInfo) (*topologyPairsMaps, error) { func getTPMapMatchingExistingAntiAffinity(pod *v1.Pod, allNodes []*schedulernodeinfo.NodeInfo) (topologyToMatchedTermCount, error) {
errCh := schedutil.NewErrorChannel() errCh := schedutil.NewErrorChannel()
var lock sync.Mutex var lock sync.Mutex
topologyMaps := newTopologyPairsMaps() topologyMap := make(topologyToMatchedTermCount)
appendTopologyPairsMaps := func(toAppend *topologyPairsMaps) { appendResult := func(toAppend topologyToMatchedTermCount) {
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
topologyMaps.appendMaps(toAppend) topologyMap.appendMaps(toAppend)
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
@ -757,7 +732,7 @@ func getTPMapMatchingExistingAntiAffinity(pod *v1.Pod, allNodes []*schedulernode
return return
} }
if existingPodTopologyMaps != nil { if existingPodTopologyMaps != nil {
appendTopologyPairsMaps(existingPodTopologyMaps) appendResult(existingPodTopologyMaps)
} }
} }
} }
@ -767,30 +742,30 @@ func getTPMapMatchingExistingAntiAffinity(pod *v1.Pod, allNodes []*schedulernode
return nil, err return nil, err
} }
return topologyMaps, nil return topologyMap, nil
} }
// getTPMapMatchingIncomingAffinityAntiAffinity finds existing Pods that match affinity terms of the given "pod". // getTPMapMatchingIncomingAffinityAntiAffinity finds existing Pods that match affinity terms of the given "pod".
// It returns a topologyPairsMaps that are checked later by the affinity // It returns a topologyToMatchedTermCount that are checked later by the affinity
// predicate. With this topologyPairsMaps available, the affinity predicate does not // predicate. With this topologyToMatchedTermCount available, the affinity predicate does not
// need to check all the pods in the cluster. // need to check all the pods in the cluster.
func getTPMapMatchingIncomingAffinityAntiAffinity(pod *v1.Pod, allNodes []*schedulernodeinfo.NodeInfo) (topologyPairsAffinityPodsMaps *topologyPairsMaps, topologyPairsAntiAffinityPodsMaps *topologyPairsMaps, err error) { func getTPMapMatchingIncomingAffinityAntiAffinity(pod *v1.Pod, allNodes []*schedulernodeinfo.NodeInfo) (topologyToMatchedTermCount, topologyToMatchedTermCount, error) {
topologyPairsAffinityPodsMap := make(topologyToMatchedTermCount)
topologyToMatchedExistingAntiAffinityTerms := make(topologyToMatchedTermCount)
affinity := pod.Spec.Affinity affinity := pod.Spec.Affinity
if affinity == nil || (affinity.PodAffinity == nil && affinity.PodAntiAffinity == nil) { if affinity == nil || (affinity.PodAffinity == nil && affinity.PodAntiAffinity == nil) {
return newTopologyPairsMaps(), newTopologyPairsMaps(), nil return topologyPairsAffinityPodsMap, topologyToMatchedExistingAntiAffinityTerms, nil
} }
var lock sync.Mutex var lock sync.Mutex
topologyPairsAffinityPodsMaps = newTopologyPairsMaps() appendResult := func(nodeName string, nodeTopologyPairsAffinityPodsMap, nodeTopologyPairsAntiAffinityPodsMap topologyToMatchedTermCount) {
topologyPairsAntiAffinityPodsMaps = newTopologyPairsMaps()
appendResult := func(nodeName string, nodeTopologyPairsAffinityPodsMaps, nodeTopologyPairsAntiAffinityPodsMaps *topologyPairsMaps) {
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
if len(nodeTopologyPairsAffinityPodsMaps.topologyPairToPods) > 0 { if len(nodeTopologyPairsAffinityPodsMap) > 0 {
topologyPairsAffinityPodsMaps.appendMaps(nodeTopologyPairsAffinityPodsMaps) topologyPairsAffinityPodsMap.appendMaps(nodeTopologyPairsAffinityPodsMap)
} }
if len(nodeTopologyPairsAntiAffinityPodsMaps.topologyPairToPods) > 0 { if len(nodeTopologyPairsAntiAffinityPodsMap) > 0 {
topologyPairsAntiAffinityPodsMaps.appendMaps(nodeTopologyPairsAntiAffinityPodsMaps) topologyToMatchedExistingAntiAffinityTerms.appendMaps(nodeTopologyPairsAntiAffinityPodsMap)
} }
} }
@ -813,37 +788,23 @@ func getTPMapMatchingIncomingAffinityAntiAffinity(pod *v1.Pod, allNodes []*sched
klog.Error("node not found") klog.Error("node not found")
return return
} }
nodeTopologyPairsAffinityPodsMaps := newTopologyPairsMaps() nodeTopologyPairsAffinityPodsMap := make(topologyToMatchedTermCount)
nodeTopologyPairsAntiAffinityPodsMaps := newTopologyPairsMaps() nodeTopologyPairsAntiAffinityPodsMap := make(topologyToMatchedTermCount)
for _, existingPod := range nodeInfo.Pods() { for _, existingPod := range nodeInfo.Pods() {
// Check affinity properties. // Check affinity properties.
if podMatchesAllAffinityTermProperties(existingPod, affinityProperties) { nodeTopologyPairsAffinityPodsMap.updateWithAffinityTerms(existingPod, node, affinityProperties, 1)
for _, term := range affinityTerms {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue}
nodeTopologyPairsAffinityPodsMaps.addTopologyPair(pair, existingPod)
}
}
}
// Check anti-affinity properties. // Check anti-affinity properties.
for i, term := range antiAffinityTerms { nodeTopologyPairsAntiAffinityPodsMap.updateWithAntiAffinityTerms(existingPod, node, antiAffinityProperties, 1)
p := antiAffinityProperties[i]
if priorityutil.PodMatchesTermsNamespaceAndSelector(existingPod, p.namespaces, p.selector) {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue}
nodeTopologyPairsAntiAffinityPodsMaps.addTopologyPair(pair, existingPod)
}
}
}
} }
if len(nodeTopologyPairsAffinityPodsMaps.topologyPairToPods) > 0 || len(nodeTopologyPairsAntiAffinityPodsMaps.topologyPairToPods) > 0 { if len(nodeTopologyPairsAffinityPodsMap) > 0 || len(nodeTopologyPairsAntiAffinityPodsMap) > 0 {
appendResult(node.Name, nodeTopologyPairsAffinityPodsMaps, nodeTopologyPairsAntiAffinityPodsMaps) appendResult(node.Name, nodeTopologyPairsAffinityPodsMap, nodeTopologyPairsAntiAffinityPodsMap)
} }
} }
workqueue.ParallelizeUntil(context.Background(), 16, len(allNodes), processNode) workqueue.ParallelizeUntil(context.Background(), 16, len(allNodes), processNode)
return topologyPairsAffinityPodsMaps, topologyPairsAntiAffinityPodsMaps, nil return topologyPairsAffinityPodsMap, topologyToMatchedExistingAntiAffinityTerms, nil
} }
// targetPodMatchesAffinityOfPod returns true if "targetPod" matches ALL affinity terms of // targetPodMatchesAffinityOfPod returns true if "targetPod" matches ALL affinity terms of
@ -862,20 +823,3 @@ func targetPodMatchesAffinityOfPod(pod, targetPod *v1.Pod) bool {
} }
return podMatchesAllAffinityTermProperties(targetPod, affinityProperties) return podMatchesAllAffinityTermProperties(targetPod, affinityProperties)
} }
// targetPodMatchesAntiAffinityOfPod returns true if "targetPod" matches ANY anti-affinity
// term of "pod". This function does not check topology.
// So, whether the targetPod actually matches or not needs further checks for a specific
// node.
func targetPodMatchesAntiAffinityOfPod(pod, targetPod *v1.Pod) bool {
affinity := pod.Spec.Affinity
if affinity == nil || affinity.PodAntiAffinity == nil {
return false
}
properties, err := getAffinityTermProperties(pod, GetPodAntiAffinityTerms(affinity.PodAntiAffinity))
if err != nil {
klog.Errorf("error in getting anti-affinity properties of Pod %v", pod.Name)
return false
}
return podMatchesAnyAffinityTermProperties(targetPod, properties)
}

View File

@ -70,19 +70,15 @@ func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error {
for !reflect.DeepEqual(meta1.podFitsHostPortsMetadata.podPorts, meta2.podFitsHostPortsMetadata.podPorts) { for !reflect.DeepEqual(meta1.podFitsHostPortsMetadata.podPorts, meta2.podFitsHostPortsMetadata.podPorts) {
return fmt.Errorf("podPorts are not equal") return fmt.Errorf("podPorts are not equal")
} }
if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyPairsPotentialAffinityPods, meta2.podAffinityMetadata.topologyPairsPotentialAffinityPods) { if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyToMatchedAffinityTerms, meta2.podAffinityMetadata.topologyToMatchedAffinityTerms) {
return fmt.Errorf("topologyPairsPotentialAffinityPods are not equal") return fmt.Errorf("topologyToMatchedAffinityTerms are not equal")
} }
if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyPairsPotentialAntiAffinityPods, meta2.podAffinityMetadata.topologyPairsPotentialAntiAffinityPods) { if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyToMatchedAntiAffinityTerms, meta2.podAffinityMetadata.topologyToMatchedAntiAffinityTerms) {
return fmt.Errorf("topologyPairsPotentialAntiAffinityPods are not equal") return fmt.Errorf("topologyToMatchedAntiAffinityTerms are not equal")
} }
if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyPairsAntiAffinityPodsMap.podToTopologyPairs, if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyToMatchedExistingAntiAffinityTerms,
meta2.podAffinityMetadata.topologyPairsAntiAffinityPodsMap.podToTopologyPairs) { meta2.podAffinityMetadata.topologyToMatchedExistingAntiAffinityTerms) {
return fmt.Errorf("topologyPairsAntiAffinityPodsMap.podToTopologyPairs are not equal") return fmt.Errorf("topologyToMatchedExistingAntiAffinityTerms are not equal, got: %v, want: %v", meta1.podAffinityMetadata.topologyToMatchedExistingAntiAffinityTerms, meta2.podAffinityMetadata.topologyToMatchedExistingAntiAffinityTerms)
}
if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyPairsAntiAffinityPodsMap.topologyPairToPods,
meta2.podAffinityMetadata.topologyPairsAntiAffinityPodsMap.topologyPairToPods) {
return fmt.Errorf("topologyPairsAntiAffinityPodsMap.topologyPairToPods are not equal")
} }
if meta1.serviceAffinityMetadata != nil { if meta1.serviceAffinityMetadata != nil {
sortablePods1 := sortablePods(meta1.serviceAffinityMetadata.matchingPodList) sortablePods1 := sortablePods(meta1.serviceAffinityMetadata.matchingPodList)
@ -379,7 +375,7 @@ func TestPredicateMetadata_AddRemovePod(t *testing.T) {
// Remove the added pod and from existingPodsMeta1 an make sure it is equal // Remove the added pod and from existingPodsMeta1 an make sure it is equal
// to meta generated for existing pods. // to meta generated for existing pods.
existingPodsMeta2, _ := getMeta(fakelisters.PodLister(test.existingPods)) existingPodsMeta2, _ := getMeta(fakelisters.PodLister(test.existingPods))
if err := existingPodsMeta1.RemovePod(test.addedPod, nil); err != nil { if err := existingPodsMeta1.RemovePod(test.addedPod, nodeInfo.Node()); err != nil {
t.Errorf("error removing pod from meta: %v", err) t.Errorf("error removing pod from meta: %v", err)
} }
if err := predicateMetadataEquivalent(existingPodsMeta1, existingPodsMeta2); err != nil { if err := predicateMetadataEquivalent(existingPodsMeta1, existingPodsMeta2); err != nil {
@ -393,7 +389,6 @@ func TestPredicateMetadata_AddRemovePod(t *testing.T) {
// on the idea that shallow-copy should produce an object that is deep-equal to the original // on the idea that shallow-copy should produce an object that is deep-equal to the original
// object. // object.
func TestPredicateMetadata_ShallowCopy(t *testing.T) { func TestPredicateMetadata_ShallowCopy(t *testing.T) {
selector1 := map[string]string{"foo": "bar"}
source := predicateMetadata{ source := predicateMetadata{
pod: &v1.Pod{ pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
@ -421,95 +416,17 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) {
}, },
}, },
podAffinityMetadata: &podAffinityMetadata{ podAffinityMetadata: &podAffinityMetadata{
topologyPairsAntiAffinityPodsMap: &topologyPairsMaps{ topologyToMatchedExistingAntiAffinityTerms: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "name", value: "machine1"}: 1,
{key: "name", value: "machine1"}: { {key: "name", value: "machine2"}: 1,
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2", Labels: selector1},
Spec: v1.PodSpec{NodeName: "nodeC"},
}: struct{}{},
},
{key: "name", value: "machine2"}: {
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
Spec: v1.PodSpec{NodeName: "nodeA"},
}: struct{}{},
},
},
podToTopologyPairs: map[string]topologyPairSet{
"p2_": {
topologyPair{key: "name", value: "machine1"}: struct{}{},
},
"p1_": {
topologyPair{key: "name", value: "machine2"}: struct{}{},
},
},
}, },
topologyPairsPotentialAffinityPods: &topologyPairsMaps{ topologyToMatchedAffinityTerms: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "name", value: "nodeA"}: 1,
{key: "name", value: "nodeA"}: { {key: "name", value: "nodeC"}: 2,
&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{}{},
},
},
podToTopologyPairs: map[string]topologyPairSet{
"p1_": {
topologyPair{key: "name", value: "nodeA"}: struct{}{},
},
"p2_": {
topologyPair{key: "name", value: "nodeC"}: struct{}{},
},
"p6_": {
topologyPair{key: "name", value: "nodeC"}: struct{}{},
},
},
}, },
topologyPairsPotentialAntiAffinityPods: &topologyPairsMaps{ topologyToMatchedAntiAffinityTerms: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "name", value: "nodeN"}: 3,
{key: "name", value: "nodeN"}: { {key: "name", value: "nodeM"}: 1,
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
Spec: v1.PodSpec{NodeName: "nodeN"},
}: struct{}{},
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2"},
Spec: v1.PodSpec{
NodeName: "nodeM",
},
}: struct{}{},
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p3"},
Spec: v1.PodSpec{
NodeName: "nodeM",
},
}: struct{}{},
},
{key: "name", value: "nodeM"}: {
&v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p6", Labels: selector1},
Spec: v1.PodSpec{NodeName: "nodeM"},
}: struct{}{},
},
},
podToTopologyPairs: map[string]topologyPairSet{
"p1_": {
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{}{},
},
},
}, },
}, },
evenPodsSpreadMetadata: &evenPodsSpreadMetadata{ evenPodsSpreadMetadata: &evenPodsSpreadMetadata{
@ -573,13 +490,13 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
nodeA := &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"hostname": "nodeA"}}} nodeA := &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"hostname": "nodeA"}}}
tests := []struct { tests := []struct {
name string name string
existingPods []*v1.Pod existingPods []*v1.Pod
nodes []*v1.Node nodes []*v1.Node
pod *v1.Pod pod *v1.Pod
wantAffinityPodsMaps *topologyPairsMaps wantAffinityPodsMap topologyToMatchedTermCount
wantAntiAffinityPodsMaps *topologyPairsMaps wantAntiAffinityPodsMap topologyToMatchedTermCount
wantErr bool wantErr bool
}{ }{
{ {
name: "nil test", name: "nil test",
@ -587,8 +504,8 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
pod: &v1.Pod{ pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "aaa-normal"}, ObjectMeta: metav1.ObjectMeta{Name: "aaa-normal"},
}, },
wantAffinityPodsMaps: newTopologyPairsMaps(), wantAffinityPodsMap: make(topologyToMatchedTermCount),
wantAntiAffinityPodsMaps: newTopologyPairsMaps(), wantAntiAffinityPodsMap: make(topologyToMatchedTermCount),
}, },
{ {
name: "incoming pod without affinity/anti-affinity causes a no-op", name: "incoming pod without affinity/anti-affinity causes a no-op",
@ -597,8 +514,8 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
pod: &v1.Pod{ pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "aaa-normal"}, ObjectMeta: metav1.ObjectMeta{Name: "aaa-normal"},
}, },
wantAffinityPodsMaps: newTopologyPairsMaps(), wantAffinityPodsMap: make(topologyToMatchedTermCount),
wantAntiAffinityPodsMaps: newTopologyPairsMaps(), wantAntiAffinityPodsMap: make(topologyToMatchedTermCount),
}, },
{ {
name: "no pod has label that violates incoming pod's affinity and anti-affinity", name: "no pod has label that violates incoming pod's affinity and anti-affinity",
@ -617,8 +534,8 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
}, },
}, },
}, },
wantAffinityPodsMaps: newTopologyPairsMaps(), wantAffinityPodsMap: make(topologyToMatchedTermCount),
wantAntiAffinityPodsMaps: newTopologyPairsMaps(), wantAntiAffinityPodsMap: make(topologyToMatchedTermCount),
}, },
{ {
name: "existing pod matches incoming pod's affinity and anti-affinity - single term case", name: "existing pod matches incoming pod's affinity and anti-affinity - single term case",
@ -637,29 +554,15 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
}, },
}, },
}, },
wantAffinityPodsMaps: &topologyPairsMaps{ wantAffinityPodsMap: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "hostname", value: "nodeA"}: 1,
{key: "hostname", value: "nodeA"}: {normalPodA: struct{}{}},
},
podToTopologyPairs: map[string]topologyPairSet{
"normal_": {
topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
},
},
}, },
wantAntiAffinityPodsMaps: &topologyPairsMaps{ wantAntiAffinityPodsMap: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "hostname", value: "nodeA"}: 1,
{key: "hostname", value: "nodeA"}: {normalPodA: struct{}{}},
},
podToTopologyPairs: map[string]topologyPairSet{
"normal_": {
topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
},
},
}, },
}, },
{ {
name: "existing pod matches incoming pod's affinity and anti-affinity - mutiple terms case", name: "existing pod matches incoming pod's affinity and anti-affinity - multiple terms case",
existingPods: []*v1.Pod{normalPodAB}, existingPods: []*v1.Pod{normalPodAB},
nodes: []*v1.Node{nodeA}, nodes: []*v1.Node{nodeA},
pod: &v1.Pod{ pod: &v1.Pod{
@ -675,25 +578,11 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
}, },
}, },
}, },
wantAffinityPodsMaps: &topologyPairsMaps{ wantAffinityPodsMap: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "hostname", value: "nodeA"}: 2, // 2 one for each term.
{key: "hostname", value: "nodeA"}: {normalPodAB: struct{}{}},
},
podToTopologyPairs: map[string]topologyPairSet{
"normal_": {
topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
},
},
}, },
wantAntiAffinityPodsMaps: &topologyPairsMaps{ wantAntiAffinityPodsMap: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "hostname", value: "nodeA"}: 1,
{key: "hostname", value: "nodeA"}: {normalPodAB: struct{}{}},
},
podToTopologyPairs: map[string]topologyPairSet{
"normal_": {
topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
},
},
}, },
}, },
{ {
@ -713,16 +602,9 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
}, },
}, },
}, },
wantAffinityPodsMaps: newTopologyPairsMaps(), wantAffinityPodsMap: make(topologyToMatchedTermCount),
wantAntiAffinityPodsMaps: &topologyPairsMaps{ wantAntiAffinityPodsMap: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "hostname", value: "nodeA"}: 1,
{key: "hostname", value: "nodeA"}: {normalPodA: struct{}{}},
},
podToTopologyPairs: map[string]topologyPairSet{
"normal_": {
topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
},
},
}, },
}, },
{ {
@ -742,16 +624,9 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
}, },
}, },
}, },
wantAffinityPodsMaps: newTopologyPairsMaps(), wantAffinityPodsMap: make(topologyToMatchedTermCount),
wantAntiAffinityPodsMaps: &topologyPairsMaps{ wantAntiAffinityPodsMap: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "hostname", value: "nodeA"}: 1,
{key: "hostname", value: "nodeA"}: {normalPodAB: struct{}{}},
},
podToTopologyPairs: map[string]topologyPairSet{
"normal_": {
topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
},
},
}, },
}, },
{ {
@ -771,16 +646,9 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
}, },
}, },
}, },
wantAffinityPodsMaps: newTopologyPairsMaps(), wantAffinityPodsMap: make(topologyToMatchedTermCount),
wantAntiAffinityPodsMaps: &topologyPairsMaps{ wantAntiAffinityPodsMap: topologyToMatchedTermCount{
topologyPairToPods: map[topologyPair]podSet{ {key: "hostname", value: "nodeA"}: 1,
{key: "hostname", value: "nodeA"}: {normalPodB: struct{}{}},
},
podToTopologyPairs: map[string]topologyPairSet{
"normal_": {
topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
},
},
}, },
}, },
} }
@ -788,16 +656,16 @@ func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
s := nodeinfosnapshot.NewSnapshot(nodeinfosnapshot.CreateNodeInfoMap(tt.existingPods, tt.nodes)) s := nodeinfosnapshot.NewSnapshot(nodeinfosnapshot.CreateNodeInfoMap(tt.existingPods, tt.nodes))
l, _ := s.NodeInfos().List() l, _ := s.NodeInfos().List()
gotAffinityPodsMaps, gotAntiAffinityPodsMaps, err := getTPMapMatchingIncomingAffinityAntiAffinity(tt.pod, l) gotAffinityPodsMap, gotAntiAffinityPodsMap, err := getTPMapMatchingIncomingAffinityAntiAffinity(tt.pod, l)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if !reflect.DeepEqual(gotAffinityPodsMaps, tt.wantAffinityPodsMaps) { if !reflect.DeepEqual(gotAffinityPodsMap, tt.wantAffinityPodsMap) {
t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() gotAffinityPodsMaps = %#v, want %#v", gotAffinityPodsMaps, tt.wantAffinityPodsMaps) t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() gotAffinityPodsMap = %#v, want %#v", gotAffinityPodsMap, tt.wantAffinityPodsMap)
} }
if !reflect.DeepEqual(gotAntiAffinityPodsMaps, tt.wantAntiAffinityPodsMaps) { if !reflect.DeepEqual(gotAntiAffinityPodsMap, tt.wantAntiAffinityPodsMap) {
t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() gotAntiAffinityPodsMaps = %#v, want %#v", gotAntiAffinityPodsMaps, tt.wantAntiAffinityPodsMaps) t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() gotAntiAffinityPodsMap = %#v, want %#v", gotAntiAffinityPodsMap, tt.wantAntiAffinityPodsMap)
} }
}) })
} }

View File

@ -1298,13 +1298,13 @@ func GetPodAntiAffinityTerms(podAntiAffinity *v1.PodAntiAffinity) (terms []v1.Po
// getMatchingAntiAffinityTopologyPairs calculates the following for "existingPod" on given node: // getMatchingAntiAffinityTopologyPairs calculates the following for "existingPod" on given node:
// (1) Whether it has PodAntiAffinity // (1) Whether it has PodAntiAffinity
// (2) Whether ANY AffinityTerm matches the incoming pod // (2) Whether ANY AffinityTerm matches the incoming pod
func getMatchingAntiAffinityTopologyPairsOfPod(newPod *v1.Pod, existingPod *v1.Pod, node *v1.Node) (*topologyPairsMaps, error) { func getMatchingAntiAffinityTopologyPairsOfPod(newPod *v1.Pod, existingPod *v1.Pod, node *v1.Node) (topologyToMatchedTermCount, error) {
affinity := existingPod.Spec.Affinity affinity := existingPod.Spec.Affinity
if affinity == nil || affinity.PodAntiAffinity == nil { if affinity == nil || affinity.PodAntiAffinity == nil {
return nil, nil return nil, nil
} }
topologyMaps := newTopologyPairsMaps() topologyMap := make(topologyToMatchedTermCount)
for _, term := range GetPodAntiAffinityTerms(affinity.PodAntiAffinity) { for _, term := range GetPodAntiAffinityTerms(affinity.PodAntiAffinity) {
selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector) selector, err := metav1.LabelSelectorAsSelector(term.LabelSelector)
if err != nil { if err != nil {
@ -1314,15 +1314,15 @@ func getMatchingAntiAffinityTopologyPairsOfPod(newPod *v1.Pod, existingPod *v1.P
if priorityutil.PodMatchesTermsNamespaceAndSelector(newPod, namespaces, selector) { if priorityutil.PodMatchesTermsNamespaceAndSelector(newPod, namespaces, selector) {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok { if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue} pair := topologyPair{key: term.TopologyKey, value: topologyValue}
topologyMaps.addTopologyPair(pair, existingPod) topologyMap[pair]++
} }
} }
} }
return topologyMaps, nil return topologyMap, nil
} }
func (c *PodAffinityChecker) getMatchingAntiAffinityTopologyPairsOfPods(pod *v1.Pod, existingPods []*v1.Pod) (*topologyPairsMaps, error) { func (c *PodAffinityChecker) getMatchingAntiAffinityTopologyPairsOfPods(pod *v1.Pod, existingPods []*v1.Pod) (topologyToMatchedTermCount, error) {
topologyMaps := newTopologyPairsMaps() topologyMaps := make(topologyToMatchedTermCount)
for _, existingPod := range existingPods { for _, existingPod := range existingPods {
existingPodNodeInfo, err := c.nodeInfoLister.Get(existingPod.Spec.NodeName) existingPodNodeInfo, err := c.nodeInfoLister.Get(existingPod.Spec.NodeName)
@ -1346,9 +1346,9 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
if node == nil { if node == nil {
return ErrExistingPodsAntiAffinityRulesNotMatch, fmt.Errorf("node not found") return ErrExistingPodsAntiAffinityRulesNotMatch, fmt.Errorf("node not found")
} }
var topologyMaps *topologyPairsMaps var topologyMap topologyToMatchedTermCount
if predicateMeta, ok := meta.(*predicateMetadata); ok { if predicateMeta, ok := meta.(*predicateMetadata); ok {
topologyMaps = predicateMeta.podAffinityMetadata.topologyPairsAntiAffinityPodsMap topologyMap = predicateMeta.podAffinityMetadata.topologyToMatchedExistingAntiAffinityTerms
} else { } else {
// Filter out pods whose nodeName is equal to nodeInfo.node.Name, but are not // Filter out pods whose nodeName is equal to nodeInfo.node.Name, but are not
// present in nodeInfo. Pods on other nodes pass the filter. // present in nodeInfo. Pods on other nodes pass the filter.
@ -1358,7 +1358,7 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
klog.Error(errMessage) klog.Error(errMessage)
return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage) return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage)
} }
if topologyMaps, err = c.getMatchingAntiAffinityTopologyPairsOfPods(pod, filteredPods); err != nil { if topologyMap, err = c.getMatchingAntiAffinityTopologyPairsOfPods(pod, filteredPods); err != nil {
errMessage := fmt.Sprintf("Failed to get all terms that match pod %s: %v", podName(pod), err) errMessage := fmt.Sprintf("Failed to get all terms that match pod %s: %v", podName(pod), err)
klog.Error(errMessage) klog.Error(errMessage)
return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage) return ErrExistingPodsAntiAffinityRulesNotMatch, errors.New(errMessage)
@ -1368,7 +1368,7 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
// Iterate over topology pairs to get any of the pods being affected by // Iterate over topology pairs to get any of the pods being affected by
// the scheduled pod anti-affinity terms // the scheduled pod anti-affinity terms
for topologyKey, topologyValue := range node.Labels { for topologyKey, topologyValue := range node.Labels {
if topologyMaps.topologyPairToPods[topologyPair{key: topologyKey, value: topologyValue}] != nil { if topologyMap[topologyPair{key: topologyKey, value: topologyValue}] > 0 {
klog.V(10).Infof("Cannot schedule pod %+v onto node %v", podName(pod), node.Name) klog.V(10).Infof("Cannot schedule pod %+v onto node %v", podName(pod), node.Name)
return ErrExistingPodsAntiAffinityRulesNotMatch, nil return ErrExistingPodsAntiAffinityRulesNotMatch, nil
} }
@ -1384,12 +1384,12 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
// nodeMatchesAllTopologyTerms checks whether "nodeInfo" matches // nodeMatchesAllTopologyTerms checks whether "nodeInfo" matches
// topology of all the "terms" for the given "pod". // topology of all the "terms" for the given "pod".
func (c *PodAffinityChecker) nodeMatchesAllTopologyTerms(pod *v1.Pod, topologyPairs *topologyPairsMaps, nodeInfo *schedulernodeinfo.NodeInfo, terms []v1.PodAffinityTerm) bool { func (c *PodAffinityChecker) nodeMatchesAllTopologyTerms(pod *v1.Pod, topologyPairs topologyToMatchedTermCount, nodeInfo *schedulernodeinfo.NodeInfo, terms []v1.PodAffinityTerm) bool {
node := nodeInfo.Node() node := nodeInfo.Node()
for _, term := range terms { for _, term := range terms {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok { if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue} pair := topologyPair{key: term.TopologyKey, value: topologyValue}
if _, ok := topologyPairs.topologyPairToPods[pair]; !ok { if topologyPairs[pair] <= 0 {
return false return false
} }
} else { } else {
@ -1401,12 +1401,12 @@ func (c *PodAffinityChecker) nodeMatchesAllTopologyTerms(pod *v1.Pod, topologyPa
// nodeMatchesAnyTopologyTerm checks whether "nodeInfo" matches // nodeMatchesAnyTopologyTerm checks whether "nodeInfo" matches
// topology of any "term" for the given "pod". // topology of any "term" for the given "pod".
func (c *PodAffinityChecker) nodeMatchesAnyTopologyTerm(pod *v1.Pod, topologyPairs *topologyPairsMaps, nodeInfo *schedulernodeinfo.NodeInfo, terms []v1.PodAffinityTerm) bool { func (c *PodAffinityChecker) nodeMatchesAnyTopologyTerm(pod *v1.Pod, topologyPairs topologyToMatchedTermCount, nodeInfo *schedulernodeinfo.NodeInfo, terms []v1.PodAffinityTerm) bool {
node := nodeInfo.Node() node := nodeInfo.Node()
for _, term := range terms { for _, term := range terms {
if topologyValue, ok := node.Labels[term.TopologyKey]; ok { if topologyValue, ok := node.Labels[term.TopologyKey]; ok {
pair := topologyPair{key: term.TopologyKey, value: topologyValue} pair := topologyPair{key: term.TopologyKey, value: topologyValue}
if _, ok := topologyPairs.topologyPairToPods[pair]; ok { if topologyPairs[pair] > 0 {
return true return true
} }
} }
@ -1424,15 +1424,15 @@ 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.
topologyPairsPotentialAffinityPods := predicateMeta.podAffinityMetadata.topologyPairsPotentialAffinityPods topologyToMatchedAffinityTerms := predicateMeta.podAffinityMetadata.topologyToMatchedAffinityTerms
if affinityTerms := GetPodAffinityTerms(affinity.PodAffinity); len(affinityTerms) > 0 { if affinityTerms := GetPodAffinityTerms(affinity.PodAffinity); len(affinityTerms) > 0 {
matchExists := c.nodeMatchesAllTopologyTerms(pod, topologyPairsPotentialAffinityPods, nodeInfo, affinityTerms) matchExists := c.nodeMatchesAllTopologyTerms(pod, topologyToMatchedAffinityTerms, nodeInfo, affinityTerms)
if !matchExists { if !matchExists {
// This pod may the first pod in a series that have affinity to themselves. In order // This pod may the first pod in a series that have affinity to themselves. In order
// 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(topologyPairsPotentialAffinityPods.topologyPairToPods) == 0 && targetPodMatchesAffinityOfPod(pod, pod)) { if len(topologyToMatchedAffinityTerms) != 0 || !targetPodMatchesAffinityOfPod(pod, pod) {
klog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAffinity", klog.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
@ -1441,9 +1441,9 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod,
} }
// Check all anti-affinity terms. // Check all anti-affinity terms.
topologyPairsPotentialAntiAffinityPods := predicateMeta.podAffinityMetadata.topologyPairsPotentialAntiAffinityPods topologyToMatchedAntiAffinityTerms := predicateMeta.podAffinityMetadata.topologyToMatchedAntiAffinityTerms
if antiAffinityTerms := GetPodAntiAffinityTerms(affinity.PodAntiAffinity); len(antiAffinityTerms) > 0 { if antiAffinityTerms := GetPodAntiAffinityTerms(affinity.PodAntiAffinity); len(antiAffinityTerms) > 0 {
matchExists := c.nodeMatchesAnyTopologyTerm(pod, topologyPairsPotentialAntiAffinityPods, nodeInfo, antiAffinityTerms) matchExists := c.nodeMatchesAnyTopologyTerm(pod, topologyToMatchedAntiAffinityTerms, nodeInfo, antiAffinityTerms)
if matchExists { if matchExists {
klog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAntiAffinity", klog.V(10).Infof("Cannot schedule pod %+v onto node %v, because of PodAntiAffinity",
podName(pod), node.Name) podName(pod), node.Name)