/
githubmirror
/
kubernetes
Обзор
Документация
Войти
/
githubmirror
/
kubernetes
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/e2e/common/node/dra_node_allocatable_resources.go
1 052 строки
44 KB
Praveen Krishna
test(e2e): verify container cgroups and status after pod and container spec resize with DRA claims
23 июл 2026, 06:35
23 июл 2026, 06:35
9a1babe
Код
Авторство
О чём код?
/* Copyright 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 node import ( "context" "encoding/json" "fmt" "slices" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" resourceapi "k8s.io/api/resource/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" admissionapi "k8s.io/pod-security-admission/api" "k8s.io/dynamic-resource-allocation/resourceslice" v1qos "k8s.io/kubernetes/pkg/apis/core/v1/helper/qos" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/test/e2e/common/node/framework/cgroups" "k8s.io/kubernetes/test/e2e/common/node/framework/podresize" drautils "k8s.io/kubernetes/test/e2e/dra/utils" "k8s.io/kubernetes/test/e2e/feature" "k8s.io/kubernetes/test/e2e/framework" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" "k8s.io/kubernetes/test/utils/client-go/ktesting" ) type draContainerInfo struct { Name string Resources *cgroups.ContainerResources Claims []*resourceapi.ResourceClaim HugepageReqLim string } var ( overheadMem = resource.MustParse("100Mi") overheadCPU = resource.MustParse("100m") overheadDevices = []resourceapi.Device{ { Name: "device-01", NodeAllocatableResources: map[v1.ResourceName]resourceapi.NodeAllocatableResource{ v1.ResourceMemory: { Overhead: &resourceapi.NodeAllocatableOverhead{ PerPod: &overheadMem, PerContainer: &overheadMem, }, }, v1.ResourceCPU: { Overhead: &resourceapi.NodeAllocatableOverhead{ PerPod: &overheadCPU, PerContainer: &overheadCPU, }, }, }, }, } directDevices = []resourceapi.Device{ { Name: "device-01", NodeAllocatableResources: map[v1.ResourceName]resourceapi.NodeAllocatableResource{ v1.ResourceMemory: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("1000Mi")), }, }, v1.ResourceCPU: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("1")), }, }, }, }, } directDevices2 = []resourceapi.Device{ { Name: "device-01", NodeAllocatableResources: map[v1.ResourceName]resourceapi.NodeAllocatableResource{ v1.ResourceMemory: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("1000Mi")), }, }, v1.ResourceCPU: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("100m")), }, }, }, }, { Name: "device-02", NodeAllocatableResources: map[v1.ResourceName]resourceapi.NodeAllocatableResource{ v1.ResourceMemory: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("2000Mi")), }, }, v1.ResourceCPU: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("100m")), }, }, }, }, } combinedDevices = []resourceapi.Device{ { Name: "device-direct-01", NodeAllocatableResources: map[v1.ResourceName]resourceapi.NodeAllocatableResource{ v1.ResourceMemory: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("1000Mi")), }, }, v1.ResourceCPU: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("1")), }, }, }, }, { Name: "device-overhead-01", NodeAllocatableResources: map[v1.ResourceName]resourceapi.NodeAllocatableResource{ v1.ResourceMemory: { Overhead: &resourceapi.NodeAllocatableOverhead{ PerPod: &overheadMem, PerContainer: &overheadMem, }, }, v1.ResourceCPU: { Overhead: &resourceapi.NodeAllocatableOverhead{ PerPod: &overheadCPU, PerContainer: &overheadCPU, }, }, }, }, } mappingAndOverheadDevice = []resourceapi.Device{ { Name: "device-mapping-overhead-01", NodeAllocatableResources: map[v1.ResourceName]resourceapi.NodeAllocatableResource{ v1.ResourceMemory: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("1000Mi")), }, Overhead: &resourceapi.NodeAllocatableOverhead{ PerPod: &overheadMem, PerContainer: &overheadMem, }, }, v1.ResourceCPU: { Mapping: &resourceapi.NodeAllocatableMapping{ DeviceMultiplier: new(resource.MustParse("1")), }, Overhead: &resourceapi.NodeAllocatableOverhead{ PerPod: &overheadCPU, PerContainer: &overheadCPU, }, }, }, }, } hugepageDevices = []resourceapi.Device{ { Name: "device-hugepages-01", NodeAllocatableResources: map[v1.ResourceName]resourceapi.NodeAllocatableResource{ v1.ResourceName("hugepages-2Mi"): { Overhead: &resourceapi.NodeAllocatableOverhead{ PerPod: new(resource.MustParse("100Mi")), PerContainer: new(resource.MustParse("50Mi")), }, }, }, }, } res100mCPU1GiCg = &cgroups.ContainerResources{CPUReq: "100m", CPULim: "200m", MemReq: "1Gi", MemLim: "2Gi"} res1CPU1GiCg = &cgroups.ContainerResources{CPUReq: "1", CPULim: "2", MemReq: "1Gi", MemLim: "2Gi"} res2CPU2GiCg = &cgroups.ContainerResources{CPUReq: "2", CPULim: "4", MemReq: "2Gi", MemLim: "4Gi"} res2500m2500MiCg = &cgroups.ContainerResources{CPUReq: "2500m", CPULim: "4", MemReq: "2500Mi", MemLim: "4Gi"} req1CPU1GiCg = &cgroups.ContainerResources{CPUReq: "1000m", MemReq: "1Gi"} res1CPU1GiGuaranteed = &cgroups.ContainerResources{CPUReq: "1", CPULim: "1", MemReq: "1Gi", MemLim: "1Gi"} claimCPUMem = &resourceapi.ResourceClaim{ ObjectMeta: metav1.ObjectMeta{ Name: "cpu-mem-claim", }, } claimCPUMem2 = &resourceapi.ResourceClaim{ ObjectMeta: metav1.ObjectMeta{ Name: "cpu-mem-claim-2", }, } claimHugepages = &resourceapi.ResourceClaim{ ObjectMeta: metav1.ObjectMeta{ Name: "hugepages-claim", }, } ) func doNodeAllocatableCgroupsTests(f *framework.Framework) { tests := []struct { name string resourceSliceDevices []resourceapi.Device podResources *cgroups.ContainerResources containers []draContainerInfo unreferencedClaims []*resourceapi.ResourceClaim expectedPodCgroup cgroups.ContainerResources expectedContainersCgroup []cgroups.ContainerResources // per container expectedContainersScoreMemRequest []int64 // per container requiresHugepages bool expectedPodHugepagesLimit string expectedContainerHugepagesLimits []string // per container }{ { name: "direct mappings", resourceSliceDevices: directDevices, containers: []draContainerInfo{ {Name: "c1", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 1000m (c1 from spec) + 1000m (c2 from spec) + 1000m (CPU claim) // CPU limit: 2000m (c1 from spec) + 2000m (c2 from spec) + 1000m (CPU claim) // Memory limit: 2048Mi (c1 from spec) + 2048Mi (c2 from spec) + 1000Mi (memory claim) CPUReq: "3000m", CPULim: "5000m", MemLim: "5096Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 1000m (CPU claim) // Memory limit: 2048Mi (from spec) + 1000Mi (memory claim) {CPUReq: "1000m", CPULim: "3000m", MemLim: "3048Mi"}, // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 1000m (CPU claim) // Memory limit: 2048Mi (from spec) + 1000Mi (memory claim) {CPUReq: "1000m", CPULim: "3000m", MemLim: "3048Mi"}, }, expectedContainersScoreMemRequest: []int64{1524, 1524}, // 1024 (c1) + 1000/2 (Direct memory) = 1524Mi }, { name: "overhead mappings", resourceSliceDevices: overheadDevices, containers: []draContainerInfo{ {Name: "c1", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 1000m (c1 from spec) + 1000m (c2 from spec) + 100m (CPU Claim - PerPod) + 200m (CPU Claim - PerContainer * 2) // CPU limit: 2000m (c1 from spec) + 2000m (c2 from spec) + 100m (CPU Claim - PerPod) + 200m (CPU Claim - PerContainer * 2) // Memory limit: 2048Mi (c1 from spec) + 2048Mi (c2 from spec) + 100Mi (Memory Claim - PerPod) + 200Mi (Memory Claim - PerContainer * 2) CPUReq: "2300m", CPULim: "4300m", MemLim: "4396Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 100m (CPU Claim - PerContainer) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (from spec) + 100Mi (Memory Claim - PerContainer) + 100Mi (Memory Claim - PerPod) // Note: PerPod overhead is counted fully in both the containers, but counted only once at the pod level limiting the overall limit. {CPUReq: "1000m", CPULim: "2200m", MemLim: "2248Mi"}, // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 100m (CPU Claim - PerContainer) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (from spec) + 100Mi (Memory Claim - PerContainer) + 100Mi (Memory Claim - PerPod) {CPUReq: "1000m", CPULim: "2200m", MemLim: "2248Mi"}, }, expectedContainersScoreMemRequest: []int64{1174, 1174}, // 1024 (c1) + 100 (PerContainer) + 100/2 (PerPod) = 1174Mi }, { name: "combined direct and overhead mappings", resourceSliceDevices: combinedDevices, containers: []draContainerInfo{ {Name: "c1", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem, claimCPUMem2}}, {Name: "c2", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem, claimCPUMem2}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 1000m (c1 from spec) + 1000m (c2 from spec) + 1000m (Direct CPU) + 100m (CPU Claim - PerPod) + 200m (CPU Claim - PerContainer * 2) // CPU limit: 2000m (c1 from spec) + 2000m (c2 from spec) + 1000m (Direct CPU) + 100m (CPU Claim - PerPod) + 200m (CPU Claim - PerContainer * 2) // Memory limit: 2048Mi (c1 from spec) + 2048Mi (c2 from spec) + 1000Mi (Direct Mem) + 100Mi (Memory Claim - PerPod) + 200Mi (Memory Claim - PerContainer * 2) CPUReq: "3300m", CPULim: "5300m", MemLim: "5396Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 1000m (Direct CPU) + 100m (CPU Claim - PerContainer) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (from spec) + 1000Mi (Direct Mem) + 100Mi (Memory Claim - PerContainer) + 100Mi (Memory Claim - PerPod) {CPUReq: "1000m", CPULim: "3200m", MemLim: "3248Mi"}, // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 1000m (Direct CPU) + 100m (CPU Claim - PerContainer) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (from spec) + 1000Mi (Direct Mem) + 100Mi (Memory Claim - PerContainer) + 100Mi (Memory Claim - PerPod) {CPUReq: "1000m", CPULim: "3200m", MemLim: "3248Mi"}, }, expectedContainersScoreMemRequest: []int64{1674, 1674}, // 1024 (c1) + 1000/2 (Direct Mem) + 100 (PerContainer) + 100/2 (PerPod) = 1674Mi }, { name: "single device with both mapping and overhead", resourceSliceDevices: mappingAndOverheadDevice, containers: []draContainerInfo{ {Name: "c1", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 1000m (c1 from spec) + 1000m (c2 from spec) + 1000m (Direct CPU) + 100m (CPU Claim - PerPod) + 200m (CPU Claim - PerContainer * 2) // CPU limit: 2000m (c1 from spec) + 2000m (c2 from spec) + 1000m (Direct CPU) + 100m (CPU Claim - PerPod) + 200m (CPU Claim - PerContainer * 2) // Memory limit: 2048Mi (c1 from spec) + 2048Mi (c2 from spec) + 1000Mi (Direct Mem) + 100Mi (Memory Claim - PerPod) + 200Mi (Memory Claim - PerContainer * 2) CPUReq: "3300m", CPULim: "5300m", MemLim: "5396Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 1000m (Direct CPU) + 100m (CPU Claim - PerContainer) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (from spec) + 1000Mi (Direct Mem) + 100Mi (Memory Claim - PerContainer) + 100Mi (Memory Claim - PerPod) {CPUReq: "1000m", CPULim: "3200m", MemLim: "3248Mi"}, // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 1000m (Direct CPU) + 100m (CPU Claim - PerContainer) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (from spec) + 1000Mi (Direct Mem) + 100Mi (Memory Claim - PerContainer) + 100Mi (Memory Claim -PerPod) {CPUReq: "1000m", CPULim: "3200m", MemLim: "3248Mi"}, }, expectedContainersScoreMemRequest: []int64{1674, 1674}, // 1024 (c1) + 1000/2 (Direct Mem) + 100 (PerContainer) + 100/2 (PerPod) = 1674Mi }, { name: "unreferenced overhead claim", resourceSliceDevices: overheadDevices, unreferencedClaims: []*resourceapi.ResourceClaim{claimCPUMem}, containers: []draContainerInfo{ {Name: "c1", Resources: res1CPU1GiCg}, {Name: "c2", Resources: res1CPU1GiCg}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 1000m (c1 from spec) + 1000m (c2 from spec) + 100m (CPU Claim - PerPod) // CPU limit: 2000m (c1 from spec) + 2000m (c2 from spec) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (c1 from spec) + 2048Mi (c2 from spec) + 100Mi (Memory Claim - PerPod) CPUReq: "2100m", CPULim: "4100m", MemLim: "4196Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) // CPU limit: 2 (from spec - uninflated) // Memory limit: 2Gi (from spec - uninflated) {CPUReq: "1000m", CPULim: "2", MemLim: "2Gi"}, // CPU request: 1000m (from spec) // CPU limit: 2 (from spec - uninflated) // Memory limit: 2Gi (from spec - uninflated) {CPUReq: "1000m", CPULim: "2", MemLim: "2Gi"}, }, expectedContainersScoreMemRequest: []int64{1024, 1024}, // 1024 (c1) + 0 (DRA share) = 1024Mi }, { name: "pod-level resources specified, container-level limits omitted", resourceSliceDevices: directDevices, podResources: res2CPU2GiCg, containers: []draContainerInfo{ {Name: "c1", Resources: nil, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Resources: nil, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 2000m (from pod-level spec) // CPU limit: 4000m (from pod-level spec) // Memory limit: 4096Mi (from pod-level spec) CPUReq: "2000m", CPULim: "4000m", MemLim: "4096Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: empty // CPU limit: 4 (inherits pod-level limits directly) // Memory limit: 4Gi (inherits pod-level limits directly) {CPULim: "4", MemLim: "4Gi"}, // CPU request: empty // CPU limit: 4 (inherits pod-level limits directly) // Memory limit: 4Gi (inherits pod-level limits directly) {CPULim: "4", MemLim: "4Gi"}, }, expectedContainersScoreMemRequest: []int64{1024, 1024}, // pod level memory requests (2048Mi) / 2 = 1024Mi }, { name: "pod-level resources specified, container-level limits specified", resourceSliceDevices: overheadDevices, podResources: res2500m2500MiCg, containers: []draContainerInfo{ {Name: "c1", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 2500m (from pod-level spec) // CPU limit: 4000m (from pod-level spec) // Memory limit: 4096Mi (from pod-level spec) CPUReq: "2500m", CPULim: "4000m", MemLim: "4096Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 100m (CPU Claim - PerContainer) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (from spec) + 100Mi (Memory Claim - PerContainer) + 100Mi (Memory Claim - PerPod) {CPUReq: "1000m", CPULim: "2200m", MemLim: "2248Mi"}, // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) + 100m (CPU Claim - PerContainer) + 100m (CPU Claim - PerPod) // Memory limit: 2048Mi (from spec) + 100Mi (Memory Claim - PerContainer) + 100Mi (Memory Claim - PerPod) {CPUReq: "1000m", CPULim: "2200m", MemLim: "2248Mi"}, }, expectedContainersScoreMemRequest: []int64{1250, 1250}, // c_effective (1174) + remaining ((2500-2348)/2) = 1174 + 76 = 1250Mi }, { name: "hugepages overhead mapping", resourceSliceDevices: hugepageDevices, containers: []draContainerInfo{ {Name: "c1", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimHugepages}, HugepageReqLim: "2Mi"}, {Name: "c2", Resources: res1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimHugepages}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 1000m (c1 from spec) + 1000m (c2 from spec) // CPU limit: 2000m (c1 from spec) + 2000m (c2 from spec) // Memory limit: 2048Mi (c1 from spec) + 2048Mi (c2 from spec) CPUReq: "2000m", CPULim: "4000m", MemLim: "4096Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) // Memory limit: 2Gi (from spec) {CPUReq: "1000m", CPULim: "2000m", MemLim: "2Gi"}, // CPU request: 1000m (from spec) // CPU limit: 2000m (from spec) // Memory limit: 2Gi (from spec) {CPUReq: "1000m", CPULim: "2000m", MemLim: "2Gi"}, }, expectedContainersScoreMemRequest: []int64{1024, 1024}, requiresHugepages: true, expectedPodHugepagesLimit: "211812352", // Sum(limits) + PerPod (100Mi) + PerContainer*2 (100Mi) = 2Mi + 0 + 100Mi + 100Mi = 202Mi (211812352 bytes) expectedContainerHugepagesLimits: []string{ "159383552", // Container 1: c1_lim (2Mi) + PerContainer (50Mi) + PerPod (100Mi) = 152Mi (159383552 bytes) "157286400", // Container 2: c2_lim (0) + PerContainer (50Mi) + PerPod (100Mi) = 150Mi (157286400 bytes) }, }, { name: "container-level requests and limits omitted (BestEffort)", resourceSliceDevices: directDevices, containers: []draContainerInfo{ {Name: "c1", Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroup: cgroups.ContainerResources{ CPUReq: "", CPULim: "", MemLim: "", }, expectedContainersCgroup: []cgroups.ContainerResources{ {CPUReq: "", CPULim: "", MemLim: ""}, {CPUReq: "", CPULim: "", MemLim: ""}, }, expectedContainersScoreMemRequest: []int64{0, 0}, }, { name: "container-level CPU/Memory limits omitted (Burstable)", resourceSliceDevices: directDevices, containers: []draContainerInfo{ {Name: "c1", Resources: req1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Resources: req1CPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 1000m (c1 from spec) + 1000m (c2 from spec) + 1000m (DRA Direct CPU) CPUReq: "3000m", CPULim: "", MemLim: "", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) {CPUReq: "1000m", CPULim: "", MemLim: ""}, // CPU request: 1000m (from spec) {CPUReq: "1000m", CPULim: "", MemLim: ""}, }, expectedContainersScoreMemRequest: []int64{1524, 1524}, // 1024 (c1) + 1000/2 (Direct memory) = 1524Mi }, { name: "hugepages overhead mapping with container limits omitted", resourceSliceDevices: hugepageDevices, containers: []draContainerInfo{ {Name: "c1", Claims: []*resourceapi.ResourceClaim{claimHugepages}}, {Name: "c2", Claims: []*resourceapi.ResourceClaim{claimHugepages}}, }, expectedPodCgroup: cgroups.ContainerResources{ CPUReq: "", CPULim: "", MemLim: "", }, expectedContainersCgroup: []cgroups.ContainerResources{ {CPUReq: "", CPULim: "", MemLim: ""}, {CPUReq: "", CPULim: "", MemLim: ""}, }, expectedContainersScoreMemRequest: []int64{0, 0}, requiresHugepages: true, expectedPodHugepagesLimit: "209715200", // Sum(limits) + PerPod (100Mi) + PerContainer*2 (100Mi) = 0 + 100Mi + 100Mi = 200Mi (209715200 bytes) expectedContainerHugepagesLimits: []string{ "157286400", // Container 1: c1_lim (0) + claim - PerContainer (50Mi) + claim - PerPod (100Mi) = 150Mi "157286400", // Container 2: c2_lim (0) + claim - PerContainer (50Mi) + claim -PerPod (100Mi) = 150Mi }, }, { name: "Guaranteed QoS pod with direct mapping", resourceSliceDevices: directDevices, containers: []draContainerInfo{ {Name: "c1", Resources: res1CPU1GiGuaranteed, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Resources: res1CPU1GiGuaranteed, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 1000m (c1 from spec) + 1000m (c2 from spec) + 1000m (DRA Direct CPU) // CPU limit: 1000m (c1 from spec) + 1000m (c2 from spec) + 1000m (DRA Direct CPU) // Memory limit: 1024Mi (c1 from spec) + 1024Mi (c2 from spec) + 1000Mi (DRA Direct memory) CPUReq: "3000m", CPULim: "3000m", MemLim: "3048Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 1000m (from spec) // CPU limit: 1000m (from spec) + 1000m (DRA Direct CPU) // Memory limit: 1024Mi (from spec) + 1000Mi (DRA Direct memory) {CPUReq: "1000m", CPULim: "2000m", MemLim: "2024Mi"}, // CPU request: 1000m (from spec) // CPU limit: 1000m (from spec) + 1000m (DRA Direct CPU) // Memory limit: 1024Mi (from spec) + 1000Mi (DRA Direct memory) {CPUReq: "1000m", CPULim: "2000m", MemLim: "2024Mi"}, }, expectedContainersScoreMemRequest: []int64{0, 0}, }, { name: "direct mapping multiple claims", resourceSliceDevices: directDevices2, containers: []draContainerInfo{ {Name: "c1", Resources: res100mCPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, {Name: "c2", Resources: res100mCPU1GiCg, Claims: []*resourceapi.ResourceClaim{claimCPUMem2}}, }, expectedPodCgroup: cgroups.ContainerResources{ // CPU request: 100m (c1 from spec) + 100m (c2 from spec) + 100m (direct1) + 100m (direct2) // CPU limit: 200m (c1 from spec) + 200m (c2 from spec) + 100m (direct1) + 100m (direct2) // Memory limit: 2048Mi (c1 from spec) + 2048Mi (c2 from spec) + 1000Mi (direct1) + 2000Mi (direct2) CPUReq: "400m", CPULim: "600m", MemLim: "7096Mi", }, expectedContainersCgroup: []cgroups.ContainerResources{ // CPU request: 100m (from spec) // CPU limit: 200m (from spec) + 100m (direct1) // Memory limit: 2048Mi (from spec) + 1000Mi (direct1) {CPUReq: "100m", CPULim: "300m", MemLim: "3048Mi"}, // CPU request: 100m (from spec) // CPU limit: 200m (from spec) + 100m (direct2) // Memory limit: 2048Mi (from spec) + 2000Mi (direct2) {CPUReq: "100m", CPULim: "300m", MemLim: "4048Mi"}, }, expectedContainersScoreMemRequest: []int64{2024, 3024}, // c1: 1024 + 1000Mi = 2024Mi, c2: 1024 + 2000Mi = 3024Mi }, } for _, tc := range tests { ginkgo.It(fmt.Sprintf("verifies cgroup inflation and container OOM adjustment with %s", tc.name), func(ctx context.Context) { tCtx := f.TContext(ctx) nodes := drautils.NewNodesNow(tCtx, 1, 4) if tc.requiresHugepages { node, err := f.ClientSet.CoreV1().Nodes().Get(ctx, nodes.NodeNames[0], metav1.GetOptions{}) framework.ExpectNoError(err) if limit, exists := node.Status.Allocatable[v1.ResourceName("hugepages-2Mi")]; !exists || limit.IsZero() { ginkgo.Skip("Skipping hugepages test because Node does not support hugepages-2Mi") } } driver := drautils.NewDriverInstance(tCtx) b := drautils.NewBuilderNow(tCtx, driver) // Run driver with these custom devices driverResources := map[string]resourceslice.DriverResources{ nodes.NodeNames[0]: { Pools: map[string]resourceslice.Pool{ nodes.NodeNames[0]: { Slices: []resourceslice.Slice{{ Devices: tc.resourceSliceDevices, }}, }, }, }, } driver.Run(tCtx, framework.TestContext.KubeletRootDir, nodes, driverResources) // Create claims and classes createdClaims := createClaims(tCtx, b, tc.containers, tc.unreferencedClaims) pod := makeTestPod(tc.podResources, tc.containers, tc.unreferencedClaims, createdClaims) pod.Namespace = f.Namespace.Name podJSON, _ := json.Marshal(pod) tCtx.Logf("Pod JSON to create: %s", string(podJSON)) ginkgo.By("creating pod and waiting for it to be running") podClient := e2epod.NewPodClient(f) pod = podClient.CreateSync(ctx, pod) // Verify Pod-level cgroups on the node ginkgo.By("verifying pod cgroup limits on the node") err := cgroups.VerifyPodCgroups(ctx, f, pod, &tc.expectedPodCgroup) framework.ExpectNoError(err) ginkgo.By("verifying containers cgroup limits on the node") onCgroupV2 := cgroups.IsPodOnCgroupv2Node(f, pod.Name, pod.Spec.Containers[0].Name) for i, container := range pod.Spec.Containers { expectedContainer := &v1.Container{ Name: container.Name, Resources: *tc.expectedContainersCgroup[i].ResourceRequirements(), } if expectedContainer.Resources.Requests == nil { expectedContainer.Resources.Requests = container.Resources.Requests } err = cgroups.VerifyContainerCgroupValues(ctx, f, pod, expectedContainer, onCgroupV2) framework.ExpectNoError(err) } if tc.requiresHugepages { ginkgo.By("verifying pod hugepages limits on the node") err = cgroups.VerifyPodHugepagesLimit(ctx, f, pod, "2MB", tc.expectedPodHugepagesLimit, onCgroupV2) framework.ExpectNoError(err) ginkgo.By("verifying containers hugepages limits on the node") for i, container := range pod.Spec.Containers { err = cgroups.VerifyContainerHugepagesLimit(ctx, f, pod, container.Name, "2MB", tc.expectedContainerHugepagesLimits[i], onCgroupV2) framework.ExpectNoError(err) } } ginkgo.By("verifying containers oom_score_adj matches QoS rules with overhead") // Retrieve node capacity to check exact adjustment node, err := f.ClientSet.CoreV1().Nodes().Get(ctx, pod.Spec.NodeName, metav1.GetOptions{}) framework.ExpectNoError(err) nodeMemBytes := node.Status.Capacity.Memory().Value() qosClass := v1qos.GetPodQOS(pod) for i, container := range pod.Spec.Containers { var expectedScore int64 switch qosClass { case v1.PodQOSGuaranteed: expectedScore = -997 case v1.PodQOSBestEffort: expectedScore = 1000 case v1.PodQOSBurstable: expectedScore = computeExpectedOomScoreAdj(tc.expectedContainersScoreMemRequest[i], nodeMemBytes) } err = cgroups.VerifyOomScoreAdjValue(f, pod, container.Name, fmt.Sprintf("%d", expectedScore)) framework.ExpectNoError(err) } ginkgo.By("deleting pods") delErr := e2epod.DeletePodWithWait(ctx, f.ClientSet, pod) framework.ExpectNoError(delErr, "failed to delete pod %s", delErr) }) } } func doNodeAllocatableResizeTests(f *framework.Framework) { tests := []struct { name string resourceSliceDevices []resourceapi.Device podResources *cgroups.ContainerResources desiredPodResources *cgroups.ContainerResources containers []draContainerInfo desiredContainers []draContainerInfo unreferencedClaims []*resourceapi.ResourceClaim expectedPodCgroupAfterResize cgroups.ContainerResources expectedContainersCgroupAfterResize []cgroups.ContainerResources // per container expectedPodAllocatedResourcesAfterResize v1.ResourceList expectedContainersAllocatedResourcesAfterResize []v1.ResourceList }{ { name: "direct mappings with resize", resourceSliceDevices: directDevices, containers: []draContainerInfo{ {Name: "c1", Resources: &cgroups.ContainerResources{CPUReq: "500m", CPULim: "1000m", MemReq: "500Mi", MemLim: "1000Mi"}, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, desiredContainers: []draContainerInfo{ {Name: "c1", Resources: &cgroups.ContainerResources{CPUReq: "500m", CPULim: "1500m", MemReq: "1000Mi", MemLim: "2000Mi"}, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, // CPU request: 500m (from resized spec) + 1000m (DRA Direct CPU) // CPU limit: 1500m (from resized spec) + 1000m (DRA Direct CPU) // Memory limit: 2000Mi (from resized spec) + 1000Mi (DRA Direct memory) expectedPodCgroupAfterResize: cgroups.ContainerResources{CPUReq: "1500m", CPULim: "2500m", MemLim: "3000Mi"}, expectedContainersCgroupAfterResize: []cgroups.ContainerResources{ {CPUReq: "500m", CPULim: "2500m", MemLim: "3000Mi"}, }, // Pod level allocated resources includes DRA resources expectedPodAllocatedResourcesAfterResize: v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1500m"), v1.ResourceMemory: resource.MustParse("2000Mi"), }, // Container level allocated resources does not include DRA resources expectedContainersAllocatedResourcesAfterResize: []v1.ResourceList{ { v1.ResourceCPU: resource.MustParse("500m"), v1.ResourceMemory: resource.MustParse("1000Mi"), }, }, }, { name: "overhead mappings with resize", resourceSliceDevices: overheadDevices, containers: []draContainerInfo{ {Name: "c1", Resources: &cgroups.ContainerResources{CPUReq: "1", CPULim: "2", MemReq: "1Gi", MemLim: "2Gi"}, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, desiredContainers: []draContainerInfo{ {Name: "c1", Resources: &cgroups.ContainerResources{CPUReq: "1500m", CPULim: "2500m", MemReq: "1500Mi", MemLim: "3000Mi"}, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, // CPU request: 1500m (from resized spec) + 100m (DRA PerPod CPU) + 100m (DRA PerContainer CPU) // CPU limit: 2500m (from resized spec) + 100m (DRA PerPod CPU) + 100m (DRA PerContainer CPU) // Memory limit: 3000Mi (from resized spec) + 100Mi (DRA PerPod memory) + 100Mi (DRA PerContainer memory) expectedPodCgroupAfterResize: cgroups.ContainerResources{CPUReq: "1700m", CPULim: "2700m", MemLim: "3200Mi"}, expectedContainersCgroupAfterResize: []cgroups.ContainerResources{ {CPUReq: "1500m", CPULim: "2700m", MemLim: "3200Mi"}, }, expectedPodAllocatedResourcesAfterResize: v1.ResourceList{ v1.ResourceCPU: resource.MustParse("1700m"), v1.ResourceMemory: resource.MustParse("1700Mi"), }, expectedContainersAllocatedResourcesAfterResize: []v1.ResourceList{ { v1.ResourceCPU: resource.MustParse("1500m"), v1.ResourceMemory: resource.MustParse("1500Mi"), }, }, }, { name: "pod-level resources resize with container level request/limit omitted", resourceSliceDevices: directDevices, podResources: &cgroups.ContainerResources{CPUReq: "2", CPULim: "4", MemReq: "2Gi", MemLim: "4Gi"}, containers: []draContainerInfo{ {Name: "c1", Resources: nil, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, desiredPodResources: &cgroups.ContainerResources{CPUReq: "3", CPULim: "5", MemReq: "3Gi", MemLim: "5Gi"}, desiredContainers: []draContainerInfo{ {Name: "c1", Resources: nil, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, // CPU request: 3000m (from resized pod-level spec) // CPU limit: 5000m (from resized pod-level spec) // Memory limit: 5Gi (from resized pod-level spec) expectedPodCgroupAfterResize: cgroups.ContainerResources{CPUReq: "3000m", CPULim: "5000m", MemLim: "5120Mi"}, // Container level limit default to pod level values and limits are not explicitly specified in the container spec expectedContainersCgroupAfterResize: []cgroups.ContainerResources{ {CPULim: "5", MemLim: "5Gi"}, }, // Pod status allocated resources is purely based on pod level resources expectedPodAllocatedResourcesAfterResize: v1.ResourceList{ v1.ResourceCPU: resource.MustParse("3"), v1.ResourceMemory: resource.MustParse("3Gi"), }, }, { name: "Pod level resize, container level request/limit present", resourceSliceDevices: directDevices, podResources: &cgroups.ContainerResources{CPUReq: "2", CPULim: "4", MemReq: "2Gi", MemLim: "4Gi"}, containers: []draContainerInfo{ {Name: "c1", Resources: &cgroups.ContainerResources{CPUReq: "1", CPULim: "2", MemReq: "1Gi", MemLim: "2Gi"}, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, desiredPodResources: &cgroups.ContainerResources{CPUReq: "3", CPULim: "6", MemReq: "3Gi", MemLim: "6Gi"}, desiredContainers: []draContainerInfo{ {Name: "c1", Resources: &cgroups.ContainerResources{CPUReq: "1", CPULim: "2", MemReq: "1Gi", MemLim: "2Gi"}, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, expectedPodCgroupAfterResize: cgroups.ContainerResources{CPUReq: "3000m", CPULim: "6000m", MemLim: "6Gi"}, expectedContainersCgroupAfterResize: []cgroups.ContainerResources{ {CPUReq: "1000m", CPULim: "3000m", MemLim: "3048Mi"}, }, expectedPodAllocatedResourcesAfterResize: v1.ResourceList{ v1.ResourceCPU: resource.MustParse("3"), v1.ResourceMemory: resource.MustParse("3Gi"), }, expectedContainersAllocatedResourcesAfterResize: []v1.ResourceList{ { v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("1Gi"), }, }, }, { name: "pod level resources present, container level resize", resourceSliceDevices: directDevices, podResources: &cgroups.ContainerResources{CPUReq: "2", CPULim: "4", MemReq: "2Gi", MemLim: "4Gi"}, containers: []draContainerInfo{ {Name: "c1", Resources: nil, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, desiredPodResources: &cgroups.ContainerResources{CPUReq: "2", CPULim: "4", MemReq: "2Gi", MemLim: "4Gi"}, desiredContainers: []draContainerInfo{ {Name: "c1", Resources: &cgroups.ContainerResources{CPUReq: "1", CPULim: "2", MemReq: "1Gi", MemLim: "2Gi"}, Claims: []*resourceapi.ResourceClaim{claimCPUMem}}, }, // Pod cgroup remains the same after container resize expectedPodCgroupAfterResize: cgroups.ContainerResources{CPUReq: "2000m", CPULim: "4000m", MemLim: "4Gi"}, // Container cgroup updated after resize and includes DRA expectedContainersCgroupAfterResize: []cgroups.ContainerResources{ {CPUReq: "1000m", CPULim: "3000m", MemLim: "3048Mi"}, }, // Pod level allocated resources based on only pod level resources expectedPodAllocatedResourcesAfterResize: v1.ResourceList{ v1.ResourceCPU: resource.MustParse("2"), v1.ResourceMemory: resource.MustParse("2Gi"), }, // Container level allocated resources includes resized spec values (and excludes DRA) expectedContainersAllocatedResourcesAfterResize: []v1.ResourceList{ { v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("1Gi"), }, }, }, } for _, tc := range tests { ginkgo.It(fmt.Sprintf("verifies cgroup settings and pod status after resize with %s", tc.name), func(ctx context.Context) { tCtx := f.TContext(ctx) nodes := drautils.NewNodesNow(tCtx, 1, 4) driver := drautils.NewDriverInstance(tCtx) b := drautils.NewBuilderNow(tCtx, driver) driverResources := map[string]resourceslice.DriverResources{ nodes.NodeNames[0]: { Pools: map[string]resourceslice.Pool{ nodes.NodeNames[0]: { Slices: []resourceslice.Slice{{ Devices: tc.resourceSliceDevices, }}, }, }, }, } driver.Run(tCtx, framework.TestContext.KubeletRootDir, nodes, driverResources) createdClaims := createClaims(tCtx, b, tc.containers, tc.unreferencedClaims) pod := makeTestPod(tc.podResources, tc.containers, tc.unreferencedClaims, createdClaims) pod.Namespace = f.Namespace.Name podJSON, _ := json.Marshal(pod) tCtx.Logf("Pod JSON to create: %s", string(podJSON)) ginkgo.By("creating pod and waiting for it to be running") podClient := e2epod.NewPodClient(f) pod = podClient.CreateSync(ctx, pod) originalContainers := mapToResizableContainerInfo(tc.containers) desiredContainers := mapToResizableContainerInfo(tc.desiredContainers) var originalPodResources *v1.ResourceRequirements if tc.podResources != nil { originalPodResources = tc.podResources.ResourceRequirements() } var desiredPodResources *v1.ResourceRequirements if tc.desiredPodResources != nil { desiredPodResources = tc.desiredPodResources.ResourceRequirements() } patch := podresize.MakeResizePatch(originalContainers, desiredContainers, originalPodResources, desiredPodResources) ginkgo.By("patching the pod for resize") patchedPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Patch(ctx, pod.Name, types.StrategicMergePatchType, patch, metav1.PatchOptions{}, "resize") framework.ExpectNoError(err) ginkgo.By("waiting for resize actuation to complete") resizedPod := podresize.WaitForPodResizeActuation(ctx, f, podClient, pod, desiredContainers) ginkgo.By("verifying updated pod cgroup limits after resize") err = cgroups.VerifyPodCgroups(ctx, f, resizedPod, &tc.expectedPodCgroupAfterResize) framework.ExpectNoError(err) ginkgo.By("verifying updated container cgroup limits after resize") onCgroupV2 := cgroups.IsPodOnCgroupv2Node(f, resizedPod.Name, resizedPod.Spec.Containers[0].Name) for i, container := range resizedPod.Spec.Containers { expectedContainer := &v1.Container{ Name: container.Name, Resources: *tc.expectedContainersCgroupAfterResize[i].ResourceRequirements(), } if expectedContainer.Resources.Requests == nil { expectedContainer.Resources.Requests = container.Resources.Requests } err = cgroups.VerifyContainerCgroupValues(ctx, f, resizedPod, expectedContainer, onCgroupV2) framework.ExpectNoError(err) } ginkgo.By("verifying pod status updates match spec after resize") framework.ExpectNoError(verifyDRAPodLevelStatusResources(resizedPod, tc.expectedPodAllocatedResourcesAfterResize)) ginkgo.By("verifying pod spec resources after patch") podresize.VerifyPodResources(patchedPod, desiredContainers, desiredPodResources) ginkgo.By("deleting pods") delErr := e2epod.DeletePodWithWait(ctx, f.ClientSet, resizedPod) framework.ExpectNoError(delErr, "failed to delete pod %s", delErr) }) } } func makeTestPod(podResources *cgroups.ContainerResources, containers []draContainerInfo, unreferencedClaims []*resourceapi.ResourceClaim, createdClaims map[string]*resourceapi.ResourceClaim) *v1.Pod { var testContainers []v1.Container for _, container := range containers { c := cgroups.MakeContainerWithResources(container.Name, container.Resources, "trap exit TERM; while true; do sleep 1; done") if len(container.Claims) > 0 { c.Resources.Claims = make([]v1.ResourceClaim, len(container.Claims)) for idx, claim := range container.Claims { c.Resources.Claims[idx] = v1.ResourceClaim{Name: claim.Name} } } if container.HugepageReqLim != "" { if c.Resources.Limits == nil { c.Resources.Requests = make(v1.ResourceList) c.Resources.Limits = make(v1.ResourceList) } c.Resources.Requests[v1.ResourceName("hugepages-2Mi")] = resource.MustParse(container.HugepageReqLim) c.Resources.Limits[v1.ResourceName("hugepages-2Mi")] = resource.MustParse(container.HugepageReqLim) } testContainers = append(testContainers, c) } pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "tester-1", }, Spec: v1.PodSpec{ RestartPolicy: v1.RestartPolicyNever, Containers: testContainers, }, } cgroups.ConfigureHostPathForPodCgroup(pod) if podResources != nil { pod.Spec.Resources = podResources.ResourceRequirements() } uniqueClaims := sets.New[string]() for _, container := range containers { for _, claim := range container.Claims { uniqueClaims.Insert(claim.Name) } } for _, claim := range unreferencedClaims { uniqueClaims.Insert(claim.Name) } if uniqueClaims.Len() > 0 { sortedClaims := uniqueClaims.UnsortedList() slices.Sort(sortedClaims) pod.Spec.ResourceClaims = make([]v1.PodResourceClaim, len(sortedClaims)) for idx, claimName := range sortedClaims { var actualClaimName *string if actualClaim, exists := createdClaims[claimName]; exists { actualClaimName = &actualClaim.Name } pod.Spec.ResourceClaims[idx] = v1.PodResourceClaim{ Name: claimName, ResourceClaimName: actualClaimName, } } } return pod } func computeExpectedOomScoreAdj(memReqMi int64, nodeMemBytes int64) int64 { // This implements the OOM score calculation formula in Kubelet's GetContainerOOMScoreAdjust() in pkg/kubelet/qos/policy.go. score := 1000 - (1000 * memReqMi * 1024 * 1024 / nodeMemBytes) if score < 2 { return 2 } return score } func createClaims(tCtx ktesting.TContext, b *drautils.Builder, containers []draContainerInfo, unreferencedClaims []*resourceapi.ResourceClaim) map[string]*resourceapi.ResourceClaim { uniqueClaims := make(map[string]bool) for _, container := range containers { for _, claim := range container.Claims { uniqueClaims[claim.Name] = true } } for _, claim := range unreferencedClaims { uniqueClaims[claim.Name] = true } createdClaims := make(map[string]*resourceapi.ResourceClaim) for templateName := range uniqueClaims { createdClaimObj := b.Create(tCtx, b.ExternalClaim())[0] createdClaims[templateName] = createdClaimObj.(*resourceapi.ResourceClaim) } return createdClaims } func verifyDRAPodLevelStatusResources(gotPod *v1.Pod, wantAllocatedResources v1.ResourceList) error { ginkgo.GinkgoHelper() var errs []error if wantAllocatedResources != nil { if err := framework.Gomega().Expect(gotPod.Status.AllocatedResources).To(gomega.BeComparableTo(wantAllocatedResources)); err != nil { errs = append(errs, fmt.Errorf("pod[%s] status allocatedResources mismatch: %w", gotPod.Name, err)) } } return errors.NewAggregate(errs) } func mapToResizableContainerInfo(containers []draContainerInfo) []podresize.ResizableContainerInfo { res := make([]podresize.ResizableContainerInfo, len(containers)) for i, c := range containers { res[i] = podresize.ResizableContainerInfo{ Name: c.Name, Resources: c.Resources, } } return res } var _ = SIGDescribe("DRA Node Allocatable Resources", framework.WithSerial(), feature.DynamicResourceAllocation, framework.WithFeatureGate(features.DRANodeAllocatableResources), framework.WithFeatureGate(features.InPlacePodLevelResourcesVerticalScaling), func() { f := framework.NewDefaultFramework("dra-node-allocatable-resources") f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged ginkgo.BeforeEach(func(ctx context.Context) { if framework.NodeOSDistroIs("windows") { e2eskipper.Skipf("not supported on windows -- skipping") } }) doNodeAllocatableCgroupsTests(f) doNodeAllocatableResizeTests(f) })