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:
parent
b3f12b2ffa
commit
36050b100f
17 changed files with 1890 additions and 0 deletions
92
scripts/vendor_custodian_allocation_review.py
Normal file
92
scripts/vendor_custodian_allocation_review.py
Normal 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())
|
||||
Loading…
Add table
Add a link
Reference in a new issue