diff --git a/CHANGELOG.md b/CHANGELOG.md index b0095fa..bee5568 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,39 @@ # CHANGELOG — Set-OPS +## 2026-08-09 — Le plan bascule sur le gabarit recapturé, prouvé par une VM réelle + +`proxmox_clone_source_nom` / `proxmox_clone_vmid_modele` pointent désormais sur +`modeleChezlepro-travail` (99998). L'ancien (99999) reste sur le cluster : il porte encore +un `/etc/resolv.conf` et une clé privée d'hôte SSH du réseau de fabrication. À supprimer +quand plusieurs VM seront nées du nouveau — pas avant. + +**Preuve par une machine réelle**, et non par lecture de configuration : `web-dorsal-01` — +l'hôte le moins engagé de la flotte, 12 Ko dans `/var/www` — rasé puis recréé par le chemin +normal (`make raser HOTE=…`, `make creer-vm`, `make deployer`). + +Ce qu'elle a hérité du nouveau gabarit : + +``` +resolv.conf → les commentaires seuls, aucune identité de fabrication +machine-id → cc9c58c1… neuf et unique +clé d'hôte → SHA256:pES0/… régénérée +cloud-init → done +``` + +Déploiement complet, **zéro échec**, et les cinq devis de service `CONFORME`. + +**`raser` accepte maintenant `--hote`.** Raser une seule machine sert à éprouver un gabarit +ou à reprendre un hôte ; les **quatre verrous restent en vigueur** — on ne fait que +restreindre la liste dérivée du plan, jamais l'élargir. + +**Un défaut relevé au passage, non corrigé.** Le premier déploiement s'est interrompu sur +`client_unbound`, à l'instant où le résolveur bascule vers `127.0.0.1` : toute résolution +en vol se fige le temps qu'Unbound réponde, y compris celle que fait `sshd` à l'ouverture +de session — d'où « Connection timed out during banner exchange ». L'hôte répondait de +nouveau une minute plus tard et la reprise est passée intégralement, presque tout en +`changed=0`. C'est une **course**, de la même famille que celles de la reconstruction, et +elle mérite le même remède : attendre une condition plutôt que de subir la bascule. + ## 2026-08-09 — Gabarit recapturé sur copie de travail, sans toucher à l'original `modeleChezlepro` (99999) cloné en `modeleChezlepro-travail` (99998), préparé, vérifié, diff --git a/Makefile b/Makefile index 5618522..78b280e 100644 --- a/Makefile +++ b/Makefile @@ -588,7 +588,7 @@ _attendre-flotte: ansible-runtime .PHONY: reconstruire raser: ansible-runtime _instance-requise ## DESTRUCTIF : detruit les VM derivees du plan — exige CONFIRMER=true ET INSTANCE= - @python3 scripts/raser.py $(if $(INSTANCE),--instance $(INSTANCE)) $(if $(filter true,$(CONFIRMER)),--confirmer) + @python3 scripts/raser.py $(if $(INSTANCE),--instance $(INSTANCE)) $(if $(HOTE),--hote $(HOTE)) $(if $(filter true,$(CONFIRMER)),--confirmer) reconstruire: _instance-requise ## Reconstruit un ecosysteme depuis zero : VM puis deploiement complet @set -e; \ diff --git a/scripts/raser.py b/scripts/raser.py index 84ba9ef..044b3f5 100755 --- a/scripts/raser.py +++ b/scripts/raser.py @@ -71,11 +71,20 @@ def plan_derive(base: Path) -> list[tuple[str, int]]: def main(argv: list[str] | None = None) -> int: ap = argparse.ArgumentParser(description="Rase les VM derivees du plan de l'instance active.") ap.add_argument("--instance", help="nom de l'ecosysteme a raser (doit correspondre au monte)") + ap.add_argument("--hote", help="ne raser QUE cet hote (les quatre verrous s'appliquent)") ap.add_argument("--confirmer", action="store_true") a = ap.parse_args(argv) base, nom_actif = instance_active() couples = plan_derive(base) + if a.hote: + # Les quatre verrous restent en vigueur : on ne fait que RESTREINDRE la liste + # derivee du plan. Raser un seul hote sert a eprouver un gabarit ou a reprendre + # une machine, sans toucher aux treize autres. + couples = [c for c in couples if c[0] == a.hote] + if not couples: + print(f"L'hote « {a.hote} » n'est pas au plan : rien a raser.") + return 2 if not couples: print("Le plan ne derive aucune VM : rien a raser.") return 0 @@ -116,7 +125,8 @@ def main(argv: list[str] | None = None) -> int: if not a.confirmer: print(f"\n{len(presentes)} VM seraient DETRUITES, disques compris.\n" - f"Relancer avec : make raser CONFIRMER=true INSTANCE={nom_actif}") + f"Relancer avec : make raser CONFIRMER=true INSTANCE={nom_actif}" + + (f" HOTE={a.hote}" if a.hote else "")) return 0 if (a.instance or "").lower() != nom_actif: