--- - name: Résoudre la base IcingaDB depuis le registre (rôle partagé) ansible.builtin.include_role: name: resoudre_base vars: resoudre_base_groupe: "{{ serveur_icingaweb2_icinga_groupe }}" # ON NE RESOUT PAS UN ANNUAIRE QUAND ON N'EN A PAS (2026-09-14). # # `resoudre_annuaire` etait appele SANS CONDITION. Au site — qui n'a ni LDAP ni Keycloak — # il tombait sur un plan sans application d'annuaire : # # object of type 'NoneType' has no len() # # Un message qui ne nomme ni l'annuaire, ni le role qui le demandait, ni la raison. Le # mode `locale` existe precisement pour se passer d'annuaire : il n'a rien a resoudre. - name: Résoudre l'annuaire (rôle partagé) ansible.builtin.include_role: name: resoudre_annuaire vars: # SON compte, pas celui de l'administrateur de l'annuaire (2026-09-13). resoudre_annuaire_bind_cn: "icingaweb2" resoudre_annuaire_secret: "vault_ldap_bind_icingaweb2" when: serveur_icingaweb2_auth != 'locale' - name: Adopter la connexion annuaire pour Icinga Web 2 ansible.builtin.set_fact: serveur_icingaweb2_ldap_url: "{{ resoudre_annuaire_uri }}" serveur_icingaweb2_ldap_port: "{{ resoudre_annuaire_port }}" serveur_icingaweb2_ldap_base: "{{ resoudre_annuaire_base_dn }}" serveur_icingaweb2_ldap_users_dn: "{{ resoudre_annuaire_users_dn }}" serveur_icingaweb2_ldap_bind_dn: "{{ resoudre_annuaire_bind_dn }}" serveur_icingaweb2_ldap_bind_password: "{{ resoudre_annuaire_bind_password }}" no_log: true when: serveur_icingaweb2_auth != 'locale' # LE CACHE DU CONTROLEUR D'ABORD, LE DEPOT DISTANT POUR LE RESTE (2026-09-03). # # Les depots tiers sont en HTTPS, et `client_artefacts` pose # `Acquire::https::Proxy "DIRECT"` — ils CONTOURNENT donc le cache du site et sortent sur # Internet a chaque construction de VM. `make cacher-paquets` les tire une fois, versions # epinglees et empreintes verifiees ; ce role les depose depuis ce cache. - name: Poser les paquets tiers depuis le cache du controleur ansible.builtin.include_role: name: paquets_tiers vars: paquets_tiers_noms: "{{ serveur_icingaweb2_paquets }}" - name: Installer Icinga Web 2 + module IcingaDB + PHP-FPM + nginx ansible.builtin.apt: # CE QUE LE CACHE N'A PAS FOURNI, ET RIEN D'AUTRE. Les dependances Debian passent # par le cache du site en HTTP ; seuls les paquets tiers non caches exigent Internet. # Reinstaller ce que le cache vient de poser ferait un `update_cache` inutile — et # hors ligne, il echouerait APRES un travail deja fait. name: "{{ serveur_icingaweb2_paquets | difference((paquets_tiers_disponibles | default({})).keys() | list) }}" state: present update_cache: true when: (serveur_icingaweb2_paquets | difference((paquets_tiers_disponibles | default({})).keys() | list)) | length > 0 - name: Ajouter www-data au groupe icingaweb2 (lecture de la config) ansible.builtin.user: name: www-data groups: icingaweb2 append: true notify: Redémarrer php-fpm - name: Assurer le répertoire du module IcingaDB ansible.builtin.file: path: "{{ serveur_icingaweb2_config_dir }}/modules/icingadb" state: directory owner: root group: icingaweb2 mode: "0750" - name: Déployer la configuration icingaweb2 (.ini) ansible.builtin.template: src: "{{ item.s }}" dest: "{{ serveur_icingaweb2_config_dir }}/{{ item.d }}" owner: root group: icingaweb2 mode: "0640" no_log: "{{ item.secret | default(false) }}" loop: - { s: config.ini.j2, d: config.ini } - { s: resources.ini.j2, d: resources.ini, secret: true } - { s: authentication.ini.j2, d: authentication.ini } - { s: groups.ini.j2, d: groups.ini } - { s: roles.ini.j2, d: roles.ini } - { s: icingadb-config.ini.j2, d: modules/icingadb/config.ini } - { s: icingadb-redis.ini.j2, d: modules/icingadb/redis.ini } loop_control: label: "{{ item.d }}" notify: Redémarrer php-fpm - name: Activer les modules icingaweb2 (IcingaDB, BPM) ansible.builtin.command: "icingacli module enable {{ item }}" args: creates: "{{ serveur_icingaweb2_config_dir }}/enabledModules/{{ item }}" loop: "{{ serveur_icingaweb2_modules }}" when: not ansible_check_mode - name: Assurer le répertoire des processus BPM (éditable via l'UI) ansible.builtin.file: path: "{{ serveur_icingaweb2_config_dir }}/modules/businessprocess/processes" state: directory owner: root group: icingaweb2 mode: "2770" when: "'businessprocess' in serveur_icingaweb2_modules" - name: Semer les processus métier BPM (IaC, optionnel) ansible.builtin.copy: content: "{{ item.value }}" dest: "{{ serveur_icingaweb2_config_dir }}/modules/businessprocess/processes/{{ item.key }}.conf" owner: root group: icingaweb2 mode: "0660" loop: "{{ serveur_icingaweb2_bpm_processes | dict2items }}" loop_control: label: "{{ item.key }}" when: serveur_icingaweb2_bpm_processes | length > 0 # --- MODE `locale` : LE VESTIBULE, AVANT LA PORTE (2026-09-14) ------------------------ # # Un SITE n'a ni annuaire ni passerelle SSO — ce sont des services d'ecosysteme. La # console de supervision etait donc impossible chez lui, et 88 verdicts se calculaient # sans que personne puisse les lire. # # `htpasswd` A LA MAIN PLUTOT QUE LE MODULE `community.general.htpasswd` : ce module # reecrit le fichier a chaque passage quand le hachage porte un sel aleatoire, et le role # se declarerait `changed` pour toujours. On hache une fois, on compare, on n'ecrit que # si ca differe. - name: Exiger un mot de passe pour la console locale ansible.builtin.assert: that: - serveur_icingaweb2_admin_motdepasse | length > 0 fail_msg: >- `serveur_icingaweb2_auth: locale` mais `vault_icingaweb2_admin` est vide. Une console qui montre l'etat de toute une fabric ne s'ouvre pas avec un mot de passe devine : ajouter la cle a la voute de cet ecosysteme. when: serveur_icingaweb2_auth == 'locale' - name: Installer de quoi hacher un mot de passe pour nginx ansible.builtin.apt: name: apache2-utils state: present when: serveur_icingaweb2_auth == 'locale' # CE QUI EST DEJA POSE EST-IL LE BON MOT DE PASSE ? `htpasswd -v` le VERIFIE sans rien # reecrire — c'est lui qui rend la tache idempotente, pas une comparaison de fichiers # (le sel change a chaque hachage, deux fichiers justes different toujours). - name: Le mot de passe deja pose est-il le bon ? ansible.builtin.command: argv: - htpasswd - -vb - "{{ serveur_icingaweb2_htpasswd }}" - "{{ serveur_icingaweb2_admin_utilisateur }}" - "{{ serveur_icingaweb2_admin_motdepasse }}" register: serveur_icingaweb2_htpasswd_verif changed_when: false failed_when: false no_log: true when: serveur_icingaweb2_auth == 'locale' - name: Poser le mot de passe de la console locale ansible.builtin.command: argv: - htpasswd - -cbB - "{{ serveur_icingaweb2_htpasswd }}" - "{{ serveur_icingaweb2_admin_utilisateur }}" - "{{ serveur_icingaweb2_admin_motdepasse }}" no_log: true # ELLE NE S'EXECUTE QUE SI LA VERIFICATION A ECHOUE — donc quand elle tourne, elle # change vraiment quelque chose. `changed_when: true` n'est pas une complaisance ici : # c'est l'idempotence qui vit dans le `when`, pas dans un test de sortie. changed_when: true when: - serveur_icingaweb2_auth == 'locale' - (serveur_icingaweb2_htpasswd_verif.rc | default(1)) != 0 notify: Recharger nginx - name: Refermer le fichier de mots de passe sur nginx ansible.builtin.file: path: "{{ serveur_icingaweb2_htpasswd }}" owner: root group: www-data mode: "0640" when: serveur_icingaweb2_auth == 'locale' - name: Déployer le vhost nginx local d'Icinga Web 2 ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/sites-available/icingaweb2.conf owner: root group: root mode: "0644" notify: Recharger nginx - name: Activer le vhost Icinga Web 2 ansible.builtin.file: src: /etc/nginx/sites-available/icingaweb2.conf dest: /etc/nginx/sites-enabled/icingaweb2.conf state: link notify: Recharger nginx - name: Retirer le site nginx par défaut ansible.builtin.file: path: /etc/nginx/sites-enabled/default state: absent notify: Recharger nginx - name: Activer et démarrer PHP-FPM et nginx ansible.builtin.systemd: name: "{{ item }}" enabled: true state: started loop: - "{{ serveur_icingaweb2_php_fpm_service }}" - "{{ serveur_icingaweb2_nginx_service }}" when: not ansible_check_mode # LE ROLE QUI POSSEDE LA VERITE DEPOSE SA PROPRE SONDE. `client_sante` la fait tourner et # pousse le resultat ; les greffons standard, eux, sont poses par le porteur. # # LA SUPERVISION SURVEILLE SA PROPRE VITRINE. Sans cette sonde, une console morte laisse # tous les verdicts au vert — le moteur va bien, les sondes poussent, et personne ne peut # plus rien lire. - name: Assurer le repertoire des sondes de supervision ansible.builtin.file: path: /usr/local/lib/setops/sondes state: directory owner: root group: root mode: "0755" - name: Deposer la sonde « console » ansible.builtin.template: src: sonde-console.sh.j2 dest: /usr/local/lib/setops/sondes/console.sh owner: root group: root mode: "0750"