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  }