Some checks failed
continuous-integration/drone/push Build is failing
The M2 keycloak enrollment made the canonical collision-free at the DOMAIN layer
(warm-canon-keycloak vs warm-keycloak) but warm STATE stayed keyed by bare recipe:
warmsnap.app_dir("keycloak") resolved both the live-warm reconciler's last_good and
the data-warm canonical's canonical.json + snapshot/ into /var/lib/ci-warm/keycloak/.
snapshot() atomically REPLACES that slot, so the two deployments destroyed each
other's known-good; restore() then raised SnapshotError (fails closed, no cross-stack
data write). Worst case: a sweep promote landing inside the reconciler's
snapshot->wait_healthy window makes its rollback restore() raise after
abra.undeploy(live), leaving the shared OIDC provider undeployed.
Fix: canonical.canonical_ns() is now the single namespace from which BOTH the
canonical's domain and its warm-state slot derive, so they cannot drift apart. A
live-warm provider gets ns "canon-<recipe>": domain warm-canon-keycloak (unchanged)
and slot /var/lib/ci-warm/canon-keycloak/. Every other recipe keeps ns "<recipe>" —
zero on-disk change for the 15 existing canonicals, and no migration on cc-ci
(keycloak's canonical was never seeded: its dir holds only last_good).
- warmsnap: functions take a SLOT, not a recipe; add live_slot(); meta records "slot".
- warmsnap: _assert_slot_not_foreign() refuses to snapshot/restore a slot recorded
against a different domain -- defence in depth, naming-scheme-independent, fails
before the destructive swap rather than at the next restore.
- canonical: registry_path/seed_canonical/prune_stale go through canonical_slot().
- prune_stale: the "reconciler dirs are never pruned" invariant is now STRUCTURAL --
<recipe>/ never gains a canonical.json, so de-enrolling keycloak can no longer
rmtree the reconciler's last_good (consequence 4).
- warm_reconcile: last_good + snapshot/restore go through warmsnap.live_slot().
- run_recipe_ci: canonical rollback restores from canonical_slot(recipe).
- Correct the two comments that claimed the deployments "can never touch each other".
Tests: 10 new (slot disjointness for every WARM_DOMAINS recipe, slot<->stack 1:1,
registry not in the reconciler dir, prune spares last_good, foreign-slot refusal in
both snapshot and restore). Unit suite 315 -> 325, no regressions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FS8p1esg57UAC69riNvuBX
21 lines
1.4 KiB
Python
21 lines
1.4 KiB
Python
# Per-recipe harness config for keycloak (DB-backed: keycloak + mariadb). Read by the shared
|
|
# conftest — enrolling this recipe needs NO change to runner/harness code (D5).
|
|
HEALTH_PATH = "/realms/master" # 200 JSON once keycloak is up (not "/", which redirects)
|
|
HEALTH_OK = (200,)
|
|
DEPLOY_TIMEOUT = (
|
|
900 # JVM + DB migration are slow on a 2-vCPU VM; observed 502 fallback up to ~10min
|
|
)
|
|
HTTP_TIMEOUT = 900
|
|
|
|
# phase redfix: keycloak IS now a data-warm canonical. The original canon §2.B exception de-enrolled
|
|
# it because its canonical would have used the SAME domain as the live-warm OIDC provider
|
|
# (warm-keycloak.ci.commoninternet.net), so the sweep's promote deploy/teardown would collide with the
|
|
# live service lasuite-*/drone depend on. The canonical is now namespaced apart from the live provider
|
|
# on BOTH axes it shares with it — `canonical.canonical_ns()` gives any recipe in `warm.WARM_DOMAINS`
|
|
# (keycloak) a `canon-<recipe>` namespace, from which BOTH its domain/stack (`warm-canon-keycloak…`)
|
|
# and its warm-state slot (`/var/lib/ci-warm/canon-keycloak/`) derive. Domain separation alone was NOT
|
|
# enough: warm state was keyed by bare recipe, so both deployments shared one snapshot slot and each
|
|
# destroyed the other's known-good (F-redfix-4). keycloak therefore gets full data-warm canonical
|
|
# coverage (a real promote on its latest release) without risking the live OIDC service.
|
|
WARM_CANONICAL = True
|