diff --git a/pkg/kubelet/apis/config/validation/validation.go b/pkg/kubelet/apis/config/validation/validation.go index 6fefe704f40..2fd6b14d374 100644 --- a/pkg/kubelet/apis/config/validation/validation.go +++ b/pkg/kubelet/apis/config/validation/validation.go @@ -23,6 +23,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/sets" utilvalidation "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/component-base/featuregate" @@ -55,9 +56,6 @@ func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration, featur if kc.NodeLeaseDurationSeconds <= 0 { allErrors = append(allErrors, fmt.Errorf("invalid configuration: nodeLeaseDurationSeconds must be greater than 0")) } - if !kc.CgroupsPerQOS && len(kc.EnforceNodeAllocatable) > 0 { - allErrors = append(allErrors, fmt.Errorf("invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) is not supported unless cgroupsPerQOS (--cgroups-per-qos) is set to true")) - } if kc.SystemCgroups != "" && kc.CgroupRoot == "" { allErrors = append(allErrors, fmt.Errorf("invalid configuration: systemCgroups (--system-cgroups) was specified and cgroupRoot (--cgroup-root) was not specified")) } @@ -205,7 +203,14 @@ func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration, featur allErrors = append(allErrors, fmt.Errorf("invalid configuration: memorySwap.swapBehavior cannot be set when NodeSwap feature flag is disabled")) } + uniqueEnforcements := sets.Set[string]{} for _, val := range kc.EnforceNodeAllocatable { + if uniqueEnforcements.Has(val) { + allErrors = append(allErrors, fmt.Errorf("invalid configuration: duplicated enforcements %q in enforceNodeAllocatable (--enforce-node-allocatable)", val)) + continue + } + uniqueEnforcements.Insert(val) + switch val { case kubetypes.NodeAllocatableEnforcementKey: case kubetypes.SystemReservedEnforcementKey: @@ -220,9 +225,16 @@ func ValidateKubeletConfiguration(kc *kubeletconfig.KubeletConfiguration, featur if len(kc.EnforceNodeAllocatable) > 1 { allErrors = append(allErrors, fmt.Errorf("invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) may not contain additional enforcements when %q is specified", kubetypes.NodeAllocatableNoneKey)) } + // skip all further checks when this is explicitly "none" + continue default: allErrors = append(allErrors, fmt.Errorf("invalid configuration: option %q specified for enforceNodeAllocatable (--enforce-node-allocatable). Valid options are %q, %q, %q, or %q", val, kubetypes.NodeAllocatableEnforcementKey, kubetypes.SystemReservedEnforcementKey, kubetypes.KubeReservedEnforcementKey, kubetypes.NodeAllocatableNoneKey)) + continue + } + + if !kc.CgroupsPerQOS { + allErrors = append(allErrors, fmt.Errorf("invalid configuration: cgroupsPerQOS (--cgroups-per-qos) must be set to true when %q contained in enforceNodeAllocatable (--enforce-node-allocatable)", val)) } } switch kc.HairpinMode { diff --git a/pkg/kubelet/apis/config/validation/validation_test.go b/pkg/kubelet/apis/config/validation/validation_test.go index e014c7c15a4..22df9e3ab90 100644 --- a/pkg/kubelet/apis/config/validation/validation_test.go +++ b/pkg/kubelet/apis/config/validation/validation_test.go @@ -105,10 +105,10 @@ func TestValidateKubeletConfiguration(t *testing.T) { name: "specify EnforceNodeAllocatable without enabling CgroupsPerQOS", configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { conf.CgroupsPerQOS = false - conf.EnforceNodeAllocatable = []string{"pods"} + conf.EnforceNodeAllocatable = []string{kubetypes.NodeAllocatableEnforcementKey} return conf }, - errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) is not supported unless cgroupsPerQOS (--cgroups-per-qos) is set to true", + errMsg: "invalid configuration: cgroupsPerQOS (--cgroups-per-qos) must be set to true when \"pods\" contained in enforceNodeAllocatable (--enforce-node-allocatable)", }, { name: "specify SystemCgroups without CgroupRoot", configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { @@ -399,6 +399,13 @@ func TestValidateKubeletConfiguration(t *testing.T) { return conf }, errMsg: "invalid configuration: enforceNodeAllocatable (--enforce-node-allocatable) may not contain additional enforcements when \"none\" is specified", + }, { + name: "duplicated EnforceNodeAllocatable", + configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { + conf.EnforceNodeAllocatable = []string{kubetypes.NodeAllocatableNoneKey, kubetypes.NodeAllocatableNoneKey} + return conf + }, + errMsg: "invalid configuration: duplicated enforcements \"none\" in enforceNodeAllocatable (--enforce-node-allocatable)", }, { name: "invalid EnforceNodeAllocatable", configure: func(conf *kubeletconfig.KubeletConfiguration) *kubeletconfig.KubeletConfiguration { diff --git a/pkg/kubelet/apis/config/validation/validation_windows.go b/pkg/kubelet/apis/config/validation/validation_windows.go index a6f0cba34c6..325b3cbab1a 100644 --- a/pkg/kubelet/apis/config/validation/validation_windows.go +++ b/pkg/kubelet/apis/config/validation/validation_windows.go @@ -22,7 +22,10 @@ package validation import ( "k8s.io/klog/v2" + "k8s.io/apimachinery/pkg/util/sets" + kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" + kubetypes "k8s.io/kubernetes/pkg/kubelet/types" ) // validateKubeletOSConfiguration validates os specific kubelet configuration and returns an error if it is invalid. @@ -33,7 +36,8 @@ func validateKubeletOSConfiguration(kc *kubeletconfig.KubeletConfiguration) erro klog.Warningf(message, "CgroupsPerQOS", "--cgroups-per-qos", kc.CgroupsPerQOS) } - if len(kc.EnforceNodeAllocatable) > 0 { + enforceNodeAllocatableWithoutNone := sets.New(kc.EnforceNodeAllocatable...).Delete(kubetypes.NodeAllocatableNoneKey) + if len(enforceNodeAllocatableWithoutNone) > 0 { klog.Warningf(message, "EnforceNodeAllocatable", "--enforce-node-allocatable", kc.EnforceNodeAllocatable) }