mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 05:27:21 +00:00
Merge pull request #83286 from draveness/feature/refactor-predicate-metadata
feat(scheduler): refactor predicateMetadata into a collection of sub types
This commit is contained in:
commit
464952fcc8
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
@ -110,11 +110,11 @@ func (paths *criticalPaths) update(tpVal string, num int32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// podSpreadCache combines tpKeyToCriticalPaths and tpPairToMatchNum
|
// evenPodsSpreadMetadata combines tpKeyToCriticalPaths and tpPairToMatchNum
|
||||||
// to represent:
|
// to represent:
|
||||||
// (1) critical paths where the least pods are matched on each spread constraint.
|
// (1) critical paths where the least pods are matched on each spread constraint.
|
||||||
// (2) number of pods matched on each spread constraint.
|
// (2) number of pods matched on each spread constraint.
|
||||||
type podSpreadCache struct {
|
type evenPodsSpreadMetadata struct {
|
||||||
// We record 2 critical paths instead of all critical paths here.
|
// We record 2 critical paths instead of all critical paths here.
|
||||||
// criticalPaths[0].matchNum always holds the minimum matching number.
|
// criticalPaths[0].matchNum always holds the minimum matching number.
|
||||||
// criticalPaths[1].matchNum is always greater or equal to criticalPaths[0].matchNum, but
|
// criticalPaths[1].matchNum is always greater or equal to criticalPaths[0].matchNum, but
|
||||||
@ -124,14 +124,57 @@ type podSpreadCache struct {
|
|||||||
tpPairToMatchNum map[topologyPair]int32
|
tpPairToMatchNum map[topologyPair]int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: When new fields are added/removed or logic is changed, please make sure that
|
type serviceAffinityMetadata struct {
|
||||||
// RemovePod, AddPod, and ShallowCopy functions are updated to work with the new changes.
|
matchingPodList []*v1.Pod
|
||||||
type predicateMetadata struct {
|
matchingPodServices []*v1.Service
|
||||||
pod *v1.Pod
|
}
|
||||||
podBestEffort bool
|
|
||||||
podRequest *schedulernodeinfo.Resource
|
|
||||||
podPorts []*v1.ContainerPort
|
|
||||||
|
|
||||||
|
func (m *serviceAffinityMetadata) addPod(addedPod *v1.Pod, pod *v1.Pod, node *v1.Node) {
|
||||||
|
// If addedPod is in the same namespace as the pod, update the list
|
||||||
|
// of matching pods if applicable.
|
||||||
|
if m == nil || addedPod.Namespace != pod.Namespace {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
selector := CreateSelectorFromLabels(pod.Labels)
|
||||||
|
if selector.Matches(labels.Set(addedPod.Labels)) {
|
||||||
|
m.matchingPodList = append(m.matchingPodList, addedPod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *serviceAffinityMetadata) removePod(deletedPod *v1.Pod, node *v1.Node) {
|
||||||
|
deletedPodFullName := schedutil.GetPodFullName(deletedPod)
|
||||||
|
|
||||||
|
if m == nil ||
|
||||||
|
len(m.matchingPodList) == 0 ||
|
||||||
|
deletedPod.Namespace != m.matchingPodList[0].Namespace {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, pod := range m.matchingPodList {
|
||||||
|
if schedutil.GetPodFullName(pod) == deletedPodFullName {
|
||||||
|
m.matchingPodList = append(m.matchingPodList[:i], m.matchingPodList[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *serviceAffinityMetadata) clone() *serviceAffinityMetadata {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
copy := serviceAffinityMetadata{}
|
||||||
|
|
||||||
|
copy.matchingPodServices = append([]*v1.Service(nil),
|
||||||
|
m.matchingPodServices...)
|
||||||
|
copy.matchingPodList = append([]*v1.Pod(nil),
|
||||||
|
m.matchingPodList...)
|
||||||
|
|
||||||
|
return ©
|
||||||
|
}
|
||||||
|
|
||||||
|
type podAffinityMetadata struct {
|
||||||
topologyPairsAntiAffinityPodsMap *topologyPairsMaps
|
topologyPairsAntiAffinityPodsMap *topologyPairsMaps
|
||||||
// A map of topology pairs to a list of Pods that can potentially match
|
// A map of topology pairs to a list of Pods that can potentially match
|
||||||
// the affinity terms of the "pod" and its inverse.
|
// the affinity terms of the "pod" and its inverse.
|
||||||
@ -139,9 +182,70 @@ type predicateMetadata struct {
|
|||||||
// A map of topology pairs to a list of Pods that can potentially match
|
// A map of topology pairs to a list of Pods that can potentially match
|
||||||
// the anti-affinity terms of the "pod" and its inverse.
|
// the anti-affinity terms of the "pod" and its inverse.
|
||||||
topologyPairsPotentialAntiAffinityPods *topologyPairsMaps
|
topologyPairsPotentialAntiAffinityPods *topologyPairsMaps
|
||||||
serviceAffinityInUse bool
|
}
|
||||||
serviceAffinityMatchingPodList []*v1.Pod
|
|
||||||
serviceAffinityMatchingPodServices []*v1.Service
|
func (m *podAffinityMetadata) addPod(addedPod *v1.Pod, pod *v1.Pod, node *v1.Node) error {
|
||||||
|
// Add matching anti-affinity terms of the addedPod to the map.
|
||||||
|
topologyPairsMaps, err := getMatchingAntiAffinityTopologyPairsOfPod(pod, addedPod, node)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.topologyPairsAntiAffinityPodsMap.appendMaps(topologyPairsMaps)
|
||||||
|
// Add the pod to nodeNameToMatchingAffinityPods and nodeNameToMatchingAntiAffinityPods if needed.
|
||||||
|
affinity := pod.Spec.Affinity
|
||||||
|
podNodeName := addedPod.Spec.NodeName
|
||||||
|
if affinity != nil && len(podNodeName) > 0 {
|
||||||
|
// It is assumed that when the added pod matches affinity of the pod, all the terms must match,
|
||||||
|
// 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) {
|
||||||
|
if m == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.topologyPairsAntiAffinityPodsMap.removePod(deletedPod)
|
||||||
|
// Delete pod from the matching affinity or anti-affinity topology pairs maps.
|
||||||
|
m.topologyPairsPotentialAffinityPods.removePod(deletedPod)
|
||||||
|
m.topologyPairsPotentialAntiAffinityPods.removePod(deletedPod)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *podAffinityMetadata) clone() *podAffinityMetadata {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
copy := podAffinityMetadata{}
|
||||||
|
copy.topologyPairsPotentialAffinityPods = m.topologyPairsPotentialAffinityPods.clone()
|
||||||
|
copy.topologyPairsPotentialAntiAffinityPods = m.topologyPairsPotentialAntiAffinityPods.clone()
|
||||||
|
copy.topologyPairsAntiAffinityPodsMap = m.topologyPairsAntiAffinityPodsMap.clone()
|
||||||
|
|
||||||
|
return ©
|
||||||
|
}
|
||||||
|
|
||||||
|
type podFitsResourcesMetadata struct {
|
||||||
// ignoredExtendedResources is a set of extended resource names that will
|
// ignoredExtendedResources is a set of extended resource names that will
|
||||||
// be ignored in the PodFitsResources predicate.
|
// be ignored in the PodFitsResources predicate.
|
||||||
//
|
//
|
||||||
@ -149,9 +253,50 @@ type predicateMetadata struct {
|
|||||||
// which should be accounted only by the extenders. This set is synthesized
|
// which should be accounted only by the extenders. This set is synthesized
|
||||||
// from scheduler extender configuration and does not change per pod.
|
// from scheduler extender configuration and does not change per pod.
|
||||||
ignoredExtendedResources sets.String
|
ignoredExtendedResources sets.String
|
||||||
// podSpreadCache holds info of the minimum match number on each topology spread constraint,
|
podRequest *schedulernodeinfo.Resource
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *podFitsResourcesMetadata) clone() *podFitsResourcesMetadata {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
copy := podFitsResourcesMetadata{}
|
||||||
|
copy.ignoredExtendedResources = m.ignoredExtendedResources
|
||||||
|
copy.podRequest = m.podRequest
|
||||||
|
|
||||||
|
return ©
|
||||||
|
}
|
||||||
|
|
||||||
|
type podFitsHostPortsMetadata struct {
|
||||||
|
podPorts []*v1.ContainerPort
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *podFitsHostPortsMetadata) clone() *podFitsHostPortsMetadata {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
copy := podFitsHostPortsMetadata{}
|
||||||
|
copy.podPorts = append([]*v1.ContainerPort(nil), m.podPorts...)
|
||||||
|
|
||||||
|
return ©
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: When new fields are added/removed or logic is changed, please make sure that
|
||||||
|
// RemovePod, AddPod, and ShallowCopy functions are updated to work with the new changes.
|
||||||
|
type predicateMetadata struct {
|
||||||
|
pod *v1.Pod
|
||||||
|
podBestEffort bool
|
||||||
|
|
||||||
|
// evenPodsSpreadMetadata holds info of the minimum match number on each topology spread constraint,
|
||||||
// and the match number of all valid topology pairs.
|
// and the match number of all valid topology pairs.
|
||||||
podSpreadCache *podSpreadCache
|
evenPodsSpreadMetadata *evenPodsSpreadMetadata
|
||||||
|
|
||||||
|
serviceAffinityMetadata *serviceAffinityMetadata
|
||||||
|
podAffinityMetadata *podAffinityMetadata
|
||||||
|
podFitsResourcesMetadata *podFitsResourcesMetadata
|
||||||
|
podFitsHostPortsMetadata *podFitsHostPortsMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that predicateMetadata implements algorithm.PredicateMetadata.
|
// Ensure that predicateMetadata implements algorithm.PredicateMetadata.
|
||||||
@ -180,7 +325,7 @@ func EmptyPredicateMetadataProducer(pod *v1.Pod, nodeNameToInfo map[string]*sche
|
|||||||
// See the comments in "predicateMetadata" for the explanation of the options.
|
// See the comments in "predicateMetadata" for the explanation of the options.
|
||||||
func RegisterPredicateMetadataProducerWithExtendedResourceOptions(ignoredExtendedResources sets.String) {
|
func RegisterPredicateMetadataProducerWithExtendedResourceOptions(ignoredExtendedResources sets.String) {
|
||||||
RegisterPredicateMetadataProducer("PredicateWithExtendedResourceOptions", func(pm *predicateMetadata) {
|
RegisterPredicateMetadataProducer("PredicateWithExtendedResourceOptions", func(pm *predicateMetadata) {
|
||||||
pm.ignoredExtendedResources = ignoredExtendedResources
|
pm.podFitsResourcesMetadata.ignoredExtendedResources = ignoredExtendedResources
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,35 +335,27 @@ func GetPredicateMetadata(pod *v1.Pod, nodeNameToInfoMap map[string]*schedulerno
|
|||||||
if pod == nil {
|
if pod == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// existingPodSpreadCache represents how existing pods match "pod"
|
// evenPodsSpreadMetadata represents how existing pods match "pod"
|
||||||
// on its spread constraints
|
// on its spread constraints
|
||||||
existingPodSpreadCache, err := getExistingPodSpreadCache(pod, nodeNameToInfoMap)
|
evenPodsSpreadMetadata, err := getEvenPodsSpreadMetadata(pod, nodeNameToInfoMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Error calculating spreadConstraintsMap: %v", err)
|
klog.Errorf("Error calculating spreadConstraintsMap: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// existingPodAntiAffinityMap will be used later for efficient check on existing pods' anti-affinity
|
|
||||||
existingPodAntiAffinityMap, err := getTPMapMatchingExistingAntiAffinity(pod, nodeNameToInfoMap)
|
podAffinityMetadata, err := getPodAffinityMetadata(pod, nodeNameToInfoMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Error calculating existingPodAntiAffinityMap: %v", err)
|
klog.Errorf("Error calculating podAffinityMetadata: %v", err)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// incomingPodAffinityMap will be used later for efficient check on incoming pod's affinity
|
|
||||||
// incomingPodAntiAffinityMap will be used later for efficient check on incoming pod's anti-affinity
|
|
||||||
incomingPodAffinityMap, incomingPodAntiAffinityMap, err := getTPMapMatchingIncomingAffinityAntiAffinity(pod, nodeNameToInfoMap)
|
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("Error calculating incomingPod(Anti)AffinityMap: %v", err)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
predicateMetadata := &predicateMetadata{
|
predicateMetadata := &predicateMetadata{
|
||||||
pod: pod,
|
pod: pod,
|
||||||
podBestEffort: isPodBestEffort(pod),
|
podBestEffort: isPodBestEffort(pod),
|
||||||
podRequest: GetResourceRequest(pod),
|
evenPodsSpreadMetadata: evenPodsSpreadMetadata,
|
||||||
podPorts: schedutil.GetContainerPorts(pod),
|
podAffinityMetadata: podAffinityMetadata,
|
||||||
topologyPairsPotentialAffinityPods: incomingPodAffinityMap,
|
podFitsResourcesMetadata: getPodFitsResourcesMetedata(pod),
|
||||||
topologyPairsPotentialAntiAffinityPods: incomingPodAntiAffinityMap,
|
podFitsHostPortsMetadata: getPodFitsHostPortsMetadata(pod),
|
||||||
topologyPairsAntiAffinityPodsMap: existingPodAntiAffinityMap,
|
|
||||||
podSpreadCache: existingPodSpreadCache,
|
|
||||||
}
|
}
|
||||||
for predicateName, precomputeFunc := range predicateMetadataProducers {
|
for predicateName, precomputeFunc := range predicateMetadataProducers {
|
||||||
klog.V(10).Infof("Precompute: %v", predicateName)
|
klog.V(10).Infof("Precompute: %v", predicateName)
|
||||||
@ -227,7 +364,39 @@ func GetPredicateMetadata(pod *v1.Pod, nodeNameToInfoMap map[string]*schedulerno
|
|||||||
return predicateMetadata
|
return predicateMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExistingPodSpreadCache(pod *v1.Pod, nodeInfoMap map[string]*schedulernodeinfo.NodeInfo) (*podSpreadCache, error) {
|
func getPodFitsHostPortsMetadata(pod *v1.Pod) *podFitsHostPortsMetadata {
|
||||||
|
return &podFitsHostPortsMetadata{
|
||||||
|
podPorts: schedutil.GetContainerPorts(pod),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPodFitsResourcesMetedata(pod *v1.Pod) *podFitsResourcesMetadata {
|
||||||
|
return &podFitsResourcesMetadata{
|
||||||
|
podRequest: GetResourceRequest(pod),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPodAffinityMetadata(pod *v1.Pod, nodeNameToInfoMap map[string]*schedulernodeinfo.NodeInfo) (*podAffinityMetadata, error) {
|
||||||
|
// existingPodAntiAffinityMap will be used later for efficient check on existing pods' anti-affinity
|
||||||
|
existingPodAntiAffinityMap, err := getTPMapMatchingExistingAntiAffinity(pod, nodeNameToInfoMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// incomingPodAffinityMap will be used later for efficient check on incoming pod's affinity
|
||||||
|
// incomingPodAntiAffinityMap will be used later for efficient check on incoming pod's anti-affinity
|
||||||
|
incomingPodAffinityMap, incomingPodAntiAffinityMap, err := getTPMapMatchingIncomingAffinityAntiAffinity(pod, nodeNameToInfoMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &podAffinityMetadata{
|
||||||
|
topologyPairsPotentialAffinityPods: incomingPodAffinityMap,
|
||||||
|
topologyPairsPotentialAntiAffinityPods: incomingPodAntiAffinityMap,
|
||||||
|
topologyPairsAntiAffinityPodsMap: existingPodAntiAffinityMap,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEvenPodsSpreadMetadata(pod *v1.Pod, nodeInfoMap map[string]*schedulernodeinfo.NodeInfo) (*evenPodsSpreadMetadata, error) {
|
||||||
// We have feature gating in APIServer to strip the spec
|
// We have feature gating in APIServer to strip the spec
|
||||||
// so don't need to re-check feature gate, just check length of constraints.
|
// so don't need to re-check feature gate, just check length of constraints.
|
||||||
constraints := getHardTopologySpreadConstraints(pod)
|
constraints := getHardTopologySpreadConstraints(pod)
|
||||||
@ -245,7 +414,7 @@ func getExistingPodSpreadCache(pod *v1.Pod, nodeInfoMap map[string]*schedulernod
|
|||||||
|
|
||||||
// TODO(Huang-Wei): It might be possible to use "make(map[topologyPair]*int32)".
|
// TODO(Huang-Wei): It might be possible to use "make(map[topologyPair]*int32)".
|
||||||
// In that case, need to consider how to init each tpPairToCount[pair] in an atomic fashion.
|
// In that case, need to consider how to init each tpPairToCount[pair] in an atomic fashion.
|
||||||
m := podSpreadCache{
|
m := evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: make(map[string]*criticalPaths, len(constraints)),
|
tpKeyToCriticalPaths: make(map[string]*criticalPaths, len(constraints)),
|
||||||
tpPairToMatchNum: make(map[topologyPair]int32),
|
tpPairToMatchNum: make(map[topologyPair]int32),
|
||||||
}
|
}
|
||||||
@ -396,15 +565,15 @@ func (m *topologyPairsMaps) clone() *topologyPairsMaps {
|
|||||||
return copy
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *podSpreadCache) addPod(addedPod, preemptorPod *v1.Pod, node *v1.Node) error {
|
func (c *evenPodsSpreadMetadata) addPod(addedPod, preemptorPod *v1.Pod, node *v1.Node) error {
|
||||||
return c.updatePod(addedPod, preemptorPod, node, 1)
|
return c.updatePod(addedPod, preemptorPod, node, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *podSpreadCache) removePod(deletedPod, preemptorPod *v1.Pod, node *v1.Node) error {
|
func (c *evenPodsSpreadMetadata) removePod(deletedPod, preemptorPod *v1.Pod, node *v1.Node) error {
|
||||||
return c.updatePod(deletedPod, preemptorPod, node, -1)
|
return c.updatePod(deletedPod, preemptorPod, node, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *podSpreadCache) updatePod(updatedPod, preemptorPod *v1.Pod, node *v1.Node, delta int32) error {
|
func (c *evenPodsSpreadMetadata) updatePod(updatedPod, preemptorPod *v1.Pod, node *v1.Node, delta int32) error {
|
||||||
if updatedPod.Namespace != preemptorPod.Namespace || node == nil {
|
if updatedPod.Namespace != preemptorPod.Namespace || node == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -430,12 +599,12 @@ func (c *podSpreadCache) updatePod(updatedPod, preemptorPod *v1.Pod, node *v1.No
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *podSpreadCache) clone() *podSpreadCache {
|
func (c *evenPodsSpreadMetadata) clone() *evenPodsSpreadMetadata {
|
||||||
// c could be nil when EvenPodsSpread feature is disabled
|
// c could be nil when EvenPodsSpread feature is disabled
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
copy := podSpreadCache{
|
copy := evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: make(map[string]*criticalPaths),
|
tpKeyToCriticalPaths: make(map[string]*criticalPaths),
|
||||||
tpPairToMatchNum: make(map[topologyPair]int32),
|
tpPairToMatchNum: make(map[topologyPair]int32),
|
||||||
}
|
}
|
||||||
@ -456,29 +625,13 @@ 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.topologyPairsAntiAffinityPodsMap.removePod(deletedPod)
|
meta.podAffinityMetadata.removePod(deletedPod)
|
||||||
// Delete pod from the matching affinity or anti-affinity topology pairs maps.
|
|
||||||
meta.topologyPairsPotentialAffinityPods.removePod(deletedPod)
|
|
||||||
meta.topologyPairsPotentialAntiAffinityPods.removePod(deletedPod)
|
|
||||||
// Delete pod from the pod spread topology maps.
|
// Delete pod from the pod spread topology maps.
|
||||||
if err := meta.podSpreadCache.removePod(deletedPod, meta.pod, node); err != nil {
|
if err := meta.evenPodsSpreadMetadata.removePod(deletedPod, meta.pod, node); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// All pods in the serviceAffinityMatchingPodList are in the same namespace.
|
meta.serviceAffinityMetadata.removePod(deletedPod, node)
|
||||||
// So, if the namespace of the first one is not the same as the namespace of the
|
|
||||||
// deletedPod, we don't need to check the list, as deletedPod isn't in the list.
|
|
||||||
if meta.serviceAffinityInUse &&
|
|
||||||
len(meta.serviceAffinityMatchingPodList) > 0 &&
|
|
||||||
deletedPod.Namespace == meta.serviceAffinityMatchingPodList[0].Namespace {
|
|
||||||
for i, pod := range meta.serviceAffinityMatchingPodList {
|
|
||||||
if schedutil.GetPodFullName(pod) == deletedPodFullName {
|
|
||||||
meta.serviceAffinityMatchingPodList = append(
|
|
||||||
meta.serviceAffinityMatchingPodList[:i],
|
|
||||||
meta.serviceAffinityMatchingPodList[i+1:]...)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,53 +645,18 @@ func (meta *predicateMetadata) AddPod(addedPod *v1.Pod, node *v1.Node) error {
|
|||||||
if node == nil {
|
if node == nil {
|
||||||
return fmt.Errorf("node not found")
|
return fmt.Errorf("node not found")
|
||||||
}
|
}
|
||||||
// Add matching anti-affinity terms of the addedPod to the map.
|
|
||||||
topologyPairsMaps, err := getMatchingAntiAffinityTopologyPairsOfPod(meta.pod, addedPod, node)
|
if err := meta.podAffinityMetadata.addPod(addedPod, meta.pod, node); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
meta.topologyPairsAntiAffinityPodsMap.appendMaps(topologyPairsMaps)
|
// Update meta.evenPodsSpreadMetadata if meta.pod has hard spread constraints
|
||||||
// Add the pod to nodeNameToMatchingAffinityPods and nodeNameToMatchingAntiAffinityPods if needed.
|
|
||||||
affinity := meta.pod.Spec.Affinity
|
|
||||||
podNodeName := addedPod.Spec.NodeName
|
|
||||||
if affinity != nil && len(podNodeName) > 0 {
|
|
||||||
// It is assumed that when the added pod matches affinity of the meta.pod, all the terms must match,
|
|
||||||
// this should be changed when the implementation of targetPodMatchesAffinityOfPod/podMatchesAffinityTermProperties
|
|
||||||
// is changed
|
|
||||||
if targetPodMatchesAffinityOfPod(meta.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}
|
|
||||||
meta.topologyPairsPotentialAffinityPods.addTopologyPair(pair, addedPod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if targetPodMatchesAntiAffinityOfPod(meta.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}
|
|
||||||
meta.topologyPairsPotentialAntiAffinityPods.addTopologyPair(pair, addedPod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update meta.podSpreadCache if meta.pod has hard spread constraints
|
|
||||||
// and addedPod matches that
|
// and addedPod matches that
|
||||||
if err := meta.podSpreadCache.addPod(addedPod, meta.pod, node); err != nil {
|
if err := meta.evenPodsSpreadMetadata.addPod(addedPod, meta.pod, node); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If addedPod is in the same namespace as the meta.pod, update the list
|
meta.serviceAffinityMetadata.addPod(addedPod, meta.pod, node)
|
||||||
// of matching pods if applicable.
|
|
||||||
if meta.serviceAffinityInUse && addedPod.Namespace == meta.pod.Namespace {
|
|
||||||
selector := CreateSelectorFromLabels(meta.pod.Labels)
|
|
||||||
if selector.Matches(labels.Set(addedPod.Labels)) {
|
|
||||||
meta.serviceAffinityMatchingPodList = append(meta.serviceAffinityMatchingPodList,
|
|
||||||
addedPod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,19 +666,12 @@ func (meta *predicateMetadata) ShallowCopy() PredicateMetadata {
|
|||||||
newPredMeta := &predicateMetadata{
|
newPredMeta := &predicateMetadata{
|
||||||
pod: meta.pod,
|
pod: meta.pod,
|
||||||
podBestEffort: meta.podBestEffort,
|
podBestEffort: meta.podBestEffort,
|
||||||
podRequest: meta.podRequest,
|
|
||||||
serviceAffinityInUse: meta.serviceAffinityInUse,
|
|
||||||
ignoredExtendedResources: meta.ignoredExtendedResources,
|
|
||||||
}
|
}
|
||||||
newPredMeta.podPorts = append([]*v1.ContainerPort(nil), meta.podPorts...)
|
newPredMeta.podFitsHostPortsMetadata = meta.podFitsHostPortsMetadata.clone()
|
||||||
newPredMeta.topologyPairsPotentialAffinityPods = meta.topologyPairsPotentialAffinityPods.clone()
|
newPredMeta.podAffinityMetadata = meta.podAffinityMetadata.clone()
|
||||||
newPredMeta.topologyPairsPotentialAntiAffinityPods = meta.topologyPairsPotentialAntiAffinityPods.clone()
|
newPredMeta.evenPodsSpreadMetadata = meta.evenPodsSpreadMetadata.clone()
|
||||||
newPredMeta.topologyPairsAntiAffinityPodsMap = meta.topologyPairsAntiAffinityPodsMap.clone()
|
newPredMeta.serviceAffinityMetadata = meta.serviceAffinityMetadata.clone()
|
||||||
newPredMeta.podSpreadCache = meta.podSpreadCache.clone()
|
newPredMeta.podFitsResourcesMetadata = meta.podFitsResourcesMetadata.clone()
|
||||||
newPredMeta.serviceAffinityMatchingPodServices = append([]*v1.Service(nil),
|
|
||||||
meta.serviceAffinityMatchingPodServices...)
|
|
||||||
newPredMeta.serviceAffinityMatchingPodList = append([]*v1.Pod(nil),
|
|
||||||
meta.serviceAffinityMatchingPodList...)
|
|
||||||
return (PredicateMetadata)(newPredMeta)
|
return (PredicateMetadata)(newPredMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
|
schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
|
||||||
@ -62,41 +62,38 @@ func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error {
|
|||||||
if meta1.podBestEffort != meta2.podBestEffort {
|
if meta1.podBestEffort != meta2.podBestEffort {
|
||||||
return fmt.Errorf("podBestEfforts are not equal")
|
return fmt.Errorf("podBestEfforts are not equal")
|
||||||
}
|
}
|
||||||
if meta1.serviceAffinityInUse != meta2.serviceAffinityInUse {
|
if len(meta1.podFitsHostPortsMetadata.podPorts) != len(meta2.podFitsHostPortsMetadata.podPorts) {
|
||||||
return fmt.Errorf("serviceAffinityInUses are not equal")
|
|
||||||
}
|
|
||||||
if len(meta1.podPorts) != len(meta2.podPorts) {
|
|
||||||
return fmt.Errorf("podPorts are not equal")
|
return fmt.Errorf("podPorts are not equal")
|
||||||
}
|
}
|
||||||
for !reflect.DeepEqual(meta1.podPorts, meta2.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.topologyPairsPotentialAffinityPods, meta2.topologyPairsPotentialAffinityPods) {
|
if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyPairsPotentialAffinityPods, meta2.podAffinityMetadata.topologyPairsPotentialAffinityPods) {
|
||||||
return fmt.Errorf("topologyPairsPotentialAffinityPods are not equal")
|
return fmt.Errorf("topologyPairsPotentialAffinityPods are not equal")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(meta1.topologyPairsPotentialAntiAffinityPods, meta2.topologyPairsPotentialAntiAffinityPods) {
|
if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyPairsPotentialAntiAffinityPods, meta2.podAffinityMetadata.topologyPairsPotentialAntiAffinityPods) {
|
||||||
return fmt.Errorf("topologyPairsPotentialAntiAffinityPods are not equal")
|
return fmt.Errorf("topologyPairsPotentialAntiAffinityPods are not equal")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.podToTopologyPairs,
|
if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyPairsAntiAffinityPodsMap.podToTopologyPairs,
|
||||||
meta2.topologyPairsAntiAffinityPodsMap.podToTopologyPairs) {
|
meta2.podAffinityMetadata.topologyPairsAntiAffinityPodsMap.podToTopologyPairs) {
|
||||||
return fmt.Errorf("topologyPairsAntiAffinityPodsMap.podToTopologyPairs are not equal")
|
return fmt.Errorf("topologyPairsAntiAffinityPodsMap.podToTopologyPairs are not equal")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.topologyPairToPods,
|
if !reflect.DeepEqual(meta1.podAffinityMetadata.topologyPairsAntiAffinityPodsMap.topologyPairToPods,
|
||||||
meta2.topologyPairsAntiAffinityPodsMap.topologyPairToPods) {
|
meta2.podAffinityMetadata.topologyPairsAntiAffinityPodsMap.topologyPairToPods) {
|
||||||
return fmt.Errorf("topologyPairsAntiAffinityPodsMap.topologyPairToPods are not equal")
|
return fmt.Errorf("topologyPairsAntiAffinityPodsMap.topologyPairToPods are not equal")
|
||||||
}
|
}
|
||||||
if meta1.serviceAffinityInUse {
|
if meta1.serviceAffinityMetadata != nil {
|
||||||
sortablePods1 := sortablePods(meta1.serviceAffinityMatchingPodList)
|
sortablePods1 := sortablePods(meta1.serviceAffinityMetadata.matchingPodList)
|
||||||
sort.Sort(sortablePods1)
|
sort.Sort(sortablePods1)
|
||||||
sortablePods2 := sortablePods(meta2.serviceAffinityMatchingPodList)
|
sortablePods2 := sortablePods(meta2.serviceAffinityMetadata.matchingPodList)
|
||||||
sort.Sort(sortablePods2)
|
sort.Sort(sortablePods2)
|
||||||
if !reflect.DeepEqual(sortablePods1, sortablePods2) {
|
if !reflect.DeepEqual(sortablePods1, sortablePods2) {
|
||||||
return fmt.Errorf("serviceAffinityMatchingPodLists are not euqal")
|
return fmt.Errorf("serviceAffinityMatchingPodLists are not euqal")
|
||||||
}
|
}
|
||||||
|
|
||||||
sortableServices1 := sortableServices(meta1.serviceAffinityMatchingPodServices)
|
sortableServices1 := sortableServices(meta1.serviceAffinityMetadata.matchingPodServices)
|
||||||
sort.Sort(sortableServices1)
|
sort.Sort(sortableServices1)
|
||||||
sortableServices2 := sortableServices(meta2.serviceAffinityMatchingPodServices)
|
sortableServices2 := sortableServices(meta2.serviceAffinityMetadata.matchingPodServices)
|
||||||
sort.Sort(sortableServices2)
|
sort.Sort(sortableServices2)
|
||||||
if !reflect.DeepEqual(sortableServices1, sortableServices2) {
|
if !reflect.DeepEqual(sortableServices1, sortableServices2) {
|
||||||
return fmt.Errorf("serviceAffinityMatchingPodServices are not euqal")
|
return fmt.Errorf("serviceAffinityMatchingPodServices are not euqal")
|
||||||
@ -407,11 +404,14 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
podBestEffort: true,
|
podBestEffort: true,
|
||||||
|
podFitsResourcesMetadata: &podFitsResourcesMetadata{
|
||||||
podRequest: &schedulernodeinfo.Resource{
|
podRequest: &schedulernodeinfo.Resource{
|
||||||
MilliCPU: 1000,
|
MilliCPU: 1000,
|
||||||
Memory: 300,
|
Memory: 300,
|
||||||
AllowedPodNumber: 4,
|
AllowedPodNumber: 4,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
podFitsHostPortsMetadata: &podFitsHostPortsMetadata{
|
||||||
podPorts: []*v1.ContainerPort{
|
podPorts: []*v1.ContainerPort{
|
||||||
{
|
{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
@ -421,6 +421,8 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) {
|
|||||||
HostIP: "1.2.3.4",
|
HostIP: "1.2.3.4",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
podAffinityMetadata: &podAffinityMetadata{
|
||||||
topologyPairsAntiAffinityPodsMap: &topologyPairsMaps{
|
topologyPairsAntiAffinityPodsMap: &topologyPairsMaps{
|
||||||
topologyPairToPods: map[topologyPair]podSet{
|
topologyPairToPods: map[topologyPair]podSet{
|
||||||
{key: "name", value: "machine1"}: {
|
{key: "name", value: "machine1"}: {
|
||||||
@ -511,7 +513,8 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
podSpreadCache: &podSpreadCache{
|
},
|
||||||
|
evenPodsSpreadMetadata: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"name": {{"nodeA", 1}, {"nodeC", 2}},
|
"name": {{"nodeA", 1}, {"nodeC", 2}},
|
||||||
},
|
},
|
||||||
@ -520,14 +523,15 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) {
|
|||||||
{key: "name", value: "nodeC"}: 2,
|
{key: "name", value: "nodeC"}: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
serviceAffinityInUse: true,
|
serviceAffinityMetadata: &serviceAffinityMetadata{
|
||||||
serviceAffinityMatchingPodList: []*v1.Pod{
|
matchingPodList: []*v1.Pod{
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "pod1"}},
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "pod2"}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "pod2"}},
|
||||||
},
|
},
|
||||||
serviceAffinityMatchingPodServices: []*v1.Service{
|
matchingPodServices: []*v1.Service{
|
||||||
{ObjectMeta: metav1.ObjectMeta{Name: "service1"}},
|
{ObjectMeta: metav1.ObjectMeta{Name: "service1"}},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(source.ShallowCopy().(*predicateMetadata), &source) {
|
if !reflect.DeepEqual(source.ShallowCopy().(*predicateMetadata), &source) {
|
||||||
@ -896,7 +900,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
nodes []*v1.Node
|
nodes []*v1.Node
|
||||||
existingPods []*v1.Pod
|
existingPods []*v1.Pod
|
||||||
want *podSpreadCache
|
want *evenPodsSpreadMetadata
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "clean cluster with one spreadConstraint",
|
name: "clean cluster with one spreadConstraint",
|
||||||
@ -909,7 +913,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||||
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
|
st.MakeNode().Name("node-y").Label("zone", "zone2").Label("node", "node-y").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 0}, {"zone2", 0}},
|
"zone": {{"zone1", 0}, {"zone2", 0}},
|
||||||
},
|
},
|
||||||
@ -937,7 +941,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
|
||||||
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone2", 2}, {"zone1", 3}},
|
"zone": {{"zone2", 2}, {"zone1", 3}},
|
||||||
},
|
},
|
||||||
@ -967,7 +971,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y1").Node("node-y").Label("foo", "").Obj(),
|
||||||
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone3", 0}, {"zone2", 2}},
|
"zone": {{"zone3", 0}, {"zone2", 2}},
|
||||||
},
|
},
|
||||||
@ -996,7 +1000,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakePod().Name("p-y1").Namespace("ns2").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y1").Namespace("ns2").Node("node-y").Label("foo", "").Obj(),
|
||||||
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y2").Node("node-y").Label("foo", "").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone2", 1}, {"zone1", 2}},
|
"zone": {{"zone2", 1}, {"zone1", 2}},
|
||||||
},
|
},
|
||||||
@ -1027,7 +1031,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
||||||
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 3}, {"zone2", 4}},
|
"zone": {{"zone1", 3}, {"zone2", 4}},
|
||||||
"node": {{"node-x", 0}, {"node-b", 1}},
|
"node": {{"node-x", 0}, {"node-b", 1}},
|
||||||
@ -1064,7 +1068,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
||||||
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 3}, {"zone2", 4}},
|
"zone": {{"zone1", 3}, {"zone2", 4}},
|
||||||
"node": {{"node-b", 1}, {"node-a", 2}},
|
"node": {{"node-b", 1}, {"node-a", 2}},
|
||||||
@ -1093,7 +1097,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakePod().Name("p-a").Node("node-a").Label("foo", "").Obj(),
|
st.MakePod().Name("p-a").Node("node-a").Label("foo", "").Obj(),
|
||||||
st.MakePod().Name("p-b").Node("node-b").Label("bar", "").Obj(),
|
st.MakePod().Name("p-b").Node("node-b").Label("bar", "").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone2", 0}, {"zone1", 1}},
|
"zone": {{"zone2", 0}, {"zone1", 1}},
|
||||||
"node": {{"node-a", 0}, {"node-y", 0}},
|
"node": {{"node-a", 0}, {"node-y", 0}},
|
||||||
@ -1127,7 +1131,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
||||||
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Label("bar", "").Obj(),
|
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Label("bar", "").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 3}, {"zone2", 4}},
|
"zone": {{"zone1", 3}, {"zone2", 4}},
|
||||||
"node": {{"node-b", 0}, {"node-a", 1}},
|
"node": {{"node-b", 0}, {"node-a", 1}},
|
||||||
@ -1163,7 +1167,7 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y3").Node("node-y").Label("foo", "").Obj(),
|
||||||
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
|
st.MakePod().Name("p-y4").Node("node-y").Label("foo", "").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 3}, {"zone2", 4}},
|
"zone": {{"zone1", 3}, {"zone2", 4}},
|
||||||
"node": {{"node-b", 1}, {"node-a", 2}},
|
"node": {{"node-b", 1}, {"node-a", 2}},
|
||||||
@ -1181,10 +1185,10 @@ func TestGetTPMapMatchingSpreadConstraints(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(tt.existingPods, tt.nodes)
|
nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(tt.existingPods, tt.nodes)
|
||||||
got, _ := getExistingPodSpreadCache(tt.pod, nodeInfoMap)
|
got, _ := getEvenPodsSpreadMetadata(tt.pod, nodeInfoMap)
|
||||||
got.sortCriticalPaths()
|
got.sortCriticalPaths()
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("getExistingPodSpreadCache() = %v, want %v", *got, *tt.want)
|
t.Errorf("getEvenPodsSpreadMetadata() = %v, want %v", *got, *tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1198,7 +1202,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
existingPods []*v1.Pod
|
existingPods []*v1.Pod
|
||||||
nodeIdx int // denotes which node 'addedPod' belongs to
|
nodeIdx int // denotes which node 'addedPod' belongs to
|
||||||
nodes []*v1.Node
|
nodes []*v1.Node
|
||||||
want *podSpreadCache
|
want *evenPodsSpreadMetadata
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "node a and b both impact current min match",
|
name: "node a and b both impact current min match",
|
||||||
@ -1212,7 +1216,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"node": {{"node-b", 0}, {"node-a", 1}},
|
"node": {{"node-b", 0}, {"node-a", 1}},
|
||||||
},
|
},
|
||||||
@ -1236,7 +1240,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"node": {{"node-a", 1}, {"node-b", 1}},
|
"node": {{"node-a", 1}, {"node-b", 1}},
|
||||||
},
|
},
|
||||||
@ -1260,7 +1264,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"node": {{"node-a", 0}, {"node-b", 1}},
|
"node": {{"node-a", 0}, {"node-b", 1}},
|
||||||
},
|
},
|
||||||
@ -1284,7 +1288,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"node": {{"node-a", 0}, {"node-b", 2}},
|
"node": {{"node-a", 0}, {"node-b", 2}},
|
||||||
},
|
},
|
||||||
@ -1307,7 +1311,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone2", 0}, {"zone1", 1}},
|
"zone": {{"zone2", 0}, {"zone1", 1}},
|
||||||
"node": {{"node-x", 0}, {"node-a", 1}},
|
"node": {{"node-x", 0}, {"node-a", 1}},
|
||||||
@ -1335,7 +1339,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
st.MakeNode().Name("node-a").Label("zone", "zone1").Label("node", "node-a").Obj(),
|
||||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 1}, {"zone2", 1}},
|
"zone": {{"zone1", 1}, {"zone2", 1}},
|
||||||
"node": {{"node-a", 1}, {"node-x", 1}},
|
"node": {{"node-a", 1}, {"node-x", 1}},
|
||||||
@ -1366,7 +1370,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone2", 1}, {"zone1", 3}},
|
"zone": {{"zone2", 1}, {"zone1", 3}},
|
||||||
"node": {{"node-a", 1}, {"node-x", 1}},
|
"node": {{"node-a", 1}, {"node-x", 1}},
|
||||||
@ -1398,7 +1402,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone2", 1}, {"zone1", 2}},
|
"zone": {{"zone2", 1}, {"zone1", 2}},
|
||||||
"node": {{"node-a", 0}, {"node-b", 1}},
|
"node": {{"node-a", 0}, {"node-b", 1}},
|
||||||
@ -1430,7 +1434,7 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
st.MakeNode().Name("node-b").Label("zone", "zone1").Label("node", "node-b").Obj(),
|
||||||
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
st.MakeNode().Name("node-x").Label("zone", "zone2").Label("node", "node-x").Obj(),
|
||||||
},
|
},
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 1}, {"zone2", 1}},
|
"zone": {{"zone1", 1}, {"zone2", 1}},
|
||||||
"node": {{"node-a", 1}, {"node-b", 1}},
|
"node": {{"node-a", 1}, {"node-b", 1}},
|
||||||
@ -1448,12 +1452,12 @@ func TestPodSpreadCache_addPod(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(tt.existingPods, tt.nodes)
|
nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(tt.existingPods, tt.nodes)
|
||||||
podSpreadCache, _ := getExistingPodSpreadCache(tt.preemptor, nodeInfoMap)
|
evenPodsSpreadMetadata, _ := getEvenPodsSpreadMetadata(tt.preemptor, nodeInfoMap)
|
||||||
|
|
||||||
podSpreadCache.addPod(tt.addedPod, tt.preemptor, tt.nodes[tt.nodeIdx])
|
evenPodsSpreadMetadata.addPod(tt.addedPod, tt.preemptor, tt.nodes[tt.nodeIdx])
|
||||||
podSpreadCache.sortCriticalPaths()
|
evenPodsSpreadMetadata.sortCriticalPaths()
|
||||||
if !reflect.DeepEqual(podSpreadCache, tt.want) {
|
if !reflect.DeepEqual(evenPodsSpreadMetadata, tt.want) {
|
||||||
t.Errorf("podSpreadCache#addPod() = %v, want %v", podSpreadCache, tt.want)
|
t.Errorf("evenPodsSpreadMetadata#addPod() = %v, want %v", evenPodsSpreadMetadata, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1468,7 +1472,7 @@ func TestPodSpreadCache_removePod(t *testing.T) {
|
|||||||
deletedPodIdx int // need to reuse *Pod of existingPods[i]
|
deletedPodIdx int // need to reuse *Pod of existingPods[i]
|
||||||
deletedPod *v1.Pod // this field is used only when deletedPodIdx is -1
|
deletedPod *v1.Pod // this field is used only when deletedPodIdx is -1
|
||||||
nodeIdx int // denotes which node "deletedPod" belongs to
|
nodeIdx int // denotes which node "deletedPod" belongs to
|
||||||
want *podSpreadCache
|
want *evenPodsSpreadMetadata
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
// A high priority pod may not be scheduled due to node taints or resource shortage.
|
// A high priority pod may not be scheduled due to node taints or resource shortage.
|
||||||
@ -1489,7 +1493,7 @@ func TestPodSpreadCache_removePod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
deletedPodIdx: 0, // remove pod "p-a1"
|
deletedPodIdx: 0, // remove pod "p-a1"
|
||||||
nodeIdx: 0, // node-a
|
nodeIdx: 0, // node-a
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 1}, {"zone2", 1}},
|
"zone": {{"zone1", 1}, {"zone2", 1}},
|
||||||
},
|
},
|
||||||
@ -1518,7 +1522,7 @@ func TestPodSpreadCache_removePod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
deletedPodIdx: 0, // remove pod "p-a1"
|
deletedPodIdx: 0, // remove pod "p-a1"
|
||||||
nodeIdx: 0, // node-a
|
nodeIdx: 0, // node-a
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 1}, {"zone2", 2}},
|
"zone": {{"zone1", 1}, {"zone2", 2}},
|
||||||
},
|
},
|
||||||
@ -1548,7 +1552,7 @@ func TestPodSpreadCache_removePod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
deletedPodIdx: 0, // remove pod "p-a0"
|
deletedPodIdx: 0, // remove pod "p-a0"
|
||||||
nodeIdx: 0, // node-a
|
nodeIdx: 0, // node-a
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 2}, {"zone2", 2}},
|
"zone": {{"zone1", 2}, {"zone2", 2}},
|
||||||
},
|
},
|
||||||
@ -1578,7 +1582,7 @@ func TestPodSpreadCache_removePod(t *testing.T) {
|
|||||||
deletedPodIdx: -1,
|
deletedPodIdx: -1,
|
||||||
deletedPod: st.MakePod().Name("p-a0").Node("node-a").Label("bar", "").Obj(),
|
deletedPod: st.MakePod().Name("p-a0").Node("node-a").Label("bar", "").Obj(),
|
||||||
nodeIdx: 0, // node-a
|
nodeIdx: 0, // node-a
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone1", 2}, {"zone2", 2}},
|
"zone": {{"zone1", 2}, {"zone2", 2}},
|
||||||
},
|
},
|
||||||
@ -1608,7 +1612,7 @@ func TestPodSpreadCache_removePod(t *testing.T) {
|
|||||||
},
|
},
|
||||||
deletedPodIdx: 3, // remove pod "p-x1"
|
deletedPodIdx: 3, // remove pod "p-x1"
|
||||||
nodeIdx: 2, // node-x
|
nodeIdx: 2, // node-x
|
||||||
want: &podSpreadCache{
|
want: &evenPodsSpreadMetadata{
|
||||||
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
tpKeyToCriticalPaths: map[string]*criticalPaths{
|
||||||
"zone": {{"zone2", 1}, {"zone1", 3}},
|
"zone": {{"zone2", 1}, {"zone1", 3}},
|
||||||
"node": {{"node-b", 1}, {"node-x", 1}},
|
"node": {{"node-b", 1}, {"node-x", 1}},
|
||||||
@ -1626,7 +1630,7 @@ func TestPodSpreadCache_removePod(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(tt.existingPods, tt.nodes)
|
nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(tt.existingPods, tt.nodes)
|
||||||
podSpreadCache, _ := getExistingPodSpreadCache(tt.preemptor, nodeInfoMap)
|
evenPodsSpreadMetadata, _ := getEvenPodsSpreadMetadata(tt.preemptor, nodeInfoMap)
|
||||||
|
|
||||||
var deletedPod *v1.Pod
|
var deletedPod *v1.Pod
|
||||||
if tt.deletedPodIdx < len(tt.existingPods) && tt.deletedPodIdx >= 0 {
|
if tt.deletedPodIdx < len(tt.existingPods) && tt.deletedPodIdx >= 0 {
|
||||||
@ -1634,10 +1638,10 @@ func TestPodSpreadCache_removePod(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
deletedPod = tt.deletedPod
|
deletedPod = tt.deletedPod
|
||||||
}
|
}
|
||||||
podSpreadCache.removePod(deletedPod, tt.preemptor, tt.nodes[tt.nodeIdx])
|
evenPodsSpreadMetadata.removePod(deletedPod, tt.preemptor, tt.nodes[tt.nodeIdx])
|
||||||
podSpreadCache.sortCriticalPaths()
|
evenPodsSpreadMetadata.sortCriticalPaths()
|
||||||
if !reflect.DeepEqual(podSpreadCache, tt.want) {
|
if !reflect.DeepEqual(evenPodsSpreadMetadata, tt.want) {
|
||||||
t.Errorf("podSpreadCache#removePod() = %v, want %v", podSpreadCache, tt.want)
|
t.Errorf("evenPodsSpreadMetadata#removePod() = %v, want %v", evenPodsSpreadMetadata, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1686,7 +1690,7 @@ func BenchmarkTestGetTPMapMatchingSpreadConstraints(b *testing.B) {
|
|||||||
nodeNameToInfo := schedulernodeinfo.CreateNodeNameToInfoMap(existingPods, allNodes)
|
nodeNameToInfo := schedulernodeinfo.CreateNodeNameToInfoMap(existingPods, allNodes)
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
getExistingPodSpreadCache(tt.pod, nodeNameToInfo)
|
getEvenPodsSpreadMetadata(tt.pod, nodeNameToInfo)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1698,7 +1702,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// sortCriticalPaths is only served for testing purpose.
|
// sortCriticalPaths is only served for testing purpose.
|
||||||
func (c *podSpreadCache) sortCriticalPaths() {
|
func (c *evenPodsSpreadMetadata) sortCriticalPaths() {
|
||||||
for _, paths := range c.tpKeyToCriticalPaths {
|
for _, paths := range c.tpKeyToCriticalPaths {
|
||||||
// If two paths both hold minimum matching number, and topologyValue is unordered.
|
// If two paths both hold minimum matching number, and topologyValue is unordered.
|
||||||
if paths[0].matchNum == paths[1].matchNum && paths[0].topologyValue > paths[1].topologyValue {
|
if paths[0].matchNum == paths[1].matchNum && paths[0].topologyValue > paths[1].topologyValue {
|
||||||
|
@ -867,10 +867,10 @@ func PodFitsResources(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulerno
|
|||||||
ignoredExtendedResources := sets.NewString()
|
ignoredExtendedResources := sets.NewString()
|
||||||
|
|
||||||
var podRequest *schedulernodeinfo.Resource
|
var podRequest *schedulernodeinfo.Resource
|
||||||
if predicateMeta, ok := meta.(*predicateMetadata); ok {
|
if predicateMeta, ok := meta.(*predicateMetadata); ok && predicateMeta.podFitsResourcesMetadata != nil {
|
||||||
podRequest = predicateMeta.podRequest
|
podRequest = predicateMeta.podFitsResourcesMetadata.podRequest
|
||||||
if predicateMeta.ignoredExtendedResources != nil {
|
if predicateMeta.podFitsResourcesMetadata.ignoredExtendedResources != nil {
|
||||||
ignoredExtendedResources = predicateMeta.ignoredExtendedResources
|
ignoredExtendedResources = predicateMeta.podFitsResourcesMetadata.ignoredExtendedResources
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We couldn't parse metadata - fallback to computing it.
|
// We couldn't parse metadata - fallback to computing it.
|
||||||
@ -1062,10 +1062,8 @@ func (s *ServiceAffinity) serviceAffinityMetadataProducer(pm *predicateMetadata)
|
|||||||
klog.Errorf("Cannot precompute service affinity, a pod is required to calculate service affinity.")
|
klog.Errorf("Cannot precompute service affinity, a pod is required to calculate service affinity.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pm.serviceAffinityInUse = true
|
|
||||||
var err error
|
|
||||||
// Store services which match the pod.
|
// Store services which match the pod.
|
||||||
pm.serviceAffinityMatchingPodServices, err = s.serviceLister.GetPodServices(pm.pod)
|
matchingPodServices, err := s.serviceLister.GetPodServices(pm.pod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("Error precomputing service affinity: could not list services: %v", err)
|
klog.Errorf("Error precomputing service affinity: could not list services: %v", err)
|
||||||
}
|
}
|
||||||
@ -1076,7 +1074,11 @@ func (s *ServiceAffinity) serviceAffinityMetadataProducer(pm *predicateMetadata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// consider only the pods that belong to the same namespace
|
// consider only the pods that belong to the same namespace
|
||||||
pm.serviceAffinityMatchingPodList = FilterPodsByNamespace(allMatches, pm.pod.Namespace)
|
matchingPodList := FilterPodsByNamespace(allMatches, pm.pod.Namespace)
|
||||||
|
pm.serviceAffinityMetadata = &serviceAffinityMetadata{
|
||||||
|
matchingPodList: matchingPodList,
|
||||||
|
matchingPodServices: matchingPodServices,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServiceAffinityPredicate creates a ServiceAffinity.
|
// NewServiceAffinityPredicate creates a ServiceAffinity.
|
||||||
@ -1120,14 +1122,14 @@ func NewServiceAffinityPredicate(podLister algorithm.PodLister, serviceLister al
|
|||||||
func (s *ServiceAffinity) checkServiceAffinity(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {
|
func (s *ServiceAffinity) checkServiceAffinity(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {
|
||||||
var services []*v1.Service
|
var services []*v1.Service
|
||||||
var pods []*v1.Pod
|
var pods []*v1.Pod
|
||||||
if pm, ok := meta.(*predicateMetadata); ok && (pm.serviceAffinityMatchingPodList != nil || pm.serviceAffinityMatchingPodServices != nil) {
|
if pm, ok := meta.(*predicateMetadata); ok && pm.serviceAffinityMetadata != nil && (pm.serviceAffinityMetadata.matchingPodList != nil || pm.serviceAffinityMetadata.matchingPodServices != nil) {
|
||||||
services = pm.serviceAffinityMatchingPodServices
|
services = pm.serviceAffinityMetadata.matchingPodServices
|
||||||
pods = pm.serviceAffinityMatchingPodList
|
pods = pm.serviceAffinityMetadata.matchingPodList
|
||||||
} else {
|
} else {
|
||||||
// Make the predicate resilient in case metadata is missing.
|
// Make the predicate resilient in case metadata is missing.
|
||||||
pm = &predicateMetadata{pod: pod}
|
pm = &predicateMetadata{pod: pod}
|
||||||
s.serviceAffinityMetadataProducer(pm)
|
s.serviceAffinityMetadataProducer(pm)
|
||||||
pods, services = pm.serviceAffinityMatchingPodList, pm.serviceAffinityMatchingPodServices
|
pods, services = pm.serviceAffinityMetadata.matchingPodList, pm.serviceAffinityMetadata.matchingPodServices
|
||||||
}
|
}
|
||||||
filteredPods := nodeInfo.FilterOutPods(pods)
|
filteredPods := nodeInfo.FilterOutPods(pods)
|
||||||
node := nodeInfo.Node()
|
node := nodeInfo.Node()
|
||||||
@ -1158,8 +1160,8 @@ func (s *ServiceAffinity) checkServiceAffinity(pod *v1.Pod, meta PredicateMetada
|
|||||||
// PodFitsHostPorts checks if a node has free ports for the requested pod ports.
|
// PodFitsHostPorts checks if a node has free ports for the requested pod ports.
|
||||||
func PodFitsHostPorts(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {
|
func PodFitsHostPorts(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {
|
||||||
var wantPorts []*v1.ContainerPort
|
var wantPorts []*v1.ContainerPort
|
||||||
if predicateMeta, ok := meta.(*predicateMetadata); ok {
|
if predicateMeta, ok := meta.(*predicateMetadata); ok && predicateMeta.podFitsHostPortsMetadata != nil {
|
||||||
wantPorts = predicateMeta.podPorts
|
wantPorts = predicateMeta.podFitsHostPortsMetadata.podPorts
|
||||||
} else {
|
} else {
|
||||||
// We couldn't parse metadata - fallback to computing it.
|
// We couldn't parse metadata - fallback to computing it.
|
||||||
wantPorts = schedutil.GetContainerPorts(pod)
|
wantPorts = schedutil.GetContainerPorts(pod)
|
||||||
@ -1410,7 +1412,7 @@ func (c *PodAffinityChecker) satisfiesExistingPodsAntiAffinity(pod *v1.Pod, meta
|
|||||||
}
|
}
|
||||||
var topologyMaps *topologyPairsMaps
|
var topologyMaps *topologyPairsMaps
|
||||||
if predicateMeta, ok := meta.(*predicateMetadata); ok {
|
if predicateMeta, ok := meta.(*predicateMetadata); ok {
|
||||||
topologyMaps = predicateMeta.topologyPairsAntiAffinityPodsMap
|
topologyMaps = predicateMeta.podAffinityMetadata.topologyPairsAntiAffinityPodsMap
|
||||||
} 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.
|
||||||
@ -1486,7 +1488,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.
|
||||||
topologyPairsPotentialAffinityPods := predicateMeta.topologyPairsPotentialAffinityPods
|
topologyPairsPotentialAffinityPods := predicateMeta.podAffinityMetadata.topologyPairsPotentialAffinityPods
|
||||||
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, topologyPairsPotentialAffinityPods, nodeInfo, affinityTerms)
|
||||||
if !matchExists {
|
if !matchExists {
|
||||||
@ -1503,7 +1505,7 @@ func (c *PodAffinityChecker) satisfiesPodsAffinityAntiAffinity(pod *v1.Pod,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check all anti-affinity terms.
|
// Check all anti-affinity terms.
|
||||||
topologyPairsPotentialAntiAffinityPods := predicateMeta.topologyPairsPotentialAntiAffinityPods
|
topologyPairsPotentialAntiAffinityPods := predicateMeta.podAffinityMetadata.topologyPairsPotentialAntiAffinityPods
|
||||||
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, topologyPairsPotentialAntiAffinityPods, nodeInfo, antiAffinityTerms)
|
||||||
if matchExists {
|
if matchExists {
|
||||||
@ -1783,15 +1785,15 @@ func EvenPodsSpreadPredicate(pod *v1.Pod, meta PredicateMetadata, nodeInfo *sche
|
|||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var podSpreadCache *podSpreadCache
|
var evenPodsSpreadMetadata *evenPodsSpreadMetadata
|
||||||
if predicateMeta, ok := meta.(*predicateMetadata); ok {
|
if predicateMeta, ok := meta.(*predicateMetadata); ok {
|
||||||
podSpreadCache = predicateMeta.podSpreadCache
|
evenPodsSpreadMetadata = predicateMeta.evenPodsSpreadMetadata
|
||||||
} else { // We don't have precomputed metadata. We have to follow a slow path to check spread constraints.
|
} else { // We don't have precomputed metadata. We have to follow a slow path to check spread constraints.
|
||||||
// TODO(autoscaler): get it implemented
|
// TODO(autoscaler): get it implemented
|
||||||
return false, nil, errors.New("metadata not pre-computed for EvenPodsSpreadPredicate")
|
return false, nil, errors.New("metadata not pre-computed for EvenPodsSpreadPredicate")
|
||||||
}
|
}
|
||||||
|
|
||||||
if podSpreadCache == nil || len(podSpreadCache.tpPairToMatchNum) == 0 {
|
if evenPodsSpreadMetadata == nil || len(evenPodsSpreadMetadata.tpPairToMatchNum) == 0 {
|
||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1814,16 +1816,16 @@ func EvenPodsSpreadPredicate(pod *v1.Pod, meta PredicateMetadata, nodeInfo *sche
|
|||||||
}
|
}
|
||||||
|
|
||||||
pair := topologyPair{key: tpKey, value: tpVal}
|
pair := topologyPair{key: tpKey, value: tpVal}
|
||||||
paths, ok := podSpreadCache.tpKeyToCriticalPaths[tpKey]
|
paths, ok := evenPodsSpreadMetadata.tpKeyToCriticalPaths[tpKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
// error which should not happen
|
// error which should not happen
|
||||||
klog.Errorf("internal error: get paths from key %q of %#v", tpKey, podSpreadCache.tpKeyToCriticalPaths)
|
klog.Errorf("internal error: get paths from key %q of %#v", tpKey, evenPodsSpreadMetadata.tpKeyToCriticalPaths)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// judging criteria:
|
// judging criteria:
|
||||||
// 'existing matching num' + 'if self-match (1 or 0)' - 'global min matching num' <= 'maxSkew'
|
// 'existing matching num' + 'if self-match (1 or 0)' - 'global min matching num' <= 'maxSkew'
|
||||||
minMatchNum := paths[0].matchNum
|
minMatchNum := paths[0].matchNum
|
||||||
matchNum := podSpreadCache.tpPairToMatchNum[pair]
|
matchNum := evenPodsSpreadMetadata.tpPairToMatchNum[pair]
|
||||||
skew := matchNum + selfMatchNum - minMatchNum
|
skew := matchNum + selfMatchNum - minMatchNum
|
||||||
if skew > constraint.MaxSkew {
|
if skew > constraint.MaxSkew {
|
||||||
klog.V(5).Infof("node '%s' failed spreadConstraint[%s]: matchNum(%d) + selfMatchNum(%d) - minMatchNum(%d) > maxSkew(%d)", node.Name, tpKey, matchNum, selfMatchNum, minMatchNum, constraint.MaxSkew)
|
klog.V(5).Infof("node '%s' failed spreadConstraint[%s]: matchNum(%d) + selfMatchNum(%d) - minMatchNum(%d) > maxSkew(%d)", node.Name, tpKey, matchNum, selfMatchNum, minMatchNum, constraint.MaxSkew)
|
||||||
|
Loading…
Reference in New Issue
Block a user