fix(argocd): pin activity-core child to live 8884b12 and add pin drift check
Two attended activity-core releases patched the live Application without committing the pin, so a hand sync of railiance-apps-root would have rolled activity-core back to ce9a8f8. Git now matches live (no sync run). make argocd-pin-drift compares all railiance01 child pins with live and is required before root syncs. informed-decision drift is flagged for its owner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 244572@bnt-lap001 Assistant-Session: 3b235e1a-ae45-4d0f-ae70-17a9bd78ece8
This commit is contained in:
parent
53d34bc4f4
commit
141609f96f
6 changed files with 137 additions and 1 deletions
61
scripts/argocd_child_pin_drift.py
Normal file
61
scripts/argocd_child_pin_drift.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Read-only drift check between child Application pins in Git and on railiance01.
|
||||
|
||||
`railiance-apps-root` syncs by hand from `argocd/railiance01/applications`. If a
|
||||
release patches a child's live targetRevision without committing the same pin
|
||||
here, the next root sync silently rolls that child back. Run this before any
|
||||
root sync and after every release. Exit 1 on drift, 2 on a read failure.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import yaml
|
||||
|
||||
APPS_DIR = Path(__file__).resolve().parent.parent / "argocd/railiance01/applications"
|
||||
|
||||
|
||||
def declared() -> dict[str, str]:
|
||||
pins = {}
|
||||
for path in sorted(APPS_DIR.glob("*.y*ml")):
|
||||
for doc in yaml.safe_load_all(path.read_text()):
|
||||
if doc and doc.get("kind") == "Application":
|
||||
pins[doc["metadata"]["name"]] = doc["spec"]["source"]["targetRevision"]
|
||||
return pins
|
||||
|
||||
|
||||
def live() -> dict[str, str]:
|
||||
out = subprocess.run(
|
||||
["kubectl", "-n", "argocd", "get", "applications.argoproj.io", "-o", "json"],
|
||||
capture_output=True, text=True, check=True,
|
||||
).stdout
|
||||
return {
|
||||
item["metadata"]["name"]: item["spec"].get("source", {}).get("targetRevision", "")
|
||||
for item in json.loads(out)["items"]
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
try:
|
||||
running = live()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError) as exc:
|
||||
print(f"ERROR: cannot read live Applications: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
drift = 0
|
||||
for name, pin in declared().items():
|
||||
current = running.get(name)
|
||||
if current == pin:
|
||||
print(f"ok {name} {pin[:12]}")
|
||||
else:
|
||||
drift += 1
|
||||
print(f"DRIFT {name} git={pin[:12]} live={(current or 'absent')[:12]}")
|
||||
if drift:
|
||||
print(f"{drift} child pin(s) differ: commit the live pin here (or revert live) "
|
||||
"before syncing railiance-apps-root.", file=sys.stderr)
|
||||
return 1 if drift else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue