k8s.io/kubernetes@v1.29.3/pkg/kubelet/kuberuntime/kuberuntime_container_windows_test.go (about) 1 //go:build windows 2 // +build windows 3 4 /* 5 Copyright 2022 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package kuberuntime 21 22 import ( 23 "testing" 24 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27 28 v1 "k8s.io/api/core/v1" 29 "k8s.io/apimachinery/pkg/api/resource" 30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1" 32 "k8s.io/kubernetes/pkg/kubelet/winstats" 33 ) 34 35 func TestApplyPlatformSpecificContainerConfig(t *testing.T) { 36 _, _, fakeRuntimeSvc, err := createTestRuntimeManager() 37 require.NoError(t, err) 38 39 containerConfig := &runtimeapi.ContainerConfig{} 40 41 resources := v1.ResourceRequirements{ 42 Requests: v1.ResourceList{ 43 v1.ResourceMemory: resource.MustParse("128Mi"), 44 v1.ResourceCPU: resource.MustParse("1"), 45 }, 46 Limits: v1.ResourceList{ 47 v1.ResourceMemory: resource.MustParse("256Mi"), 48 v1.ResourceCPU: resource.MustParse("3"), 49 }, 50 } 51 52 gmsaCredSpecName := "gmsa spec name" 53 gmsaCredSpec := "credential spec" 54 username := "ContainerAdministrator" 55 asHostProcess := true 56 pod := &v1.Pod{ 57 ObjectMeta: metav1.ObjectMeta{ 58 UID: "12345678", 59 Name: "bar", 60 Namespace: "new", 61 }, 62 Spec: v1.PodSpec{ 63 Containers: []v1.Container{ 64 { 65 Name: "foo", 66 Image: "busybox", 67 ImagePullPolicy: v1.PullIfNotPresent, 68 Command: []string{"testCommand"}, 69 WorkingDir: "testWorkingDir", 70 Resources: resources, 71 SecurityContext: &v1.SecurityContext{ 72 WindowsOptions: &v1.WindowsSecurityContextOptions{ 73 GMSACredentialSpecName: &gmsaCredSpecName, 74 GMSACredentialSpec: &gmsaCredSpec, 75 RunAsUserName: &username, 76 HostProcess: &asHostProcess, 77 }, 78 }, 79 }, 80 }, 81 }, 82 } 83 84 err = fakeRuntimeSvc.applyPlatformSpecificContainerConfig(containerConfig, &pod.Spec.Containers[0], pod, new(int64), "foo", nil) 85 require.NoError(t, err) 86 87 limit := int64(3000) 88 expectedCpuMax := 10 * limit / int64(winstats.ProcessorCount()) 89 // Above, we're setting the limit to 3 CPUs. But we can't expect more than 100% of the CPUs 90 // we have. (e.g.: if we only have 2 CPUs, we can't have 150% CPU max). 91 if expectedCpuMax > 10000 { 92 expectedCpuMax = 10000 93 } 94 expectedWindowsConfig := &runtimeapi.WindowsContainerConfig{ 95 Resources: &runtimeapi.WindowsContainerResources{ 96 CpuMaximum: expectedCpuMax, 97 MemoryLimitInBytes: 256 * 1024 * 1024, 98 }, 99 SecurityContext: &runtimeapi.WindowsContainerSecurityContext{ 100 CredentialSpec: gmsaCredSpec, 101 RunAsUsername: "ContainerAdministrator", 102 HostProcess: true, 103 }, 104 } 105 assert.Equal(t, expectedWindowsConfig, containerConfig.Windows) 106 } 107 108 func TestCalculateCPUMaximum(t *testing.T) { 109 tests := []struct { 110 name string 111 cpuLimit resource.Quantity 112 cpuCount int64 113 want int64 114 }{ 115 { 116 name: "max range when same amount", 117 cpuLimit: resource.MustParse("1"), 118 cpuCount: 1, 119 want: 10000, 120 }, 121 { 122 name: "percentage calculation is working as intended", 123 cpuLimit: resource.MustParse("94"), 124 cpuCount: 96, 125 want: 9791, 126 }, 127 { 128 name: "half range when half amount", 129 cpuLimit: resource.MustParse("1"), 130 cpuCount: 2, 131 want: 5000, 132 }, 133 { 134 name: "max range when more requested than available", 135 cpuLimit: resource.MustParse("2"), 136 cpuCount: 1, 137 want: 10000, 138 }, 139 { 140 name: "min range when less than minimum", 141 cpuLimit: resource.MustParse("1m"), 142 cpuCount: 100, 143 want: 1, 144 }, 145 } 146 for _, tt := range tests { 147 t.Run(tt.name, func(t *testing.T) { 148 assert.Equal(t, tt.want, calculateCPUMaximum(&tt.cpuLimit, tt.cpuCount)) 149 }) 150 } 151 } 152 153 func TestCalculateWindowsResources(t *testing.T) { 154 _, _, fakeRuntimeSvc, err := createTestRuntimeManager() 155 require.NoError(t, err) 156 157 tests := []struct { 158 name string 159 cpuLim resource.Quantity 160 memLim resource.Quantity 161 expected *runtimeapi.WindowsContainerResources 162 }{ 163 { 164 name: "Request128MBLimit256MB", 165 cpuLim: resource.MustParse("2"), 166 memLim: resource.MustParse("128Mi"), 167 expected: &runtimeapi.WindowsContainerResources{ 168 CpuMaximum: 2500, 169 MemoryLimitInBytes: 134217728, 170 }, 171 }, 172 { 173 name: "RequestNoMemory", 174 cpuLim: resource.MustParse("8"), 175 memLim: resource.MustParse("0"), 176 expected: &runtimeapi.WindowsContainerResources{ 177 CpuMaximum: 10000, 178 MemoryLimitInBytes: 0, 179 }, 180 }, 181 { 182 name: "RequestZeroCPU", 183 cpuLim: resource.MustParse("0"), 184 memLim: resource.MustParse("128Mi"), 185 expected: &runtimeapi.WindowsContainerResources{ 186 CpuMaximum: 1, 187 MemoryLimitInBytes: 134217728, 188 }, 189 }, 190 } 191 for _, test := range tests { 192 windowsContainerResources := fakeRuntimeSvc.calculateWindowsResources(&test.cpuLim, &test.memLim) 193 assert.Equal(t, test.expected, windowsContainerResources) 194 } 195 }