64 lines
2.3 KiB
Python
64 lines
2.3 KiB
Python
# requires: yaml
|
|
"""对清单做团队规范检查(kubeconform 只校验结构,这里检查“写对了但不合规范”的问题)。
|
|
|
|
运行:pytest -q test_manifests.py
|
|
结构校验(可选):kubeconform -strict -summary *.yaml
|
|
"""
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
HERE = Path(__file__).parent
|
|
|
|
|
|
def load_all() -> list[dict]:
|
|
docs = []
|
|
for f in sorted(HERE.glob("*.yaml")):
|
|
docs += [d for d in yaml.safe_load_all(f.read_text(encoding="utf-8")) if d]
|
|
return docs
|
|
|
|
|
|
DOCS = load_all()
|
|
|
|
|
|
def by_kind(kind: str) -> list[dict]:
|
|
return [d for d in DOCS if d["kind"] == kind]
|
|
|
|
|
|
def test_selector_matches_pod_labels():
|
|
for dep in by_kind("Deployment"):
|
|
sel = dep["spec"]["selector"]["matchLabels"]
|
|
labels = dep["spec"]["template"]["metadata"]["labels"]
|
|
assert sel.items() <= labels.items()
|
|
for svc in by_kind("Service"):
|
|
assert svc["spec"]["selector"].items() <= labels.items(), "Service 选择器和 Pod 标签不一致"
|
|
|
|
|
|
def test_containers_follow_rules():
|
|
for dep in by_kind("Deployment"):
|
|
for c in dep["spec"]["template"]["spec"]["containers"]:
|
|
image = c["image"]
|
|
assert ":" in image.rsplit("/", 1)[-1] and not image.endswith(":latest"), "镜像必须固定版本"
|
|
assert "requests" in c["resources"] and "memory" in c["resources"].get("limits", {})
|
|
for probe in ("readinessProbe", "livenessProbe"):
|
|
assert probe in c, f"缺少 {probe}"
|
|
assert c["securityContext"]["allowPrivilegeEscalation"] is False
|
|
for e in c.get("env", []):
|
|
assert "value" not in e or "KEY" not in e["name"].upper(), "密钥不能明文写在清单中"
|
|
|
|
|
|
def test_rolling_update_keeps_capacity():
|
|
for dep in by_kind("Deployment"):
|
|
ru = dep["spec"]["strategy"]["rollingUpdate"]
|
|
assert ru["maxUnavailable"] == 0
|
|
|
|
|
|
def test_pdb_lower_than_min_replicas():
|
|
hpa_min = min(h["spec"]["minReplicas"] for h in by_kind("HorizontalPodAutoscaler"))
|
|
for pdb in by_kind("PodDisruptionBudget"):
|
|
assert pdb["spec"]["minAvailable"] < hpa_min, "PDB 要求的可用数不小于副本数会导致节点无法驱逐"
|
|
|
|
|
|
def test_no_secret_objects_in_repo():
|
|
assert not by_kind("Secret"), "Secret 不应提交到仓库"
|