diff --git a/CHANGELOG.md b/CHANGELOG.md index 44e8943..e0df099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,12 @@ fois la voûte du locataire et l'accès au runner du site) : sauf `ARMER=oui`) → `monter` (`make monter-flotte` sur le runner du locataire, suivi toutes les 30 s) → `parefeu` (`--flotte`) → `bilan` (ce que chaque jeu d'état est devenu). -Le nom de l'écosystème s'écrit en toutes lettres (`INSTANCE=`), comme pour `raser`, qui -n'a pas d'autre condition. Arrêt à la première étape en échec, avec la commande de reprise +`TENANT=` désigne l'écosystème en toutes lettres ; le nom qu'exige `raser` en est DÉRIVÉ +(`raser.nom_court`, une seule dérivation), pas redemandé. La première version exigeait aussi +`INSTANCE=` — relevé par l'exploitant : « pourquoi cette cible a besoin de se faire dire +"chezlepro" deux fois ? ». Le garde-fou de `raser` n'a de sens que pour `raser` seul, qui rase +l'écosystème du lien `instance/` ; ici, rien d'implicite n'est à confirmer. `raser` n'a pas +d'autre condition que sa confirmation. Arrêt à la première étape en échec, avec la commande de reprise (`DEPUIS=<étape>`) ; journal complet dans `/logs/`. **Le runner du site se met à jour avant sa première étape** (quelle que soit la reprise) : diff --git a/Makefile b/Makefile index 3b4dfee..4d70b8a 100644 --- a/Makefile +++ b/Makefile @@ -1451,16 +1451,16 @@ monter-flotte: _instance-requise ## Monte une flotte deja creee : flux, AC et DN # RECONSTRUIRE UN LOCATAIRE DE BOUT EN BOUT, DEPUIS LE POSTE (2026-09-30). Les deux # reconstructions du 2026-09-30 passaient par cinq endroits et des commandes tapees a la # main ; la sequence vit desormais dans `scripts/reconstruire_locataire.py` (voir son -# en-tete). Le nom de l'ecosysteme s'ecrit en toutes lettres (`INSTANCE=`), comme pour -# `raser`. L'armement marque une pause, sauf `ARMER=oui`. `DEPUIS=` reprend apres un +# en-tete). `TENANT=` designe l'ecosysteme en toutes lettres : le nom qu'exige `raser` en est +# derive, pas redemande. L'armement marque une pause, sauf `ARMER=oui`. `DEPUIS=` reprend apres un # arret. Le journal complet va dans `/logs/`. .PHONY: reconstruire-locataire -reconstruire-locataire: ## Rase et reconstruit un locataire, du site a la recette, etat remis — TENANT= INSTANCE= CONFIRMER=true - @if [[ -z "$(TENANT)" || -z "$(INSTANCE)" ]]; then \ - printf '%s\n' 'Refus: TENANT= et INSTANCE= requis.'; \ +reconstruire-locataire: ## Rase et reconstruit un locataire, du site a la recette, etat remis — TENANT=OPS-X CONFIRMER=true + @if [[ -z "$(TENANT)" ]]; then \ + printf '%s\n' 'Refus: TENANT= requis (le dossier du locataire, en toutes lettres).'; \ exit 2; \ fi - python3 scripts/reconstruire_locataire.py --tenant "$(TENANT)" --instance "$(INSTANCE)" \ + python3 scripts/reconstruire_locataire.py --tenant "$(TENANT)" \ $(if $(filter true,$(CONFIRMER)),--confirmer) $(if $(DEPUIS),--depuis "$(DEPUIS)") \ $(if $(filter oui,$(ARMER)),--armer) diff --git a/docs/runbooks-construction.yml b/docs/runbooks-construction.yml index 33837b7..6bf513f 100644 --- a/docs/runbooks-construction.yml +++ b/docs/runbooks-construction.yml @@ -480,7 +480,7 @@ runbooks: nature: destructif portee: poste duree: "long" - variables: [TENANT, INSTANCE, DEPUIS, ARMER] + variables: [TENANT, DEPUIS, ARMER] fixes: {CONFIRMER: "true"} pourquoi: >- TOUT, d'une commande, depuis le poste : sauvegarder, raser et recreer (runner du diff --git a/scripts/raser.py b/scripts/raser.py index b7542ce..627b773 100755 --- a/scripts/raser.py +++ b/scripts/raser.py @@ -41,14 +41,22 @@ from inventory_rules import instance_courante # noqa: E402 RACINE = Path(__file__).resolve().parent.parent +def nom_court(dossier: Path) -> str: + """Le nom qu'il faut TAPER pour raser cet ecosysteme : `OPS-Technolibre` -> `technolibre`. + + Une seule derivation : `reconstruire_locataire.py` l'importe au lieu de redemander le + nom (2026-09-30) — la ou l'ecosysteme est deja designe explicitement par `TENANT=`. + """ + return dossier.name.removeprefix("OPS-").lower() + + def instance_active() -> tuple[Path, str]: """Dossier de l'instance montee, et son nom court (celui qu'il faudra taper).""" base = instance_courante() if not base.exists(): raise SystemExit("Aucune instance montee : rien a raser.") reel = base.resolve() - nom = reel.name.removeprefix("OPS-").lower() - return reel, nom + return reel, nom_court(reel) def plan_derive(base: Path) -> list[tuple[str, int]]: diff --git a/scripts/reconstruire_locataire.py b/scripts/reconstruire_locataire.py index 1fcd818..2c55934 100644 --- a/scripts/reconstruire_locataire.py +++ b/scripts/reconstruire_locataire.py @@ -15,7 +15,7 @@ pas les secrets du locataire, et c'est voulu : l'armement reste un geste du post LES ETAPES, dans l'ordre (`--depuis` reprend a l'une d'elles apres un arret) : sauvegarder poste deposer l'etat de chaque noeud MAINTENANT (sinon on perd la journee) - raser runner du site detruire les VM — le nom de l'ecosysteme s'ecrit en toutes lettres + raser runner du site detruire les VM creer runner du site recreer les VM depuis le gabarit inseminer runner du site amorcer le runner du locataire (socle + moteur, sans secret) armer poste lui remettre sa voute et sa cle — pause, sauf `--armer` @@ -26,6 +26,12 @@ LES ETAPES, dans l'ordre (`--depuis` reprend a l'une d'elles apres un arret) : La premiere etape en echec arrete tout, et le dit. `raser` n'a pas d'autre condition que sa confirmation (decision de l'exploitant) : c'est la PROCEDURE qui sauvegarde avant. + +LE NOM N'EST DEMANDE QU'UNE FOIS. `raser`, seul, exige qu'on tape le nom de l'ecosysteme +parce qu'il rase celui du lien `instance/`, qui peut pointer n'importe ou. Ici l'ecosysteme +est deja designe en toutes lettres par `TENANT=` : le nom que `raser` attend en est DERIVE +(`raser.nom_court`), pas redemande. Une premiere version l'exigeait deux fois — une +occasion de se tromper de plus, et aucune protection de plus (2026-09-30). """ from __future__ import annotations @@ -42,6 +48,7 @@ sys.path.insert(0, str(RACINE / "scripts")) from devis_reseau import DOSSIER_INSTANCES # noqa: E402 from eprouver_parefeu import _ip_par_hote # noqa: E402 +from raser import nom_court # noqa: E402 ETAPES = ["sauvegarder", "raser", "creer", "inseminer", "armer", "monter", "parefeu", "bilan"] SSH = ["ssh", "-o", "BatchMode=yes", "-o", "ConnectTimeout=15", "-o", "ServerAliveInterval=30", @@ -134,8 +141,6 @@ def main() -> int: global JOURNAL ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) ap.add_argument("--tenant", required=True, help="dossier du locataire, ex. OPS-Technolibre") - ap.add_argument("--instance", required=True, - help="nom de l'ecosysteme, ecrit en toutes lettres (celui qu'exige `raser`)") ap.add_argument("--confirmer", action="store_true", help="sans lui, rien n'est fait") ap.add_argument("--depuis", choices=ETAPES, default=ETAPES[0], help="reprendre a cette etape") ap.add_argument("--armer", action="store_true", @@ -148,6 +153,7 @@ def main() -> int: T = args.tenant dossier = DOSSIER_INSTANCES / T + ecosysteme = nom_court(dossier) inv = dossier / "inventories" / "principal" / "hosts.yml" if not inv.is_file(): print(f"REFUS : {inv} introuvable.") @@ -155,7 +161,7 @@ def main() -> int: runner_nom, runner_ip = runner_du_locataire(T) a_faire = ETAPES[ETAPES.index(args.depuis):] if not args.confirmer: - print(f"Refus : RECONSTRUCTION de {T} ({args.instance}) — ses VM seront DETRUITES puis refaites.") + print(f"Refus : RECONSTRUCTION de {T} ({ecosysteme}) — ses VM seront DETRUITES puis refaites.") print(f" etapes : {' -> '.join(a_faire)} ; runner du locataire : {runner_nom} ({runner_ip})") print(" Relancer avec CONFIRMER=true.") return 2 @@ -172,7 +178,7 @@ def main() -> int: def arret(nom: str, rc: int, quoi: str = "") -> int: dire(f"\nARRET a l'etape « {nom} » (code {rc}){' — ' + quoi if quoi else ''}.") dire(f"Reprendre, une fois la cause comprise : make reconstruire-locataire TENANT={T} " - f"INSTANCE={args.instance} CONFIRMER=true DEPUIS={nom}") + f"CONFIRMER=true DEPUIS={nom}") return rc or 1 site_tire = False @@ -189,7 +195,7 @@ def main() -> int: filtre=("fatal:", "PLAY RECAP", "failed=")) elif nom == "raser": rc = sur_site(args, f"SETOPS_INSTANCE={args.racine_runner}/{T} make raser CONFIRMER=true " - f"INSTANCE={shlex.quote(args.instance)}", + f"INSTANCE={shlex.quote(ecosysteme)}", filtre=("detruite", "VM detruites", "Refus", "REFUS", "ERREUR")) elif nom == "creer": rc = sur_site(args, f"SETOPS_INSTANCE={args.racine_runner}/{T} make flotte-creer "