From 1d25338d26abd1f5f915eafa4c55f8c3bfe12d5a Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Sun, 21 Jun 2026 21:31:03 -0400 Subject: [PATCH] Ajouter les dependances causales des groupes --- AGENTS.md | 9 +++ CHANGELOG.md | 3 + Makefile | 12 ++-- README.md | 2 + docs/catalogue-services.md | 46 +++++++++---- docs/dependances-groupes.yml | 86 ++++++++++++++++++++++++ docs/nomenclature-vm.md | 2 + inventories/production/hosts.yml | 7 ++ playbooks/groupes/serveurs_powerdns.yml | 10 +++ scripts/inventory_gui.py | 46 ++++++++++++- scripts/inventory_host.py | 89 +++++++++++++++++++++++++ scripts/inventory_rules.py | 35 ++++++++++ 12 files changed, 326 insertions(+), 21 deletions(-) create mode 100644 docs/dependances-groupes.yml create mode 100644 playbooks/groupes/serveurs_powerdns.yml diff --git a/AGENTS.md b/AGENTS.md index 8140cac..59f0af3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -297,6 +297,7 @@ Quand un nouveau groupe opérationnel est ajouté : - créer le playbook homonyme dans `playbooks/groupes/` ; - documenter son intention opérationnelle ; +- déclarer ses dépendances causales dans `docs/dependances-groupes.yml` si son exécution requiert un autre service actif ; - prévoir les rôles nécessaires ; - valider au minimum sa syntaxe ; - l'ajouter aux facilités d'exploitation si l'opérateur doit l'utiliser directement. @@ -367,6 +368,14 @@ Grafana → datasources et dashboards côté plateforme Quand un nouveau service central est ajouté, prévoir aussi le ou les rôles clients nécessaires pour intégrer les VM existantes et futures. +Les dépendances entre groupes doivent être déclarées dans : + +```text +docs/dependances-groupes.yml +``` + +Ces dépendances servent à refuser un déploiement lorsque les prérequis actifs sont absents et à préparer les futurs checks de supervision. + Les intégrations clientes doivent être : - idempotentes ; diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cc019f..a698179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Ajouté - Ajout de `make hote-planifier` pour renseigner un hôte, son VMID et ses groupes sans création ni déploiement immédiat. - Ajout de `scripts/inventory_rules.py` pour centraliser les règles partagées entre la gestion CLI et l'interface locale d'inventaire. +- Ajout de `docs/dependances-groupes.yml` comme registre exploitable des dépendances causales entre groupes. +- Ajout du contrat `serveurs_powerdns` afin de représenter la capacité DNS centrale requise par `clients_dns`. ### Modifié - Renforcement de la validation d'inventaire : @@ -16,6 +18,7 @@ - Alignement de l'aide Makefile et de la documentation sur le flux opérateur : planifier, activer/créer, déployer. - Retrait des groupes génériques obsolètes `serveurs_bases_donnees` et `serveurs_supervision` au profit des groupes de services précis. - Consolidation des groupes Icinga en `serveurs_icinga` afin de représenter une seule capacité de supervision serveur sur `mon-01`. +- Validation des prérequis actifs avant déploiement d'un groupe, déploiement d'un hôte ou sauvegarde active via l'interface d'inventaire. ## 2026-06-21 diff --git a/Makefile b/Makefile index 115f17f..9b374ca 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ export ANSIBLE_SSH_ARGS ?= -F /dev/null -o ControlMaster=no INVENTAIRE_LAB ?= inventories/lab/hosts.yml INVENTAIRE_PRODUCTION ?= inventories/production/hosts.yml FICHIER_INVENTAIRE ?= $(INVENTAIRE_PRODUCTION) +FICHIER_DEPENDANCES ?= docs/dependances-groupes.yml GROUPE_MODELE ?= modeles_vm GROUPE_DEBIAN ?= serveurs_debian GROUPE_HOTES_ACTIFS ?= hotes_actifs @@ -141,7 +142,7 @@ aide: @printf '%s\n' 'Variables frequentes' @printf '%s\n' ' HOTE=web-01 GROUPE=serveurs_debian GROUPES="serveurs_debian serveurs_durcis"' @printf '%s\n' ' VMID=101 VLAN=12 ADRESSE_IP=192.168.12.101 PASSERELLE=192.168.12.1' - @printf '%s\n' ' FICHIER_INVENTAIRE=inventories/production/hosts.yml CONFIRMER=true' + @printf '%s\n' ' FICHIER_INVENTAIRE=inventories/production/hosts.yml FICHIER_DEPENDANCES=docs/dependances-groupes.yml CONFIRMER=true' .PHONY: lint lint: ansible-runtime @@ -187,7 +188,7 @@ hote-ajouter: ansible-runtime printf '%s\n' 'Refus: relancer avec HOTE=nom_hote ADRESSE_IP=adresse_ip.'; \ exit 2; \ fi - python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) ajouter --hote $(HOTE) --adresse-ip $(ADRESSE_IP) --utilisateur-ansible $(UTILISATEUR_ANSIBLE) --vmid "$(VMID)" --groupes "$(GROUPES)" --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) + 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)" @@ -196,7 +197,7 @@ hote-planifier: ansible-runtime printf '%s\n' 'Refus: relancer avec HOTE=nom_hote GROUPES="groupe1 groupe2".'; \ exit 2; \ fi - python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) ajouter --hote $(HOTE) --vmid "$(VMID)" --groupes "$(GROUPES)" --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) + 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)" @@ -205,7 +206,7 @@ hote-groupes: ansible-runtime printf '%s\n' 'Refus: relancer avec HOTE=nom_hote GROUPES="groupe1 groupe2".'; \ exit 2; \ fi - python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) definir-groupes --hote $(HOTE) --groupes "$(GROUPES)" --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) + 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)" @@ -225,6 +226,7 @@ appliquer: ansible-runtime printf '%s\n' 'Refus: aucun playbook pour ce groupe: $(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml'; \ exit 2; \ fi + python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) --dependances $(FICHIER_DEPENDANCES) verifier-dependances-groupe --groupe $(GROUPE) ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml" --limit '$(GROUPE):&$(GROUPE_HOTES_ACTIFS)' deployer: @@ -234,6 +236,7 @@ deployer: fi @python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) playbooks --hote $(HOTE) --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) > /dev/null @python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) verifier-actif --hote $(HOTE) + @python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) --dependances $(FICHIER_DEPENDANCES) verifier-dependances-hote --hote $(HOTE) $(MAKE) _verifier-acces-hote LIMITE="$(HOTE)" $(MAKE) _verifier-privileges-hote LIMITE="$(HOTE)" @playbooks="$$(python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) playbooks --hote $(HOTE) --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES))" || exit $$?; \ @@ -322,6 +325,7 @@ inventaire-verifier: ansible-runtime ansible-inventory -i $(INVENTAIRE_LAB) --list > /dev/null ansible-inventory -i $(INVENTAIRE_PRODUCTION) --list > /dev/null python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) verifier-playbooks --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) + python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) --dependances $(FICHIER_DEPENDANCES) verifier-dependances --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) inventaire-lister: ansible-runtime ansible-inventory -i $(FICHIER_INVENTAIRE) --list diff --git a/README.md b/README.md index 234a5fc..206d176 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ Les groupes opérationnels avec des hôtes, comme `serveurs_web` ou `clients_dns Le catalogue des services et intégrations prévus est dans `docs/catalogue-services.md`. +Les dépendances causales entre groupes sont dans `docs/dependances-groupes.yml`. + La nomenclature des noms de VM et des VMID est dans `docs/nomenclature-vm.md`. Créer un clone depuis le modèle Debian 13 via l'API Proxmox : diff --git a/docs/catalogue-services.md b/docs/catalogue-services.md index 80a6a5d..cfd8e43 100644 --- a/docs/catalogue-services.md +++ b/docs/catalogue-services.md @@ -28,6 +28,7 @@ Un service central peut partager un hôte avec d'autres services du même domain | Forgejo | `serveurs_forgejo` | `playbooks/groupes/serveurs_forgejo.yml` | `forgejo` | | Sendmail MTA | `serveurs_sendmail` | `playbooks/groupes/serveurs_sendmail.yml` | `sendmail` | | step-ca | `serveurs_step_ca` | `playbooks/groupes/serveurs_step_ca.yml` | `step_ca` | +| PowerDNS | `serveurs_powerdns` | `playbooks/groupes/serveurs_powerdns.yml` | `powerdns` | | Redis | `serveurs_redis` | `playbooks/groupes/serveurs_redis.yml` | `redis` | | NGINX WAF et reverse proxy | `serveurs_nginx` | `playbooks/groupes/serveurs_nginx.yml` | `nginx` | | Nextcloud | `serveurs_nextcloud` | `playbooks/groupes/serveurs_nextcloud.yml` | `nextcloud` | @@ -40,6 +41,7 @@ Un service central peut partager un hôte avec d'autres services du même domain | `infra-pki-01` | step-ca | | `infra-edge-01` | NGINX WAF et reverse proxy | | `infra-mail-01` | Sendmail MTA | +| `infra-dns-01` | PowerDNS | | `idm-01` | OpenLDAP, Keycloak | | `data-01` | PostgreSQL, Redis | | `obs-01` | Prometheus, Loki, Grafana | @@ -65,58 +67,63 @@ L'ordre ci-dessous privilégie les dépendances structurantes avant les applicat ### Phase 1 - Fondations transversales -1. `serveurs_step_ca` +1. `serveurs_powerdns` + - Service central : DNS interne autoritaire et/ou résolution interne selon le design retenu. + - Intégration à prévoir : `clients_dns`. + - Raison : les autres intégrations auront besoin de noms stables plutôt que d'adresses IP. + +2. `serveurs_step_ca` - Service central : autorité de certification interne et ACME. - Intégration à prévoir : `clients_pki`. - Raison : les autres services auront besoin de certificats fiables avant d'être exposés proprement. -2. `serveurs_nginx` +3. `serveurs_nginx` - Service central : reverse proxy, terminaison TLS, publication HTTP(S), WAF. - Intégration à prévoir : publication des services HTTP derrière le proxy. - Raison : plusieurs services seront consommés par navigateur ou API et doivent passer par un point d'entrée cohérent. -3. `serveurs_sendmail` +4. `serveurs_sendmail` - Service central : relais SMTP sortant. - Intégration à prévoir : `clients_smtp`. - Raison : les notifications, réinitialisations de mot de passe et alertes doivent fonctionner tôt. ### Phase 2 - Données et identité -4. `serveurs_postgresql` +5. `serveurs_postgresql` - Service central : base de données relationnelle partagée. - Intégration à prévoir : bases dédiées par application, comptes applicatifs et sauvegardes. - Raison : Keycloak, Grafana, Icinga Web 2, Forgejo et Nextcloud peuvent dépendre de PostgreSQL. -5. `serveurs_openldap` +6. `serveurs_openldap` - Service central : annuaire interne. - Intégration à prévoir : `clients_ldap`. - Raison : l'identité Unix et l'annuaire doivent exister avant les intégrations d'authentification avancées. -6. `serveurs_keycloak` +7. `serveurs_keycloak` - Service central : SSO/OIDC/SAML. - Intégration à prévoir : applications web derrière `serveurs_nginx`. - Raison : les applications devraient être branchées au SSO dès leur arrivée plutôt qu'après coup. ### Phase 3 - Observabilité minimale -7. `serveurs_prometheus` +8. `serveurs_prometheus` - Service central : métriques. - Intégration à prévoir : `clients_metriques`. - Raison : les prochains services doivent être mesurables dès leur déploiement. -8. `serveurs_loki` +9. `serveurs_loki` - Service central : journaux centralisés. - Intégration à prévoir : `clients_journaux`. - Raison : les journaux centralisés accélèrent le diagnostic des services suivants. -9. `serveurs_grafana` +10. `serveurs_grafana` - Service central : tableaux de bord. - Intégration à prévoir : datasources Prometheus et Loki, authentification Keycloak. - Raison : Grafana consolide les métriques et journaux après leur mise en place. ### Phase 4 - Supervision active -10. `serveurs_icinga` +11. `serveurs_icinga` - Service central : supervision active, interface web et vues métiers Icinga. - Composants prévus : Icinga 2, Icinga Web 2, Icinga BPM. - Intégrations à prévoir : `clients_supervision`, PostgreSQL, NGINX, Keycloak si retenu. @@ -124,22 +131,22 @@ L'ordre ci-dessous privilégie les dépendances structurantes avant les applicat ### Phase 5 - Services applicatifs internes -11. `serveurs_redis` +12. `serveurs_redis` - Service central : cache et files internes. - Intégration à prévoir : Nextcloud et autres applications qui en ont besoin. - Raison : Redis est une dépendance applicative, pas une fondation globale. -12. `serveurs_forgejo` +13. `serveurs_forgejo` - Service central : forge Git. - Intégration à prévoir : PostgreSQL, NGINX, Keycloak, SMTP, sauvegardes. - Raison : la forge devient plus utile après SSO, TLS, SMTP et observabilité. -13. `serveurs_nextcloud` +14. `serveurs_nextcloud` - Service central : collaboration fichiers. - Intégration à prévoir : PostgreSQL, Redis, NGINX, Keycloak, SMTP, sauvegardes. - Raison : Nextcloud dépend de plusieurs fondations et doit arriver après elles. -14. `serveurs_collabora` +15. `serveurs_collabora` - Service central : édition documentaire en ligne. - Intégration à prévoir : Nextcloud, NGINX, certificats. - Raison : Collabora est une extension de Nextcloud et doit venir après lui. @@ -154,3 +161,14 @@ L'ordre ci-dessous privilégie les dépendances structurantes avant les applicat - Tout rôle serveur doit documenter ses ports, secrets, sauvegardes, dépendances et groupes clients associés. Les groupes clients peuvent être ajoutés aux VM existantes quand le service central correspondant est réellement disponible. + +## Dépendances causales + +Les dépendances exécutables sont déclarées dans `docs/dependances-groupes.yml`. + +Ce fichier sert à deux usages : + +- bloquer le déploiement d'un groupe tant que ses prérequis actifs ne sont pas présents ; +- fournir une source exploitable pour les futurs modèles de supervision. + +Un hôte peut porter un groupe client à l'état planifié. Le déploiement est refusé tant que le groupe serveur requis n'a pas au moins un hôte actif. diff --git a/docs/dependances-groupes.yml b/docs/dependances-groupes.yml new file mode 100644 index 0000000..a89c906 --- /dev/null +++ b/docs/dependances-groupes.yml @@ -0,0 +1,86 @@ +--- +groupes: + clients_dns: + requiert_groupes_actifs: + - serveurs_powerdns + raison: "Les resolvers clients ne doivent pas pointer vers un service DNS absent." + surveillance: "Verifier resolution interne et disponibilite du service DNS." + + clients_pki: + requiert_groupes_actifs: + - serveurs_step_ca + raison: "La confiance CA et ACME client dependent de l'autorite interne." + surveillance: "Verifier validite CA, emission ACME et expiration des certificats." + + clients_ldap: + requiert_groupes_actifs: + - serveurs_openldap + raison: "La configuration NSS/PAM/SSSD depend de l'annuaire LDAP." + surveillance: "Verifier bind LDAP, latence et expiration des certificats LDAP." + + clients_supervision: + requiert_groupes_actifs: + - serveurs_icinga + raison: "Les agents ou checks clients doivent se rattacher a une plateforme Icinga active." + surveillance: "Verifier enregistrement des hotes, fraicheur des checks et notifications." + + clients_metriques: + requiert_groupes_actifs: + - serveurs_prometheus + raison: "Les exporters clients doivent etre collectes par Prometheus." + surveillance: "Verifier targets Prometheus, scrape duration et erreurs de collecte." + + clients_journaux: + requiert_groupes_actifs: + - serveurs_loki + raison: "L'expedition des journaux depend du collecteur central Loki." + surveillance: "Verifier ingestion Loki, retard et volume de journaux." + + clients_smtp: + requiert_groupes_actifs: + - serveurs_sendmail + raison: "Les notifications locales doivent relayer vers un MTA actif." + surveillance: "Verifier file d'attente, relais SMTP et echecs de livraison." + + serveurs_keycloak: + requiert_groupes_actifs: + - serveurs_postgresql + raison: "Keycloak doit utiliser une base PostgreSQL geree." + surveillance: "Verifier connexion base, etat realm et disponibilite OIDC." + + serveurs_grafana: + requiert_groupes_actifs: + - serveurs_prometheus + - serveurs_loki + raison: "Grafana est utile comme interface aux metriques et journaux centraux." + surveillance: "Verifier datasources Prometheus/Loki et authentification." + + serveurs_icinga: + requiert_groupes_actifs: + - serveurs_postgresql + raison: "La plateforme Icinga Web/BPM depend d'une base relationnelle." + surveillance: "Verifier moteur Icinga, base, interface web et notifications." + + serveurs_forgejo: + requiert_groupes_actifs: + - serveurs_postgresql + - serveurs_nginx + - serveurs_sendmail + raison: "Forgejo depend d'une base, d'une publication HTTP(S) et du courriel." + surveillance: "Verifier HTTP(S), base, files Git et envoi courriel." + + serveurs_nextcloud: + requiert_groupes_actifs: + - serveurs_postgresql + - serveurs_redis + - serveurs_nginx + - serveurs_sendmail + raison: "Nextcloud depend d'une base, d'un cache, d'un frontal web et du courriel." + surveillance: "Verifier jobs, base, Redis, HTTP(S), stockage et courriel." + + serveurs_collabora: + requiert_groupes_actifs: + - serveurs_nextcloud + - serveurs_nginx + raison: "Collabora est expose via le frontal web et integre a Nextcloud." + surveillance: "Verifier connectivite Nextcloud, websocket et disponibilite HTTP(S)." diff --git a/docs/nomenclature-vm.md b/docs/nomenclature-vm.md index d97918b..44d77ee 100644 --- a/docs/nomenclature-vm.md +++ b/docs/nomenclature-vm.md @@ -18,6 +18,7 @@ Exemples : infra-pki-01 infra-edge-01 infra-mail-01 +infra-dns-01 idm-01 data-01 obs-01 @@ -35,6 +36,7 @@ Les noms courts historiques `web-01` et `web-02` restent valides pour les deux p | `infra-pki-01` | `serveurs_step_ca` | | `infra-edge-01` | `serveurs_nginx` | | `infra-mail-01` | `serveurs_sendmail` | +| `infra-dns-01` | `serveurs_powerdns` | | `idm-01` | `serveurs_openldap`, `serveurs_keycloak` | | `data-01` | `serveurs_postgresql`, `serveurs_redis` | | `obs-01` | `serveurs_prometheus`, `serveurs_loki`, `serveurs_grafana` | diff --git a/inventories/production/hosts.yml b/inventories/production/hosts.yml index 2eeb10a..c62ee5d 100644 --- a/inventories/production/hosts.yml +++ b/inventories/production/hosts.yml @@ -20,6 +20,8 @@ all: proxmox_vmid: 91201 infra-mail-01: proxmox_vmid: 91301 + infra-dns-01: + proxmox_vmid: 91401 idm-01: proxmox_vmid: 92101 data-01: @@ -43,6 +45,7 @@ all: infra-pki-01: {} infra-edge-01: {} infra-mail-01: {} + infra-dns-01: {} idm-01: {} data-01: {} obs-01: {} @@ -60,6 +63,7 @@ all: infra-pki-01: {} infra-edge-01: {} infra-mail-01: {} + infra-dns-01: {} idm-01: {} data-01: {} obs-01: {} @@ -104,6 +108,9 @@ all: serveurs_step_ca: hosts: infra-pki-01: {} + serveurs_powerdns: + hosts: + infra-dns-01: {} serveurs_redis: hosts: data-01: {} diff --git a/playbooks/groupes/serveurs_powerdns.yml b/playbooks/groupes/serveurs_powerdns.yml new file mode 100644 index 0000000..d8ddc1b --- /dev/null +++ b/playbooks/groupes/serveurs_powerdns.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_powerdns + hosts: serveurs_powerdns + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service PowerDNS reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_powerdns." diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py index af499d4..cba5676 100644 --- a/scripts/inventory_gui.py +++ b/scripts/inventory_gui.py @@ -15,6 +15,7 @@ from inventory_rules import ( GROUPE_HOTES_ACTIFS, GROUPE_HOTES_PLANIFIES, GROUPES_ETAT_HOTE, + charger_dependances, est_groupe_operationnel, groupes_operationnels_connus, ) @@ -22,6 +23,7 @@ from inventory_rules import ( RACINE = Path(__file__).resolve().parents[1] INVENTAIRE_DEFAUT = RACINE / "inventories/production/hosts.yml" DOSSIER_PLAYBOOKS_GROUPES = RACINE / "playbooks/groupes" +FICHIER_DEPENDANCES = RACINE / "docs/dependances-groupes.yml" def charger_yaml(path: Path) -> dict: @@ -99,9 +101,11 @@ def liste_hotes(data: dict) -> list[dict]: def inventaire_api(path: Path) -> dict: data = charger_yaml(path) + dependencies = charger_dependances(FICHIER_DEPENDANCES) return { "inventaire": str(path.relative_to(RACINE)), "groupes": groupes_disponibles(data), + "dependances": dependencies, "hotes": liste_hotes(data), } @@ -145,7 +149,30 @@ def construire_inventaire(payload: dict, groupes_connus: list[str]) -> dict: return {"all": {"children": enfants_data}} -def valider_payload(payload: dict, groupes_connus: list[str]) -> None: +def valider_dependances_payload(payload: dict, dependencies: dict) -> None: + hotes = payload.get("hotes", []) + active_groups: set[str] = set() + + for hote in hotes: + if hote.get("etat") != "actif": + continue + active_groups.update(hote.get("groupes", [])) + + missing: list[str] = [] + for hote in hotes: + if hote.get("etat") != "actif": + continue + nom = str(hote.get("nom", "")).strip() + for groupe in hote.get("groupes", []): + for required_group in dependencies.get(groupe, {}).get("requiert_groupes_actifs", []): + if required_group not in active_groups: + missing.append(f"{nom}: {groupe} requiert {required_group} actif") + + if missing: + raise ValueError("Dependances manquantes: " + "; ".join(missing)) + + +def valider_payload(payload: dict, groupes_connus: list[str], dependencies: dict) -> None: noms: set[str] = set() vmids: dict[str, str] = {} for hote in payload.get("hotes", []): @@ -170,6 +197,8 @@ def valider_payload(payload: dict, groupes_connus: list[str]) -> None: raise ValueError(f"VMID en double: {vmid} pour {vmids[vmid]} et {nom}") vmids[vmid] = nom + valider_dependances_payload(payload, dependencies) + HTML = r""" @@ -242,6 +271,7 @@ HTML = r"""