Merge pull request #265 from MaciekPytel/ignore_unneded_if_min_size
Skip nodes in min-sized groups in scale-down simulation
This commit is contained in:
		
						commit
						6ad7ca21e8
					
				|  | @ -144,7 +144,7 @@ func (sd *ScaleDown) CleanUpUnneededNodes() { | |||
| // managed by CA.
 | ||||
| func (sd *ScaleDown) UpdateUnneededNodes( | ||||
| 	nodes []*apiv1.Node, | ||||
| 	managedNodes []*apiv1.Node, | ||||
| 	nodesToCheck []*apiv1.Node, | ||||
| 	pods []*apiv1.Pod, | ||||
| 	timestamp time.Time, | ||||
| 	pdbs []*policyv1.PodDisruptionBudget) errors.AutoscalerError { | ||||
|  | @ -154,24 +154,24 @@ func (sd *ScaleDown) UpdateUnneededNodes( | |||
| 	utilizationMap := make(map[string]float64) | ||||
| 
 | ||||
| 	// Filter out nodes that were recently checked
 | ||||
| 	nodesToCheck := make([]*apiv1.Node, 0) | ||||
| 	for _, node := range managedNodes { | ||||
| 	filteredNodesToCheck := make([]*apiv1.Node, 0) | ||||
| 	for _, node := range nodesToCheck { | ||||
| 		if unremovableTimestamp, found := sd.unremovableNodes[node.Name]; found { | ||||
| 			if unremovableTimestamp.After(timestamp) { | ||||
| 				continue | ||||
| 			} | ||||
| 			delete(sd.unremovableNodes, node.Name) | ||||
| 		} | ||||
| 		nodesToCheck = append(nodesToCheck, node) | ||||
| 		filteredNodesToCheck = append(filteredNodesToCheck, node) | ||||
| 	} | ||||
| 	skipped := len(managedNodes) - len(nodesToCheck) | ||||
| 	skipped := len(nodesToCheck) - len(filteredNodesToCheck) | ||||
| 	if skipped > 0 { | ||||
| 		glog.V(1).Infof("Scale-down calculation: ignoring %v nodes, that were unremovable in the last %v", skipped, UnremovableNodeRecheckTimeout) | ||||
| 	} | ||||
| 
 | ||||
| 	// Phase1 - look at the nodes utilization. Calculate the utilization
 | ||||
| 	// only for the managed nodes.
 | ||||
| 	for _, node := range nodesToCheck { | ||||
| 	for _, node := range filteredNodesToCheck { | ||||
| 
 | ||||
| 		// Skip nodes marked to be deleted, if they were marked recently.
 | ||||
| 		// Old-time marked nodes are again eligible for deletion - something went wrong with them
 | ||||
|  |  | |||
|  | @ -266,9 +266,9 @@ func (a *StaticAutoscaler) RunOnce(currentTime time.Time) errors.AutoscalerError | |||
| 		glog.V(4).Infof("Calculating unneeded nodes") | ||||
| 
 | ||||
| 		scaleDown.CleanUp(time.Now()) | ||||
| 		managedNodes := getManagedNodes(autoscalingContext, allNodes) | ||||
| 		potentiallyUnneeded := getPotentiallyUnneededNodes(autoscalingContext, allNodes) | ||||
| 
 | ||||
| 		typedErr := scaleDown.UpdateUnneededNodes(allNodes, managedNodes, allScheduled, time.Now(), pdbs) | ||||
| 		typedErr := scaleDown.UpdateUnneededNodes(allNodes, potentiallyUnneeded, allScheduled, time.Now(), pdbs) | ||||
| 		if typedErr != nil { | ||||
| 			glog.Errorf("Failed to scale down: %v", typedErr) | ||||
| 			return typedErr | ||||
|  |  | |||
|  | @ -359,8 +359,10 @@ func fixNodeGroupSize(context *AutoscalingContext, currentTime time.Time) (bool, | |||
| 	return fixed, nil | ||||
| } | ||||
| 
 | ||||
| // getManagedNodes returns the nodes managed by the cluster autoscaler.
 | ||||
| func getManagedNodes(context *AutoscalingContext, nodes []*apiv1.Node) []*apiv1.Node { | ||||
| // getPotentiallyUnneededNodes returns nodes that are:
 | ||||
| // - managed by the cluster autoscaler
 | ||||
| // - in groups with size > min size
 | ||||
| func getPotentiallyUnneededNodes(context *AutoscalingContext, nodes []*apiv1.Node) []*apiv1.Node { | ||||
| 	result := make([]*apiv1.Node, 0, len(nodes)) | ||||
| 	for _, node := range nodes { | ||||
| 		nodeGroup, err := context.CloudProvider.NodeGroupForNode(node) | ||||
|  | @ -372,6 +374,15 @@ func getManagedNodes(context *AutoscalingContext, nodes []*apiv1.Node) []*apiv1. | |||
| 			glog.V(4).Infof("Skipping %s - no node group config", node.Name) | ||||
| 			continue | ||||
| 		} | ||||
| 		size, err := nodeGroup.TargetSize() | ||||
| 		if err != nil { | ||||
| 			glog.Errorf("Error while checking node group size %s: %v", nodeGroup.Id(), err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if size <= nodeGroup.MinSize() { | ||||
| 			glog.V(1).Infof("Skipping %s - node group min size reached", node.Name) | ||||
| 			continue | ||||
| 		} | ||||
| 		result = append(result, node) | ||||
| 	} | ||||
| 	return result | ||||
|  |  | |||
|  | @ -256,3 +256,26 @@ func TestRemoveFixNodeTargetSize(t *testing.T) { | |||
| 	change := getStringFromChan(sizeChanges) | ||||
| 	assert.Equal(t, "ng1/-2", change) | ||||
| } | ||||
| 
 | ||||
| func TestGetPotentiallyUnneededNodes(t *testing.T) { | ||||
| 	ng1_1 := BuildTestNode("ng1-1", 1000, 1000) | ||||
| 	ng1_2 := BuildTestNode("ng1-2", 1000, 1000) | ||||
| 	ng2_1 := BuildTestNode("ng2-1", 1000, 1000) | ||||
| 	noNg := BuildTestNode("no-ng", 1000, 1000) | ||||
| 	provider := testprovider.NewTestCloudProvider(nil, nil) | ||||
| 	provider.AddNodeGroup("ng1", 1, 10, 2) | ||||
| 	provider.AddNodeGroup("ng2", 1, 10, 1) | ||||
| 	provider.AddNode("ng1", ng1_1) | ||||
| 	provider.AddNode("ng1", ng1_2) | ||||
| 	provider.AddNode("ng2", ng2_1) | ||||
| 
 | ||||
| 	context := &AutoscalingContext{ | ||||
| 		CloudProvider: provider, | ||||
| 	} | ||||
| 
 | ||||
| 	result := getPotentiallyUnneededNodes(context, []*apiv1.Node{ng1_1, ng1_2, ng2_1, noNg}) | ||||
| 	assert.Equal(t, 2, len(result)) | ||||
| 	ok1 := result[0].Name == "ng1-1" && result[1].Name == "ng1-2" | ||||
| 	ok2 := result[1].Name == "ng1-1" && result[0].Name == "ng1-2" | ||||
| 	assert.True(t, ok1 || ok2) | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue