// GetRequiredPodsForNode returns a list od pods that would appear on the node if the // node was just created (like deamonset and manifest-run pods). It reuses kubectl // drain command to get the list. func GetRequiredPodsForNode(nodename string, client *kube_client.Client) ([]*kube_api.Pod, error) { podsToRemoveList, _, _, err := cmd.GetPodsForDeletionOnNodeDrain(client, nodename, kube_api.Codecs.UniversalDecoder(), true, true) if err != nil { return []*kube_api.Pod{}, err } podsToRemoveMap := make(map[string]struct{}) for _, pod := range podsToRemoveList { podsToRemoveMap[pod.SelfLink] = struct{}{} } allPodList, err := client.Pods(kube_api.NamespaceAll).List( kube_api.ListOptions{FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": nodename})}) if err != nil { return []*kube_api.Pod{}, err } podsOnNewNode := make([]*kube_api.Pod, 0) for i, pod := range allPodList.Items { if _, found := podsToRemoveMap[pod.SelfLink]; !found { podsOnNewNode = append(podsOnNewNode, &allPodList.Items[i]) } } return podsOnNewNode, nil }
// FindNodeToRemove finds a node that can be removed. func FindNodeToRemove(nodes []*kube_api.Node, pods []*kube_api.Pod, client *kube_client.Client) (*kube_api.Node, error) { nodeNameToNodeInfo := schedulercache.CreateNodeNameToInfoMap(pods) //TODO: Interate over underutulized nodes first. for _, node := range nodes { nodeInfo, found := nodeNameToNodeInfo[node.Name] if !found { glog.Errorf("Node info for %s not found", node.Name) continue } reservation, err := calculateReservation(node, nodeInfo) if err != nil { glog.Warningf("Failed to calculate reservation for %s: %v", node.Name, err) } glog.V(4).Infof("Node %s - reservation %f", node.Name, reservation) if reservation > unusedThreshold { glog.Infof("Node %s is not suitable for removal - reservation to big (%f)", node.Name, reservation) continue } // Let's try to remove this one. glog.V(2).Infof("Considering %s for removal", node.Name) podsToRemoveList, _, _, err := cmd.GetPodsForDeletionOnNodeDrain(client, node.Name, kube_api.Codecs.UniversalDecoder(), false, true) if err != nil { glog.V(1).Infof("Node %s cannot be removed: %v", node.Name, err) continue } tempNodeNameToNodeInfo := schedulercache.CreateNodeNameToInfoMap(pods) delete(tempNodeNameToNodeInfo, node.Name) for _, node := range nodes { if nodeInfo, found := tempNodeNameToNodeInfo[node.Name]; found { nodeInfo.SetNode(node) } } ptrPodsToRemove := make([]*kube_api.Pod, 0, len(podsToRemoveList)) for i := range podsToRemoveList { ptrPodsToRemove = append(ptrPodsToRemove, &podsToRemoveList[i]) } findProblems := findPlaceFor(ptrPodsToRemove, nodes, tempNodeNameToNodeInfo) if findProblems == nil { return node, nil } glog.Infof("Node %s is not suitable for removal %v", node.Name, err) } return nil, nil }
// FindNodesToRemove finds nodes that can be removed. func FindNodesToRemove(candidates []*kube_api.Node, allNodes []*kube_api.Node, pods []*kube_api.Pod, client *kube_client.Client, predicateChecker *PredicateChecker, maxCount int, fastCheck bool) ([]*kube_api.Node, error) { nodeNameToNodeInfo := schedulercache.CreateNodeNameToInfoMap(pods) for _, node := range allNodes { if nodeInfo, found := nodeNameToNodeInfo[node.Name]; found { nodeInfo.SetNode(node) } } result := make([]*kube_api.Node, 0) candidateloop: for _, node := range candidates { glog.V(2).Infof("Considering %s for removal", node.Name) var podsToRemove []*kube_api.Pod var err error if fastCheck { if nodeInfo, found := nodeNameToNodeInfo[node.Name]; found { podsToRemove, err = FastGetPodsToMove(nodeInfo, false, true, kube_api.Codecs.UniversalDecoder()) } } else { drainResult, _, _, err := cmd.GetPodsForDeletionOnNodeDrain(client, node.Name, kube_api.Codecs.UniversalDecoder(), false, true) if err != nil { glog.V(2).Infof("Node %s cannot be removed: %v", node.Name, err) continue } podsToRemove = make([]*kube_api.Pod, 0, len(drainResult)) for i := range drainResult { podsToRemove = append(podsToRemove, &drainResult[i]) } } findProblems := findPlaceFor(node.Name, podsToRemove, allNodes, nodeNameToNodeInfo, predicateChecker) if findProblems == nil { result = append(result, node) if len(result) >= maxCount { break candidateloop } } else { glog.V(2).Infof("Node %s is not suitable for removal %v", node.Name, err) } } return result, nil }
// FindNodesToRemove finds nodes that can be removed. Returns also an information about good // rescheduling location for each of the pods. func FindNodesToRemove(candidates []*kube_api.Node, allNodes []*kube_api.Node, pods []*kube_api.Pod, client *kube_client.Client, predicateChecker *PredicateChecker, maxCount int, fastCheck bool, oldHints map[string]string, usageTracker *UsageTracker, timestamp time.Time) (nodesToRemove []*kube_api.Node, podReschedulingHints map[string]string, finalError error) { nodeNameToNodeInfo := schedulercache.CreateNodeNameToInfoMap(pods) for _, node := range allNodes { if nodeInfo, found := nodeNameToNodeInfo[node.Name]; found { nodeInfo.SetNode(node) } } result := make([]*kube_api.Node, 0) evaluationType := "Detailed evaluation" if fastCheck { evaluationType = "Fast evaluation" } newHints := make(map[string]string, len(oldHints)) candidateloop: for _, node := range candidates { glog.V(2).Infof("%s: %s for removal", evaluationType, node.Name) var podsToRemove []*kube_api.Pod var err error if fastCheck { if nodeInfo, found := nodeNameToNodeInfo[node.Name]; found { podsToRemove, err = FastGetPodsToMove(nodeInfo, false, *skipNodesWithSystemPods, *skipNodesWithLocalStorage) if err != nil { glog.V(2).Infof("%s: node %s cannot be removed: %v", evaluationType, node.Name, err) continue candidateloop } } else { glog.V(2).Infof("%s: nodeInfo for %s not found", evaluationType, node.Name) continue candidateloop } } else { drainResult, _, _, err := cmd.GetPodsForDeletionOnNodeDrain(client, node.Name, kube_api.Codecs.UniversalDecoder(), false, true) if err != nil { glog.V(2).Infof("%s: node %s cannot be removed: %v", evaluationType, node.Name, err) continue candidateloop } podsToRemove = make([]*kube_api.Pod, 0, len(drainResult)) for i := range drainResult { podsToRemove = append(podsToRemove, &drainResult[i]) } } findProblems := findPlaceFor(node.Name, podsToRemove, allNodes, nodeNameToNodeInfo, predicateChecker, oldHints, newHints, usageTracker, timestamp) if findProblems == nil { result = append(result, node) glog.V(2).Infof("%s: node %s may be removed", evaluationType, node.Name) if len(result) >= maxCount { break candidateloop } } else { glog.V(2).Infof("%s: node %s is not suitable for removal %v", evaluationType, node.Name, err) } } return result, newHints, nil }