From 7ddc2fedadc057a83e8262c316ca3216c85e65ae Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Wed, 24 Jun 2026 10:12:03 -0400 Subject: [PATCH] Moteur : robustesse pour une instance hors depot (os.path.relpath) Path.relative_to(RACINE) levait quand l'instance est externe (SETOPS_INSTANCE = ../OPS-laPreuve par ex.). Remplace par os.path.relpath dans instancier.py / inventory_gui.py / config_proxmox.py. Revele par une instance d'essai agnostique (lapreuve.local, 10.9.0.0/16) : le moteur genere un inventaire distinct, zero fuite Chezlepro. Cas normal (OPS-Chezlepro via symlink) inchange : diff vide, lint 0. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 3 +++ scripts/config_proxmox.py | 6 +++--- scripts/instancier.py | 4 ++-- scripts/inventory_gui.py | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e2e9b6..da382de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 2026-06-23 +### Corrigé +- **Robustesse du moteur pour une instance hors dépôt (révélé par une instance d'essai agnostique).** Les scripts affichaient des chemins via `Path.relative_to(RACINE)`, qui **lève** quand l'instance est en dehors du dépôt (`SETOPS_INSTANCE` pointant un chemin externe, ex. `../OPS-laPreuve`). Remplacé par `os.path.relpath` (`scripts/instancier.py`, `inventory_gui.py`, `config_proxmox.py`). Le moteur génère désormais correctement depuis n'importe quel emplacement d'instance — agnosticité prouvée (instance `lapreuve.local` / `10.9.0.0/16` : inventaire distinct, **zéro fuite Chezlepro**). + ### Modifié - **Dette doc soldée après le découpage moteur/instance.** Rafraîchissement des chemins dans les docs secondaires, README de rôles, messages et docstrings : `inventories/...` → `instance/inventories/...`, `docs/.yml` → `instance/plan/.yml`. Correction au passage de chemins de playbooks périmés (préexistants) dans `CLAUDE.md`/`SOLUTION.md` : `playbooks/vm_templates/debian13_proxmox_prepare|verify|cleanup.yml` → `playbooks/modeles_vm/debian13_proxmox_preparer|verifier|nettoyer.yml`, et `confirm_template_cleanup` → `template_cleanup_confirm`. Validé : diff vide, `ansible-lint` 0 échec, `make inventaire-verifier`. - **Découpage moteur/instance — Phase 3 (modèle A) : deux dépôts.** Le contenu de `instance/` (plan + inventaire) part dans un **dépôt d'instance dédié** (`OPS-Chezlepro` pour Chezlepro, sur la forge). `Set-OPS` devient le **moteur pur** (rôles, scripts, playbooks, guides, exemples). L'instance est **montée via un symlink** `instance -> ../OPS-Chezlepro` (gitignoré) : le défaut `SETOPS_INSTANCE=instance` la résout sans configuration. Le moteur lit le plan et **régénère `hosts.yml` dans le dépôt d'instance**. `.ansible-lint` exclut `instance/`. Validé : diff vide, `ansible-lint` 0 échec, `make inventaire-verifier`, `instancier-appliquer`. **Modèle A (dépôts frères)** retenu jusqu'à preuve du concept ; le **modèle B (moteur en sous-module)** pour la meute viendra ensuite. Le moteur ne contient plus aucune donnée Chezlepro. diff --git a/scripts/config_proxmox.py b/scripts/config_proxmox.py index 3e1683e..43cbc9a 100644 --- a/scripts/config_proxmox.py +++ b/scripts/config_proxmox.py @@ -107,7 +107,7 @@ def configurer_proxmox() -> None: nouveau[identifiant] = demander(identifiant, courant.get(identifiant, VALEURS_DEFAUT[identifiant])) ecrire_yaml(FICHIER_PROXMOX, nouveau) - print(f"\nEcrit: {FICHIER_PROXMOX.relative_to(RACINE)}") + print(f"\nEcrit: {os.path.relpath(FICHIER_PROXMOX, RACINE)}") def demander_oui_non(question: str, defaut: bool = False) -> bool: @@ -123,7 +123,7 @@ def configurer_vault() -> None: return if FICHIER_VAULT.exists(): - print(f"Ouverture du Vault existant: {FICHIER_VAULT.relative_to(RACINE)}") + print(f"Ouverture du Vault existant: {os.path.relpath(FICHIER_VAULT, RACINE)}") subprocess.run(["ansible-vault", "edit", str(FICHIER_VAULT)], check=True) return @@ -147,7 +147,7 @@ def configurer_vault() -> None: sort_keys=False, ) subprocess.run(["ansible-vault", "encrypt", str(FICHIER_VAULT)], check=True) - print(f"Vault cree: {FICHIER_VAULT.relative_to(RACINE)}") + print(f"Vault cree: {os.path.relpath(FICHIER_VAULT, RACINE)}") except Exception: if FICHIER_VAULT.exists(): FICHIER_VAULT.unlink() diff --git a/scripts/instancier.py b/scripts/instancier.py index 7e7828b..05a16db 100644 --- a/scripts/instancier.py +++ b/scripts/instancier.py @@ -152,7 +152,7 @@ def appliquer(force: bool = False) -> int: "Utilise FORCE=1 pour appliquer un changement intentionnel du plan.") return 1 ecrire(INVENTAIRE) - print(f"\n{INVENTAIRE.relative_to(RACINE)} (re)genere depuis le plan. " + print(f"\n{os.path.relpath(INVENTAIRE, RACINE)} (re)genere depuis le plan. " "git est le filet : git diff / git checkout pour revenir.") return 0 @@ -169,7 +169,7 @@ def main() -> int: try: if args.commande == "generer": ecrire() - print(f"{GENERE.relative_to(RACINE)} genere depuis le plan.") + print(f"{os.path.relpath(GENERE, RACINE)} genere depuis le plan.") elif args.commande == "comparer": return comparer() elif args.commande == "appliquer": diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py index 220bd36..abf93db 100644 --- a/scripts/inventory_gui.py +++ b/scripts/inventory_gui.py @@ -199,7 +199,7 @@ def inventaire_api(path: Path) -> dict: data = charger_yaml(path) dependencies = charger_dependances(FICHIER_DEPENDANCES) return { - "inventaire": str(path.relative_to(RACINE)), + "inventaire": os.path.relpath(path, RACINE), "production": path.resolve() == INVENTAIRE_PRODUCTION, "groupes": groupes_disponibles(data), "dependances": dependencies,