From f8e5e4d928d820a2f1dbbb9ab056c1bc65223d92 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Wed, 24 Jun 2026 18:52:04 -0400 Subject: [PATCH] Fermer la couture creer-vm <-> plan (etape 4) creer-vm HOTE= ne prend plus qu'un argument : il lit VMID/IP/CIDR/passerelle/VLAN/stockage/disque/noeud dans l'inventaire genere (nouvelle sous-commande inventory_host parametres-proxmox), comme deployer lit ses groupes, et n'ecrit plus dans l'inventaire (plus de hote-ajouter). Les 3 cibles legacy hote-ajouter/planifier/groupes sont neutralisees (refus -> plan). Aide + docs alignees. Premier test stdlib du depot + cible make test, cablee dans make verifier. Verifie : make verifier exit 0 (4 tests), extraction testee sur l'inventaire reel + chemins de refus. Clonage reel non execute (Proxmox). Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 4 + Makefile | 92 ++++++++-------- QUICKSTART.md | 10 +- README.md | 4 +- docs/procedure-template-debian13-proxmox.md | 10 +- scripts/inventory_host.py | 60 ++++++++++ scripts/tests/test_inventory_host.py | 115 ++++++++++++++++++++ 7 files changed, 233 insertions(+), 62 deletions(-) create mode 100644 scripts/tests/test_inventory_host.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 876976a..92b1d13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ### Modifié - **Consolidation minimale post-diagnostic (ménage documentaire, sans risque).** Suite à une relecture à froid « auteur » de l'état réel du dépôt. (1) **En-tête généré rafraîchi** : `instance/inventories/production/hosts.yml` pointait encore vers l'ancienne source `docs/` ; régénéré via `instancier-appliquer` (diff sémantique **vide** — contenu inchangé, seul l'en-tête a bougé ; commité côté instance `OPS-Chezlepro`). (2) **`docs/catalogue-services.md`** : nouvelle section **« État d'implémentation des rôles »** qui distingue sans ambiguïté les rôles **implémentés** (validés *en tant que code*, **non éprouvés en prod**), les **échafaudages** (playbooks-ancres `debug` sans rôle : `serveur_nextcloud`, `serveur_collabora`, `client_supervision`, `serveur_web_frontal`, `serveur_web_dorsal`) et les **rôles-catégories inertes** (`applications`, `backup`, `database`, `identity`, `monitoring`, `proxmox`, `storage`, `web` — vestiges d'un regroupement par catégorie abandonné, l'architecture réelle étant plate `serveur_*`/`client_*`) ; colonnes « Rôle futur » → « Rôle ». (3) **`docs/vm-lifecycle.md` §8** : flux de déploiement réaligné sur le plan (`instancier-appliquer` puis `deployer`) au lieu de la commande supplantée `hote-ajouter`. Vérifié : `make verifier` (exit 0), `ansible-lint` 0 échec. **Non touché à dessein** : les références `instance/inventories/lab/` des docs de template sont **correctes** (contexte golden template, distinct de `production`) ; le bas du `README.md` (« Premier chantier »/« Principe ») est daté mais **exact** (template = socle), donc laissé tel quel pour éviter le churn. +- **`creer-vm` enfin piloté par le plan — couture « inventaire → création VM » fermée (étape 4 du diagnostic).** `make creer-vm HOTE=` ne prend plus qu'**un argument** : il **lit VMID/IP/CIDR/passerelle/VLAN/stockage/disque/nœud directement dans l'inventaire généré** (comme `deployer` lit ses groupes) au lieu de les redemander à la main, et **n'écrit plus** dans l'inventaire (l'appel à `hote-ajouter` est supprimé — l'hôte est déjà présent via le plan). Repli sur le nœud par défaut de `config` si `proxmox_noeud` absent. Les 3 cibles legacy `hote-ajouter` / `hote-planifier` / `hote-groupes` (qui éditaient l'inventaire généré à la main — anti-pattern) sont **neutralisées** : refus explicite renvoyant vers `serveurs.yml` + `instancier-appliquer`. `aide` et docs (`README`, `QUICKSTART`, `procedure-template-debian13-proxmox`) alignées sur `creer-vm HOTE=…`. La chaîne déclarative est désormais **continue** : `plan → instancier-appliquer → creer-vm HOTE → (activer) → deployer HOTE`. Activation laissée **manuelle** (édit du plan, par décision). Vérifié : `make verifier` exit 0 (dont 4 tests unitaires), extraction testée sur l'inventaire réel (`data-01` avec nœud, `collab-01` sans nœud → repli), chemins de refus (HOTE vide, hôte absent, cibles legacy) exit 2. *(Clonage réel non exécuté : exige Proxmox — c'est la preuve VM, étape suivante.)* + +### Ajouté +- **Sous-commande `inventory_host.py parametres-proxmox --hote X`** : émet, machine-lisible (`SETOPS_*='valeur'`), les paramètres de clonage Proxmox d'un hôte lus dans l'inventaire généré ; refuse si l'hôte est absent ou s'il manque un champ requis (VMID/IP/CIDR/passerelle/VLAN). Consommée par `make creer-vm`. **Premier test stdlib du dépôt** `scripts/tests/test_inventory_host.py` (sans pytest) + cible **`make test`**, câblée dans `make verifier`. ## 2026-06-23 diff --git a/Makefile b/Makefile index 0d54410..7ee2564 100644 --- a/Makefile +++ b/Makefile @@ -96,32 +96,23 @@ aide: @printf '%s\n' 'Flux: editer le plan -> make instancier -> make instancier-appliquer -> make deployer' @printf '%s\n' '' @printf '%s\n' 'VM' - @printf '%s\n' ' Creer une VM complete:' - @printf '%s\n' ' make creer-vm \' - @printf '%s\n' ' HOTE=web-frontal-01 \' - @printf '%s\n' ' VMID=95301 \' - @printf '%s\n' ' VLAN=15 \' - @printf '%s\n' ' ADRESSE_IP=10.1.15.31 \' - @printf '%s\n' ' PASSERELLE=10.1.15.1 \' - @printf '%s\n' ' GROUPES="serveur_debian serveur_durci"' - @printf '%s\n' ' Cloner seulement, sans inventaire:' + @printf '%s\n' ' Creer une VM (VMID/IP/VLAN/passerelle lus dans le plan):' + @printf '%s\n' ' make creer-vm HOTE=web-frontal-01' + @printf '%s\n' ' Cloner seulement, sans passer par le plan:' @printf '%s\n' ' make cloner-vm HOTE=web-frontal-01 VMID=95301 VLAN=15 ADRESSE_IP=10.1.15.31 PASSERELLE=10.1.15.1' @printf '%s\n' ' Configurer Proxmox et le Vault API:' @printf '%s\n' ' make config' @printf '%s\n' '' @printf '%s\n' 'Hotes' - @printf '%s\n' ' Planifier un hote sans le deployer:' - @printf '%s\n' ' make hote-planifier HOTE=obs-01 VMID=94101 GROUPES="serveur_debian serveur_durci serveur_prometheus serveur_loki"' + @printf '%s\n' ' Planifier/modifier un hote: editer le plan, puis regenerer:' + @printf '%s\n' ' editer instance/plan/serveurs.yml (ou la vue Serveurs du GUI)' + @printf '%s\n' ' make instancier-appliquer' @printf '%s\n' ' Verifier un deploiement a blanc (dry-run):' @printf '%s\n' ' make verifier-deploiement HOTE=web-frontal-01' @printf '%s\n' ' Remettre un hote en conformite selon ses groupes:' @printf '%s\n' ' make deployer HOTE=web-frontal-01' @printf '%s\n' ' Afficher un hote:' @printf '%s\n' ' make hote-afficher HOTE=web-frontal-01' - @printf '%s\n' ' Ajouter un hote existant:' - @printf '%s\n' ' make hote-ajouter HOTE=web-frontal-01 VMID=95301 ADRESSE_IP=10.1.15.31 GROUPES="serveur_debian serveur_durci"' - @printf '%s\n' ' Modifier ses groupes:' - @printf '%s\n' ' make hote-groupes HOTE=web-frontal-01 GROUPES="serveur_debian serveur_durci"' @printf '%s\n' ' Diagnostiquer:' @printf '%s\n' ' make verifier-hote LIMITE=web-frontal-01' @printf '%s\n' '' @@ -187,8 +178,12 @@ syntaxe-groupes: ansible-runtime syntaxe-proxmox: ansible-runtime ansible-playbook -i localhost, $(PLAYBOOK_PROXMOX_CLONER_VM) --syntax-check +.PHONY: test +test: + python3 scripts/tests/test_inventory_host.py + .PHONY: verifier -verifier: lint inventaire-verifier syntaxe +verifier: lint test inventaire-verifier syntaxe .PHONY: inventaire hote-planifier hote-ajouter hote-groupes hote-afficher appliquer deployer deployer-groupe cloner-vm creer-vm config inventaire-ui inventaire-verifier inventaire-lister inventaire-graphe inventaire-hote inventaire-lab inventaire-production inventaire: inventaire-production @@ -199,32 +194,12 @@ config: inventaire-ui: _instance-requise python3 scripts/inventory_gui.py --inventaire $(FICHIER_INVENTAIRE) -hote-ajouter: ansible-runtime - @if [[ -z "$(HOTE)" || -z "$(ADRESSE_IP)" ]]; then \ - printf '%s\n' 'Refus: relancer avec HOTE=nom_hote ADRESSE_IP=adresse_ip.'; \ - exit 2; \ - fi - python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) --dependances $(FICHIER_DEPENDANCES) ajouter --hote $(HOTE) --adresse-ip $(ADRESSE_IP) --utilisateur-ansible $(UTILISATEUR_ANSIBLE) --vmid "$(VMID)" --groupes "$(GROUPES)" --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) - $(MAKE) inventaire-verifier - $(MAKE) hote-afficher HOTE="$(HOTE)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)" - -hote-planifier: ansible-runtime - @if [[ -z "$(HOTE)" ]]; then \ - printf '%s\n' 'Refus: relancer avec HOTE=nom_hote GROUPES="groupe1 groupe2".'; \ - exit 2; \ - fi - python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) --dependances $(FICHIER_DEPENDANCES) ajouter --hote $(HOTE) --vmid "$(VMID)" --groupes "$(GROUPES)" --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) - $(MAKE) inventaire-verifier - $(MAKE) hote-afficher HOTE="$(HOTE)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)" - -hote-groupes: ansible-runtime - @if [[ -z "$(HOTE)" ]]; then \ - printf '%s\n' 'Refus: relancer avec HOTE=nom_hote GROUPES="groupe1 groupe2".'; \ - exit 2; \ - fi - python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) --dependances $(FICHIER_DEPENDANCES) definir-groupes --hote $(HOTE) --groupes "$(GROUPES)" --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) - $(MAKE) inventaire-verifier - $(MAKE) hote-afficher HOTE="$(HOTE)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)" +hote-ajouter hote-planifier hote-groupes: + @printf '%s\n' 'Cible depreciee: l inventaire est GENERE depuis le plan, il ne s edite plus a la main.' + @printf '%s\n' 'Declare ou modifie l hote dans instance/plan/serveurs.yml (ou la vue Serveurs du GUI), puis :' + @printf '%s\n' ' make instancier-appliquer' + @printf '%s\n' '(creer-vm lit desormais VMID/IP/VLAN/passerelle directement dans l inventaire genere.)' + @exit 2 hote-afficher: ansible-runtime @if [[ -z "$(HOTE)" ]]; then \ @@ -371,13 +346,34 @@ cloner-vm: ansible-runtime fi; \ ansible-playbook -i localhost, $(PLAYBOOK_PROXMOX_CLONER_VM) "$${vault_args[@]}" "$${extra_vars[@]}" -creer-vm: - @if [[ -z "$(ADRESSE_IP)" ]]; then \ - printf '%s\n' 'Refus: creer-vm doit recevoir ADRESSE_IP pour inscrire l hote dans l inventaire.'; \ +creer-vm: _instance-requise + @set -e; \ + if [[ -z "$(HOTE)" ]]; then \ + printf '%s\n' 'Refus: relancer avec HOTE=nom_hote (declare dans le plan).'; \ exit 2; \ - fi - $(MAKE) cloner-vm HOTE="$(HOTE)" VMID_MODELE="$(VMID_MODELE)" VMID="$(VMID)" NOEUD_PROXMOX="$(NOEUD_PROXMOX)" STOCKAGE_PROXMOX="$(STOCKAGE_PROXMOX)" FORMAT_DISQUE="$(FORMAT_DISQUE)" TAILLE_DISQUE="$(TAILLE_DISQUE)" DISQUE_PROXMOX="$(DISQUE_PROXMOX)" ADRESSE_IP="$(ADRESSE_IP)" CIDR="$(CIDR)" PASSERELLE="$(PASSERELLE)" DNS="$(DNS)" DHCP="$(DHCP)" CIUSER="$(CIUSER)" CLE_SSH_PUBLIQUE="$(CLE_SSH_PUBLIQUE)" PONT_PROXMOX="$(PONT_PROXMOX)" VLAN="$(VLAN)" DEMARRER="$(DEMARRER)" CLONE_COMPLET="$(CLONE_COMPLET)" - $(MAKE) hote-ajouter HOTE="$(HOTE)" ADRESSE_IP="$(ADRESSE_IP)" VMID="$(VMID)" GROUPES="$(GROUPES)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)" + fi; \ + params="$$(python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) parametres-proxmox --hote $(HOTE))"; \ + eval "$$params"; \ + $(MAKE) cloner-vm \ + HOTE="$(HOTE)" \ + VMID="$$SETOPS_VMID" \ + ADRESSE_IP="$$SETOPS_IP" \ + CIDR="$$SETOPS_CIDR" \ + PASSERELLE="$$SETOPS_PASSERELLE" \ + VLAN="$$SETOPS_VLAN" \ + STOCKAGE_PROXMOX="$${SETOPS_STOCKAGE:-$(STOCKAGE_PROXMOX)}" \ + TAILLE_DISQUE="$${SETOPS_DISQUE:-$(TAILLE_DISQUE)}" \ + NOEUD_PROXMOX="$${SETOPS_NOEUD:-$(NOEUD_PROXMOX)}" \ + VMID_MODELE="$(VMID_MODELE)" \ + FORMAT_DISQUE="$(FORMAT_DISQUE)" \ + DISQUE_PROXMOX="$(DISQUE_PROXMOX)" \ + DNS="$(DNS)" \ + DHCP="$(DHCP)" \ + CIUSER="$(CIUSER)" \ + CLE_SSH_PUBLIQUE="$(CLE_SSH_PUBLIQUE)" \ + PONT_PROXMOX="$(PONT_PROXMOX)" \ + DEMARRER="$(DEMARRER)" \ + CLONE_COMPLET="$(CLONE_COMPLET)" inventaire-verifier: ansible-runtime _instance-requise ansible-inventory -i $(INVENTAIRE_LAB) --list > /dev/null diff --git a/QUICKSTART.md b/QUICKSTART.md index 456d05b..d533239 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -70,13 +70,13 @@ make instancier-appliquer FORCE=1 # 1re génération : écrit instance/invento Tes hôtes sont là, en état `planifie`. `make serveurs` te montre leurs VMID/IP dérivés. ## 7. Créer les VM (clone du template + cloud-init) -Pour chaque hôte, avec ses valeurs dérivées (`make serveurs`) : +Pour chaque hôte — `creer-vm` lit ses VMID/IP/VLAN/passerelle directement dans +l'inventaire généré (`make serveurs` te les montre) : ```bash -make cloner-vm HOTE=infra-dns-01 VMID= ADRESSE_IP= VLAN= PASSERELLE= +make creer-vm HOTE=infra-dns-01 ``` -*(Les valeurs de nœud/stockage/template viennent de `make config`. Note honnête : -à ce stade la création de VM prend ces paramètres par hôte ; l'intégration -complète « plan → création » est la prochaine frontière.)* +*(Les valeurs de nœud/stockage/template viennent de `make config`. La création +suit désormais le plan de bout en bout : un seul argument, `HOTE`.)* ## 8. Activer puis déployer Passe l'hôte en `etat: actif` dans `instance/plan/serveurs.yml`, régénère, déploie : diff --git a/README.md b/README.md index b66ef7e..a54a42a 100644 --- a/README.md +++ b/README.md @@ -135,10 +135,12 @@ Créer un clone depuis le modèle Debian 13 via l'API Proxmox : ```bash make config -make creer-vm HOTE=web-frontal-01 VMID=95301 VLAN=15 ADRESSE_IP=10.1.15.31 PASSERELLE=10.1.15.1 GROUPES="serveur_debian serveur_durci" +make creer-vm HOTE=web-frontal-01 # VMID/IP/VLAN/passerelle lus dans le plan make deployer HOTE=web-frontal-01 ``` +L'hôte doit d'abord être déclaré dans `instance/plan/serveurs.yml` et l'inventaire régénéré (`make instancier-appliquer`) : `creer-vm` ne prend que `HOTE`, le reste est dérivé. + Les valeurs Cloud-Init communes déjà présentes dans le modèle Proxmox sont héritées par les clones. Préparer le golden template Debian 13 Proxmox : diff --git a/docs/procedure-template-debian13-proxmox.md b/docs/procedure-template-debian13-proxmox.md index bc50820..31e255e 100644 --- a/docs/procedure-template-debian13-proxmox.md +++ b/docs/procedure-template-debian13-proxmox.md @@ -760,16 +760,10 @@ Créer le clone et l'ajouter à l'inventaire : Exemple : ```bash -make creer-vm \ - HOTE=web-frontal-01 \ - VMID=95301 \ - VLAN=11 \ - ADRESSE_IP=10.1.15.31 \ - PASSERELLE=10.1.15.1 \ - GROUPES="serveur_debian serveur_durci" +make creer-vm HOTE=web-frontal-01 ``` -Le VLAN est volontairement saisi au moment de créer chaque VM. Il ne fait pas partie des valeurs persistantes de `make config`. +Les paramètres par VM (VMID, IP, VLAN, passerelle) ne sont plus saisis à la main : `creer-vm` les lit dans l'inventaire généré depuis le plan. L'hôte doit donc être déclaré dans `instance/plan/serveurs.yml` et l'inventaire régénéré (`make instancier-appliquer`) au préalable. Après le premier démarrage, tester l'accès : diff --git a/scripts/inventory_host.py b/scripts/inventory_host.py index 4b89a0f..ec3cbb1 100644 --- a/scripts/inventory_host.py +++ b/scripts/inventory_host.py @@ -148,6 +148,57 @@ def afficher_hote(data: dict, host: str) -> None: ) +CHAMPS_PROXMOX: tuple[tuple[str, str, bool], ...] = ( + ("SETOPS_VMID", "proxmox_vmid", True), + ("SETOPS_IP", "ansible_host", True), + ("SETOPS_CIDR", "proxmox_cidr", True), + ("SETOPS_PASSERELLE", "proxmox_passerelle", True), + ("SETOPS_VLAN", "proxmox_vlan", True), + ("SETOPS_STOCKAGE", "proxmox_stockage", False), + ("SETOPS_DISQUE", "proxmox_disque_taille", False), + ("SETOPS_NOEUD", "proxmox_noeud", False), +) + + +def parametres_proxmox_hote(data: dict, host: str) -> list[str]: + """Emet les parametres de clonage Proxmox d'un hote, lus depuis l'inventaire. + + Sortie shell-evaluable (`SETOPS_*='valeur'`) consommee par `make creer-vm`. + L'inventaire genere est la seule source : aucun parametre n'est saisi a la main. + """ + if not groupes_hote(data, host): + raise ValueError( + f"Hote absent de l'inventaire: {host}. " + "Declare-le dans le plan (instance/plan/serveurs.yml) puis " + "`make instancier-appliquer`." + ) + + vars_for_host = variables_hote(data, host) + lignes: list[str] = [] + manquants: list[str] = [] + + for var_shell, cle, requis in CHAMPS_PROXMOX: + valeur = vars_for_host.get(cle) + if valeur in (None, ""): + if requis: + manquants.append(cle) + valeur = "" + valeur = str(valeur) + if "'" in valeur: + raise ValueError( + f"Valeur Proxmox inattendue pour {cle} ({host}): apostrophe interdite." + ) + lignes.append(f"{var_shell}='{valeur}'") + + if manquants: + raise ValueError( + f"Parametres Proxmox manquants pour {host}: {', '.join(manquants)}. " + "Regenere l'inventaire (`make instancier-appliquer`)." + ) + + return lignes + + def afficher_playbooks_hote(data: dict, host: str, playbook_dir: Path) -> None: groups = groupes_hote(data, host) if not groups: @@ -307,6 +358,12 @@ def main() -> int: show_parser = subparsers.add_parser("afficher", help="Affiche les groupes et variables d'un hote.") show_parser.add_argument("--hote", required=True) + proxmox_parser = subparsers.add_parser( + "parametres-proxmox", + help="Emet les parametres de clonage Proxmox d'un hote (lus depuis l'inventaire).", + ) + proxmox_parser.add_argument("--hote", required=True) + playbooks_parser = subparsers.add_parser("playbooks", help="Affiche les playbooks de groupes pour un hote.") playbooks_parser.add_argument("--hote", required=True) playbooks_parser.add_argument("--dossier-playbooks", required=True, type=Path) @@ -369,6 +426,9 @@ def main() -> int: ecrire_inventaire(args.inventaire, data) elif args.command == "afficher": afficher_hote(data, args.hote) + elif args.command == "parametres-proxmox": + for ligne in parametres_proxmox_hote(data, args.hote): + print(ligne) elif args.command == "playbooks": afficher_playbooks_hote(data, args.hote, args.dossier_playbooks) elif args.command == "verifier-actif": diff --git a/scripts/tests/test_inventory_host.py b/scripts/tests/test_inventory_host.py new file mode 100644 index 0000000..ab62e15 --- /dev/null +++ b/scripts/tests/test_inventory_host.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +"""Tests stdlib (sans pytest) pour inventory_host.parametres_proxmox_hote. + +Lancer : python3 scripts/tests/test_inventory_host.py +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) + +from inventory_host import parametres_proxmox_hote # noqa: E402 + + +def _inventaire_factice() -> dict: + return { + "all": { + "children": { + "hotes_planifies": { + "hosts": { + "data-01": { + "ansible_host": "10.1.13.11", + "ansible_user": "ansible", + "proxmox_cidr": 24, + "proxmox_coeurs": 4, + "proxmox_disque_taille": "160G", + "proxmox_memoire": 2048, + "proxmox_noeud": "asgard", + "proxmox_passerelle": "10.1.13.1", + "proxmox_stockage": "TrueNAS", + "proxmox_vlan": 13, + "proxmox_vmid": 93101, + }, + # collab-01 : sans proxmox_noeud (champ optionnel). + "collab-01": { + "ansible_host": "10.1.15.21", + "proxmox_cidr": 24, + "proxmox_disque_taille": "16G", + "proxmox_passerelle": "10.1.15.1", + "proxmox_stockage": "TrueNAS", + "proxmox_vlan": 15, + "proxmox_vmid": 95201, + }, + # incomplet-01 : il manque l'IP (champ requis). + "incomplet-01": { + "proxmox_vmid": 99901, + "proxmox_cidr": 24, + "proxmox_passerelle": "10.1.99.1", + "proxmox_vlan": 99, + }, + } + }, + "serveur_postgresql": {"hosts": {"data-01": {}}}, + } + } + } + + +def test_hote_complet_avec_noeud() -> None: + lignes = parametres_proxmox_hote(_inventaire_factice(), "data-01") + attendu = { + "SETOPS_VMID='93101'", + "SETOPS_IP='10.1.13.11'", + "SETOPS_CIDR='24'", + "SETOPS_PASSERELLE='10.1.13.1'", + "SETOPS_VLAN='13'", + "SETOPS_STOCKAGE='TrueNAS'", + "SETOPS_DISQUE='160G'", + "SETOPS_NOEUD='asgard'", + } + assert set(lignes) == attendu, lignes + + +def test_hote_sans_noeud_emet_noeud_vide() -> None: + lignes = parametres_proxmox_hote(_inventaire_factice(), "collab-01") + assert "SETOPS_NOEUD=''" in lignes, lignes + assert "SETOPS_VMID='95201'" in lignes, lignes + + +def test_hote_absent_refuse() -> None: + try: + parametres_proxmox_hote(_inventaire_factice(), "inconnu-01") + except ValueError as exc: + assert "absent" in str(exc), exc + else: + raise AssertionError("un hote absent doit lever ValueError") + + +def test_champ_requis_manquant_refuse() -> None: + try: + parametres_proxmox_hote(_inventaire_factice(), "incomplet-01") + except ValueError as exc: + assert "manquants" in str(exc) and "ansible_host" in str(exc), exc + else: + raise AssertionError("un champ requis manquant doit lever ValueError") + + +def main() -> int: + tests = [ + test_hote_complet_avec_noeud, + test_hote_sans_noeud_emet_noeud_vide, + test_hote_absent_refuse, + test_champ_requis_manquant_refuse, + ] + for test in tests: + test() + print(f"ok {test.__name__}") + print(f"{len(tests)} tests passes.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())