Skip to content

Commit 90656aa

Browse files
committed
fix(kubernetes): validate reservation formats and reject mixed eviction types
Signed-off-by: Arsolitt <[email protected]>
1 parent 8540b91 commit 90656aa

2 files changed

Lines changed: 220 additions & 0 deletions

File tree

‎packages/apps/kubernetes/templates/cluster.yaml‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,19 @@ metadata:
211211
{{- $kubeReservedCpu := $kubeletOverride.kubeReservedCpu | default "100m" }}
212212
{{- $evictionHardMemory := $kubeletOverride.evictionHardMemory | default "7%" }}
213213
{{- $evictionSoftMemory := $kubeletOverride.evictionSoftMemory | default "10%" }}
214+
{{/* Validate reservation field formats */}}
215+
{{- if and $kubeletOverride.systemReservedMemory (not (regexMatch `^[0-9]+(\.[0-9]+)?(Ki|Mi|Gi|Ti|Pi|Ei)?$` ($kubeletOverride.systemReservedMemory | toString))) }}
216+
{{- fail (printf "nodeGroup %s: invalid systemReservedMemory value %q — must be a valid Kubernetes memory quantity (e.g. 128Mi, 1Gi)" $groupName ($kubeletOverride.systemReservedMemory | toString)) }}
217+
{{- end }}
218+
{{- if and $kubeletOverride.kubeReservedMemory (not (regexMatch `^[0-9]+(\.[0-9]+)?(Ki|Mi|Gi|Ti|Pi|Ei)?$` ($kubeletOverride.kubeReservedMemory | toString))) }}
219+
{{- fail (printf "nodeGroup %s: invalid kubeReservedMemory value %q — must be a valid Kubernetes memory quantity (e.g. 128Mi, 1Gi)" $groupName ($kubeletOverride.kubeReservedMemory | toString)) }}
220+
{{- end }}
221+
{{- if and $kubeletOverride.systemReservedCpu (not (regexMatch `^[0-9]+(\.[0-9]+)?m?$` ($kubeletOverride.systemReservedCpu | toString))) }}
222+
{{- fail (printf "nodeGroup %s: invalid systemReservedCpu value %q — must be a valid Kubernetes CPU quantity (e.g. 100m, 0.5, 1)" $groupName ($kubeletOverride.systemReservedCpu | toString)) }}
223+
{{- end }}
224+
{{- if and $kubeletOverride.kubeReservedCpu (not (regexMatch `^[0-9]+(\.[0-9]+)?m?$` ($kubeletOverride.kubeReservedCpu | toString))) }}
225+
{{- fail (printf "nodeGroup %s: invalid kubeReservedCpu value %q — must be a valid Kubernetes CPU quantity (e.g. 100m, 0.5, 1)" $groupName ($kubeletOverride.kubeReservedCpu | toString)) }}
226+
{{- end }}
214227
{{- if and (hasSuffix "%" $evictionHardMemory) (hasSuffix "%" $evictionSoftMemory) }}
215228
{{- $hardPct := trimSuffix "%" $evictionHardMemory | float64 }}
216229
{{- $softPct := trimSuffix "%" $evictionSoftMemory | float64 }}
@@ -223,6 +236,8 @@ metadata:
223236
{{- if ge $hardBytes $softBytes }}
224237
{{- fail (printf "nodeGroup %s: evictionHardMemory (%s) must be strictly less than evictionSoftMemory (%s)" $groupName $evictionHardMemory $evictionSoftMemory) }}
225238
{{- end }}
239+
{{- else }}
240+
{{- fail (printf "nodeGroup %s: evictionHardMemory and evictionSoftMemory must use the same unit type (both percentage or both absolute) — got evictionHardMemory=%s, evictionSoftMemory=%s" $groupName $evictionHardMemory $evictionSoftMemory) }}
226241
{{- end }}
227242
---
228243
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1

‎packages/apps/kubernetes/tests/kubelet-reservation_test.yaml‎

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,3 +720,208 @@ tests:
720720
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.eviction-minimum-reclaim
721721
value: "memory.available=256Mi"
722722
documentIndex: 4
723+
724+
################################################
725+
# Mixed eviction threshold types must be rejected
726+
################################################
727+
728+
- it: rejects mixed eviction types (hard absolute, soft percentage)
729+
release:
730+
name: test-k8s
731+
namespace: tenant-test
732+
set:
733+
_namespace:
734+
etcd: etcd
735+
ingress: nginx
736+
host: example.com
737+
_cluster:
738+
cluster-domain: cozy.local
739+
nodeGroups:
740+
md0:
741+
minReplicas: 0
742+
maxReplicas: 10
743+
instanceType: ""
744+
ephemeralStorage: 20Gi
745+
roles:
746+
- worker
747+
resources: {}
748+
kubelet:
749+
evictionHardMemory: "1Gi"
750+
evictionSoftMemory: "10%"
751+
asserts:
752+
- failedTemplate:
753+
errorMessage: "nodeGroup md0: evictionHardMemory and evictionSoftMemory must use the same unit type (both percentage or both absolute) — got evictionHardMemory=1Gi, evictionSoftMemory=10%"
754+
755+
- it: rejects mixed eviction types reversed (hard percentage, soft absolute)
756+
release:
757+
name: test-k8s
758+
namespace: tenant-test
759+
set:
760+
_namespace:
761+
etcd: etcd
762+
ingress: nginx
763+
host: example.com
764+
_cluster:
765+
cluster-domain: cozy.local
766+
nodeGroups:
767+
md0:
768+
minReplicas: 0
769+
maxReplicas: 10
770+
instanceType: ""
771+
ephemeralStorage: 20Gi
772+
roles:
773+
- worker
774+
resources: {}
775+
kubelet:
776+
evictionHardMemory: "10%"
777+
evictionSoftMemory: "1Gi"
778+
asserts:
779+
- failedTemplate:
780+
errorMessage: "nodeGroup md0: evictionHardMemory and evictionSoftMemory must use the same unit type (both percentage or both absolute) — got evictionHardMemory=10%, evictionSoftMemory=1Gi"
781+
782+
################################################
783+
# Reservation field format validation #
784+
################################################
785+
786+
- it: rejects invalid CPU format for kubeReservedCpu
787+
release:
788+
name: test-k8s
789+
namespace: tenant-test
790+
set:
791+
_namespace:
792+
etcd: etcd
793+
ingress: nginx
794+
host: example.com
795+
_cluster:
796+
cluster-domain: cozy.local
797+
nodeGroups:
798+
md0:
799+
minReplicas: 0
800+
maxReplicas: 10
801+
instanceType: ""
802+
ephemeralStorage: 20Gi
803+
roles:
804+
- worker
805+
resources: {}
806+
kubelet:
807+
kubeReservedCpu: "banana"
808+
asserts:
809+
- failedTemplate:
810+
errorMessage: "nodeGroup md0: invalid kubeReservedCpu value \"banana\" — must be a valid Kubernetes CPU quantity (e.g. 100m, 0.5, 1)"
811+
812+
- it: rejects invalid memory format for systemReservedMemory
813+
release:
814+
name: test-k8s
815+
namespace: tenant-test
816+
set:
817+
_namespace:
818+
etcd: etcd
819+
ingress: nginx
820+
host: example.com
821+
_cluster:
822+
cluster-domain: cozy.local
823+
nodeGroups:
824+
md0:
825+
minReplicas: 0
826+
maxReplicas: 10
827+
instanceType: ""
828+
ephemeralStorage: 20Gi
829+
roles:
830+
- worker
831+
resources: {}
832+
kubelet:
833+
systemReservedMemory: "abc"
834+
asserts:
835+
- failedTemplate:
836+
errorMessage: "nodeGroup md0: invalid systemReservedMemory value \"abc\" — must be a valid Kubernetes memory quantity (e.g. 128Mi, 1Gi)"
837+
838+
################################################
839+
# Multi-nodeGroup isolation test #
840+
################################################
841+
842+
- it: renders independent kubelet args for multiple node groups
843+
release:
844+
name: test-k8s
845+
namespace: tenant-test
846+
set:
847+
_namespace:
848+
etcd: etcd
849+
ingress: nginx
850+
host: example.com
851+
_cluster:
852+
cluster-domain: cozy.local
853+
nodeGroups:
854+
md0:
855+
minReplicas: 0
856+
maxReplicas: 10
857+
instanceType: ""
858+
ephemeralStorage: 20Gi
859+
roles:
860+
- worker
861+
resources: {}
862+
md1:
863+
minReplicas: 1
864+
maxReplicas: 5
865+
instanceType: ""
866+
ephemeralStorage: 40Gi
867+
roles:
868+
- worker
869+
resources: {}
870+
kubelet:
871+
systemReservedMemory: "512Mi"
872+
kubeReservedMemory: "256Mi"
873+
systemReservedCpu: "200m"
874+
kubeReservedCpu: "150m"
875+
evictionHardMemory: "5%"
876+
evictionSoftMemory: "15%"
877+
asserts:
878+
# md0 at documentIndex 4: defaults
879+
- isKind:
880+
of: KubeadmConfigTemplate
881+
documentIndex: 4
882+
- equal:
883+
path: metadata.name
884+
value: test-k8s-md0
885+
documentIndex: 4
886+
- equal:
887+
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.system-reserved
888+
value: "memory=64Mi,cpu=100m"
889+
documentIndex: 4
890+
- equal:
891+
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.kube-reserved
892+
value: "memory=64Mi,cpu=100m"
893+
documentIndex: 4
894+
- equal:
895+
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.eviction-hard
896+
value: "memory.available<7%"
897+
documentIndex: 4
898+
- equal:
899+
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.eviction-soft
900+
value: "memory.available<10%"
901+
documentIndex: 4
902+
# md1 at documentIndex 9: custom overrides
903+
# (each nodeGroup emits 5 documents: KubeadmConfigTemplate, KubevirtMachineTemplate,
904+
# MachineDeployment, MachineHealthCheck, WorkloadMonitor)
905+
- isKind:
906+
of: KubeadmConfigTemplate
907+
documentIndex: 9
908+
- equal:
909+
path: metadata.name
910+
value: test-k8s-md1
911+
documentIndex: 9
912+
- equal:
913+
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.system-reserved
914+
value: "memory=512Mi,cpu=200m"
915+
documentIndex: 9
916+
- equal:
917+
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.kube-reserved
918+
value: "memory=256Mi,cpu=150m"
919+
documentIndex: 9
920+
- equal:
921+
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.eviction-hard
922+
value: "memory.available<5%"
923+
documentIndex: 9
924+
- equal:
925+
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.eviction-soft
926+
value: "memory.available<15%"
927+
documentIndex: 9

0 commit comments

Comments
 (0)