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  })