diff --git a/CHANGELOG.md b/CHANGELOG.md index 97f43c6..5e0da0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,14 @@ - Modification de `make deployer HOTE=...` pour appliquer les playbooks correspondant aux groupes de l'hôte. - Ajout d'une vérification explicite de la bibliothèque Python `proxmoxer` avant les appels API Proxmox. - Retrait de la taille disque clone des paramètres Proxmox persistés afin de ne pas tenter de réduire un disque hérité du modèle. +- Ajout de la validation inventaire/playbooks pour empêcher un groupe opérationnel avec hôtes sans playbook homonyme. +- Ajout du playbook de groupe `serveurs_web` comme point d'ancrage explicite avant l'ajout d'un rôle web. +- Ajout d'un catalogue de services pour préparer Keycloak, OpenLDAP, PostgreSQL, Loki, Icinga, Prometheus, Grafana, Forgejo, Sendmail, step-ca, Redis, NGINX, Nextcloud et Collabora. +- Ajout des groupes et playbooks homonymes neutres pour les prochains services centraux et intégrations clientes. +- Documentation de l'ordre d'implémentation recommandé des services selon leurs dépendances et intégrations. +- Ajout d'une nomenclature VM/VMID et distinction entre hôtes planifiés et hôtes actifs dans l'inventaire. +- Ajout d'une interface web locale `make inventaire-ui` pour éditer et sauvegarder l'inventaire sans lancer de déploiement. +- Ajustement de la nomenclature planifiée vers des noms d'hôtes par domaine afin de permettre la cohabitation de plusieurs services sur une même VM. ## 2026-06-19 diff --git a/Makefile b/Makefile index ec34c0d..2a85933 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ INVENTAIRE_PRODUCTION ?= inventories/production/hosts.yml FICHIER_INVENTAIRE ?= $(INVENTAIRE_PRODUCTION) GROUPE_MODELE ?= modeles_vm GROUPE_DEBIAN ?= serveurs_debian +GROUPE_HOTES_ACTIFS ?= hotes_actifs LIMITE ?= $(GROUPE_DEBIAN) HOTE ?= ADRESSE_IP ?= @@ -122,6 +123,8 @@ aide: @printf '%s\n' ' make inventaire-verifier' @printf '%s\n' ' Lister les donnees brutes:' @printf '%s\n' ' make inventaire-lister' + @printf '%s\n' ' Interface locale de gestion:' + @printf '%s\n' ' make inventaire-ui' @printf '%s\n' '' @printf '%s\n' 'Modele Debian 13 Proxmox' @printf '%s\n' ' Construire et verifier:' @@ -168,20 +171,23 @@ syntaxe-proxmox: ansible-runtime ansible-playbook -i localhost, $(PLAYBOOK_PROXMOX_CLONER_VM) --syntax-check .PHONY: verifier -verifier: lint syntaxe +verifier: lint inventaire-verifier syntaxe -.PHONY: inventaire hote-ajouter hote-groupes hote-afficher appliquer deployer deployer-groupe cloner-vm creer-vm config inventaire-verifier inventaire-lister inventaire-graphe inventaire-hote inventaire-lab inventaire-production +.PHONY: inventaire 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 config: python3 scripts/config_proxmox.py +inventaire-ui: + 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) ajouter --hote $(HOTE) --adresse-ip $(ADRESSE_IP) --utilisateur-ansible $(UTILISATEUR_ANSIBLE) --groupes "$(GROUPES)" + python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) ajouter --hote $(HOTE) --adresse-ip $(ADRESSE_IP) --utilisateur-ansible $(UTILISATEUR_ANSIBLE) --groupes "$(GROUPES)" --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) $(MAKE) inventaire-verifier $(MAKE) hote-afficher HOTE="$(HOTE)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)" @@ -190,7 +196,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)" + python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) definir-groupes --hote $(HOTE) --groupes "$(GROUPES)" --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES) $(MAKE) inventaire-verifier $(MAKE) hote-afficher HOTE="$(HOTE)" FICHIER_INVENTAIRE="$(FICHIER_INVENTAIRE)" @@ -210,13 +216,15 @@ appliquer: ansible-runtime printf '%s\n' 'Refus: aucun playbook pour ce groupe: $(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml'; \ exit 2; \ fi - ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml" --limit $(GROUPE) + ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml" --limit '$(GROUPE):&$(GROUPE_HOTES_ACTIFS)' deployer: @if [[ -z "$(HOTE)" ]]; then \ printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \ exit 2; \ 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) $(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 $$?; \ @@ -304,6 +312,7 @@ creer-vm: 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) inventaire-lister: ansible-runtime ansible-inventory -i $(FICHIER_INVENTAIRE) --list diff --git a/README.md b/README.md index 3c7eebd..a7b677e 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,12 @@ make inventaire make hote-afficher HOTE=web-01 ``` +Ouvrir l'interface locale de gestion d'inventaire : + +```bash +make inventaire-ui +``` + Ajouter une VM à l'inventaire production et l'associer aux groupes qui détermineront sa configuration : ```bash @@ -71,6 +77,12 @@ Chaque groupe opérationnel doit avoir son playbook homonyme dans `playbooks/gro La conformité normale des VM passe par ces playbooks de groupes. Les rôles de socle et de durcissement sont appliqués par `serveurs_debian` et `serveurs_durcis`, pas par des playbooks de couches séparés. +Les groupes opérationnels avec des hôtes, comme `serveurs_web` ou `clients_dns`, sont validés contre `playbooks/groupes/` par les commandes d'inventaire. + +Le catalogue des services et intégrations prévus est dans `docs/catalogue-services.md`. + +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 : ```bash diff --git a/docs/catalogue-services.md b/docs/catalogue-services.md new file mode 100644 index 0000000..546e5c5 --- /dev/null +++ b/docs/catalogue-services.md @@ -0,0 +1,167 @@ +# Catalogue des services Chezlepro + +Ce document fixe les noms de groupes et de playbooks pour les prochains services. + +La règle reste : + +```text +groupe opérationnel -> playbooks/groupes/.yml +``` + +Les playbooks ajoutés maintenant sont des points d'ancrage. Ils ne doivent pas installer un service tant que le rôle correspondant n'existe pas et que ses variables, secrets et prérequis sont documentés. + +La nomenclature des VM et des VMID est documentée dans `docs/nomenclature-vm.md`. + +Un service central peut partager un hôte avec d'autres services du même domaine opérationnel. La relation stricte est entre groupe et playbook, pas entre groupe et VM. + +## Services centraux + +| Service | Groupe | Playbook | Rôle futur | +| --- | --- | --- | --- | +| Keycloak | `serveurs_keycloak` | `playbooks/groupes/serveurs_keycloak.yml` | `keycloak` | +| OpenLDAP | `serveurs_openldap` | `playbooks/groupes/serveurs_openldap.yml` | `openldap` | +| PostgreSQL | `serveurs_postgresql` | `playbooks/groupes/serveurs_postgresql.yml` | `postgresql` | +| Loki | `serveurs_loki` | `playbooks/groupes/serveurs_loki.yml` | `loki` | +| Icinga 2 | `serveurs_icinga2` | `playbooks/groupes/serveurs_icinga2.yml` | `icinga2` | +| Icinga Web 2 | `serveurs_icingaweb2` | `playbooks/groupes/serveurs_icingaweb2.yml` | `icingaweb2` | +| Icinga BPM | `serveurs_icinga_bpm` | `playbooks/groupes/serveurs_icinga_bpm.yml` | `icinga_bpm` | +| Prometheus | `serveurs_prometheus` | `playbooks/groupes/serveurs_prometheus.yml` | `prometheus` | +| Grafana | `serveurs_grafana` | `playbooks/groupes/serveurs_grafana.yml` | `grafana` | +| 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` | +| 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` | +| Collabora | `serveurs_collabora` | `playbooks/groupes/serveurs_collabora.yml` | `collabora` | + +## Hôtes planifiés + +| Hôte | Services | +| --- | --- | +| `infra-pki-01` | step-ca | +| `infra-edge-01` | NGINX WAF et reverse proxy | +| `infra-mail-01` | Sendmail MTA | +| `idm-01` | OpenLDAP, Keycloak | +| `data-01` | PostgreSQL, Redis | +| `obs-01` | Prometheus, Loki, Grafana | +| `mon-01` | Icinga 2, Icinga Web 2, Icinga BPM | +| `forge-01` | Forgejo | +| `collab-01` | Nextcloud, Collabora | + +## Intégrations clientes + +| Intégration | Groupe | Playbook | Rôle futur | +| --- | --- | --- | --- | +| Résolution DNS interne | `clients_dns` | `playbooks/groupes/clients_dns.yml` | `client_dns` | +| Confiance PKI / ACME | `clients_pki` | `playbooks/groupes/clients_pki.yml` | `client_pki` | +| Authentification LDAP | `clients_ldap` | `playbooks/groupes/clients_ldap.yml` | `client_ldap` | +| Supervision Icinga | `clients_supervision` | `playbooks/groupes/clients_supervision.yml` | `client_supervision` | +| Métriques Prometheus | `clients_metriques` | `playbooks/groupes/clients_metriques.yml` | `client_metriques` | +| Journaux vers Loki | `clients_journaux` | `playbooks/groupes/clients_journaux.yml` | `client_journaux` | +| Relais SMTP | `clients_smtp` | `playbooks/groupes/clients_smtp.yml` | `client_smtp` | + +## Ordre d'implémentation recommandé + +L'ordre ci-dessous privilégie les dépendances structurantes avant les applications. + +### Phase 1 - Fondations transversales + +1. `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` + - 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` + - 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` + - 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` + - 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` + - 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` + - 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` + - 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` + - 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_icinga2` + - Service central : supervision active, checks, alertes. + - Intégration à prévoir : `clients_supervision`. + - Raison : Icinga doit surveiller l'infrastructure déjà instrumentée. + +11. `serveurs_icingaweb2` + - Service central : interface web Icinga. + - Intégration à prévoir : PostgreSQL, NGINX, Keycloak si retenu. + - Raison : l'interface dépend du moteur Icinga et de la couche web. + +12. `serveurs_icinga_bpm` + - Service central : vues métiers Icinga. + - Intégration à prévoir : modèles de dépendances des services. + - Raison : BPM devient utile quand les premiers services critiques existent. + +### Phase 5 - Services applicatifs internes + +13. `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. + +14. `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é. + +15. `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. + +16. `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. + +## Règles d'intégration + +- Tout service exposé en HTTP(S) doit prévoir son intégration avec `serveurs_nginx`. +- Tout service avec authentification humaine doit prévoir son intégration avec `serveurs_keycloak`, sauf justification contraire. +- Tout service générant des alertes ou notifications doit prévoir `clients_smtp`. +- Toute VM de service doit rejoindre `clients_metriques`, `clients_journaux` et `clients_supervision` quand les services centraux correspondants existent. +- Tout service utilisant un certificat interne doit dépendre de `clients_pki`. +- 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. diff --git a/docs/nomenclature-vm.md b/docs/nomenclature-vm.md new file mode 100644 index 0000000..e330542 --- /dev/null +++ b/docs/nomenclature-vm.md @@ -0,0 +1,70 @@ +# Nomenclature des VM + +La nomenclature doit rendre lisible le domaine opérationnel d'une VM sans l'enfermer dans un seul service. + +Un hôte peut porter plusieurs groupes Ansible. Le nom de VM doit donc représenter une capacité ou un domaine, pas forcément un produit unique. + +## Noms de VM + +Format recommandé : + +```text +- +``` + +Exemples : + +```text +infra-pki-01 +infra-edge-01 +infra-mail-01 +idm-01 +data-01 +obs-01 +mon-01 +forge-01 +collab-01 +``` + +Les noms courts historiques `web-01` et `web-02` restent valides pour les deux premières VM déjà créées. + +## Regroupements recommandés + +| Hôte | Groupes prévus | +| --- | --- | +| `infra-pki-01` | `serveurs_step_ca` | +| `infra-edge-01` | `serveurs_nginx` | +| `infra-mail-01` | `serveurs_sendmail` | +| `idm-01` | `serveurs_openldap`, `serveurs_keycloak` | +| `data-01` | `serveurs_postgresql`, `serveurs_redis` | +| `obs-01` | `serveurs_prometheus`, `serveurs_loki`, `serveurs_grafana` | +| `mon-01` | `serveurs_icinga2`, `serveurs_icingaweb2`, `serveurs_icinga_bpm` | +| `forge-01` | `serveurs_forgejo` | +| `collab-01` | `serveurs_nextcloud`, `serveurs_collabora` | + +Les groupes restent fins et composables. La cohabitation se fait en associant plusieurs groupes au même hôte. + +## Plages VMID + +| Plage | Usage | +| --- | --- | +| `91xxx` | fondations transversales : PKI, reverse proxy, SMTP | +| `92xxx` | identité : LDAP, SSO | +| `93xxx` | données et cache : PostgreSQL, Redis | +| `94xxx` | observabilité et supervision | +| `95xxx` | applications internes | +| `99xxx` | modèles, essais initiaux ou exceptions documentées | + +## Hôtes planifiés + +Les hôtes prévus mais non encore déployés sont placés dans `hotes_planifies`. + +Les hôtes réellement joignables par Ansible sont placés dans `hotes_actifs`. + +Les déploiements groupés limitent automatiquement l'exécution à : + +```text + & hotes_actifs +``` + +Cela permet de renseigner l'inventaire complet sans tenter de configurer une VM qui n'existe pas encore. diff --git a/inventories/production/hosts.yml b/inventories/production/hosts.yml index 8037140..18d3e7e 100644 --- a/inventories/production/hosts.yml +++ b/inventories/production/hosts.yml @@ -2,6 +2,36 @@ all: children: modeles_vm: hosts: {} + hotes_actifs: + hosts: + web-01: + ansible_host: 192.168.12.101 + ansible_user: ansible + proxmox_vmid: 99101 + web-02: + ansible_host: 192.168.12.102 + ansible_user: ansible + proxmox_vmid: 99102 + hotes_planifies: + hosts: + infra-pki-01: + proxmox_vmid: 91101 + infra-edge-01: + proxmox_vmid: 91201 + infra-mail-01: + proxmox_vmid: 91301 + idm-01: + proxmox_vmid: 92101 + data-01: + proxmox_vmid: 93101 + obs-01: + proxmox_vmid: 94101 + mon-01: + proxmox_vmid: 94401 + forge-01: + proxmox_vmid: 95101 + collab-01: + proxmox_vmid: 95201 serveurs_debian: hosts: web-01: @@ -10,6 +40,15 @@ all: web-02: ansible_host: 192.168.12.102 ansible_user: ansible + infra-pki-01: {} + infra-edge-01: {} + infra-mail-01: {} + idm-01: {} + data-01: {} + obs-01: {} + mon-01: {} + forge-01: {} + collab-01: {} serveurs_durcis: hosts: web-01: @@ -18,11 +57,88 @@ all: web-02: ansible_host: 192.168.12.102 ansible_user: ansible + infra-pki-01: {} + infra-edge-01: {} + infra-mail-01: {} + idm-01: {} + data-01: {} + obs-01: {} + mon-01: {} + forge-01: {} + collab-01: {} serveurs_web: - hosts: {} + hosts: + web-01: + ansible_host: 192.168.12.101 + ansible_user: ansible + web-02: + ansible_host: 192.168.12.102 + ansible_user: ansible serveurs_bases_donnees: hosts: {} serveurs_supervision: hosts: {} + serveurs_keycloak: + hosts: + idm-01: {} + serveurs_openldap: + hosts: + idm-01: {} + serveurs_postgresql: + hosts: + data-01: {} + serveurs_loki: + hosts: + obs-01: {} + serveurs_icinga2: + hosts: + mon-01: {} + serveurs_icingaweb2: + hosts: + mon-01: {} + serveurs_icinga_bpm: + hosts: + mon-01: {} + serveurs_prometheus: + hosts: + obs-01: {} + serveurs_grafana: + hosts: + obs-01: {} + serveurs_forgejo: + hosts: + forge-01: {} + serveurs_sendmail: + hosts: + infra-mail-01: {} + serveurs_step_ca: + hosts: + infra-pki-01: {} + serveurs_redis: + hosts: + data-01: {} + serveurs_nginx: + hosts: + infra-edge-01: {} + serveurs_nextcloud: + hosts: + collab-01: {} + serveurs_collabora: + hosts: + collab-01: {} + clients_dns: + hosts: {} + clients_pki: + hosts: {} + clients_ldap: + hosts: {} + clients_supervision: + hosts: {} + clients_metriques: + hosts: {} + clients_journaux: + hosts: {} + clients_smtp: + hosts: {} hotes_proxmox: hosts: {} diff --git a/playbooks/groupes/clients_dns.yml b/playbooks/groupes/clients_dns.yml new file mode 100644 index 0000000..9bdbaf3 --- /dev/null +++ b/playbooks/groupes/clients_dns.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe clients_dns + hosts: clients_dns + become: true + gather_facts: true + + tasks: + - name: Indiquer que l'intégration cliente DNS reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe clients_dns." diff --git a/playbooks/groupes/clients_journaux.yml b/playbooks/groupes/clients_journaux.yml new file mode 100644 index 0000000..2ab057b --- /dev/null +++ b/playbooks/groupes/clients_journaux.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe clients_journaux + hosts: clients_journaux + become: true + gather_facts: true + + tasks: + - name: Indiquer que l'intégration cliente journaux reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe clients_journaux." diff --git a/playbooks/groupes/clients_ldap.yml b/playbooks/groupes/clients_ldap.yml new file mode 100644 index 0000000..35e2602 --- /dev/null +++ b/playbooks/groupes/clients_ldap.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe clients_ldap + hosts: clients_ldap + become: true + gather_facts: true + + tasks: + - name: Indiquer que l'intégration cliente LDAP reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe clients_ldap." diff --git a/playbooks/groupes/clients_metriques.yml b/playbooks/groupes/clients_metriques.yml new file mode 100644 index 0000000..ad2be79 --- /dev/null +++ b/playbooks/groupes/clients_metriques.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe clients_metriques + hosts: clients_metriques + become: true + gather_facts: true + + tasks: + - name: Indiquer que l'intégration cliente métriques reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe clients_metriques." diff --git a/playbooks/groupes/clients_pki.yml b/playbooks/groupes/clients_pki.yml new file mode 100644 index 0000000..d774f93 --- /dev/null +++ b/playbooks/groupes/clients_pki.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe clients_pki + hosts: clients_pki + become: true + gather_facts: true + + tasks: + - name: Indiquer que l'intégration cliente PKI reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe clients_pki." diff --git a/playbooks/groupes/clients_smtp.yml b/playbooks/groupes/clients_smtp.yml new file mode 100644 index 0000000..dc9c449 --- /dev/null +++ b/playbooks/groupes/clients_smtp.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe clients_smtp + hosts: clients_smtp + become: true + gather_facts: true + + tasks: + - name: Indiquer que l'intégration cliente SMTP reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe clients_smtp." diff --git a/playbooks/groupes/clients_supervision.yml b/playbooks/groupes/clients_supervision.yml new file mode 100644 index 0000000..05cfd26 --- /dev/null +++ b/playbooks/groupes/clients_supervision.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe clients_supervision + hosts: clients_supervision + become: true + gather_facts: true + + tasks: + - name: Indiquer que l'intégration cliente supervision reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe clients_supervision." diff --git a/playbooks/groupes/serveurs_collabora.yml b/playbooks/groupes/serveurs_collabora.yml new file mode 100644 index 0000000..b73130e --- /dev/null +++ b/playbooks/groupes/serveurs_collabora.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_collabora + hosts: serveurs_collabora + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Collabora reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_collabora." diff --git a/playbooks/groupes/serveurs_forgejo.yml b/playbooks/groupes/serveurs_forgejo.yml new file mode 100644 index 0000000..0b25ac8 --- /dev/null +++ b/playbooks/groupes/serveurs_forgejo.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_forgejo + hosts: serveurs_forgejo + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Forgejo reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_forgejo." diff --git a/playbooks/groupes/serveurs_grafana.yml b/playbooks/groupes/serveurs_grafana.yml new file mode 100644 index 0000000..efc16e6 --- /dev/null +++ b/playbooks/groupes/serveurs_grafana.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_grafana + hosts: serveurs_grafana + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Grafana reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_grafana." diff --git a/playbooks/groupes/serveurs_icinga2.yml b/playbooks/groupes/serveurs_icinga2.yml new file mode 100644 index 0000000..9c62c6a --- /dev/null +++ b/playbooks/groupes/serveurs_icinga2.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_icinga2 + hosts: serveurs_icinga2 + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Icinga 2 reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_icinga2." diff --git a/playbooks/groupes/serveurs_icinga_bpm.yml b/playbooks/groupes/serveurs_icinga_bpm.yml new file mode 100644 index 0000000..1b3ccf3 --- /dev/null +++ b/playbooks/groupes/serveurs_icinga_bpm.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_icinga_bpm + hosts: serveurs_icinga_bpm + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Icinga BPM reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_icinga_bpm." diff --git a/playbooks/groupes/serveurs_icingaweb2.yml b/playbooks/groupes/serveurs_icingaweb2.yml new file mode 100644 index 0000000..e64e9dd --- /dev/null +++ b/playbooks/groupes/serveurs_icingaweb2.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_icingaweb2 + hosts: serveurs_icingaweb2 + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Icinga Web 2 reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_icingaweb2." diff --git a/playbooks/groupes/serveurs_keycloak.yml b/playbooks/groupes/serveurs_keycloak.yml new file mode 100644 index 0000000..3b253ea --- /dev/null +++ b/playbooks/groupes/serveurs_keycloak.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_keycloak + hosts: serveurs_keycloak + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Keycloak reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_keycloak." diff --git a/playbooks/groupes/serveurs_loki.yml b/playbooks/groupes/serveurs_loki.yml new file mode 100644 index 0000000..3ccb1cf --- /dev/null +++ b/playbooks/groupes/serveurs_loki.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_loki + hosts: serveurs_loki + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Loki reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_loki." diff --git a/playbooks/groupes/serveurs_nextcloud.yml b/playbooks/groupes/serveurs_nextcloud.yml new file mode 100644 index 0000000..b30ef6d --- /dev/null +++ b/playbooks/groupes/serveurs_nextcloud.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_nextcloud + hosts: serveurs_nextcloud + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Nextcloud reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_nextcloud." diff --git a/playbooks/groupes/serveurs_nginx.yml b/playbooks/groupes/serveurs_nginx.yml new file mode 100644 index 0000000..38d94bc --- /dev/null +++ b/playbooks/groupes/serveurs_nginx.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_nginx + hosts: serveurs_nginx + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service NGINX reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_nginx." diff --git a/playbooks/groupes/serveurs_openldap.yml b/playbooks/groupes/serveurs_openldap.yml new file mode 100644 index 0000000..aa0abfa --- /dev/null +++ b/playbooks/groupes/serveurs_openldap.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_openldap + hosts: serveurs_openldap + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service OpenLDAP reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_openldap." diff --git a/playbooks/groupes/serveurs_postgresql.yml b/playbooks/groupes/serveurs_postgresql.yml new file mode 100644 index 0000000..b0dc0b5 --- /dev/null +++ b/playbooks/groupes/serveurs_postgresql.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_postgresql + hosts: serveurs_postgresql + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service PostgreSQL reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_postgresql." diff --git a/playbooks/groupes/serveurs_prometheus.yml b/playbooks/groupes/serveurs_prometheus.yml new file mode 100644 index 0000000..6b9c5c2 --- /dev/null +++ b/playbooks/groupes/serveurs_prometheus.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_prometheus + hosts: serveurs_prometheus + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Prometheus reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_prometheus." diff --git a/playbooks/groupes/serveurs_redis.yml b/playbooks/groupes/serveurs_redis.yml new file mode 100644 index 0000000..ce1a250 --- /dev/null +++ b/playbooks/groupes/serveurs_redis.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_redis + hosts: serveurs_redis + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Redis reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_redis." diff --git a/playbooks/groupes/serveurs_sendmail.yml b/playbooks/groupes/serveurs_sendmail.yml new file mode 100644 index 0000000..ab345d9 --- /dev/null +++ b/playbooks/groupes/serveurs_sendmail.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_sendmail + hosts: serveurs_sendmail + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service Sendmail reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_sendmail." diff --git a/playbooks/groupes/serveurs_step_ca.yml b/playbooks/groupes/serveurs_step_ca.yml new file mode 100644 index 0000000..8c5af2e --- /dev/null +++ b/playbooks/groupes/serveurs_step_ca.yml @@ -0,0 +1,10 @@ +--- +- name: Appliquer le groupe serveurs_step_ca + hosts: serveurs_step_ca + become: true + gather_facts: true + + tasks: + - name: Indiquer que le service step-ca reste à définir + ansible.builtin.debug: + msg: "Aucun rôle n'est encore associé au groupe serveurs_step_ca." diff --git a/playbooks/groupes/serveurs_web.yml b/playbooks/groupes/serveurs_web.yml new file mode 100644 index 0000000..7355f40 --- /dev/null +++ b/playbooks/groupes/serveurs_web.yml @@ -0,0 +1,17 @@ +--- +- name: Appliquer le groupe serveurs_web + hosts: serveurs_web + become: true + gather_facts: true + + pre_tasks: + - name: Vérifier que la cible est Debian + ansible.builtin.assert: + that: + - ansible_facts.distribution == "Debian" + fail_msg: "Ce playbook est prévu pour Debian." + + tasks: + - name: Indiquer que le rôle web reste à définir + ansible.builtin.debug: + msg: "Aucun rôle web n'est encore associé au groupe serveurs_web." diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py new file mode 100644 index 0000000..3972518 --- /dev/null +++ b/scripts/inventory_gui.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python3 +"""Interface web locale pour gerer un inventaire Set-OPS.""" + +from __future__ import annotations + +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +import argparse +import json +from pathlib import Path +from urllib.parse import urlparse + +import yaml + + +RACINE = Path(__file__).resolve().parents[1] +INVENTAIRE_DEFAUT = RACINE / "inventories/production/hosts.yml" +DOSSIER_PLAYBOOKS_GROUPES = RACINE / "playbooks/groupes" +GROUPES_OPERATIONNELS_PREFIXES = ("serveurs_", "clients_") +GROUPES_ETAT = ("hotes_actifs", "hotes_planifies") + + +def charger_yaml(path: Path) -> dict: + if not path.exists(): + return {"all": {"children": {}}} + with path.open("r", encoding="utf-8") as fichier: + data = yaml.safe_load(fichier) or {} + if not isinstance(data, dict): + raise ValueError(f"{path} ne contient pas une table YAML.") + data.setdefault("all", {}) + data["all"].setdefault("children", {}) + return data + + +def ecrire_yaml(path: Path, data: dict) -> None: + with path.open("w", encoding="utf-8") as fichier: + yaml.safe_dump(data, fichier, default_flow_style=False, sort_keys=False, allow_unicode=True) + + +def enfants(data: dict) -> dict: + return data.setdefault("all", {}).setdefault("children", {}) + + +def groupes_disponibles(data: dict) -> list[str]: + groupes = set(enfants(data)) + groupes.update(playbook.stem for playbook in DOSSIER_PLAYBOOKS_GROUPES.glob("*.yml")) + return sorted(group for group in groupes if group.startswith(GROUPES_OPERATIONNELS_PREFIXES)) + + +def variables_hote(data: dict, hote: str) -> dict: + resultat: dict = {} + for groupe_data in enfants(data).values(): + hosts = groupe_data.get("hosts", {}) + valeurs = hosts.get(hote) + if isinstance(valeurs, dict): + resultat.update(valeurs) + return resultat + + +def liste_hotes(data: dict) -> list[dict]: + noms = set() + for groupe_data in enfants(data).values(): + noms.update(groupe_data.get("hosts", {})) + + hotes = [] + for nom in sorted(noms): + groupes = [] + etat = "planifie" + for groupe, groupe_data in enfants(data).items(): + if nom not in groupe_data.get("hosts", {}): + continue + if groupe == "hotes_actifs": + etat = "actif" + elif groupe in GROUPES_ETAT: + continue + elif groupe.startswith(GROUPES_OPERATIONNELS_PREFIXES): + groupes.append(groupe) + variables = variables_hote(data, nom) + hotes.append( + { + "nom": nom, + "etat": etat, + "adresse_ip": variables.get("ansible_host", ""), + "utilisateur_ansible": variables.get("ansible_user", "ansible"), + "vmid": variables.get("proxmox_vmid", ""), + "groupes": sorted(groupes), + } + ) + return hotes + + +def inventaire_api(path: Path) -> dict: + data = charger_yaml(path) + return { + "inventaire": str(path.relative_to(RACINE)), + "groupes": groupes_disponibles(data), + "hotes": liste_hotes(data), + } + + +def donnees_hote(hote: dict) -> dict: + variables: dict = {} + adresse_ip = str(hote.get("adresse_ip", "")).strip() + utilisateur = str(hote.get("utilisateur_ansible", "")).strip() + vmid = str(hote.get("vmid", "")).strip() + if adresse_ip: + variables["ansible_host"] = adresse_ip + if utilisateur: + variables["ansible_user"] = utilisateur + if vmid: + variables["proxmox_vmid"] = int(vmid) if vmid.isdigit() else vmid + return variables + + +def construire_inventaire(payload: dict, groupes_connus: list[str]) -> dict: + enfants_data: dict = { + "modeles_vm": {"hosts": {}}, + "hotes_actifs": {"hosts": {}}, + "hotes_planifies": {"hosts": {}}, + } + for groupe in groupes_connus: + enfants_data.setdefault(groupe, {"hosts": {}}) + enfants_data.setdefault("hotes_proxmox", {"hosts": {}}) + + for hote in payload.get("hotes", []): + nom = str(hote.get("nom", "")).strip() + if not nom: + continue + variables = donnees_hote(hote) + groupe_etat = "hotes_actifs" if hote.get("etat") == "actif" else "hotes_planifies" + enfants_data[groupe_etat]["hosts"][nom] = variables + for groupe in hote.get("groupes", []): + if groupe not in groupes_connus: + continue + enfants_data[groupe]["hosts"][nom] = {} + + return {"all": {"children": enfants_data}} + + +def valider_payload(payload: dict, groupes_connus: list[str]) -> None: + noms: set[str] = set() + for hote in payload.get("hotes", []): + nom = str(hote.get("nom", "")).strip() + if not nom: + raise ValueError("Un hote a un nom vide.") + if nom in noms: + raise ValueError(f"Hote en double: {nom}") + noms.add(nom) + groupes = hote.get("groupes", []) + if not groupes: + raise ValueError(f"Aucun groupe operationnel pour: {nom}") + inconnus = sorted(set(groupes) - set(groupes_connus)) + if inconnus: + raise ValueError(f"Groupes inconnus pour {nom}: {', '.join(inconnus)}") + + +HTML = r""" + + + + + Set-OPS - Inventaire + + + +
+
+

Inventaire Set-OPS

+
+
+
+ + + +
+
+
+
+ + + + + + + + + + + + + +
HôteÉtatAdresse IPUtilisateurVMIDGroupes
+
+ + + +""" + + +class Gestionnaire(BaseHTTPRequestHandler): + inventaire: Path = INVENTAIRE_DEFAUT + + def repondre(self, status: int, contenu: bytes, content_type: str) -> None: + self.send_response(status) + self.send_header("Content-Type", content_type) + self.send_header("Content-Length", str(len(contenu))) + self.end_headers() + self.wfile.write(contenu) + + def repondre_json(self, status: int, data: dict) -> None: + self.repondre(status, json.dumps(data, ensure_ascii=False).encode("utf-8"), "application/json; charset=utf-8") + + def do_GET(self) -> None: + chemin = urlparse(self.path).path + try: + if chemin == "/": + self.repondre(200, HTML.encode("utf-8"), "text/html; charset=utf-8") + elif chemin == "/api/inventaire": + self.repondre_json(200, inventaire_api(self.inventaire)) + else: + self.repondre_json(404, {"erreur": "Introuvable"}) + except Exception as exc: + self.repondre_json(500, {"erreur": str(exc)}) + + def do_POST(self) -> None: + chemin = urlparse(self.path).path + try: + if chemin != "/api/inventaire": + self.repondre_json(404, {"erreur": "Introuvable"}) + return + longueur = int(self.headers.get("Content-Length", "0")) + payload = json.loads(self.rfile.read(longueur).decode("utf-8")) + courant = charger_yaml(self.inventaire) + groupes_connus = groupes_disponibles(courant) + valider_payload(payload, groupes_connus) + nouveau = construire_inventaire(payload, groupes_connus) + ecrire_yaml(self.inventaire, nouveau) + self.repondre_json(200, inventaire_api(self.inventaire)) + except Exception as exc: + self.repondre_json(400, {"erreur": str(exc)}) + + +def main() -> int: + parser = argparse.ArgumentParser(description="Interface web locale pour gerer un inventaire Set-OPS.") + parser.add_argument("--inventaire", type=Path, default=INVENTAIRE_DEFAUT) + parser.add_argument("--hote", default="127.0.0.1") + parser.add_argument("--port", type=int, default=8765) + args = parser.parse_args() + + Gestionnaire.inventaire = args.inventaire.resolve() + serveur = ThreadingHTTPServer((args.hote, args.port), Gestionnaire) + print(f"Interface inventaire: http://{args.hote}:{args.port}/") + print(f"Inventaire: {Gestionnaire.inventaire}") + serveur.serve_forever() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/inventory_host.py b/scripts/inventory_host.py index 00ea508..845b224 100644 --- a/scripts/inventory_host.py +++ b/scripts/inventory_host.py @@ -10,6 +10,12 @@ import sys import yaml +GROUPES_OPERATIONNELS_PREFIXES = ("serveurs_", "clients_") +GROUPE_HOTES_ACTIFS = "hotes_actifs" +GROUPE_HOTES_PLANIFIES = "hotes_planifies" +GROUPES_ETAT_HOTE = {GROUPE_HOTES_ACTIFS, GROUPE_HOTES_PLANIFIES} + + def charger_inventaire(path: Path) -> dict: if not path.exists(): return {"all": {"children": {}}} @@ -78,12 +84,20 @@ def ajouter_hote(data: dict, host: str, groups: list[str], ip: str | None, ansib for group in groups: assurer_groupe(data, group)["hosts"][host] = dict(vars_for_host) + if ip: + assurer_groupe(data, GROUPE_HOTES_ACTIFS)["hosts"][host] = dict(vars_for_host) + assurer_groupe(data, GROUPE_HOTES_PLANIFIES)["hosts"].pop(host, None) + def definir_groupes_hote(data: dict, host: str, groups: list[str]) -> None: vars_for_host = variables_hote(data, host) - if not groupes_hote(data, host): + current_groups = groupes_hote(data, host) + if not current_groups: raise ValueError(f"Hote absent de l'inventaire: {host}") retirer_hote_de_tous_les_groupes(data, host) + for group in current_groups: + if group in GROUPES_ETAT_HOTE: + assurer_groupe(data, group)["hosts"][host] = dict(vars_for_host) for group in groups: assurer_groupe(data, group)["hosts"][host] = dict(vars_for_host) @@ -122,6 +136,8 @@ def afficher_playbooks_hote(data: dict, host: str, playbook_dir: Path) -> None: playbooks: list[Path] = [] for group in groups: + if not group.startswith(GROUPES_OPERATIONNELS_PREFIXES): + continue playbook = playbook_dir / f"{group}.yml" if playbook.exists(): playbooks.append(playbook) @@ -132,10 +148,37 @@ def afficher_playbooks_hote(data: dict, host: str, playbook_dir: Path) -> None: missing = ", ".join(missing_playbooks) raise ValueError(f"Playbook de groupe manquant pour: {missing}") + if not playbooks: + raise ValueError(f"Aucun playbook de groupe opérationnel pour: {host}") + for playbook in playbooks: print(playbook) +def verifier_hote_actif(data: dict, host: str) -> None: + hosts = enfants(data).get(GROUPE_HOTES_ACTIFS, {}).get("hosts", {}) + if host not in hosts: + raise ValueError(f"Hote non actif dans l'inventaire: {host}") + + +def verifier_playbooks_groupes(data: dict, playbook_dir: Path) -> None: + missing_playbooks: list[str] = [] + + for group, group_data in enfants(data).items(): + hosts = group_data.get("hosts", {}) + if not hosts: + continue + if not group.startswith(GROUPES_OPERATIONNELS_PREFIXES): + continue + playbook = playbook_dir / f"{group}.yml" + if not playbook.exists(): + missing_playbooks.append(group) + + if missing_playbooks: + missing = ", ".join(sorted(missing_playbooks)) + raise ValueError(f"Playbook de groupe manquant pour: {missing}") + + def main() -> int: parser = argparse.ArgumentParser(description="Gere les hotes d'un inventaire Ansible statique Set-OPS.") parser.add_argument("--inventaire", required=True, type=Path) @@ -147,10 +190,12 @@ def main() -> int: add_parser.add_argument("--groupes", required=True) add_parser.add_argument("--adresse-ip") add_parser.add_argument("--utilisateur-ansible") + add_parser.add_argument("--dossier-playbooks", type=Path) groups_parser = subparsers.add_parser("definir-groupes", help="Remplace l'appartenance aux groupes pour un hote.") groups_parser.add_argument("--hote", required=True) groups_parser.add_argument("--groupes", required=True) + groups_parser.add_argument("--dossier-playbooks", type=Path) show_parser = subparsers.add_parser("afficher", help="Affiche les groupes et variables d'un hote.") show_parser.add_argument("--hote", required=True) @@ -159,6 +204,15 @@ def main() -> int: playbooks_parser.add_argument("--hote", required=True) playbooks_parser.add_argument("--dossier-playbooks", required=True, type=Path) + active_parser = subparsers.add_parser("verifier-actif", help="Verifie qu'un hote est actif.") + active_parser.add_argument("--hote", required=True) + + verify_parser = subparsers.add_parser( + "verifier-playbooks", + help="Verifie que les groupes operationnels avec hotes ont un playbook homonyme.", + ) + verify_parser.add_argument("--dossier-playbooks", required=True, type=Path) + args = parser.parse_args() try: @@ -172,14 +226,22 @@ def main() -> int: args.adresse_ip, args.utilisateur_ansible, ) + if args.dossier_playbooks: + verifier_playbooks_groupes(data, args.dossier_playbooks) ecrire_inventaire(args.inventaire, data) elif args.command == "definir-groupes": definir_groupes_hote(data, args.hote, analyser_groupes(args.groupes)) + if args.dossier_playbooks: + verifier_playbooks_groupes(data, args.dossier_playbooks) ecrire_inventaire(args.inventaire, data) elif args.command == "afficher": afficher_hote(data, args.hote) elif args.command == "playbooks": afficher_playbooks_hote(data, args.hote, args.dossier_playbooks) + elif args.command == "verifier-actif": + verifier_hote_actif(data, args.hote) + elif args.command == "verifier-playbooks": + verifier_playbooks_groupes(data, args.dossier_playbooks) except Exception as exc: print(f"erreur: {exc}", file=sys.stderr) return 2