diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index fa0d6e731cc..5aa310e223d 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -5503,6 +5503,11 @@ func ValidatePodResize(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel return field.ErrorList{field.Forbidden(field.NewPath(""), "static pods cannot be resized")} } + // windows pods are not supported. + if oldPod.Spec.OS != nil && oldPod.Spec.OS.Name == core.Windows { + return field.ErrorList{field.Forbidden(field.NewPath(""), "windows pods cannot be resized")} + } + // Part 2: Validate that the changes between oldPod.Spec.Containers[].Resources and // newPod.Spec.Containers[].Resources are allowed. specPath := field.NewPath("spec") diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 47944ffd31a..bd457b40adf 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -25075,22 +25075,20 @@ func TestValidateSELinuxChangePolicy(t *testing.T) { } func TestValidatePodResize(t *testing.T) { - mkPod := func(req, lim core.ResourceList, tweaks ...podtest.TweakContainer) *core.Pod { - return podtest.MakePod("pod", + mkPod := func(req, lim core.ResourceList, tweaks ...podtest.Tweak) *core.Pod { + return podtest.MakePod("pod", append(tweaks, podtest.SetContainers( podtest.MakeContainer( "container", - append(tweaks, - podtest.SetContainerResources( - core.ResourceRequirements{ - Requests: req, - Limits: lim, - }, - ), - )..., + podtest.SetContainerResources( + core.ResourceRequirements{ + Requests: req, + Limits: lim, + }, + ), ), ), - ) + )...) } tests := []struct { @@ -25179,6 +25177,16 @@ func TestValidatePodResize(t *testing.T) { old: mkPod(getResources("100m", "100Mi", "", ""), getResources("200m", "200Mi", "", "")), new: mkPod(core.ResourceList{}, core.ResourceList{}), err: "Pod QOS Class may not change as a result of resizing", + }, { + test: "windows pod, no resource change", + old: mkPod(core.ResourceList{}, getResources("100m", "0", "1Gi", ""), podtest.SetOS(core.Windows)), + new: mkPod(core.ResourceList{}, getResources("100m", "0", "1Gi", ""), podtest.SetOS(core.Windows)), + err: "Forbidden: windows pods cannot be resized", + }, { + test: "windows pod, resource change", + old: mkPod(core.ResourceList{}, getResources("100m", "0", "1Gi", ""), podtest.SetOS(core.Windows)), + new: mkPod(core.ResourceList{}, getResources("200m", "0", "1Gi", ""), podtest.SetOS(core.Windows)), + err: "Forbidden: windows pods cannot be resized", }, } diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 995bb31898d..c498027ec86 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -243,10 +243,13 @@ var ( topologymanager.ErrorTopologyAffinity, nodeshutdown.NodeShutdownNotAdmittedReason, ) + + // This is exposed for unit tests. + goos = sysruntime.GOOS ) func getContainerEtcHostsPath() string { - if sysruntime.GOOS == "windows" { + if goos == "windows" { return windowsEtcHostsPath } return linuxEtcHostsPath @@ -940,7 +943,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, opt(klet) } - if sysruntime.GOOS == "linux" { + if goos == "linux" { // AppArmor is a Linux kernel security module and it does not support other operating systems. klet.appArmorValidator = apparmor.NewValidator() klet.admitHandlers.AddPodAdmitHandler(lifecycle.NewAppArmorAdmitHandler(klet.appArmorValidator)) @@ -1564,7 +1567,7 @@ func (kl *Kubelet) initializeModules() error { } } - if sysruntime.GOOS == "windows" { + if goos == "windows" { // On Windows we should not allow other users to read the logs directory // to avoid allowing non-root containers from reading the logs of other containers. if err := utilfs.Chmod(ContainerLogsDir, 0750); err != nil { @@ -2865,6 +2868,10 @@ func (kl *Kubelet) handlePodResourcesResize(pod *v1.Pod, podStatus *kubecontaine // Pod allocation does not need to be updated. return allocatedPod, nil } + if goos == "windows" { + kl.statusManager.SetPodResizeStatus(pod.UID, v1.PodResizeStatusInfeasible) + return allocatedPod, nil + } kl.podResizeMutex.Lock() defer kl.podResizeMutex.Unlock() diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index b2baa94481c..3407b9ee4a5 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -2676,6 +2676,7 @@ func TestHandlePodResourcesResize(t *testing.T) { newRequestsAllocated bool // Whether the new requests have already been allocated (but not actuated) expectedAllocations v1.ResourceList expectedResize v1.PodResizeStatus + goos string }{ { name: "Request CPU and memory decrease - expect InProgress", @@ -2741,10 +2742,23 @@ func TestHandlePodResourcesResize(t *testing.T) { expectedAllocations: v1.ResourceList{v1.ResourceCPU: cpu1000m, v1.ResourceMemory: mem1000M}, expectedResize: "", }, + { + name: "windows node, expect Infeasible", + pod: testPod2, + newRequests: v1.ResourceList{v1.ResourceCPU: cpu500m, v1.ResourceMemory: mem500M}, + expectedAllocations: v1.ResourceList{v1.ResourceCPU: cpu1000m, v1.ResourceMemory: mem1000M}, + expectedResize: v1.PodResizeStatusInfeasible, + goos: "windows", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + oldGOOS := goos + defer func() { goos = oldGOOS }() + if tt.goos != "" { + goos = tt.goos + } kubelet.statusManager = status.NewFakeManager() newPod := tt.pod.DeepCopy()