k8s.io/kubernetes@v1.29.3/test/e2e_node/runtimeclass_test.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package e2enode 18 19 import ( 20 "context" 21 "path/filepath" 22 "strings" 23 24 v1 "k8s.io/api/core/v1" 25 nodev1 "k8s.io/api/node/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/kubernetes/pkg/kubelet/cm" 28 "k8s.io/kubernetes/test/e2e/framework" 29 e2eruntimeclass "k8s.io/kubernetes/test/e2e/framework/node/runtimeclass" 30 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 31 imageutils "k8s.io/kubernetes/test/utils/image" 32 admissionapi "k8s.io/pod-security-admission/api" 33 34 "github.com/onsi/ginkgo/v2" 35 ) 36 37 // makePodToVerifyCgroups returns a pod that verifies the existence of the specified cgroups. 38 func makePodToVerifyCgroupSize(cgroupNames []string, expectedCPU string, expectedMemory string) *v1.Pod { 39 // convert the names to their literal cgroupfs forms... 40 cgroupFsNames := []string{} 41 rootCgroupName := cm.NewCgroupName(cm.RootCgroupName, defaultNodeAllocatableCgroup) 42 for _, baseName := range cgroupNames { 43 // Add top level cgroup used to enforce node allocatable. 44 cgroupComponents := strings.Split(baseName, "/") 45 cgroupName := cm.NewCgroupName(rootCgroupName, cgroupComponents...) 46 cgroupFsNames = append(cgroupFsNames, toCgroupFsName(cgroupName)) 47 } 48 framework.Logf("expecting %v cgroups to be found", cgroupFsNames) 49 50 // build the pod command to verify cgroup sizing 51 command := "" 52 for _, cgroupFsName := range cgroupFsNames { 53 memLimitCgroup := filepath.Join("/host_cgroups/memory", cgroupFsName, "memory.limit_in_bytes") 54 cpuQuotaCgroup := filepath.Join("/host_cgroups/cpu", cgroupFsName, "cpu.cfs_quota_us") 55 localCommand := "if [ ! $(cat " + memLimitCgroup + ") == " + expectedMemory + " ] || [ ! $(cat " + cpuQuotaCgroup + ") == " + expectedCPU + " ]; then exit 1; fi; " 56 57 framework.Logf("command: %v: ", localCommand) 58 command += localCommand 59 } 60 61 pod := &v1.Pod{ 62 ObjectMeta: metav1.ObjectMeta{ 63 GenerateName: "cgroup-verification-pod-", 64 }, 65 Spec: v1.PodSpec{ 66 RestartPolicy: v1.RestartPolicyNever, 67 Containers: []v1.Container{ 68 { 69 Image: busyboxImage, 70 Name: "container", 71 Command: []string{"sh", "-c", command}, 72 VolumeMounts: []v1.VolumeMount{ 73 { 74 Name: "sysfscgroup", 75 MountPath: "/host_cgroups", 76 }, 77 }, 78 }, 79 }, 80 Volumes: []v1.Volume{ 81 { 82 Name: "sysfscgroup", 83 VolumeSource: v1.VolumeSource{ 84 HostPath: &v1.HostPathVolumeSource{Path: "/sys/fs/cgroup"}, 85 }, 86 }, 87 }, 88 }, 89 } 90 return pod 91 } 92 93 var _ = SIGDescribe("Kubelet PodOverhead handling [LinuxOnly]", func() { 94 f := framework.NewDefaultFramework("podoverhead-handling") 95 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 96 ginkgo.Describe("PodOverhead cgroup accounting", func() { 97 ginkgo.Context("On running pod with PodOverhead defined", func() { 98 ginkgo.It("Pod cgroup should be sum of overhead and resource limits", func(ctx context.Context) { 99 if !kubeletCfg.CgroupsPerQOS { 100 return 101 } 102 103 var ( 104 guaranteedPod *v1.Pod 105 podUID string 106 handler string 107 ) 108 ginkgo.By("Creating a RuntimeClass with Overhead definied", func() { 109 handler = e2eruntimeclass.PreconfiguredRuntimeClassHandler 110 rc := &nodev1.RuntimeClass{ 111 ObjectMeta: metav1.ObjectMeta{Name: handler}, 112 Handler: handler, 113 Overhead: &nodev1.Overhead{ 114 PodFixed: getResourceList("200m", "140Mi"), 115 }, 116 } 117 _, err := f.ClientSet.NodeV1().RuntimeClasses().Create(ctx, rc, metav1.CreateOptions{}) 118 framework.ExpectNoError(err, "failed to create RuntimeClass resource") 119 }) 120 ginkgo.By("Creating a Guaranteed pod with which has Overhead defined", func() { 121 guaranteedPod = e2epod.NewPodClient(f).CreateSync(ctx, &v1.Pod{ 122 ObjectMeta: metav1.ObjectMeta{ 123 GenerateName: "pod-with-overhead-", 124 Namespace: f.Namespace.Name, 125 }, 126 Spec: v1.PodSpec{ 127 Containers: []v1.Container{ 128 { 129 Image: imageutils.GetPauseImageName(), 130 Name: "container", 131 Resources: getResourceRequirements(getResourceList("100m", "100Mi"), getResourceList("100m", "100Mi")), 132 }, 133 }, 134 RuntimeClassName: &handler, 135 Overhead: getResourceList("200m", "140Mi"), 136 }, 137 }) 138 podUID = string(guaranteedPod.UID) 139 }) 140 ginkgo.By("Checking if the pod cgroup was created appropriately", func() { 141 cgroupsToVerify := []string{"pod" + podUID} 142 pod := makePodToVerifyCgroupSize(cgroupsToVerify, "30000", "251658240") 143 pod = e2epod.NewPodClient(f).Create(ctx, pod) 144 err := e2epod.WaitForPodSuccessInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name) 145 framework.ExpectNoError(err) 146 }) 147 }) 148 }) 149 }) 150 })