k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 // TODO: remove skip once the failing test has been fixed. 155 t.Skip("Skip failing test on Windows.") 156 157 _, _, fakeRuntimeSvc, err := createTestRuntimeManager() 158 require.NoError(t, err) 159 160 tests := []struct { 161 name string 162 cpuLim resource.Quantity 163 memLim resource.Quantity 164 expected *runtimeapi.WindowsContainerResources 165 }{ 166 { 167 name: "Request128MBLimit256MB", 168 cpuLim: resource.MustParse("2"), 169 memLim: resource.MustParse("128Mi"), 170 expected: &runtimeapi.WindowsContainerResources{ 171 CpuMaximum: 2500, 172 MemoryLimitInBytes: 134217728, 173 }, 174 }, 175 { 176 name: "RequestNoMemory", 177 cpuLim: resource.MustParse("8"), 178 memLim: resource.MustParse("0"), 179 expected: &runtimeapi.WindowsContainerResources{ 180 CpuMaximum: 10000, 181 MemoryLimitInBytes: 0, 182 }, 183 }, 184 { 185 name: "RequestZeroCPU", 186 cpuLim: resource.MustParse("0"), 187 memLim: resource.MustParse("128Mi"), 188 expected: &runtimeapi.WindowsContainerResources{ 189 CpuMaximum: 1, 190 MemoryLimitInBytes: 134217728, 191 }, 192 }, 193 } 194 for _, test := range tests { 195 windowsContainerResources := fakeRuntimeSvc.calculateWindowsResources(&test.cpuLim, &test.memLim) 196 assert.Equal(t, test.expected, windowsContainerResources) 197 } 198 }