cluster-autoscaler/core/utils/utils.go (92 lines of code) (raw):

/* Copyright 2016 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package utils import ( "reflect" "time" apiv1 "k8s.io/api/core/v1" "k8s.io/autoscaler/cluster-autoscaler/cloudprovider" "k8s.io/autoscaler/cluster-autoscaler/clusterstate" "k8s.io/autoscaler/cluster-autoscaler/metrics" "k8s.io/autoscaler/cluster-autoscaler/utils/errors" "k8s.io/autoscaler/cluster-autoscaler/utils/gpu" ) // isVirtualNode determines if the node is created by virtual kubelet func isVirtualNode(node *apiv1.Node) bool { return node.ObjectMeta.Labels["type"] == "virtual-kubelet" } // FilterOutNodesFromNotAutoscaledGroups return subset of input nodes for which cloud provider does not // return autoscaled node group. func FilterOutNodesFromNotAutoscaledGroups(nodes []*apiv1.Node, cloudProvider cloudprovider.CloudProvider) ([]*apiv1.Node, errors.AutoscalerError) { result := make([]*apiv1.Node, 0) for _, node := range nodes { // Exclude the virtual node here since it may have lots of resource and exceed the total resource limit if isVirtualNode(node) { continue } nodeGroup, err := cloudProvider.NodeGroupForNode(node) if err != nil { return []*apiv1.Node{}, errors.ToAutoscalerError(errors.CloudProviderError, err) } if nodeGroup == nil || reflect.ValueOf(nodeGroup).IsNil() { result = append(result, node) } } return result, nil } func hasHardInterPodAffinity(affinity *apiv1.Affinity) bool { if affinity == nil { return false } if affinity.PodAffinity != nil { if len(affinity.PodAffinity.RequiredDuringSchedulingIgnoredDuringExecution) > 0 { return true } } if affinity.PodAntiAffinity != nil { if len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) > 0 { return true } } return false } // GetNodeCoresAndMemory extracts cpu and memory resources out of Node object func GetNodeCoresAndMemory(node *apiv1.Node) (int64, int64) { cores := getNodeResource(node, apiv1.ResourceCPU) memory := getNodeResource(node, apiv1.ResourceMemory) return cores, memory } func getNodeResource(node *apiv1.Node, resource apiv1.ResourceName) int64 { nodeCapacity, found := node.Status.Capacity[resource] if !found { return 0 } nodeCapacityValue := nodeCapacity.Value() if nodeCapacityValue < 0 { nodeCapacityValue = 0 } return nodeCapacityValue } // UpdateClusterStateMetrics updates metrics related to cluster state func UpdateClusterStateMetrics(csr *clusterstate.ClusterStateRegistry) { if csr == nil || reflect.ValueOf(csr).IsNil() { return } metrics.UpdateClusterSafeToAutoscale(csr.IsClusterHealthy()) readiness := csr.GetClusterReadiness() metrics.UpdateNodesCount(len(readiness.Ready), len(readiness.Unready), len(readiness.NotStarted), len(readiness.LongUnregistered), len(readiness.Unregistered)) } // GetOldestCreateTime returns oldest creation time out of the pods in the set func GetOldestCreateTime(pods []*apiv1.Pod) time.Time { oldest := time.Now() for _, pod := range pods { if oldest.After(pod.CreationTimestamp.Time) { oldest = pod.CreationTimestamp.Time } } return oldest } // GetOldestCreateTimeWithGpu returns oldest creation time out of pods with GPU in the set func GetOldestCreateTimeWithGpu(pods []*apiv1.Pod) (bool, time.Time) { oldest := time.Now() gpuFound := false for _, pod := range pods { if gpu.PodRequestsGpu(pod) { gpuFound = true if oldest.After(pod.CreationTimestamp.Time) { oldest = pod.CreationTimestamp.Time } } } return gpuFound, oldest }