mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-18 04:54:54 +00:00
Account for node allocatable claims in PodRequests
This commit updates the PodRequests and AggregateContainerRequests functions to include resources from node allocatable claims when calculating the total resource requests for a pod.
This commit is contained in:
@@ -60,6 +60,8 @@ type PodResourcesOptions struct {
|
||||
SkipPodLevelResources bool
|
||||
// SkipContainerLevelResources
|
||||
SkipContainerLevelResources bool
|
||||
// Use node allocatable resource claim information from pod status to compute the effective pod resource request.
|
||||
UseDRANodeAllocatableResourceClaimStatus bool
|
||||
}
|
||||
|
||||
var supportedPodLevelResources = sets.New(v1.ResourceCPU, v1.ResourceMemory)
|
||||
@@ -275,6 +277,16 @@ func AggregateContainerRequests(pod *v1.Pod, opts PodResourcesOptions) v1.Resour
|
||||
}
|
||||
|
||||
maxResourceList(reqs, initContainerReqs)
|
||||
|
||||
// Add resources from node allocatable ResourceClaims
|
||||
if opts.UseDRANodeAllocatableResourceClaimStatus && len(pod.Status.NodeAllocatableResourceClaimStatuses) > 0 {
|
||||
for _, claimStatus := range pod.Status.NodeAllocatableResourceClaimStatuses {
|
||||
for resName, resQty := range claimStatus.Resources {
|
||||
addResourceList(reqs, v1.ResourceList{resName: resQty})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reqs
|
||||
}
|
||||
|
||||
|
||||
@@ -2017,6 +2017,398 @@ func TestIsSupportedPodLevelResource(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var hugePageResource1Gi = v1.ResourceName(v1.ResourceHugePagesPrefix + "1Gi")
|
||||
|
||||
func TestPodResourceRequestsWithDRANodeAllocatableClaims(t *testing.T) {
|
||||
testCases := []struct {
|
||||
description string
|
||||
pod *v1.Pod
|
||||
options PodResourcesOptions
|
||||
expectedRequests v1.ResourceList
|
||||
}{
|
||||
{
|
||||
description: "No claims",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("100m"),
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: PodResourcesOptions{UseDRANodeAllocatableResourceClaimStatus: true},
|
||||
expectedRequests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("100m"),
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Single claim on one container",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("100m"),
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
hugePageResource1Gi: resource.MustParse("2"),
|
||||
},
|
||||
Claims: []v1.ResourceClaim{
|
||||
{Name: "claim-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ResourceClaims: []v1.PodResourceClaim{
|
||||
{
|
||||
Name: "claim-1",
|
||||
ResourceClaimName: ptr.To("node-allocatable-claim-1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
NodeAllocatableResourceClaimStatuses: []v1.NodeAllocatableResourceClaimStatus{
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim-1",
|
||||
Containers: []string{"c1"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("50m"),
|
||||
hugePageResource1Gi: resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: PodResourcesOptions{UseDRANodeAllocatableResourceClaimStatus: true},
|
||||
expectedRequests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("150m"), // 100m + 50m
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
hugePageResource1Gi: resource.MustParse("3"), // 2 + 1
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Multiple claims on one container",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("100m"),
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
Claims: []v1.ResourceClaim{
|
||||
{Name: "claim-1"},
|
||||
{Name: "claim-2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ResourceClaims: []v1.PodResourceClaim{
|
||||
{
|
||||
Name: "claim-1",
|
||||
ResourceClaimName: ptr.To("node-allocatable-claim-1"),
|
||||
},
|
||||
{
|
||||
Name: "claim-2",
|
||||
ResourceClaimName: ptr.To("node-allocatable-claim-2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
NodeAllocatableResourceClaimStatuses: []v1.NodeAllocatableResourceClaimStatus{
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim-1",
|
||||
Containers: []string{"c1"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("50m"),
|
||||
},
|
||||
},
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim-2",
|
||||
Containers: []string{"c1"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("25m"),
|
||||
v1.ResourceMemory: resource.MustParse("512Mi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: PodResourcesOptions{UseDRANodeAllocatableResourceClaimStatus: true},
|
||||
expectedRequests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("175m"), // 100m + 50m + 25m
|
||||
v1.ResourceMemory: resource.MustParse("1.5Gi"), // 1Gi + 512Mi
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Same claim referenced in multiple containers",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{v1.ResourceCPU: resource.MustParse("100m")},
|
||||
Claims: []v1.ResourceClaim{
|
||||
{Name: "claim-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "c2",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{v1.ResourceCPU: resource.MustParse("200m")},
|
||||
Claims: []v1.ResourceClaim{
|
||||
{Name: "claim-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ResourceClaims: []v1.PodResourceClaim{
|
||||
{
|
||||
Name: "claim-1",
|
||||
ResourceClaimName: ptr.To("node-allocatable-claim-1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
NodeAllocatableResourceClaimStatuses: []v1.NodeAllocatableResourceClaimStatus{
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim-1",
|
||||
Containers: []string{"c1", "c2"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("50m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: PodResourcesOptions{UseDRANodeAllocatableResourceClaimStatus: true},
|
||||
expectedRequests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("350m"), // 100m + 200m + 50m (claim counted once)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Different claims on multiple containers",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("100m"),
|
||||
hugePageResource1Gi: resource.MustParse("1"),
|
||||
},
|
||||
Claims: []v1.ResourceClaim{
|
||||
{Name: "claim-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "c2",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("200m"),
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
hugePageResource1Gi: resource.MustParse("2"),
|
||||
},
|
||||
Claims: []v1.ResourceClaim{
|
||||
{Name: "claim-2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ResourceClaims: []v1.PodResourceClaim{
|
||||
{
|
||||
Name: "claim-1",
|
||||
ResourceClaimName: ptr.To("node-allocatable-claim-1"),
|
||||
},
|
||||
{
|
||||
Name: "claim-2",
|
||||
ResourceClaimName: ptr.To("node-allocatable-claim-2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
NodeAllocatableResourceClaimStatuses: []v1.NodeAllocatableResourceClaimStatus{
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim-1",
|
||||
Containers: []string{"c1"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("50m"),
|
||||
hugePageResource1Gi: resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim-2",
|
||||
Containers: []string{"c2"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("25m"),
|
||||
v1.ResourceMemory: resource.MustParse("512Mi"),
|
||||
hugePageResource1Gi: resource.MustParse("2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: PodResourcesOptions{UseDRANodeAllocatableResourceClaimStatus: true},
|
||||
expectedRequests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("375m"), // 100m + 200m + 50m + 25m
|
||||
v1.ResourceMemory: resource.MustParse("1.5Gi"), // 1Gi + 1Gi + 1Gi + 512Mi
|
||||
hugePageResource1Gi: resource.MustParse("6"), // 1 + 2 + 1 + 2
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Claim on init container",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Name: "ic1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{v1.ResourceCPU: resource.MustParse("100m")},
|
||||
Claims: []v1.ResourceClaim{
|
||||
{Name: "claim-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{v1.ResourceCPU: resource.MustParse("50m")},
|
||||
},
|
||||
},
|
||||
},
|
||||
ResourceClaims: []v1.PodResourceClaim{
|
||||
{
|
||||
Name: "claim-1",
|
||||
ResourceClaimName: ptr.To("node-allocatable-claim"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
NodeAllocatableResourceClaimStatuses: []v1.NodeAllocatableResourceClaimStatus{
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim",
|
||||
Containers: []string{"ic1"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("25m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: PodResourcesOptions{UseDRANodeAllocatableResourceClaimStatus: true},
|
||||
expectedRequests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("125m"), // max(100m, 50m) + 25m
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "UseDRANodeAllocatableResourceClaimStatus flag disabled",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("100m"),
|
||||
},
|
||||
Claims: []v1.ResourceClaim{
|
||||
{Name: "claim-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ResourceClaims: []v1.PodResourceClaim{
|
||||
{
|
||||
Name: "claim-1",
|
||||
ResourceClaimName: ptr.To("node-allocatable-claim"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
NodeAllocatableResourceClaimStatuses: []v1.NodeAllocatableResourceClaimStatus{
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim",
|
||||
Containers: []string{"c1"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("50m"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: PodResourcesOptions{UseDRANodeAllocatableResourceClaimStatus: false},
|
||||
expectedRequests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("100m"),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Pod Level Resources overrides the claim request",
|
||||
pod: &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Resources: &v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("2"),
|
||||
},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("1"),
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
NodeAllocatableResourceClaimStatuses: []v1.NodeAllocatableResourceClaimStatus{
|
||||
{
|
||||
ResourceClaimName: "node-allocatable-claim",
|
||||
Containers: []string{"c1"},
|
||||
Resources: map[v1.ResourceName]resource.Quantity{
|
||||
v1.ResourceCPU: resource.MustParse("3"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
options: PodResourcesOptions{UseDRANodeAllocatableResourceClaimStatus: true, SkipPodLevelResources: false},
|
||||
expectedRequests: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("2"), // Pod level resource should not be overridden by claim request (3)
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"), // Container level resource should be included
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
request := PodRequests(tc.pod, tc.options)
|
||||
if diff := diff.Diff(tc.expectedRequests, request); diff != "" {
|
||||
t.Errorf("PodRequests() mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAggregateContainerRequestsAndLimits(t *testing.T) {
|
||||
restartAlways := v1.ContainerRestartPolicyAlways
|
||||
cases := []struct {
|
||||
|
||||
Reference in New Issue
Block a user