Skip to content

Commit 14f7dab

Browse files
annasong20toVersus
authored andcommitted
Check OS for PodLevelResources in kubelet
Reject pods with PodLevelResources running on Windows nodes at kubelet admission phase
1 parent c584fc5 commit 14f7dab

File tree

4 files changed

+106
-1
lines changed

4 files changed

+106
-1
lines changed

pkg/kubelet/kubelet.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,9 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
10091009
// AppArmor is a Linux kernel security module and it does not support other operating systems.
10101010
klet.appArmorValidator = apparmor.NewValidator()
10111011
handlers = append(handlers, lifecycle.NewAppArmorAdmitHandler(klet.appArmorValidator))
1012+
} else if goos == "windows" {
1013+
// PodLevelResources feature is not supported for Windows
1014+
handlers = append(handlers, lifecycle.NewPodLevelResourcesHandler())
10121015
}
10131016

10141017
leaseDuration := time.Duration(kubeCfg.NodeLeaseDurationSeconds) * time.Second

pkg/kubelet/kubelet_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3373,6 +3373,15 @@ func TestRecordAdmissionRejection(t *testing.T) {
33733373
kubelet_admission_rejections_total{reason="OutOfExtendedResources"} 1
33743374
`,
33753375
},
3376+
{
3377+
name: "PodLevelResources",
3378+
reason: lifecycle.PodLevelResourcesNotAdmittedReason,
3379+
wants: `
3380+
# HELP kubelet_admission_rejections_total [ALPHA] Cumulative number pod admission rejections by the Kubelet.
3381+
# TYPE kubelet_admission_rejections_total counter
3382+
kubelet_admission_rejections_total{reason="PodLevelResourcesNotSupported"} 1
3383+
`,
3384+
},
33763385
{
33773386
name: "OtherReason",
33783387
reason: "OtherReason",

pkg/kubelet/lifecycle/handlers.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"k8s.io/apimachinery/pkg/util/intstr"
3333
utilfeature "k8s.io/apiserver/pkg/util/feature"
3434
"k8s.io/client-go/tools/record"
35+
"k8s.io/component-helpers/resource"
3536
"k8s.io/klog/v2"
3637
"k8s.io/kubernetes/pkg/features"
3738
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
@@ -45,7 +46,8 @@ import (
4546
const (
4647
maxRespBodyLength = 10 * 1 << 10 // 10KB
4748

48-
AppArmorNotAdmittedReason = "AppArmor"
49+
AppArmorNotAdmittedReason = "AppArmor"
50+
PodLevelResourcesNotAdmittedReason = "PodLevelResourcesNotSupported"
4951
)
5052

5153
type handlerRunner struct {
@@ -241,3 +243,23 @@ func isHTTPResponseError(err error) bool {
241243
}
242244
return strings.Contains(urlErr.Err.Error(), "server gave HTTP response to HTTPS client")
243245
}
246+
247+
// NewPodLevelResourcesHandler returns a PodAdmitHandler which is used to evaluate
248+
// if a pod can be admitted from the perspective of PodLevelResources.
249+
func NewPodLevelResourcesHandler() PodAdmitHandler {
250+
return &podLevelResourcesHandler{}
251+
}
252+
253+
type podLevelResourcesHandler struct{}
254+
255+
func (ph *podLevelResourcesHandler) Admit(attrs *PodAdmitAttributes) PodAdmitResult {
256+
podLevelResourcesEnabled := utilfeature.DefaultFeatureGate.Enabled(features.PodLevelResources)
257+
if podLevelResourcesEnabled && resource.IsPodLevelResourcesSet(attrs.Pod) {
258+
return PodAdmitResult{
259+
Admit: false,
260+
Reason: PodLevelResourcesNotAdmittedReason,
261+
Message: "Pod level resources are not supported on Windows",
262+
}
263+
}
264+
return PodAdmitResult{Admit: true}
265+
}

pkg/kubelet/lifecycle/handlers_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
"github.com/google/go-cmp/cmp"
3232
v1 "k8s.io/api/core/v1"
33+
"k8s.io/apimachinery/pkg/api/resource"
3334
"k8s.io/apimachinery/pkg/types"
3435
"k8s.io/apimachinery/pkg/util/intstr"
3536
utilfeature "k8s.io/apiserver/pkg/util/feature"
@@ -876,3 +877,73 @@ func TestRunSleepHandler(t *testing.T) {
876877
})
877878
}
878879
}
880+
881+
func TestPodLevelResourcesOnWindowsHandler(t *testing.T) {
882+
handlerRunner := NewPodLevelResourcesHandler()
883+
pod := v1.Pod{}
884+
pod.ObjectMeta.Name = "windowsPod"
885+
886+
deniedPodAdmitResult := PodAdmitResult{
887+
Admit: false,
888+
Reason: PodLevelResourcesNotAdmittedReason,
889+
Message: "Pod level resources are not supported on Windows",
890+
}
891+
892+
tests := []struct {
893+
name string
894+
podLevelResources *v1.ResourceRequirements
895+
expectPodAdmitResult PodAdmitResult
896+
}{
897+
{
898+
name: "no pod level resources",
899+
expectPodAdmitResult: PodAdmitResult{Admit: true},
900+
},
901+
{
902+
name: "pod level resources",
903+
podLevelResources: &v1.ResourceRequirements{
904+
Requests: v1.ResourceList{
905+
v1.ResourceCPU: resource.MustParse("100m"),
906+
v1.ResourceMemory: resource.MustParse("100Mi"),
907+
},
908+
Limits: v1.ResourceList{
909+
v1.ResourceCPU: resource.MustParse("200m"),
910+
v1.ResourceMemory: resource.MustParse("200Mi"),
911+
},
912+
},
913+
expectPodAdmitResult: deniedPodAdmitResult,
914+
},
915+
{
916+
name: "pod level resources with no limits",
917+
podLevelResources: &v1.ResourceRequirements{
918+
Requests: v1.ResourceList{
919+
v1.ResourceCPU: resource.MustParse("100m"),
920+
v1.ResourceMemory: resource.MustParse("100Mi"),
921+
},
922+
},
923+
expectPodAdmitResult: deniedPodAdmitResult,
924+
},
925+
{
926+
name: "pod level resources with no requests",
927+
podLevelResources: &v1.ResourceRequirements{
928+
Limits: v1.ResourceList{
929+
v1.ResourceCPU: resource.MustParse("200m"),
930+
v1.ResourceMemory: resource.MustParse("200Mi"),
931+
},
932+
},
933+
expectPodAdmitResult: deniedPodAdmitResult,
934+
},
935+
}
936+
937+
for _, tt := range tests {
938+
t.Run(tt.name, func(t *testing.T) {
939+
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodLevelResources, true)
940+
pod.Spec.Resources = nil
941+
if tt.podLevelResources != nil {
942+
pod.Spec.Resources = tt.podLevelResources
943+
}
944+
if got := handlerRunner.Admit(&PodAdmitAttributes{Pod: &pod}); !reflect.DeepEqual(got, tt.expectPodAdmitResult) {
945+
t.Errorf("Pod admitted: expected %v, got %v", tt.expectPodAdmitResult, got)
946+
}
947+
})
948+
}
949+
}

0 commit comments

Comments
 (0)