mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	fix ImageLocality plugin score is inconsistent
This commit is contained in:
		
				
					committed by
					
						
						mengxiangyong02
					
				
			
			
				
	
			
			
			
						parent
						
							0554675d78
						
					
				
				
					commit
					5d5958e338
				
			@@ -570,7 +570,7 @@ func (ev *Evaluator) DryRunPreemption(ctx context.Context, pod *v1.Pod, potentia
 | 
				
			|||||||
	var statusesLock sync.Mutex
 | 
						var statusesLock sync.Mutex
 | 
				
			||||||
	var errs []error
 | 
						var errs []error
 | 
				
			||||||
	checkNode := func(i int) {
 | 
						checkNode := func(i int) {
 | 
				
			||||||
		nodeInfoCopy := potentialNodes[(int(offset)+i)%len(potentialNodes)].Clone()
 | 
							nodeInfoCopy := potentialNodes[(int(offset)+i)%len(potentialNodes)].Snapshot()
 | 
				
			||||||
		stateCopy := ev.State.Clone()
 | 
							stateCopy := ev.State.Clone()
 | 
				
			||||||
		pods, numPDBViolations, status := ev.SelectVictimsOnNode(ctx, stateCopy, pod, nodeInfoCopy, pdbs)
 | 
							pods, numPDBViolations, status := ev.SelectVictimsOnNode(ctx, stateCopy, pod, nodeInfoCopy, pdbs)
 | 
				
			||||||
		if status.IsSuccess() && len(pods) != 0 {
 | 
							if status.IsSuccess() && len(pods) != 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -942,7 +942,7 @@ func addNominatedPods(ctx context.Context, fh framework.Handle, pod *v1.Pod, sta
 | 
				
			|||||||
	if len(nominatedPodInfos) == 0 {
 | 
						if len(nominatedPodInfos) == 0 {
 | 
				
			||||||
		return false, state, nodeInfo, nil
 | 
							return false, state, nodeInfo, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	nodeInfoOut := nodeInfo.Clone()
 | 
						nodeInfoOut := nodeInfo.Snapshot()
 | 
				
			||||||
	stateOut := state.Clone()
 | 
						stateOut := state.Clone()
 | 
				
			||||||
	podsAdded := false
 | 
						podsAdded := false
 | 
				
			||||||
	for _, pi := range nominatedPodInfos {
 | 
						for _, pi := range nominatedPodInfos {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -462,8 +462,20 @@ func getNamespacesFromPodAffinityTerm(pod *v1.Pod, podAffinityTerm *v1.PodAffini
 | 
				
			|||||||
type ImageStateSummary struct {
 | 
					type ImageStateSummary struct {
 | 
				
			||||||
	// Size of the image
 | 
						// Size of the image
 | 
				
			||||||
	Size int64
 | 
						Size int64
 | 
				
			||||||
	// Used to track how many nodes have this image
 | 
						// Used to track how many nodes have this image, it is computed from the Nodes field below
 | 
				
			||||||
 | 
						// during the execution of Snapshot.
 | 
				
			||||||
	NumNodes int
 | 
						NumNodes int
 | 
				
			||||||
 | 
						// A set of node names for nodes having this image present. This field is used for
 | 
				
			||||||
 | 
						// keeping track of the nodes during update/add/remove events.
 | 
				
			||||||
 | 
						Nodes sets.Set[string]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Snapshot returns a copy without Nodes field of ImageStateSummary
 | 
				
			||||||
 | 
					func (iss *ImageStateSummary) Snapshot() *ImageStateSummary {
 | 
				
			||||||
 | 
						return &ImageStateSummary{
 | 
				
			||||||
 | 
							Size:     iss.Size,
 | 
				
			||||||
 | 
							NumNodes: iss.Nodes.Len(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NodeInfo is node level aggregated information.
 | 
					// NodeInfo is node level aggregated information.
 | 
				
			||||||
@@ -640,15 +652,15 @@ func (n *NodeInfo) Node() *v1.Node {
 | 
				
			|||||||
	return n.node
 | 
						return n.node
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Clone returns a copy of this node.
 | 
					// Snapshot returns a copy of this node, Except that ImageStates is copied without the Nodes field.
 | 
				
			||||||
func (n *NodeInfo) Clone() *NodeInfo {
 | 
					func (n *NodeInfo) Snapshot() *NodeInfo {
 | 
				
			||||||
	clone := &NodeInfo{
 | 
						clone := &NodeInfo{
 | 
				
			||||||
		node:             n.node,
 | 
							node:             n.node,
 | 
				
			||||||
		Requested:        n.Requested.Clone(),
 | 
							Requested:        n.Requested.Clone(),
 | 
				
			||||||
		NonZeroRequested: n.NonZeroRequested.Clone(),
 | 
							NonZeroRequested: n.NonZeroRequested.Clone(),
 | 
				
			||||||
		Allocatable:      n.Allocatable.Clone(),
 | 
							Allocatable:      n.Allocatable.Clone(),
 | 
				
			||||||
		UsedPorts:        make(HostPortInfo),
 | 
							UsedPorts:        make(HostPortInfo),
 | 
				
			||||||
		ImageStates:      n.ImageStates,
 | 
							ImageStates:      make(map[string]*ImageStateSummary),
 | 
				
			||||||
		PVCRefCounts:     make(map[string]int),
 | 
							PVCRefCounts:     make(map[string]int),
 | 
				
			||||||
		Generation:       n.Generation,
 | 
							Generation:       n.Generation,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -671,6 +683,13 @@ func (n *NodeInfo) Clone() *NodeInfo {
 | 
				
			|||||||
	if len(n.PodsWithRequiredAntiAffinity) > 0 {
 | 
						if len(n.PodsWithRequiredAntiAffinity) > 0 {
 | 
				
			||||||
		clone.PodsWithRequiredAntiAffinity = append([]*PodInfo(nil), n.PodsWithRequiredAntiAffinity...)
 | 
							clone.PodsWithRequiredAntiAffinity = append([]*PodInfo(nil), n.PodsWithRequiredAntiAffinity...)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if len(n.ImageStates) > 0 {
 | 
				
			||||||
 | 
							state := make(map[string]*ImageStateSummary, len(n.ImageStates))
 | 
				
			||||||
 | 
							for imageName, imageState := range n.ImageStates {
 | 
				
			||||||
 | 
								state[imageName] = imageState.Snapshot()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							clone.ImageStates = state
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	for key, value := range n.PVCRefCounts {
 | 
						for key, value := range n.PVCRefCounts {
 | 
				
			||||||
		clone.PVCRefCounts[key] = value
 | 
							clone.PVCRefCounts[key] = value
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -494,7 +494,7 @@ func TestNodeInfoClone(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for i, test := range tests {
 | 
						for i, test := range tests {
 | 
				
			||||||
		t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
 | 
							t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) {
 | 
				
			||||||
			ni := test.nodeInfo.Clone()
 | 
								ni := test.nodeInfo.Snapshot()
 | 
				
			||||||
			// Modify the field to check if the result is a clone of the origin one.
 | 
								// Modify the field to check if the result is a clone of the origin one.
 | 
				
			||||||
			test.nodeInfo.Generation += 10
 | 
								test.nodeInfo.Generation += 10
 | 
				
			||||||
			test.nodeInfo.UsedPorts.Remove("127.0.0.1", "TCP", 80)
 | 
								test.nodeInfo.UsedPorts.Remove("127.0.0.1", "TCP", 80)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										46
									
								
								pkg/scheduler/internal/cache/cache.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								pkg/scheduler/internal/cache/cache.go
									
									
									
									
										vendored
									
									
								
							@@ -71,8 +71,8 @@ type cacheImpl struct {
 | 
				
			|||||||
	// head of the linked list.
 | 
						// head of the linked list.
 | 
				
			||||||
	headNode *nodeInfoListItem
 | 
						headNode *nodeInfoListItem
 | 
				
			||||||
	nodeTree *nodeTree
 | 
						nodeTree *nodeTree
 | 
				
			||||||
	// A map from image name to its imageState.
 | 
						// A map from image name to its ImageStateSummary.
 | 
				
			||||||
	imageStates map[string]*imageState
 | 
						imageStates map[string]*framework.ImageStateSummary
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type podState struct {
 | 
					type podState struct {
 | 
				
			||||||
@@ -84,21 +84,6 @@ type podState struct {
 | 
				
			|||||||
	bindingFinished bool
 | 
						bindingFinished bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type imageState struct {
 | 
					 | 
				
			||||||
	// Size of the image
 | 
					 | 
				
			||||||
	size int64
 | 
					 | 
				
			||||||
	// A set of node names for nodes having this image present
 | 
					 | 
				
			||||||
	nodes sets.Set[string]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// createImageStateSummary returns a summarizing snapshot of the given image's state.
 | 
					 | 
				
			||||||
func (cache *cacheImpl) createImageStateSummary(state *imageState) *framework.ImageStateSummary {
 | 
					 | 
				
			||||||
	return &framework.ImageStateSummary{
 | 
					 | 
				
			||||||
		Size:     state.size,
 | 
					 | 
				
			||||||
		NumNodes: len(state.nodes),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newCache(ctx context.Context, ttl, period time.Duration) *cacheImpl {
 | 
					func newCache(ctx context.Context, ttl, period time.Duration) *cacheImpl {
 | 
				
			||||||
	logger := klog.FromContext(ctx)
 | 
						logger := klog.FromContext(ctx)
 | 
				
			||||||
	return &cacheImpl{
 | 
						return &cacheImpl{
 | 
				
			||||||
@@ -110,7 +95,7 @@ func newCache(ctx context.Context, ttl, period time.Duration) *cacheImpl {
 | 
				
			|||||||
		nodeTree:    newNodeTree(logger, nil),
 | 
							nodeTree:    newNodeTree(logger, nil),
 | 
				
			||||||
		assumedPods: sets.New[string](),
 | 
							assumedPods: sets.New[string](),
 | 
				
			||||||
		podStates:   make(map[string]*podState),
 | 
							podStates:   make(map[string]*podState),
 | 
				
			||||||
		imageStates: make(map[string]*imageState),
 | 
							imageStates: make(map[string]*framework.ImageStateSummary),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -182,7 +167,7 @@ func (cache *cacheImpl) Dump() *Dump {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	nodes := make(map[string]*framework.NodeInfo, len(cache.nodes))
 | 
						nodes := make(map[string]*framework.NodeInfo, len(cache.nodes))
 | 
				
			||||||
	for k, v := range cache.nodes {
 | 
						for k, v := range cache.nodes {
 | 
				
			||||||
		nodes[k] = v.info.Clone()
 | 
							nodes[k] = v.info.Snapshot()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &Dump{
 | 
						return &Dump{
 | 
				
			||||||
@@ -233,7 +218,7 @@ func (cache *cacheImpl) UpdateSnapshot(logger klog.Logger, nodeSnapshot *Snapsho
 | 
				
			|||||||
				existing = &framework.NodeInfo{}
 | 
									existing = &framework.NodeInfo{}
 | 
				
			||||||
				nodeSnapshot.nodeInfoMap[np.Name] = existing
 | 
									nodeSnapshot.nodeInfoMap[np.Name] = existing
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			clone := node.info.Clone()
 | 
								clone := node.info.Snapshot()
 | 
				
			||||||
			// We track nodes that have pods with affinity, here we check if this node changed its
 | 
								// We track nodes that have pods with affinity, here we check if this node changed its
 | 
				
			||||||
			// status from having pods with affinity to NOT having pods with affinity or the other
 | 
								// status from having pods with affinity to NOT having pods with affinity or the other
 | 
				
			||||||
			// way around.
 | 
								// way around.
 | 
				
			||||||
@@ -629,13 +614,12 @@ func (cache *cacheImpl) AddNode(logger klog.Logger, node *v1.Node) *framework.No
 | 
				
			|||||||
	cache.nodeTree.addNode(logger, node)
 | 
						cache.nodeTree.addNode(logger, node)
 | 
				
			||||||
	cache.addNodeImageStates(node, n.info)
 | 
						cache.addNodeImageStates(node, n.info)
 | 
				
			||||||
	n.info.SetNode(node)
 | 
						n.info.SetNode(node)
 | 
				
			||||||
	return n.info.Clone()
 | 
						return n.info.Snapshot()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (cache *cacheImpl) UpdateNode(logger klog.Logger, oldNode, newNode *v1.Node) *framework.NodeInfo {
 | 
					func (cache *cacheImpl) UpdateNode(logger klog.Logger, oldNode, newNode *v1.Node) *framework.NodeInfo {
 | 
				
			||||||
	cache.mu.Lock()
 | 
						cache.mu.Lock()
 | 
				
			||||||
	defer cache.mu.Unlock()
 | 
						defer cache.mu.Unlock()
 | 
				
			||||||
 | 
					 | 
				
			||||||
	n, ok := cache.nodes[newNode.Name]
 | 
						n, ok := cache.nodes[newNode.Name]
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		n = newNodeInfoListItem(framework.NewNodeInfo())
 | 
							n = newNodeInfoListItem(framework.NewNodeInfo())
 | 
				
			||||||
@@ -649,7 +633,7 @@ func (cache *cacheImpl) UpdateNode(logger klog.Logger, oldNode, newNode *v1.Node
 | 
				
			|||||||
	cache.nodeTree.updateNode(logger, oldNode, newNode)
 | 
						cache.nodeTree.updateNode(logger, oldNode, newNode)
 | 
				
			||||||
	cache.addNodeImageStates(newNode, n.info)
 | 
						cache.addNodeImageStates(newNode, n.info)
 | 
				
			||||||
	n.info.SetNode(newNode)
 | 
						n.info.SetNode(newNode)
 | 
				
			||||||
	return n.info.Clone()
 | 
						return n.info.Snapshot()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RemoveNode removes a node from the cache's tree.
 | 
					// RemoveNode removes a node from the cache's tree.
 | 
				
			||||||
@@ -693,17 +677,17 @@ func (cache *cacheImpl) addNodeImageStates(node *v1.Node, nodeInfo *framework.No
 | 
				
			|||||||
			// update the entry in imageStates
 | 
								// update the entry in imageStates
 | 
				
			||||||
			state, ok := cache.imageStates[name]
 | 
								state, ok := cache.imageStates[name]
 | 
				
			||||||
			if !ok {
 | 
								if !ok {
 | 
				
			||||||
				state = &imageState{
 | 
									state = &framework.ImageStateSummary{
 | 
				
			||||||
					size:  image.SizeBytes,
 | 
										Size:  image.SizeBytes,
 | 
				
			||||||
					nodes: sets.New(node.Name),
 | 
										Nodes: sets.New(node.Name),
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				cache.imageStates[name] = state
 | 
									cache.imageStates[name] = state
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				state.nodes.Insert(node.Name)
 | 
									state.Nodes.Insert(node.Name)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// create the imageStateSummary for this image
 | 
								// create the ImageStateSummary for this image
 | 
				
			||||||
			if _, ok := newSum[name]; !ok {
 | 
								if _, ok := newSum[name]; !ok {
 | 
				
			||||||
				newSum[name] = cache.createImageStateSummary(state)
 | 
									newSum[name] = state
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -722,8 +706,8 @@ func (cache *cacheImpl) removeNodeImageStates(node *v1.Node) {
 | 
				
			|||||||
		for _, name := range image.Names {
 | 
							for _, name := range image.Names {
 | 
				
			||||||
			state, ok := cache.imageStates[name]
 | 
								state, ok := cache.imageStates[name]
 | 
				
			||||||
			if ok {
 | 
								if ok {
 | 
				
			||||||
				state.nodes.Delete(node.Name)
 | 
									state.Nodes.Delete(node.Name)
 | 
				
			||||||
				if len(state.nodes) == 0 {
 | 
									if state.Nodes.Len() == 0 {
 | 
				
			||||||
					// Remove the unused image to make sure the length of
 | 
										// Remove the unused image to make sure the length of
 | 
				
			||||||
					// imageStates represents the total number of different
 | 
										// imageStates represents the total number of different
 | 
				
			||||||
					// images on all nodes
 | 
										// images on all nodes
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										197
									
								
								pkg/scheduler/internal/cache/cache_test.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										197
									
								
								pkg/scheduler/internal/cache/cache_test.go
									
									
									
									
										vendored
									
									
								
							@@ -1037,7 +1037,7 @@ func TestForgetPod(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// buildNodeInfo creates a NodeInfo by simulating node operations in cache.
 | 
					// buildNodeInfo creates a NodeInfo by simulating node operations in cache.
 | 
				
			||||||
func buildNodeInfo(node *v1.Node, pods []*v1.Pod) *framework.NodeInfo {
 | 
					func buildNodeInfo(node *v1.Node, pods []*v1.Pod, imageStates map[string]*framework.ImageStateSummary) *framework.NodeInfo {
 | 
				
			||||||
	expected := framework.NewNodeInfo()
 | 
						expected := framework.NewNodeInfo()
 | 
				
			||||||
	expected.SetNode(node)
 | 
						expected.SetNode(node)
 | 
				
			||||||
	expected.Allocatable = framework.NewResource(node.Status.Allocatable)
 | 
						expected.Allocatable = framework.NewResource(node.Status.Allocatable)
 | 
				
			||||||
@@ -1045,48 +1045,83 @@ func buildNodeInfo(node *v1.Node, pods []*v1.Pod) *framework.NodeInfo {
 | 
				
			|||||||
	for _, pod := range pods {
 | 
						for _, pod := range pods {
 | 
				
			||||||
		expected.AddPod(pod)
 | 
							expected.AddPod(pod)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						for _, image := range node.Status.Images {
 | 
				
			||||||
 | 
							for _, name := range image.Names {
 | 
				
			||||||
 | 
								if state, ok := imageStates[name]; ok {
 | 
				
			||||||
 | 
									expected.ImageStates[name] = state
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return expected
 | 
						return expected
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// buildImageStates creates ImageStateSummary of image from nodes that will be added in cache.
 | 
				
			||||||
 | 
					func buildImageStates(nodes []*v1.Node) map[string]*framework.ImageStateSummary {
 | 
				
			||||||
 | 
						imageStates := make(map[string]*framework.ImageStateSummary)
 | 
				
			||||||
 | 
						for _, item := range nodes {
 | 
				
			||||||
 | 
							for _, image := range item.Status.Images {
 | 
				
			||||||
 | 
								for _, name := range image.Names {
 | 
				
			||||||
 | 
									if state, ok := imageStates[name]; !ok {
 | 
				
			||||||
 | 
										state = &framework.ImageStateSummary{
 | 
				
			||||||
 | 
											Size:  image.SizeBytes,
 | 
				
			||||||
 | 
											Nodes: sets.New[string](item.Name),
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										imageStates[name] = state
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										state.Nodes.Insert(item.Name)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return imageStates
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TestNodeOperators tests node operations of cache, including add, update
 | 
					// TestNodeOperators tests node operations of cache, including add, update
 | 
				
			||||||
// and remove.
 | 
					// and remove.
 | 
				
			||||||
func TestNodeOperators(t *testing.T) {
 | 
					func TestNodeOperators(t *testing.T) {
 | 
				
			||||||
	// Test data
 | 
						// Test data
 | 
				
			||||||
	nodeName := "test-node"
 | 
					 | 
				
			||||||
	cpu1 := resource.MustParse("1000m")
 | 
					 | 
				
			||||||
	mem100m := resource.MustParse("100m")
 | 
					 | 
				
			||||||
	cpuHalf := resource.MustParse("500m")
 | 
						cpuHalf := resource.MustParse("500m")
 | 
				
			||||||
	mem50m := resource.MustParse("50m")
 | 
						mem50m := resource.MustParse("50m")
 | 
				
			||||||
	resourceFooName := "example.com/foo"
 | 
						resourceList1 := map[v1.ResourceName]string{
 | 
				
			||||||
	resourceFoo := resource.MustParse("1")
 | 
							v1.ResourceCPU:                     "1000m",
 | 
				
			||||||
 | 
							v1.ResourceMemory:                  "100m",
 | 
				
			||||||
	tests := []struct {
 | 
							v1.ResourceName("example.com/foo"): "1",
 | 
				
			||||||
		name string
 | 
						}
 | 
				
			||||||
		node *v1.Node
 | 
						resourceList2 := map[v1.ResourceName]string{
 | 
				
			||||||
		pods []*v1.Pod
 | 
							v1.ResourceCPU:                     "500m",
 | 
				
			||||||
	}{
 | 
							v1.ResourceMemory:                  "50m",
 | 
				
			||||||
		{
 | 
							v1.ResourceName("example.com/foo"): "2",
 | 
				
			||||||
			name: "operate the node with one pod",
 | 
						}
 | 
				
			||||||
			node: &v1.Node{
 | 
						taints := []v1.Taint{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{
 | 
					 | 
				
			||||||
					Name: nodeName,
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				Status: v1.NodeStatus{
 | 
					 | 
				
			||||||
					Allocatable: v1.ResourceList{
 | 
					 | 
				
			||||||
						v1.ResourceCPU:                   cpu1,
 | 
					 | 
				
			||||||
						v1.ResourceMemory:                mem100m,
 | 
					 | 
				
			||||||
						v1.ResourceName(resourceFooName): resourceFoo,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				Spec: v1.NodeSpec{
 | 
					 | 
				
			||||||
					Taints: []v1.Taint{
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Key:    "test-key",
 | 
								Key:    "test-key",
 | 
				
			||||||
			Value:  "test-value",
 | 
								Value:  "test-value",
 | 
				
			||||||
			Effect: v1.TaintEffectPreferNoSchedule,
 | 
								Effect: v1.TaintEffectPreferNoSchedule,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
					},
 | 
						}
 | 
				
			||||||
				},
 | 
						imageStatus1 := map[string]int64{
 | 
				
			||||||
 | 
							"gcr.io/80:latest":  80 * mb,
 | 
				
			||||||
 | 
							"gcr.io/80:v1":      80 * mb,
 | 
				
			||||||
 | 
							"gcr.io/300:latest": 300 * mb,
 | 
				
			||||||
 | 
							"gcr.io/300:v1":     300 * mb,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						imageStatus2 := map[string]int64{
 | 
				
			||||||
 | 
							"gcr.io/600:latest": 600 * mb,
 | 
				
			||||||
 | 
							"gcr.io/80:latest":  80 * mb,
 | 
				
			||||||
 | 
							"gcr.io/900:latest": 900 * mb,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							name  string
 | 
				
			||||||
 | 
							nodes []*v1.Node
 | 
				
			||||||
 | 
							pods  []*v1.Pod
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "operate the node with one pod",
 | 
				
			||||||
 | 
								nodes: []*v1.Node{
 | 
				
			||||||
 | 
									&st.MakeNode().Name("test-node-1").Capacity(resourceList1).Taints(taints).Images(imageStatus1).Node,
 | 
				
			||||||
 | 
									&st.MakeNode().Name("test-node-2").Capacity(resourceList2).Taints(taints).Images(imageStatus2).Node,
 | 
				
			||||||
 | 
									&st.MakeNode().Name("test-node-3").Capacity(resourceList1).Taints(taints).Images(imageStatus1).Node,
 | 
				
			||||||
 | 
									&st.MakeNode().Name("test-node-4").Capacity(resourceList2).Taints(taints).Images(imageStatus2).Node,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			pods: []*v1.Pod{
 | 
								pods: []*v1.Pod{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
@@ -1095,7 +1130,7 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
						UID:  types.UID("pod1"),
 | 
											UID:  types.UID("pod1"),
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					Spec: v1.PodSpec{
 | 
										Spec: v1.PodSpec{
 | 
				
			||||||
						NodeName: nodeName,
 | 
											NodeName: "test-node-1",
 | 
				
			||||||
						Containers: []v1.Container{
 | 
											Containers: []v1.Container{
 | 
				
			||||||
							{
 | 
												{
 | 
				
			||||||
								Resources: v1.ResourceRequirements{
 | 
													Resources: v1.ResourceRequirements{
 | 
				
			||||||
@@ -1119,26 +1154,10 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "operate the node with two pods",
 | 
								name: "operate the node with two pods",
 | 
				
			||||||
			node: &v1.Node{
 | 
								nodes: []*v1.Node{
 | 
				
			||||||
				ObjectMeta: metav1.ObjectMeta{
 | 
									&st.MakeNode().Name("test-node-1").Capacity(resourceList1).Taints(taints).Images(imageStatus1).Node,
 | 
				
			||||||
					Name: nodeName,
 | 
									&st.MakeNode().Name("test-node-2").Capacity(resourceList2).Taints(taints).Images(imageStatus2).Node,
 | 
				
			||||||
				},
 | 
									&st.MakeNode().Name("test-node-3").Capacity(resourceList1).Taints(taints).Images(imageStatus1).Node,
 | 
				
			||||||
				Status: v1.NodeStatus{
 | 
					 | 
				
			||||||
					Allocatable: v1.ResourceList{
 | 
					 | 
				
			||||||
						v1.ResourceCPU:                   cpu1,
 | 
					 | 
				
			||||||
						v1.ResourceMemory:                mem100m,
 | 
					 | 
				
			||||||
						v1.ResourceName(resourceFooName): resourceFoo,
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				Spec: v1.NodeSpec{
 | 
					 | 
				
			||||||
					Taints: []v1.Taint{
 | 
					 | 
				
			||||||
						{
 | 
					 | 
				
			||||||
							Key:    "test-key",
 | 
					 | 
				
			||||||
							Value:  "test-value",
 | 
					 | 
				
			||||||
							Effect: v1.TaintEffectPreferNoSchedule,
 | 
					 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
					},
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			pods: []*v1.Pod{
 | 
								pods: []*v1.Pod{
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
@@ -1147,7 +1166,7 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
						UID:  types.UID("pod1"),
 | 
											UID:  types.UID("pod1"),
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					Spec: v1.PodSpec{
 | 
										Spec: v1.PodSpec{
 | 
				
			||||||
						NodeName: nodeName,
 | 
											NodeName: "test-node-1",
 | 
				
			||||||
						Containers: []v1.Container{
 | 
											Containers: []v1.Container{
 | 
				
			||||||
							{
 | 
												{
 | 
				
			||||||
								Resources: v1.ResourceRequirements{
 | 
													Resources: v1.ResourceRequirements{
 | 
				
			||||||
@@ -1166,7 +1185,7 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
						UID:  types.UID("pod2"),
 | 
											UID:  types.UID("pod2"),
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					Spec: v1.PodSpec{
 | 
										Spec: v1.PodSpec{
 | 
				
			||||||
						NodeName: nodeName,
 | 
											NodeName: "test-node-1",
 | 
				
			||||||
						Containers: []v1.Container{
 | 
											Containers: []v1.Container{
 | 
				
			||||||
							{
 | 
												{
 | 
				
			||||||
								Resources: v1.ResourceRequirements{
 | 
													Resources: v1.ResourceRequirements{
 | 
				
			||||||
@@ -1188,16 +1207,24 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
			logger, ctx := ktesting.NewTestContext(t)
 | 
								logger, ctx := ktesting.NewTestContext(t)
 | 
				
			||||||
			ctx, cancel := context.WithCancel(ctx)
 | 
								ctx, cancel := context.WithCancel(ctx)
 | 
				
			||||||
			defer cancel()
 | 
								defer cancel()
 | 
				
			||||||
			expected := buildNodeInfo(tc.node, tc.pods)
 | 
								node := tc.nodes[0]
 | 
				
			||||||
			node := tc.node
 | 
					
 | 
				
			||||||
 | 
								imageStates := buildImageStates(tc.nodes)
 | 
				
			||||||
 | 
								expected := buildNodeInfo(node, tc.pods, imageStates)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			cache := newCache(ctx, time.Second, time.Second)
 | 
								cache := newCache(ctx, time.Second, time.Second)
 | 
				
			||||||
			cache.AddNode(logger, node)
 | 
								for _, nodeItem := range tc.nodes {
 | 
				
			||||||
 | 
									cache.AddNode(logger, nodeItem)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			for _, pod := range tc.pods {
 | 
								for _, pod := range tc.pods {
 | 
				
			||||||
				if err := cache.AddPod(logger, pod); err != nil {
 | 
									if err := cache.AddPod(logger, pod); err != nil {
 | 
				
			||||||
					t.Fatal(err)
 | 
										t.Fatal(err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								nodes := map[string]*framework.NodeInfo{}
 | 
				
			||||||
 | 
								for nodeItem := cache.headNode; nodeItem != nil; nodeItem = nodeItem.next {
 | 
				
			||||||
 | 
									nodes[nodeItem.info.Node().Name] = nodeItem.info
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Step 1: the node was added into cache successfully.
 | 
								// Step 1: the node was added into cache successfully.
 | 
				
			||||||
			got, found := cache.nodes[node.Name]
 | 
								got, found := cache.nodes[node.Name]
 | 
				
			||||||
@@ -1208,14 +1235,20 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Fatal(err)
 | 
									t.Fatal(err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if cache.nodeTree.numNodes != 1 || nodesList[len(nodesList)-1] != node.Name {
 | 
								if cache.nodeTree.numNodes != len(tc.nodes) || len(nodesList) != len(tc.nodes) {
 | 
				
			||||||
				t.Errorf("cache.nodeTree is not updated correctly after adding node: %v", node.Name)
 | 
									t.Errorf("cache.nodeTree is not updated correctly after adding node got: %d, expected: %d",
 | 
				
			||||||
 | 
										cache.nodeTree.numNodes, len(tc.nodes))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Generations are globally unique. We check in our unit tests that they are incremented correctly.
 | 
								// Generations are globally unique. We check in our unit tests that they are incremented correctly.
 | 
				
			||||||
			expected.Generation = got.info.Generation
 | 
								expected.Generation = got.info.Generation
 | 
				
			||||||
			if diff := cmp.Diff(expected, got.info, cmp.AllowUnexported(framework.NodeInfo{})); diff != "" {
 | 
								if diff := cmp.Diff(expected, got.info, cmp.AllowUnexported(framework.NodeInfo{})); diff != "" {
 | 
				
			||||||
				t.Errorf("Unexpected node info from cache (-want, +got):\n%s", diff)
 | 
									t.Errorf("Failed to add node into scheduler cache (-want,+got):\n%s", diff)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// check imageState of NodeInfo with specific image when node added
 | 
				
			||||||
 | 
								if !checkImageStateSummary(nodes, "gcr.io/80:latest", "gcr.io/300:latest") {
 | 
				
			||||||
 | 
									t.Error("image have different ImageStateSummary")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Step 2: dump cached nodes successfully.
 | 
								// Step 2: dump cached nodes successfully.
 | 
				
			||||||
@@ -1224,12 +1257,16 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
				t.Error(err)
 | 
									t.Error(err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			newNode, found := cachedNodes.nodeInfoMap[node.Name]
 | 
								newNode, found := cachedNodes.nodeInfoMap[node.Name]
 | 
				
			||||||
			if !found || len(cachedNodes.nodeInfoMap) != 1 {
 | 
								if !found || len(cachedNodes.nodeInfoMap) != len(tc.nodes) {
 | 
				
			||||||
				t.Errorf("failed to dump cached nodes:\n got: %v \nexpected: %v", cachedNodes, cache.nodes)
 | 
									t.Errorf("failed to dump cached nodes:\n got: %v \nexpected: %v", cachedNodes.nodeInfoMap, tc.nodes)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			expected.Generation = newNode.Generation
 | 
								expected.Generation = newNode.Generation
 | 
				
			||||||
			if diff := cmp.Diff(expected, newNode, cmp.AllowUnexported(framework.NodeInfo{})); diff != "" {
 | 
								if diff := cmp.Diff(newNode, expected.Snapshot(), cmp.AllowUnexported(framework.NodeInfo{})); diff != "" {
 | 
				
			||||||
				t.Errorf("Unexpected clone node info (-want, +got):\n%s", diff)
 | 
									t.Errorf("Failed to clone node:\n%s", diff)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// check imageState of NodeInfo with specific image when update snapshot
 | 
				
			||||||
 | 
								if !checkImageStateSummary(cachedNodes.nodeInfoMap, "gcr.io/80:latest", "gcr.io/300:latest") {
 | 
				
			||||||
 | 
									t.Error("image have different ImageStateSummary")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Step 3: update node attribute successfully.
 | 
								// Step 3: update node attribute successfully.
 | 
				
			||||||
@@ -1249,13 +1286,17 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
			if diff := cmp.Diff(expected, got.info, cmp.AllowUnexported(framework.NodeInfo{})); diff != "" {
 | 
								if diff := cmp.Diff(expected, got.info, cmp.AllowUnexported(framework.NodeInfo{})); diff != "" {
 | 
				
			||||||
				t.Errorf("Unexpected schedulertypes after updating node (-want, +got):\n%s", diff)
 | 
									t.Errorf("Unexpected schedulertypes after updating node (-want, +got):\n%s", diff)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								// check imageState of NodeInfo with specific image when update node
 | 
				
			||||||
 | 
								if !checkImageStateSummary(nodes, "gcr.io/80:latest", "gcr.io/300:latest") {
 | 
				
			||||||
 | 
									t.Error("image have different ImageStateSummary")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			// Check nodeTree after update
 | 
								// Check nodeTree after update
 | 
				
			||||||
			nodesList, err = cache.nodeTree.list()
 | 
								nodesList, err = cache.nodeTree.list()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Fatal(err)
 | 
									t.Fatal(err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if cache.nodeTree.numNodes != 1 || nodesList[len(nodesList)-1] != node.Name {
 | 
								if cache.nodeTree.numNodes != len(tc.nodes) || len(nodesList) != len(tc.nodes) {
 | 
				
			||||||
				t.Errorf("unexpected cache.nodeTree after updating node: %v", node.Name)
 | 
									t.Errorf("unexpected cache.nodeTree after updating node")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Step 4: the node can be removed even if it still has pods.
 | 
								// Step 4: the node can be removed even if it still has pods.
 | 
				
			||||||
@@ -1278,9 +1319,13 @@ func TestNodeOperators(t *testing.T) {
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Fatal(err)
 | 
									t.Fatal(err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if cache.nodeTree.numNodes != 0 || len(nodesList) != 0 {
 | 
								if cache.nodeTree.numNodes != len(tc.nodes)-1 || len(nodesList) != len(tc.nodes)-1 {
 | 
				
			||||||
				t.Errorf("unexpected cache.nodeTree after removing node: %v", node.Name)
 | 
									t.Errorf("unexpected cache.nodeTree after removing node: %v", node.Name)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								// check imageState of NodeInfo with specific image when delete node
 | 
				
			||||||
 | 
								if !checkImageStateSummary(nodes, "gcr.io/80:latest", "gcr.io/300:latest") {
 | 
				
			||||||
 | 
									t.Error("image have different ImageStateSummary after removing node")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			// Pods are still in the pods cache.
 | 
								// Pods are still in the pods cache.
 | 
				
			||||||
			for _, p := range tc.pods {
 | 
								for _, p := range tc.pods {
 | 
				
			||||||
				if _, err := cache.GetPod(p); err != nil {
 | 
									if _, err := cache.GetPod(p); err != nil {
 | 
				
			||||||
@@ -1976,6 +2021,28 @@ func makeBasePod(t testingMode, nodeName, objName, cpu, mem, extended string, po
 | 
				
			|||||||
	return podWrapper.Obj()
 | 
						return podWrapper.Obj()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// checkImageStateSummary collect ImageStateSummary of image traverse nodes,
 | 
				
			||||||
 | 
					// the collected ImageStateSummary should be equal
 | 
				
			||||||
 | 
					func checkImageStateSummary(nodes map[string]*framework.NodeInfo, imageNames ...string) bool {
 | 
				
			||||||
 | 
						for _, imageName := range imageNames {
 | 
				
			||||||
 | 
							var imageState *framework.ImageStateSummary
 | 
				
			||||||
 | 
							for _, node := range nodes {
 | 
				
			||||||
 | 
								state, ok := node.ImageStates[imageName]
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if imageState == nil {
 | 
				
			||||||
 | 
									imageState = state
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if diff := cmp.Diff(imageState, state); diff != "" {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func setupCacheOf1kNodes30kPods(b *testing.B) Cache {
 | 
					func setupCacheOf1kNodes30kPods(b *testing.B) Cache {
 | 
				
			||||||
	logger, ctx := ktesting.NewTestContext(b)
 | 
						logger, ctx := ktesting.NewTestContext(b)
 | 
				
			||||||
	ctx, cancel := context.WithCancel(ctx)
 | 
						ctx, cancel := context.WithCancel(ctx)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								pkg/scheduler/internal/cache/snapshot.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								pkg/scheduler/internal/cache/snapshot.go
									
									
									
									
										vendored
									
									
								
							@@ -130,7 +130,7 @@ func getNodeImageStates(node *v1.Node, imageExistenceMap map[string]sets.Set[str
 | 
				
			|||||||
		for _, name := range image.Names {
 | 
							for _, name := range image.Names {
 | 
				
			||||||
			imageStates[name] = &framework.ImageStateSummary{
 | 
								imageStates[name] = &framework.ImageStateSummary{
 | 
				
			||||||
				Size:     image.SizeBytes,
 | 
									Size:     image.SizeBytes,
 | 
				
			||||||
				NumNodes: len(imageExistenceMap[name]),
 | 
									NumNodes: imageExistenceMap[name].Len(),
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,6 +53,7 @@ import (
 | 
				
			|||||||
	"k8s.io/kubernetes/pkg/scheduler/framework"
 | 
						"k8s.io/kubernetes/pkg/scheduler/framework"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
 | 
						"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature"
 | 
						"k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports"
 | 
						"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources"
 | 
						"k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread"
 | 
						"k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread"
 | 
				
			||||||
@@ -71,6 +72,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	testSchedulerName       = "test-scheduler"
 | 
						testSchedulerName       = "test-scheduler"
 | 
				
			||||||
 | 
						mb                int64 = 1024 * 1024
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
@@ -2676,6 +2678,59 @@ func TestZeroRequest(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_prioritizeNodes(t *testing.T) {
 | 
					func Test_prioritizeNodes(t *testing.T) {
 | 
				
			||||||
 | 
						imageStatus1 := []v1.ContainerImage{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Names: []string{
 | 
				
			||||||
 | 
									"gcr.io/40:latest",
 | 
				
			||||||
 | 
									"gcr.io/40:v1",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								SizeBytes: int64(80 * mb),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Names: []string{
 | 
				
			||||||
 | 
									"gcr.io/300:latest",
 | 
				
			||||||
 | 
									"gcr.io/300:v1",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								SizeBytes: int64(300 * mb),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						imageStatus2 := []v1.ContainerImage{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Names: []string{
 | 
				
			||||||
 | 
									"gcr.io/300:latest",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								SizeBytes: int64(300 * mb),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Names: []string{
 | 
				
			||||||
 | 
									"gcr.io/40:latest",
 | 
				
			||||||
 | 
									"gcr.io/40:v1",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								SizeBytes: int64(80 * mb),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						imageStatus3 := []v1.ContainerImage{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Names: []string{
 | 
				
			||||||
 | 
									"gcr.io/600:latest",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								SizeBytes: int64(600 * mb),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Names: []string{
 | 
				
			||||||
 | 
									"gcr.io/40:latest",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								SizeBytes: int64(80 * mb),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Names: []string{
 | 
				
			||||||
 | 
									"gcr.io/900:latest",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								SizeBytes: int64(900 * mb),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name                string
 | 
							name                string
 | 
				
			||||||
		pod                 *v1.Pod
 | 
							pod                 *v1.Pod
 | 
				
			||||||
@@ -2862,6 +2917,115 @@ func Test_prioritizeNodes(t *testing.T) {
 | 
				
			|||||||
				{Name: "node2", Scores: []framework.PluginScore{}},
 | 
									{Name: "node2", Scores: []framework.PluginScore{}},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "the score from Image Locality plugin with image in all nodes",
 | 
				
			||||||
 | 
								pod: &v1.Pod{
 | 
				
			||||||
 | 
									Spec: v1.PodSpec{
 | 
				
			||||||
 | 
										Containers: []v1.Container{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Image: "gcr.io/40",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nodes: []*v1.Node{
 | 
				
			||||||
 | 
									makeNode("node1", 1000, schedutil.DefaultMemoryRequest*10, imageStatus1...),
 | 
				
			||||||
 | 
									makeNode("node2", 1000, schedutil.DefaultMemoryRequest*10, imageStatus2...),
 | 
				
			||||||
 | 
									makeNode("node3", 1000, schedutil.DefaultMemoryRequest*10, imageStatus3...),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								pluginRegistrations: []tf.RegisterPluginFunc{
 | 
				
			||||||
 | 
									tf.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
 | 
				
			||||||
 | 
									tf.RegisterScorePlugin(imagelocality.Name, imagelocality.New, 1),
 | 
				
			||||||
 | 
									tf.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								extenders: nil,
 | 
				
			||||||
 | 
								want: []framework.NodePluginScores{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Name: "node1",
 | 
				
			||||||
 | 
										Scores: []framework.PluginScore{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:  "ImageLocality",
 | 
				
			||||||
 | 
												Score: 5,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										TotalScore: 5,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Name: "node2",
 | 
				
			||||||
 | 
										Scores: []framework.PluginScore{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:  "ImageLocality",
 | 
				
			||||||
 | 
												Score: 5,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										TotalScore: 5,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Name: "node3",
 | 
				
			||||||
 | 
										Scores: []framework.PluginScore{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:  "ImageLocality",
 | 
				
			||||||
 | 
												Score: 5,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										TotalScore: 5,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "the score from Image Locality plugin with image in partial nodes",
 | 
				
			||||||
 | 
								pod: &v1.Pod{
 | 
				
			||||||
 | 
									Spec: v1.PodSpec{
 | 
				
			||||||
 | 
										Containers: []v1.Container{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Image: "gcr.io/300",
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								nodes: []*v1.Node{makeNode("node1", 1000, schedutil.DefaultMemoryRequest*10, imageStatus1...),
 | 
				
			||||||
 | 
									makeNode("node2", 1000, schedutil.DefaultMemoryRequest*10, imageStatus2...),
 | 
				
			||||||
 | 
									makeNode("node3", 1000, schedutil.DefaultMemoryRequest*10, imageStatus3...),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								pluginRegistrations: []tf.RegisterPluginFunc{
 | 
				
			||||||
 | 
									tf.RegisterQueueSortPlugin(queuesort.Name, queuesort.New),
 | 
				
			||||||
 | 
									tf.RegisterScorePlugin(imagelocality.Name, imagelocality.New, 1),
 | 
				
			||||||
 | 
									tf.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								extenders: nil,
 | 
				
			||||||
 | 
								want: []framework.NodePluginScores{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Name: "node1",
 | 
				
			||||||
 | 
										Scores: []framework.PluginScore{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:  "ImageLocality",
 | 
				
			||||||
 | 
												Score: 18,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										TotalScore: 18,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Name: "node2",
 | 
				
			||||||
 | 
										Scores: []framework.PluginScore{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:  "ImageLocality",
 | 
				
			||||||
 | 
												Score: 18,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										TotalScore: 18,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Name: "node3",
 | 
				
			||||||
 | 
										Scores: []framework.PluginScore{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:  "ImageLocality",
 | 
				
			||||||
 | 
												Score: 0,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										TotalScore: 0,
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, test := range tests {
 | 
						for _, test := range tests {
 | 
				
			||||||
@@ -2869,9 +3033,16 @@ func Test_prioritizeNodes(t *testing.T) {
 | 
				
			|||||||
			client := clientsetfake.NewSimpleClientset()
 | 
								client := clientsetfake.NewSimpleClientset()
 | 
				
			||||||
			informerFactory := informers.NewSharedInformerFactory(client, 0)
 | 
								informerFactory := informers.NewSharedInformerFactory(client, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			snapshot := internalcache.NewSnapshot(test.pods, test.nodes)
 | 
					 | 
				
			||||||
			ctx, cancel := context.WithCancel(context.Background())
 | 
								ctx, cancel := context.WithCancel(context.Background())
 | 
				
			||||||
			defer cancel()
 | 
								defer cancel()
 | 
				
			||||||
 | 
								cache := internalcache.New(ctx, time.Duration(0))
 | 
				
			||||||
 | 
								for _, node := range test.nodes {
 | 
				
			||||||
 | 
									cache.AddNode(klog.FromContext(ctx), node)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								snapshot := internalcache.NewEmptySnapshot()
 | 
				
			||||||
 | 
								if err := cache.UpdateSnapshot(klog.FromContext(ctx), snapshot); err != nil {
 | 
				
			||||||
 | 
									t.Fatal(err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			fwk, err := tf.NewFramework(
 | 
								fwk, err := tf.NewFramework(
 | 
				
			||||||
				ctx,
 | 
									ctx,
 | 
				
			||||||
				test.pluginRegistrations, "",
 | 
									test.pluginRegistrations, "",
 | 
				
			||||||
@@ -3151,7 +3322,7 @@ func makeScheduler(ctx context.Context, nodes []*v1.Node) *Scheduler {
 | 
				
			|||||||
	return sched
 | 
						return sched
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func makeNode(node string, milliCPU, memory int64) *v1.Node {
 | 
					func makeNode(node string, milliCPU, memory int64, images ...v1.ContainerImage) *v1.Node {
 | 
				
			||||||
	return &v1.Node{
 | 
						return &v1.Node{
 | 
				
			||||||
		ObjectMeta: metav1.ObjectMeta{Name: node},
 | 
							ObjectMeta: metav1.ObjectMeta{Name: node},
 | 
				
			||||||
		Status: v1.NodeStatus{
 | 
							Status: v1.NodeStatus{
 | 
				
			||||||
@@ -3166,6 +3337,7 @@ func makeNode(node string, milliCPU, memory int64) *v1.Node {
 | 
				
			|||||||
				v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
 | 
									v1.ResourceMemory: *resource.NewQuantity(memory, resource.BinarySI),
 | 
				
			||||||
				"pods":            *resource.NewQuantity(100, resource.DecimalSI),
 | 
									"pods":            *resource.NewQuantity(100, resource.DecimalSI),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
								Images: images,
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -232,7 +232,7 @@ func (f *FakeExtender) selectVictimsOnNodeByExtender(pod *v1.Pod, node *v1.Node)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Otherwise, as a extender support preemption and have cached node info, we will assume cachedNodeNameToInfo is available
 | 
						// Otherwise, as a extender support preemption and have cached node info, we will assume cachedNodeNameToInfo is available
 | 
				
			||||||
	// and get cached node info by given node name.
 | 
						// and get cached node info by given node name.
 | 
				
			||||||
	nodeInfoCopy := f.CachedNodeNameToInfo[node.GetName()].Clone()
 | 
						nodeInfoCopy := f.CachedNodeNameToInfo[node.GetName()].Snapshot()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var potentialVictims []*v1.Pod
 | 
						var potentialVictims []*v1.Pod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user