mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
helpers: refactor and expose function for sum of container req/limits
Currently we only care about the sum of sandbox resources, which includes a pod overhead if defined. We have a need for also calculating *just* the sum of container requests/limits for CPU / Memory, so let's do a refactor and expose this new helper function. Signed-off-by: Eric Ernst <eric_ernst@apple.com>
This commit is contained in:
parent
91be6f7926
commit
ac88cd7691
@ -36,15 +36,17 @@ func PodRequestsAndLimits(pod *v1.Pod) (reqs, limits v1.ResourceList) {
|
|||||||
return PodRequestsAndLimitsReuse(pod, nil, nil)
|
return PodRequestsAndLimitsReuse(pod, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodRequestsAndLimitsReuse returns a dictionary of all defined resources summed up for all
|
// PodRequestsAndLimitsWithoutOverhead will create a dictionary of all defined resources summed up for all
|
||||||
// containers of the pod. If PodOverhead feature is enabled, pod overhead is added to the
|
// containers of the pod.
|
||||||
// total container resource requests and to the total container limits which have a
|
func PodRequestsAndLimitsWithoutOverhead(pod *v1.Pod) (reqs, limits v1.ResourceList) {
|
||||||
// non-zero quantity. The caller may avoid allocations of resource lists by passing
|
reqs = make(v1.ResourceList, 4)
|
||||||
// a requests and limits list to the function, which will be cleared before use.
|
limits = make(v1.ResourceList, 4)
|
||||||
func PodRequestsAndLimitsReuse(pod *v1.Pod, reuseReqs, reuseLimits v1.ResourceList) (reqs, limits v1.ResourceList) {
|
podRequestsAndLimitsWithoutOverhead(pod, reqs, limits)
|
||||||
// attempt to reuse the maps if passed, or allocate otherwise
|
|
||||||
reqs, limits = reuseOrClearResourceList(reuseReqs), reuseOrClearResourceList(reuseLimits)
|
|
||||||
|
|
||||||
|
return reqs, limits
|
||||||
|
}
|
||||||
|
|
||||||
|
func podRequestsAndLimitsWithoutOverhead(pod *v1.Pod, reqs, limits v1.ResourceList) {
|
||||||
for _, container := range pod.Spec.Containers {
|
for _, container := range pod.Spec.Containers {
|
||||||
addResourceList(reqs, container.Resources.Requests)
|
addResourceList(reqs, container.Resources.Requests)
|
||||||
addResourceList(limits, container.Resources.Limits)
|
addResourceList(limits, container.Resources.Limits)
|
||||||
@ -54,6 +56,18 @@ func PodRequestsAndLimitsReuse(pod *v1.Pod, reuseReqs, reuseLimits v1.ResourceLi
|
|||||||
maxResourceList(reqs, container.Resources.Requests)
|
maxResourceList(reqs, container.Resources.Requests)
|
||||||
maxResourceList(limits, container.Resources.Limits)
|
maxResourceList(limits, container.Resources.Limits)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodRequestsAndLimitsReuse returns a dictionary of all defined resources summed up for all
|
||||||
|
// containers of the pod. If PodOverhead feature is enabled, pod overhead is added to the
|
||||||
|
// total container resource requests and to the total container limits which have a
|
||||||
|
// non-zero quantity. The caller may avoid allocations of resource lists by passing
|
||||||
|
// a requests and limits list to the function, which will be cleared before use.
|
||||||
|
func PodRequestsAndLimitsReuse(pod *v1.Pod, reuseReqs, reuseLimits v1.ResourceList) (reqs, limits v1.ResourceList) {
|
||||||
|
// attempt to reuse the maps if passed, or allocate otherwise
|
||||||
|
reqs, limits = reuseOrClearResourceList(reuseReqs), reuseOrClearResourceList(reuseLimits)
|
||||||
|
|
||||||
|
podRequestsAndLimitsWithoutOverhead(pod, reqs, limits)
|
||||||
|
|
||||||
// if PodOverhead feature is supported, add overhead for running a pod
|
// if PodOverhead feature is supported, add overhead for running a pod
|
||||||
// to the sum of requests and to non-zero limits:
|
// to the sum of requests and to non-zero limits:
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/equality"
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
)
|
)
|
||||||
@ -337,6 +337,192 @@ func TestPodRequestsAndLimits(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPodRequestsAndLimitsWithoutOverhead(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
pod *v1.Pod
|
||||||
|
name string
|
||||||
|
expectedRequests v1.ResourceList
|
||||||
|
expectedLimits v1.ResourceList
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "two container no overhead - should just be sum of containers",
|
||||||
|
pod: &v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("1"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("5"),
|
||||||
|
},
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("2"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "foobar2",
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("4"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("12"),
|
||||||
|
},
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("8"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("24"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedRequests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("5"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("17"),
|
||||||
|
},
|
||||||
|
expectedLimits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("34"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two container with overhead - shouldn't consider overhead",
|
||||||
|
pod: &v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Overhead: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("3"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("8"),
|
||||||
|
},
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("1"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("5"),
|
||||||
|
},
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("2"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "foobar2",
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("4"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("12"),
|
||||||
|
},
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("8"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("24"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedRequests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("5"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("17"),
|
||||||
|
},
|
||||||
|
expectedLimits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("10"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("34"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "two container with overhead, massive init - should just be the largest init",
|
||||||
|
pod: &v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Overhead: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("3"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("8"),
|
||||||
|
},
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "foobar",
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("1"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("5"),
|
||||||
|
},
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("2"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("10"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "foobar2",
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("4"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("12"),
|
||||||
|
},
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("8"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("24"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
InitContainers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "small-init",
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("1"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("5"),
|
||||||
|
},
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("1"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("5"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "big-init",
|
||||||
|
Resources: v1.ResourceRequirements{
|
||||||
|
Requests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("40"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("120"),
|
||||||
|
},
|
||||||
|
Limits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("80"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("240"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedRequests: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("40"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("120"),
|
||||||
|
},
|
||||||
|
expectedLimits: v1.ResourceList{
|
||||||
|
v1.ResourceName(v1.ResourceCPU): resource.MustParse("80"),
|
||||||
|
v1.ResourceName(v1.ResourceMemory): resource.MustParse("240"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for idx, tc := range cases {
|
||||||
|
resRequests, resLimits := PodRequestsAndLimitsWithoutOverhead(tc.pod)
|
||||||
|
|
||||||
|
if !equality.Semantic.DeepEqual(tc.expectedRequests, resRequests) {
|
||||||
|
t.Errorf("test case failure[%d]: %v, requests:\n expected:\t%v\ngot\t\t%v", idx, tc.name, tc.expectedRequests, resRequests)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !equality.Semantic.DeepEqual(tc.expectedLimits, resLimits) {
|
||||||
|
t.Errorf("test case failure[%d]: %v, limits:\n expected:\t%v\ngot\t\t%v", idx, tc.name, tc.expectedLimits, resLimits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type podResources struct {
|
type podResources struct {
|
||||||
cpuRequest, cpuLimit, memoryRequest, memoryLimit, cpuOverhead, memoryOverhead string
|
cpuRequest, cpuLimit, memoryRequest, memoryLimit, cpuOverhead, memoryOverhead string
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user