// PodsRequests returns sum of each resource request for each pod in list // If a given pod in the list does not have a request for the named resource, we log the error // but still attempt to get the most representative count func PodsRequests(pods []*api.Pod, resourceName api.ResourceName) *resource.Quantity { var sum *resource.Quantity for i := range pods { pod := pods[i] podQuantity, err := PodRequests(pod, resourceName) if err != nil { // log the error, but try to keep the most accurate count possible in log // rationale here is that you may have had pods in a namespace that did not have // explicit requests prior to adding the quota glog.Infof("No explicit request for resource, pod %s/%s, %s", pod.Namespace, pod.Name, resourceName) } else { if sum == nil { sum = podQuantity } else { sum.Add(*podQuantity) } } } // if list is empty if sum == nil { q := resource.MustParse("0") sum = &q } return sum }
// Calculates score for all pods and returns podInfo structure. // Score is defined as cpu_sum/node_capacity + mem_sum/node_capacity. // Pods that have bigger requirements should be processed first, thus have higher scores. func calculatePodScore(pods []*apiv1.Pod, nodeTemplate *schedulercache.NodeInfo) []*podInfo { podInfos := make([]*podInfo, 0, len(pods)) for _, pod := range pods { cpuSum := resource.Quantity{} memorySum := resource.Quantity{} for _, container := range pod.Spec.Containers { if request, ok := container.Resources.Requests[apiv1.ResourceCPU]; ok { cpuSum.Add(request) } if request, ok := container.Resources.Requests[apiv1.ResourceMemory]; ok { memorySum.Add(request) } } score := float64(0) if cpuAllocatable, ok := nodeTemplate.Node().Status.Allocatable[apiv1.ResourceCPU]; ok && cpuAllocatable.MilliValue() > 0 { score += float64(cpuSum.MilliValue()) / float64(cpuAllocatable.MilliValue()) } if memAllocatable, ok := nodeTemplate.Node().Status.Allocatable[apiv1.ResourceMemory]; ok && memAllocatable.Value() > 0 { score += float64(memorySum.Value()) / float64(memAllocatable.Value()) } podInfos = append(podInfos, &podInfo{ score: score, pod: pod, }) } return podInfos }
func getScheduableCores(nodes []v1.Node) int64 { var sc resource.Quantity for _, node := range nodes { if !node.Spec.Unschedulable { sc.Add(node.Status.Capacity[v1.ResourceCPU]) } } scInt64, scOk := sc.AsInt64() if !scOk { framework.Logf("Unable to compute integer values of schedulable cores in the cluster") return 0 } return scInt64 }
// podMemoryUsage aggregates pod memory usage. func podMemoryUsage(podStats statsapi.PodStats) (api.ResourceList, error) { disk := resource.Quantity{Format: resource.BinarySI} memory := resource.Quantity{Format: resource.BinarySI} for _, container := range podStats.Containers { // disk usage (if known) for _, fsStats := range []*statsapi.FsStats{container.Rootfs, container.Logs} { disk.Add(*diskUsage(fsStats)) } // memory usage (if known) memory.Add(*memoryUsage(container.Memory)) } return api.ResourceList{ api.ResourceMemory: memory, resourceDisk: disk, }, nil }
// podUsage aggregates usage of compute resources. // it supports the following memory and disk. func podUsage(podStats statsapi.PodStats) (api.ResourceList, error) { disk := resource.Quantity{Format: resource.BinarySI} memory := resource.Quantity{Format: resource.BinarySI} for _, container := range podStats.Containers { // disk usage (if known) // TODO: need to handle volumes for _, fsStats := range []*statsapi.FsStats{container.Rootfs, container.Logs} { if err := disk.Add(*diskUsage(fsStats)); err != nil { return nil, err } } // memory usage (if known) if err := memory.Add(*memoryUsage(container.Memory)); err != nil { return nil, err } } return api.ResourceList{ api.ResourceMemory: memory, resourceDisk: disk, }, nil }
// podDiskUsage aggregates pod disk usage for the specified stats to measure. func podDiskUsage(podStats statsapi.PodStats, pod *api.Pod, statsToMeasure []fsStatsType) (api.ResourceList, error) { disk := resource.Quantity{Format: resource.BinarySI} for _, container := range podStats.Containers { if hasFsStatsType(statsToMeasure, fsStatsRoot) { disk.Add(*diskUsage(container.Rootfs)) } if hasFsStatsType(statsToMeasure, fsStatsLogs) { disk.Add(*diskUsage(container.Logs)) } } if hasFsStatsType(statsToMeasure, fsStatsLocalVolumeSource) { volumeNames := localVolumeNames(pod) for _, volumeName := range volumeNames { for _, volumeStats := range podStats.VolumeStats { if volumeStats.Name == volumeName { disk.Add(*diskUsage(&volumeStats.FsStats)) break } } } } return api.ResourceList{ resourceDisk: disk, }, nil }
// PodRequests returns sum of each resource request across all containers in pod func PodRequests(pod *api.Pod, resourceName api.ResourceName) (*resource.Quantity, error) { if !PodHasRequests(pod, resourceName) { return nil, fmt.Errorf("Each container in pod %s/%s does not have an explicit request for resource %s.", pod.Namespace, pod.Name, resourceName) } var sum *resource.Quantity for j := range pod.Spec.Containers { value, _ := pod.Spec.Containers[j].Resources.Requests[resourceName] if sum == nil { sum = value.Copy() } else { err := sum.Add(value) if err != nil { return sum, err } } } // if list is empty if sum == nil { q := resource.MustParse("0") sum = &q } return sum, nil }