76 lines
2.3 KiB
Python
76 lines
2.3 KiB
Python
# -*- coding: utf-8 -*-
|
||||
|
|
"""Helm Chart 结构 sanity 检查(无 helm CLI 环境下的离线基本验证)。
|
|||
|
|
|
|||
|
|
检查项:
|
|||
|
|
1. Chart.yaml / values.yaml 均为合法 YAML;
|
|||
|
|
2. templates/ 下所有模板文件存在且非空;
|
|||
|
|
3. 模板中引用的 `.Values.xxx` 键均能在 values.yaml 中找到(防拼写错误);
|
|||
|
|
4. 每个模板文件的 Go template 标记 `{{` / `}}` 数量配平。
|
|||
|
|
|
|||
|
|
用法:python _sanity_check.py
|
|||
|
|
"""
|
|||
|
|
import os
|
|||
|
|
import re
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|||
|
|
TEMPLATES = os.path.join(HERE, "templates")
|
|||
|
|
|
|||
|
|
import yaml # noqa: E402
|
|||
|
|
|
|||
|
|
|
|||
|
|
def load(path):
|
|||
|
|
with open(path, "r", encoding="utf-8") as fh:
|
|||
|
|
return yaml.safe_load(fh)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def values_paths(text):
|
|||
|
|
"""提取模板文本中的 .Values.<a>.<b> 路径集合。"""
|
|||
|
|
return set(re.findall(r"\.Values\.([A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)*)", text))
|
|||
|
|
|
|||
|
|
|
|||
|
|
def resolve(values, dotted):
|
|||
|
|
node = values
|
|||
|
|
for key in dotted.split("."):
|
|||
|
|
if not isinstance(node, dict) or key not in node:
|
|||
|
|
return False
|
|||
|
|
node = node[key]
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
failures = []
|
|||
|
|
|
|||
|
|
chart = load(os.path.join(HERE, "Chart.yaml"))
|
|||
|
|
assert chart.get("apiVersion") == "v2", "Chart.yaml 应为 Helm v2 chart"
|
|||
|
|
assert chart.get("name") == "iaop", "Chart.name 应为 iaop"
|
|||
|
|
|
|||
|
|
values = load(os.path.join(HERE, "values.yaml"))
|
|||
|
|
assert values.get("inference", {}).get("backend") in ("gpu", "npu"), \
|
|||
|
|
"values.inference.backend 应为 gpu|npu"
|
|||
|
|
|
|||
|
|
for name in sorted(os.listdir(TEMPLATES)):
|
|||
|
|
path = os.path.join(TEMPLATES, name)
|
|||
|
|
if not os.path.isfile(path):
|
|||
|
|
continue
|
|||
|
|
text = open(path, "r", encoding="utf-8").read()
|
|||
|
|
if not text.strip():
|
|||
|
|
failures.append(f"{name}: 模板文件为空")
|
|||
|
|
continue
|
|||
|
|
if text.count("{{") != text.count("}}"):
|
|||
|
|
failures.append(f"{name}: Go template 标记 {{/}} 数量不配平")
|
|||
|
|
for dotted in values_paths(text):
|
|||
|
|
if not resolve(values, dotted):
|
|||
|
|
failures.append(f"{name}: 引用了 values.yaml 中不存在的键 .Values.{dotted}")
|
|||
|
|
|
|||
|
|
if failures:
|
|||
|
|
print("FAIL")
|
|||
|
|
for f in failures:
|
|||
|
|
print(" -", f)
|
|||
|
|
sys.exit(1)
|
|||
|
|
print(f"OK: Chart/values 合法,templates/{len(os.listdir(TEMPLATES))} 个模板校验通过")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|