claim(2w): WC8 + WC9 (FINAL gates) — resource-safety consolidation + stale-warm prune + docs/warm.md + --quick rollback proof
WC8: canonical.prune_stale (drop de-enrolled warm data + volumes) wired into the nightly sweep + df log; consolidated evidence (DRONE_RUNNER_CAPACITY=MAX_TESTS serialize; autoPrune drops --volumes so warm vols survive; cold teardown sacred; warm excluded from D8 — no nix source ref). +1 unit (72 pass). WC9: docs/warm.md documents the full warm/quick model; --quick rollback proof already proven live (W2 FAIL restores exact known-good; WC4 PASS byte-identical snapshot). On PASS, all WC1-WC9 (incl WC1.1/WC1.2) verified → DONE. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -138,6 +138,36 @@ def undeploy_keep_volume(recipe: str) -> None:
|
||||
_set_status(recipe, "idle")
|
||||
|
||||
|
||||
def prune_stale() -> list[str]:
|
||||
"""WC8 disk hygiene: remove warm data for DE-ENROLLED canonicals — a `/var/lib/ci-warm/<recipe>/`
|
||||
that carries a `canonical.json` but whose recipe is no longer enrolled (WARM_CANONICAL dropped).
|
||||
Drops the dir (snapshot + registry) AND the retained `warm-<recipe>` data volumes. Leaves the
|
||||
live-warm reconciler dirs (keycloak/traefik — they have a `last_good`, no `canonical.json`),
|
||||
`alerts/`, and currently-enrolled canonicals untouched. Returns the recipes pruned."""
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
root = warmsnap.warm_root()
|
||||
keep = set(enrolled_recipes())
|
||||
pruned: list[str] = []
|
||||
try:
|
||||
entries = sorted(os.listdir(root))
|
||||
except OSError:
|
||||
return pruned
|
||||
for name in entries:
|
||||
d = os.path.join(root, name)
|
||||
if not os.path.isdir(d) or name in keep:
|
||||
continue
|
||||
if not os.path.isfile(os.path.join(d, "canonical.json")):
|
||||
continue # not a data-warm canonical (e.g. keycloak/traefik reconciler dir, alerts/)
|
||||
# drop the retained warm-<recipe> volumes, then the snapshot/registry dir
|
||||
for vol in warmsnap.stack_volumes(canonical_domain(name)):
|
||||
subprocess.run(["docker", "volume", "rm", vol], capture_output=True, text=True)
|
||||
shutil.rmtree(d, ignore_errors=True)
|
||||
pruned.append(name)
|
||||
return pruned
|
||||
|
||||
|
||||
def seed_canonical(recipe: str, version: str, commit: str | None = None) -> dict:
|
||||
"""Record <warm-domain> (already deployed at `version`) as the recipe's canonical: write the
|
||||
registry, then (app must be UNDEPLOYED) take the known-good snapshot. Caller deploys + verifies
|
||||
|
||||
@ -68,6 +68,12 @@ def sweep() -> int:
|
||||
).returncode
|
||||
results[r] = rc
|
||||
print(f"nightly: {r} rc={rc} ({'green→canonical refreshed' if rc == 0 else 'red'})", flush=True)
|
||||
# WC8 disk hygiene: drop warm data for de-enrolled canonicals; log the disk budget.
|
||||
pruned = canonical.prune_stale()
|
||||
if pruned:
|
||||
print(f"nightly: pruned stale warm data for de-enrolled canonicals: {pruned}", flush=True)
|
||||
df = subprocess.run(["df", "-h", "/"], capture_output=True, text=True)
|
||||
print(f"nightly: disk / →\n{df.stdout.strip()}", flush=True)
|
||||
print("\n===== nightly sweep summary =====", flush=True)
|
||||
for r, rc in results.items():
|
||||
print(f" {r}: {'PASS' if rc == 0 else 'FAIL'}", flush=True)
|
||||
|
||||
Reference in New Issue
Block a user