CUST-WP-0071-T05: prepare weekly allocation assessment CronJob (suspended, unregistered)

New platform addon custodian-allocation-review: namespace custodian-assessment,
read-only ClusterRole (get/list nodes, pods, PVCs, PVs, storageclasses,
metrics.k8s.io nodes/pods), retained local-path PVC (Prune=false,Delete=false),
CronJob 0 8 * * 1 Europe/Berlin, Forbid, suspend: true. Code/data vendored from
the-custodian, railiance-cluster and resource-control with a sha256 lock and
an offline guard test. Draft Application only in drafts/; nothing is synced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 8340@bnt-lap001
Assistant-Session: 2e192b3d-b3e8-4403-94d4-d55a2c8b476c
This commit is contained in:
codex 2026-10-21 08:15:18 +02:00
parent b3f12b2ffa
commit 36050b100f
17 changed files with 1890 additions and 0 deletions

View file

@ -0,0 +1,92 @@
#!/usr/bin/env python3
"""Vendor or verify the CUST-WP-0071-T05 weekly allocation assessment sources.
The CronJob mounts its code and data from a ConfigMap generated from
argocd/platform-addons/custodian-allocation-review/src/. Owner sources stay in
their repositories; this script copies them at an exact clean commit and writes
vendor.lock.json (repo, commit, path, sha256). The YAML ownership map is
rendered to JSON so the job needs no PyYAML.
scripts/vendor_custodian_allocation_review.py # refresh from ~/<repo>
scripts/vendor_custodian_allocation_review.py --check # lock matches src/
"""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
import subprocess
import sys
ROOT = Path(__file__).resolve().parents[1]
ADDON = ROOT / "argocd/platform-addons/custodian-allocation-review"
SOURCES = {
"weekly_allocation_incluster.py": ("the-custodian", "scripts/weekly_allocation_incluster.py"),
"weekly_allocation_report.py": ("the-custodian", "scripts/weekly_allocation_report.py"),
"reconcile_railiance_allocation.py": ("the-custodian", "scripts/reconcile_railiance_allocation.py"),
"weekly-allocation-queries.json": ("the-custodian", "config/weekly-allocation-queries.json"),
"namespace-ownership.json": ("the-custodian", "docs/evidence/namespace-ownership.yaml"),
"observe_cluster_resources.py": ("railiance-cluster", "tools/observe_cluster_resources.py"),
"reef-railiance-k3s.json": ("resource-control", "data/resources/reef-railiance-k3s.json"),
}
def sha(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def git(repo: Path, *args: str) -> str:
return subprocess.check_output(["git", "-C", str(repo), *args], text=True).strip()
def refresh(base: Path) -> dict:
lock = {"schema": "railiance-platform.vendor-lock.v1", "workplan": "CUST-WP-0071-T05", "files": {}}
(ADDON / "src").mkdir(parents=True, exist_ok=True)
for name, (repo, path) in sorted(SOURCES.items()):
checkout = base / repo
if git(checkout, "status", "--porcelain", "--", path):
raise SystemExit(f"{repo}/{path} has uncommitted changes; commit it first")
commit = git(checkout, "rev-parse", "HEAD")
source = subprocess.check_output(["git", "-C", str(checkout), "show", f"{commit}:{path}"])
data = source
if path.endswith(".yaml"):
import yaml
data = (json.dumps(yaml.safe_load(source), indent=2, sort_keys=True) + "\n").encode()
(ADDON / "src" / name).write_bytes(data)
lock["files"][name] = {"repo": repo, "commit": commit, "path": path,
"source_sha256": sha(source), "vendored_sha256": sha(data)}
(ADDON / "vendor.lock.json").write_text(json.dumps(lock, indent=2, sort_keys=True) + "\n")
return lock
def check() -> list[str]:
lock = json.loads((ADDON / "vendor.lock.json").read_text())
problems = []
if set(lock["files"]) != set(SOURCES):
problems.append("lock file set differs from SOURCES")
for name, entry in lock["files"].items():
target = ADDON / "src" / name
if not target.exists() or sha(target.read_bytes()) != entry["vendored_sha256"]:
problems.append(f"{name}: vendored content does not match vendor.lock.json")
return problems
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--check", action="store_true")
parser.add_argument("--base", type=Path, default=Path.home(), help="directory holding the owner checkouts")
args = parser.parse_args()
if args.check:
problems = check()
for problem in problems:
print(problem, file=sys.stderr)
return 1 if problems else 0
lock = refresh(args.base)
for name, entry in sorted(lock["files"].items()):
print(f"{name}: {entry['repo']}@{entry['commit'][:12]} {entry['vendored_sha256'][:12]}")
return 0
if __name__ == "__main__":
raise SystemExit(main())