From 9a565d149eaeec6f674a78a34732d8d84bf78c86 Mon Sep 17 00:00:00 2001 From: ndixita Date: Wed, 30 Oct 2024 01:24:36 +0000 Subject: [PATCH] QOS changes for Pod Level resources Kubernetes-commit: 26f11c458620751733250b35d1f60c9ed2a96e57 --- pkg/util/qos/qos.go | 105 ++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/pkg/util/qos/qos.go b/pkg/util/qos/qos.go index 68b1b9072..1b102a0fe 100644 --- a/pkg/util/qos/qos.go +++ b/pkg/util/qos/qos.go @@ -37,6 +37,45 @@ func GetPodQOS(pod *core.Pod) core.PodQOSClass { return ComputePodQOS(pod) } +// zeroQuantity represents a resource.Quantity with value "0", used as a baseline +// for resource comparisons. +var zeroQuantity = resource.MustParse("0") + +// processResourceList adds non-zero quantities for supported QoS compute resources +// quantities from newList to list. +func processResourceList(list, newList core.ResourceList) { + for name, quantity := range newList { + if !isSupportedQoSComputeResource(name) { + continue + } + if quantity.Cmp(zeroQuantity) == 1 { + delta := quantity.DeepCopy() + if _, exists := list[name]; !exists { + list[name] = delta + } else { + delta.Add(list[name]) + list[name] = delta + } + } + } +} + +// getQOSResources returns a set of resource names from the provided resource list that: +// 1. Are supported QoS compute resources +// 2. Have quantities greater than zero +func getQOSResources(list core.ResourceList) sets.Set[string] { + qosResources := sets.New[string]() + for name, quantity := range list { + if !isSupportedQoSComputeResource(name) { + continue + } + if quantity.Cmp(zeroQuantity) == 1 { + qosResources.Insert(string(name)) + } + } + return qosResources +} + // ComputePodQOS evaluates the list of containers to determine a pod's QoS class. This function is more // expensive than GetPodQOS which should be used for pods having a non-empty .Status.QOSClass. // A pod is besteffort if none of its containers have specified any requests or limits. @@ -45,50 +84,38 @@ func GetPodQOS(pod *core.Pod) core.PodQOSClass { func ComputePodQOS(pod *core.Pod) core.PodQOSClass { requests := core.ResourceList{} limits := core.ResourceList{} - zeroQuantity := resource.MustParse("0") isGuaranteed := true - // note, ephemeral containers are not considered for QoS as they cannot define resources - allContainers := []core.Container{} - allContainers = append(allContainers, pod.Spec.Containers...) - allContainers = append(allContainers, pod.Spec.InitContainers...) - for _, container := range allContainers { - // process requests - for name, quantity := range container.Resources.Requests { - if !isSupportedQoSComputeResource(name) { - continue - } - if quantity.Cmp(zeroQuantity) == 1 { - delta := quantity.DeepCopy() - if _, exists := requests[name]; !exists { - requests[name] = delta - } else { - delta.Add(requests[name]) - requests[name] = delta - } - } - } - // process limits - qosLimitsFound := sets.NewString() - for name, quantity := range container.Resources.Limits { - if !isSupportedQoSComputeResource(name) { - continue - } - if quantity.Cmp(zeroQuantity) == 1 { - qosLimitsFound.Insert(string(name)) - delta := quantity.DeepCopy() - if _, exists := limits[name]; !exists { - limits[name] = delta - } else { - delta.Add(limits[name]) - limits[name] = delta - } - } + if pod.Spec.Resources != nil { + if pod.Spec.Resources.Requests != nil { + // process requests + processResourceList(requests, pod.Spec.Resources.Requests) } - if !qosLimitsFound.HasAll(string(core.ResourceMemory), string(core.ResourceCPU)) { - isGuaranteed = false + if pod.Spec.Resources.Limits != nil { + // process limits + processResourceList(limits, pod.Spec.Resources.Limits) + qosLimitResources := getQOSResources(pod.Spec.Resources.Limits) + if !qosLimitResources.HasAll(string(core.ResourceMemory), string(core.ResourceCPU)) { + isGuaranteed = false + } + } + } else { + // note, ephemeral containers are not considered for QoS as they cannot define resources + allContainers := []core.Container{} + allContainers = append(allContainers, pod.Spec.Containers...) + allContainers = append(allContainers, pod.Spec.InitContainers...) + for _, container := range allContainers { + // process requests + processResourceList(requests, container.Resources.Requests) + // process limits + processResourceList(limits, container.Resources.Limits) + qosLimitResources := getQOSResources(container.Resources.Limits) + if !qosLimitResources.HasAll(string(core.ResourceMemory), string(core.ResourceCPU)) { + isGuaranteed = false + } } } + if len(requests) == 0 && len(limits) == 0 { return core.PodQOSBestEffort }