mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-09 22:13:18 +09:00
fix(kubernetes): validate absolute eviction format and guard against memory over-reservation
Add regex format validation for absolute eviction threshold values before they reach toFloat conversion, preventing silent zero returns on invalid input like "banana". Add a check that systemReservedMemory + kubeReservedMemory does not exceed effective node memory. Include helm unit tests for both validations. Signed-off-by: Arsolitt <arsolitt@gmail.com>
This commit is contained in:
2 files changed
+206
No files matched your search
@@ -224,6 +224,17 @@ metadata:
|
||||
{{- if and $kubeletOverride.kubeReservedCpu (not (regexMatch `^[0-9]+(\.[0-9]+)?m?$` ($kubeletOverride.kubeReservedCpu | toString))) }}
|
||||
{{- 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)) }}
|
||||
{{- end }}
|
||||
{{/* Validate absolute eviction threshold formats before converting */}}
|
||||
{{- if not (hasSuffix "%" $evictionHardMemory) }}
|
||||
{{- if not (regexMatch `^[0-9]+(\.[0-9]+)?(Ki|Mi|Gi|Ti|Pi|Ei)?$` $evictionHardMemory) }}
|
||||
{{- fail (printf "nodeGroup %s: invalid evictionHardMemory value %q — must be a percentage (e.g. 7%%) or a valid Kubernetes memory quantity (e.g. 500Mi, 1Gi)" $groupName $evictionHardMemory) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if not (hasSuffix "%" $evictionSoftMemory) }}
|
||||
{{- if not (regexMatch `^[0-9]+(\.[0-9]+)?(Ki|Mi|Gi|Ti|Pi|Ei)?$` $evictionSoftMemory) }}
|
||||
{{- fail (printf "nodeGroup %s: invalid evictionSoftMemory value %q — must be a percentage (e.g. 10%%) or a valid Kubernetes memory quantity (e.g. 500Mi, 1Gi)" $groupName $evictionSoftMemory) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and (hasSuffix "%" $evictionHardMemory) (hasSuffix "%" $evictionSoftMemory) }}
|
||||
{{- $hardPct := trimSuffix "%" $evictionHardMemory | float64 }}
|
||||
{{- $softPct := trimSuffix "%" $evictionSoftMemory | float64 }}
|
||||
@@ -239,6 +250,16 @@ metadata:
|
||||
{{- else }}
|
||||
{{- 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) }}
|
||||
{{- end }}
|
||||
{{/* Validate that reserved memory does not exceed effective node memory */}}
|
||||
{{- if $effectiveMemory }}
|
||||
{{- $sysBytes := include "cozy-lib.resources.toFloat" $systemReservedMemory | float64 }}
|
||||
{{- $kubeBytes := include "cozy-lib.resources.toFloat" $kubeReservedMemory | float64 }}
|
||||
{{- $totalReservedBytes := mulf $sysBytes 1.0 | addf $kubeBytes }}
|
||||
{{- $effectiveMemBytes := include "cozy-lib.resources.toFloat" $effectiveMemory | float64 }}
|
||||
{{- if ge $totalReservedBytes $effectiveMemBytes }}
|
||||
{{- fail (printf "nodeGroup %s: total reserved memory (systemReservedMemory=%s + kubeReservedMemory=%s) must be less than effective node memory (%s)" $groupName $systemReservedMemory $kubeReservedMemory $effectiveMemory) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
|
||||
kind: KubeadmConfigTemplate
|
||||
|
||||
@@ -925,3 +925,188 @@ tests:
|
||||
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.eviction-soft
|
||||
value: "memory.available<15%"
|
||||
documentIndex: 9
|
||||
|
||||
################################################
|
||||
# Absolute eviction format validation #
|
||||
################################################
|
||||
|
||||
- it: rejects invalid format for absolute evictionHardMemory
|
||||
release:
|
||||
name: test-k8s
|
||||
namespace: tenant-test
|
||||
set:
|
||||
_namespace:
|
||||
etcd: etcd
|
||||
ingress: nginx
|
||||
host: example.com
|
||||
_cluster:
|
||||
cluster-domain: cozy.local
|
||||
nodeGroups:
|
||||
md0:
|
||||
minReplicas: 0
|
||||
maxReplicas: 10
|
||||
instanceType: ""
|
||||
ephemeralStorage: 20Gi
|
||||
roles:
|
||||
- worker
|
||||
resources: {}
|
||||
kubelet:
|
||||
evictionHardMemory: "banana"
|
||||
evictionSoftMemory: "500Mi"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "nodeGroup md0: invalid evictionHardMemory value \"banana\" — must be a percentage (e.g. 7%) or a valid Kubernetes memory quantity (e.g. 500Mi, 1Gi)"
|
||||
|
||||
- it: rejects invalid format for absolute evictionSoftMemory
|
||||
release:
|
||||
name: test-k8s
|
||||
namespace: tenant-test
|
||||
set:
|
||||
_namespace:
|
||||
etcd: etcd
|
||||
ingress: nginx
|
||||
host: example.com
|
||||
_cluster:
|
||||
cluster-domain: cozy.local
|
||||
nodeGroups:
|
||||
md0:
|
||||
minReplicas: 0
|
||||
maxReplicas: 10
|
||||
instanceType: ""
|
||||
ephemeralStorage: 20Gi
|
||||
roles:
|
||||
- worker
|
||||
resources: {}
|
||||
kubelet:
|
||||
evictionHardMemory: "200Mi"
|
||||
evictionSoftMemory: "not-a-quantity"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "nodeGroup md0: invalid evictionSoftMemory value \"not-a-quantity\" — must be a percentage (e.g. 10%) or a valid Kubernetes memory quantity (e.g. 500Mi, 1Gi)"
|
||||
|
||||
- it: accepts valid absolute eviction thresholds with correct format
|
||||
release:
|
||||
name: test-k8s
|
||||
namespace: tenant-test
|
||||
set:
|
||||
_namespace:
|
||||
etcd: etcd
|
||||
ingress: nginx
|
||||
host: example.com
|
||||
_cluster:
|
||||
cluster-domain: cozy.local
|
||||
nodeGroups:
|
||||
md0:
|
||||
minReplicas: 0
|
||||
maxReplicas: 10
|
||||
instanceType: ""
|
||||
ephemeralStorage: 20Gi
|
||||
roles:
|
||||
- worker
|
||||
resources: {}
|
||||
kubelet:
|
||||
evictionHardMemory: "500Mi"
|
||||
evictionSoftMemory: "1Gi"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.eviction-hard
|
||||
value: "memory.available<500Mi"
|
||||
documentIndex: 4
|
||||
- equal:
|
||||
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.eviction-soft
|
||||
value: "memory.available<1Gi"
|
||||
documentIndex: 4
|
||||
|
||||
####################################################
|
||||
# Reserved memory exceeds node memory validation #
|
||||
####################################################
|
||||
|
||||
- it: rejects reserved memory exceeding effective node memory
|
||||
release:
|
||||
name: test-k8s
|
||||
namespace: tenant-test
|
||||
set:
|
||||
_namespace:
|
||||
etcd: etcd
|
||||
ingress: nginx
|
||||
host: example.com
|
||||
_cluster:
|
||||
cluster-domain: cozy.local
|
||||
nodeGroups:
|
||||
md0:
|
||||
minReplicas: 0
|
||||
maxReplicas: 10
|
||||
instanceType: ""
|
||||
ephemeralStorage: 20Gi
|
||||
roles:
|
||||
- worker
|
||||
resources:
|
||||
memory: "1Gi"
|
||||
kubelet:
|
||||
systemReservedMemory: "512Mi"
|
||||
kubeReservedMemory: "600Mi"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "nodeGroup md0: total reserved memory (systemReservedMemory=512Mi + kubeReservedMemory=600Mi) must be less than effective node memory (1Gi)"
|
||||
|
||||
- it: rejects reserved memory equal to effective node memory
|
||||
release:
|
||||
name: test-k8s
|
||||
namespace: tenant-test
|
||||
set:
|
||||
_namespace:
|
||||
etcd: etcd
|
||||
ingress: nginx
|
||||
host: example.com
|
||||
_cluster:
|
||||
cluster-domain: cozy.local
|
||||
nodeGroups:
|
||||
md0:
|
||||
minReplicas: 0
|
||||
maxReplicas: 10
|
||||
instanceType: ""
|
||||
ephemeralStorage: 20Gi
|
||||
roles:
|
||||
- worker
|
||||
resources:
|
||||
memory: "1Gi"
|
||||
kubelet:
|
||||
systemReservedMemory: "512Mi"
|
||||
kubeReservedMemory: "512Mi"
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorMessage: "nodeGroup md0: total reserved memory (systemReservedMemory=512Mi + kubeReservedMemory=512Mi) must be less than effective node memory (1Gi)"
|
||||
|
||||
- it: allows reserved memory within effective node memory bounds
|
||||
release:
|
||||
name: test-k8s
|
||||
namespace: tenant-test
|
||||
set:
|
||||
_namespace:
|
||||
etcd: etcd
|
||||
ingress: nginx
|
||||
host: example.com
|
||||
_cluster:
|
||||
cluster-domain: cozy.local
|
||||
nodeGroups:
|
||||
md0:
|
||||
minReplicas: 0
|
||||
maxReplicas: 10
|
||||
instanceType: ""
|
||||
ephemeralStorage: 20Gi
|
||||
roles:
|
||||
- worker
|
||||
resources:
|
||||
memory: "4Gi"
|
||||
kubelet:
|
||||
systemReservedMemory: "512Mi"
|
||||
kubeReservedMemory: "512Mi"
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.system-reserved
|
||||
value: "memory=512Mi,cpu=100m"
|
||||
documentIndex: 4
|
||||
- equal:
|
||||
path: spec.template.spec.joinConfiguration.nodeRegistration.kubeletExtraArgs.kube-reserved
|
||||
value: "memory=512Mi,cpu=100m"
|
||||
documentIndex: 4
|
||||
Reference in new issue
Block a user