Решали с коллегами задачу по генерации манифестов Provisioner в цикле, при таком создании есть один деструктивный момент - нужно выбрать Container Runtime Interface (CRI), иначе provisioner.spec.kubeletConfiguration.containerRuntime
в манифесте Provisioner в паре с AWSNodeTemplate karpenter по дефолту выставят нам containerd
(подтверждение в тесте)
Собрали ряд требований:
- CRI не указан в провиженере, значит выбираем дефолтный для нас (в нашем случае dockerd)
- CRI указан в провиженере, выбираем его
- CRI не указан в провиженере, но в
provisioner.spec.kubeletConfiguration
есть другие параметры
Получился следующий код валидации:
helm
# Kubelet
# If Provisioner.kubeletConfiguration is not empty
{{- if .kubeletConfiguration }}
kubeletConfiguration:
# If containerRuntime has been configured in Provisioner.kubeletConfiguration
{{- if hasKey .kubeletConfiguration "containerRuntime" -}}
{{- toYaml .kubeletConfiguration | nindent 4 }}
# ElseIf containerRuntime has not been configured in Provisioner.kubeletConfiguration
{{- else }}
# Pick default CRI from karpenter.default.kubeletConfiguration and add it to current .kubeletConfiguration
{{- $CRI := dict "containerRuntime" $.Values.karpenter.default.kubeletConfiguration.containerRuntime -}}
{{- $kubeletConfiguration := merge $CRI .kubeletConfiguration }}
{{- toYaml $kubeletConfiguration | nindent 4 }}
{{- end }}
# ElseIf Provisioner.kubeletConfiguration is empty
{{- else }}
kubeletConfiguration:
{{- toYaml $.Values.karpenter.default.kubeletConfiguration | nindent 4 }}
{{- end }}
Тесты
Test cases:
- 1) CRI не указан в провиженере values.yml
karpenter:
payload:
ahorbach:
foo: bar
result:
spec:
# Kubelet
# If Provisioner.kubeletConfiguration is not empty
kubeletConfiguration:
containerRuntime: dockerd
- 2) CRI указан в провиженере
values.yml
karpenter:
payload:
ahorbach:
kubeletConfiguration:
bar: baz
containerRuntime: rocket
result:
spec:
# Kubelet
# If Provisioner.kubeletConfiguration is not empty
kubeletConfiguration:
# If containerRuntime has been configured in Provisioner.kubeletConfiguration
bar: baz
containerRuntime: rocket
# ElseIf containerRuntime has not been configured in Provisioner.kubeletConfiguration
# ElseIf Provisioner.kubeletConfiguration is empty
- 3) CRI не указан в провиженере, но есть конфиг
values.yml
payload:
ahorbach:
kubeletConfiguration:
spam: eggs
result:
spec:
# Kubelet
# If Provisioner.kubeletConfiguration is not empty
kubeletConfiguration:
# If containerRuntime has been configured in Provisioner.kubeletConfiguration
# Pick default CRI from karpenter.default.kubeletConfiguration and add it to current .kubeletConfiguration
containerRuntime: dockerd
spam: eggs
python
from pydantic import BaseModel, validator
DEFAULT_CRI = {"containerRuntime": "dockerd"}
class karpenterPayloadProvisioner(BaseModel):
name: str
kubelet_configuration: dict = DEFAULT_CRI
@validator('kubelet_configuration')
def kubelet_container_runtime(cls, v):
cri = v.get("containerRuntime")
# option two - Mutating
if cri not in ["dockerd", "containerd"]:
v.update(DEFAULT_CRI)
return v
Тесты
import typing as t
import pytest
from karpenter import karpenterPayloadProvisioner
# without selected CRI in Provisioner
case1 = ("foo", {}, "dockerd")
# with containerd as a CRI for Provisioner
case2 = ("bar", {"kubeReserved": "testMe", "containerRuntime": "containerd"}, "containerd")
# with typo in CRI for Provisioner
case3 = ("baz", {"kubeReserved": "testMe", "containerRuntime": "qwerty"}, "dockerd")
test_cases = [
case1,
case2,
case3,
]
@pytest.mark.parametrize("name, kubelet_configuration, expected_CRI", test_cases)
def test_cri_provisioner(name: str, kubelet_configuration: t.Optional[dict], expected_CRI: str):
provisioner = karpenterPayloadProvisioner(name=name, kubelet_configuration=kubelet_configuration)
assert provisioner.kubelet_configuration["containerRuntime"] == expected_CRI
pytest .
=========================================================== test session starts ============================================================
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /Users/a.horbach/repository-self/python-monorepo/pydantic-karpenter
plugins: django-4.4.0, cov-3.0.0
collected 3 items
test_karpenter.py ... [100%]
============================================================ 3 passed in 0.08s =============================================================