diff --git a/CHANGELOG.md b/CHANGELOG.md index 6357c01..9b0b81f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,47 @@ # CHANGELOG — Set-OPS +## 2026-10-04 (71) — Vues métier dans la vigie : une par clientèle interne, dérivées + +**Demande de l'exploitant** : que le module Business Process d'Icinga offre des vues +d'ensemble à différentes clientèles internes. Choisi avec lui : personnel, direction, +exploitation ; au site et chez les locataires ; dérivées du plan. Catalogue validé avant +d'écrire. + +**Constat** : le seul processus existant (`supervision`, écrit à la main dans les group_vars +des deux locataires) visait un hôte `icinga` et des contrôles (`load`, `procs`, `swap`, `ssh`) +qui n'existent plus. Il ne pouvait rien montrer de juste. **Retiré.** + +**Fait** : +- chaque sonde déclare son service métier dans le `meta/supervision.yml` de son rôle + (`metier:`, 47 sondes, 38 rôles) ; +- `serveur_icingaweb2` porte le catalogue (`serveur_icingaweb2_bpm_vues`, `_services`) : + titres, clientèles, regroupement « fondations » et socle par machine ; +- `bpm-membres.json.j2` calcule les contrôles de chaque service avec la même dérivation que + `serveur_icinga` (hôtes du rôle et de `client_sante`, condition `seulement_si`), plus ce qui + ne vient pas des rôles : sauvegardes (les deux modèles, lus chez `client_backup`), `sante` + et `ping4` de chaque machine, `materiel` des hyperviseurs, pattes de la frontière ; +- `bpm-vue.conf.j2` écrit `setops-.conf`. Une vue sans service n'est pas posée, et + « Mes outils » n'existe que là où des personnes se connectent : pas au site. + +**Trois vues** : **Mes outils** (personnel — se connecter, courriel, fichiers, édition, +sites web, sans nom de machine) ; **Services rendus** (direction — un voyant par service, +sûreté des données, « Fondations techniques ») ; **Exploitation** (tout, déplié jusqu'au +contrôle et à la machine). + +**Éprouvé** : chaque contrôle nommé comparé à ce qu'Icinga surveille vraiment — site 152, +Chezlepro 183 : aucun absent, aucun service laissé hors vue. Trois défauts trouvés ainsi et +corrigés : la condition `seulement_si` passée par `| bool` (« frontiere » devenait faux, +`journaux-frontiere` disparaissait) ; les sauvegardes écrites « l'un ou l'autre » alors que +le site porte les deux modèles ; l'edge classé « sites web publics » (c'est la passerelle des +services internes : il fabriquait une vue « Mes outils » au site). Puis chaque vue évaluée par +le module (`icingacli businessprocess process check`) au site et chez les deux locataires, +sans erreur. Ce qu'elles disent aujourd'hui, et c'est juste : au site, socle en +avertissement (gandalf, matériel) ; chez les deux locataires, sûreté des données en +avertissement (sauvegarde VIDE de `web-dorsal-01`) ; chez Chezlepro, socle (correctif redis +de `edge-mta-01`). + +**Validation** : `ansible-lint` (0 violation), `make verifier` conforme (83/83). + ## 2026-10-04 (70) — Un tableau de synthèse, au site et chez les locataires **Demande de l'exploitant** : la seconde moitié de « rendre les tableaux plus parlants » — un diff --git a/roles/client_journal/meta/supervision.yml b/roles/client_journal/meta/supervision.yml index c6ce14a..ee28f0f 100644 --- a/roles/client_journal/meta/supervision.yml +++ b/roles/client_journal/meta/supervision.yml @@ -19,6 +19,7 @@ # precedent : ce qui AUGMENTE est une perte en cours, ce qui stagne est une cicatrice. sondes: - nom: journaux + metier: socle ttl: 5400 raison: >- Les journaux de cette machine partent-ils vraiment vers Loki ? Alloy peut tourner, diff --git a/roles/client_metrique/meta/supervision.yml b/roles/client_metrique/meta/supervision.yml index 54eb273..7bd4d9b 100644 --- a/roles/client_metrique/meta/supervision.yml +++ b/roles/client_metrique/meta/supervision.yml @@ -17,6 +17,7 @@ # donc DECLARES sans objet, dans une liste qu'une machine de metal peut vider. sondes: - nom: metriques + metier: socle # Six fois la periode du porteur (15 min) : cinq passages peuvent manquer avant # qu'Icinga ne perime. On ne crie pas pour un hoquet, on crie pour un silence. ttl: 5400 diff --git a/roles/client_pki/meta/supervision.yml b/roles/client_pki/meta/supervision.yml index 3d6850c..e90fc88 100644 --- a/roles/client_pki/meta/supervision.yml +++ b/roles/client_pki/meta/supervision.yml @@ -27,6 +27,7 @@ # contraire. La sonde compare donc les deux quand un service consomme le certificat. sondes: - nom: certificat + metier: socle # 5400 s = une heure et demie, soit six fois la periode du porteur (15 min). Cinq # passages peuvent manquer avant qu'Icinga ne perime : on ne crie pas pour un hoquet, # on crie pour un silence. diff --git a/roles/client_sante/meta/supervision.yml b/roles/client_sante/meta/supervision.yml index 4cc0871..f101dfb 100644 --- a/roles/client_sante/meta/supervision.yml +++ b/roles/client_sante/meta/supervision.yml @@ -9,12 +9,14 @@ # script, et P64 veut, a juste titre, que la declaration suive le role qui depose. sondes: - nom: disque + metier: socle ttl: 5400 raison: >- Reste-t-il de la place, et des inodes, sur chaque systeme de fichiers ? Seuls le cache apt et les depots de sauvegarde etaient surveilles : un disque plein arretait la base ou le courriel sans prevenir. - nom: plancher + metier: socle ttl: 5400 # Posee sous la condition du plancher (voir `setops-sondes.conf.j2`, 2026-09-28). seulement_si: hosts_statiques_actif diff --git a/roles/serveur_artefacts/meta/supervision.yml b/roles/serveur_artefacts/meta/supervision.yml index 5683edb..284b809 100644 --- a/roles/serveur_artefacts/meta/supervision.yml +++ b/roles/serveur_artefacts/meta/supervision.yml @@ -2,10 +2,12 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: cache-apt + metier: paquets ttl: 5400 raison: Le cache d'artefacts repond-il ? S'il se tait, TOUT apt de l'ecosysteme echoue — on agit dans la minute. - nom: cache-apt-volume + metier: paquets ttl: 5400 raison: 'Reste-t-il de la place au cache ? Un cache plein cesse d''ecrire sans se plaindre, et l''echec apparait chez les clients. Verdict distinct de la disponibilite : il appelle un billet, pas un reveil.' diff --git a/roles/serveur_backup/meta/supervision.yml b/roles/serveur_backup/meta/supervision.yml index 22a5ecf..a6382fe 100644 --- a/roles/serveur_backup/meta/supervision.yml +++ b/roles/serveur_backup/meta/supervision.yml @@ -21,6 +21,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: depot + metier: donnees ttl: 5400 raison: 'Le depot accepte-t-il encore une ecriture ? Il ne juge pas le contenu — chiffre cote client, il ne peut pas l''ouvrir. Il constate que l''endroit prend encore : en diff --git a/roles/serveur_backup_site/meta/supervision.yml b/roles/serveur_backup_site/meta/supervision.yml index 764da00..b30bd36 100644 --- a/roles/serveur_backup_site/meta/supervision.yml +++ b/roles/serveur_backup_site/meta/supervision.yml @@ -27,6 +27,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: depot-locataires + metier: sauvegardes_locataires ttl: 5400 raison: 'Les depots des locataires sont-ils toujours etanches, et reste-t-il de la place devant eux ? Un mode qui glisse laisse un locataire lire ou effacer les diff --git a/roles/serveur_cache_site/meta/supervision.yml b/roles/serveur_cache_site/meta/supervision.yml index 73d1d0d..f95b0f9 100644 --- a/roles/serveur_cache_site/meta/supervision.yml +++ b/roles/serveur_cache_site/meta/supervision.yml @@ -28,6 +28,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: cache-site-racine + metier: paquets ttl: 5400 raison: 'Ce cache est-il toujours la RACINE de la chaine, et peut-il encore remplir ? Un cache chaine sur lui-meme ou coupe de Debian repond parfaitement — il sert ce diff --git a/roles/serveur_collabora/meta/supervision.yml b/roles/serveur_collabora/meta/supervision.yml index 78b7703..2e10cbc 100644 --- a/roles/serveur_collabora/meta/supervision.yml +++ b/roles/serveur_collabora/meta/supervision.yml @@ -15,6 +15,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: edition + metier: edition ttl: 5400 raison: 'L''edition en ligne repond-elle ? `/hosting/discovery` est l''adresse que Nextcloud interroge lui-meme pour savoir quels documents Collabora sait ouvrir. Sans elle, le diff --git a/roles/serveur_debian/meta/supervision.yml b/roles/serveur_debian/meta/supervision.yml index fb2a153..b9f327a 100644 --- a/roles/serveur_debian/meta/supervision.yml +++ b/roles/serveur_debian/meta/supervision.yml @@ -27,12 +27,14 @@ # correctif publie en exposition acceptee. sondes: - nom: correctifs + metier: socle ttl: 5400 raison: >- Des correctifs de securite attendent-ils d'etre appliques, et depuis quand ? Set-OPS desarme les mises a jour automatiques et les applique au deploiement : sans cette mesure, rien ne dit quand le geste est du. - nom: horloge + metier: socle ttl: 5400 raison: >- L'heure est-elle disciplinee, et par la SOURCE DECLAREE ? Une machine peut etre diff --git a/roles/serveur_dns_public/meta/supervision.yml b/roles/serveur_dns_public/meta/supervision.yml index e72b6d0..c85fbd6 100644 --- a/roles/serveur_dns_public/meta/supervision.yml +++ b/roles/serveur_dns_public/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: zones-publiques + metier: noms_publics ttl: 5400 raison: 'Le serveur public sert-il TOUTES les zones de ses locataires ? Un secondaire qui n''a jamais recu une zone repond REFUSED : pour Internet, ce domaine n''a plus de serveur de noms, pendant que le diff --git a/roles/serveur_dovecot/meta/supervision.yml b/roles/serveur_dovecot/meta/supervision.yml index 05a1123..382e086 100644 --- a/roles/serveur_dovecot/meta/supervision.yml +++ b/roles/serveur_dovecot/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: boites + metier: courriel ttl: 5400 raison: 'Dovecot repond-il, et sait-il encore RESOUDRE un utilisateur dans l''annuaire ? Un Dovecot dont le lien LDAP est tombe accepte les connexions et refuse toutes les authentifications : le service diff --git a/roles/serveur_durci/meta/supervision.yml b/roles/serveur_durci/meta/supervision.yml index 2bdc09e..2d1c941 100644 --- a/roles/serveur_durci/meta/supervision.yml +++ b/roles/serveur_durci/meta/supervision.yml @@ -18,6 +18,7 @@ # laisse la meme trace qu'un audit en bonne sante pour qui ne regarde que `systemctl`. sondes: - nom: audit + metier: socle ttl: 5400 # Posee par `auditd` seulement si `auditd_enabled` : Icinga ne l'attend qu'a ces # conditions (voir `setops-sondes.conf.j2`, 2026-09-28). @@ -28,6 +29,7 @@ sondes: prouvent pas qu'un demon collecte : le 2026-08-30, quinze machines ont eu les deux apparences de la sante sans qu'une seule ligne soit ecrite. - nom: connectivite + metier: socle ttl: 180 # Attendue a la minute, et non au quart d'heure : c'est tout son interet. Voir le mode # `minute` du porteur (`client_sante`). diff --git a/roles/serveur_forge_site/meta/supervision.yml b/roles/serveur_forge_site/meta/supervision.yml index a5dea09..bed0aea 100644 --- a/roles/serveur_forge_site/meta/supervision.yml +++ b/roles/serveur_forge_site/meta/supervision.yml @@ -27,6 +27,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: genome-servi + metier: forge ttl: 5400 raison: 'Cette forge a-t-elle encore un genome a servir ? Une forge vide repond parfaitement : son API marche, son Git est lisible, elle n''a simplement plus rien diff --git a/roles/serveur_forgejo/meta/supervision.yml b/roles/serveur_forgejo/meta/supervision.yml index 7b3734a..28156f0 100644 --- a/roles/serveur_forgejo/meta/supervision.yml +++ b/roles/serveur_forgejo/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: forge + metier: forge ttl: 5400 raison: La forge repond-elle a son API, et son depot Git est-il lisible ? Une forge qui sert sa page d'accueil mais ne peut plus lire ses depots est une panne complete pour tout ce qui clone — et elle diff --git a/roles/serveur_grafana/meta/supervision.yml b/roles/serveur_grafana/meta/supervision.yml index 0eb2bb7..479c74f 100644 --- a/roles/serveur_grafana/meta/supervision.yml +++ b/roles/serveur_grafana/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: tableaux + metier: supervision ttl: 5400 raison: 'Grafana repond-il, sa base tient-elle, et ses SOURCES DE DONNEES aussi ? Un Grafana dont la base est tombee sert encore sa page de connexion ; un Grafana dont la source Loki diff --git a/roles/serveur_icinga/meta/supervision.yml b/roles/serveur_icinga/meta/supervision.yml index fa3091b..90f78d6 100644 --- a/roles/serveur_icinga/meta/supervision.yml +++ b/roles/serveur_icinga/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: moteur + metier: supervision ttl: 5400 raison: 'L''etat des controles arrive-t-il encore jusqu''a la base ? On ne mesure ni le service ni le port : on mesure la FRAICHEUR de ce que la base contient. Un moteur vert dont la synchronisation diff --git a/roles/serveur_icingaweb2/defaults/main.yml b/roles/serveur_icingaweb2/defaults/main.yml index eac7250..8f7bd9a 100644 --- a/roles/serveur_icingaweb2/defaults/main.yml +++ b/roles/serveur_icingaweb2/defaults/main.yml @@ -118,6 +118,69 @@ serveur_icingaweb2_modules: # les processus sont normalement édités via l'UI. Un contenu ici est géré par Ansible. serveur_icingaweb2_bpm_processes: {} +# --- LES VUES METIER, DERIVEES (2026-10-04) -------------------------------------------- +# +# Une vue d'ensemble par CLIENTELE INTERNE, construite seule : chaque sonde declare dans le +# `meta/supervision.yml` de son role le service metier auquel elle contribue (`metier:`) ; +# ce catalogue dit comment chaque service s'appelle et QUI le voit. Les vues ne retiennent +# que les services presents dans l'ecosysteme : un site sans courriel n'a pas de case +# « courriel », un locataire sans forge pas de case « forge ». +# +# Fichiers poses : `setops-.conf` dans le repertoire des processus. Le prefixe les +# distingue des processus ecrits a la main ou dans l'interface, que le role ne touche pas. +serveur_icingaweb2_bpm_vues: + personnel: + titre: "Mes outils" + # PAS DE PERSONNEL SANS COMPTES : la vue n'existe que la ou l'on se connecte. Au site, + # le seul « outil » trouve etait son relais de courriel — celui des alertes. + requiert: connexion + description: >- + Les outils du quotidien fonctionnent-ils ? Vert : tout marche. Rouge : un outil est en + panne, et la supervision le voit aussi. + direction: + titre: "Services rendus" + description: >- + Les services que l'organisation rend sont-ils rendus, et ses données sont-elles en + sûreté ? Un voyant par service, et un pour les fondations techniques. + exploitation: + titre: "Exploitation" + description: >- + Qu'est-ce qui casse, et où ? Chaque service se déplie jusqu'au contrôle Icinga et à la + machine en cause ; le socle se lit machine par machine. + +# L'ORDRE EST CELUI DE L'AFFICHAGE. `fondation: true` : regroupe sous « Fondations +# techniques » dans la vue de la direction. `par_machine: true` : un sous-noeud par machine. +serveur_icingaweb2_bpm_services: + - {cle: connexion, titre: "Se connecter (compte unique)", vues: [personnel, direction, exploitation]} + - {cle: courriel, titre: "Courriel", vues: [personnel, direction, exploitation]} + - {cle: fichiers, titre: "Fichiers partagés", vues: [personnel, direction, exploitation]} + - {cle: edition, titre: "Édition en ligne", vues: [personnel, direction, exploitation]} + - {cle: web, titre: "Sites web publics", vues: [personnel, direction, exploitation]} + - {cle: noms_publics, titre: "Noms publics des locataires", vues: [direction, exploitation]} + - {cle: sauvegardes_locataires, titre: "Sauvegardes des locataires", vues: [direction, exploitation]} + - {cle: forge, titre: "Forge et génome", vues: [direction, exploitation]} + - {cle: paquets, titre: "Dépôt de paquets", vues: [direction, exploitation]} + - {cle: machines, titre: "Création des machines", vues: [direction, exploitation]} + - {cle: donnees, titre: "Sûreté des données", vues: [direction, exploitation]} + # L'EDGE N'EST PAS LE WEB PUBLIC : c'est la passerelle par laquelle on joint les services + # internes. Classe « sites web publics », il faisait apparaitre une vue « Mes outils » au + # site, qui n'a pas d'utilisateurs. + - {cle: acces, titre: "Passerelle d'accès (edge)", vues: [direction, exploitation], fondation: true} + - {cle: frontiere, titre: "Frontière (une patte par zone)", vues: [direction, exploitation], fondation: true} + - {cle: noms, titre: "Résolution des noms", vues: [direction, exploitation], fondation: true} + - {cle: confiance, titre: "Autorité de certification", vues: [direction, exploitation], fondation: true} + - {cle: base, titre: "Bases de données", vues: [direction, exploitation], fondation: true} + - {cle: supervision, titre: "Supervision", vues: [direction, exploitation], fondation: true} + - {cle: pilotage, titre: "Pilotage (console et runner)", vues: [direction, exploitation], fondation: true} + - {cle: socle, titre: "Socle des machines", vues: [direction, exploitation], fondation: true, par_machine: true} + +# Les processus que le role a poses autrefois et qu'il retire (sans extension). +# `supervision` : l'exemple ecrit a la main dans les group_vars des locataires — il visait +# un hote `icinga` et des controles (`load`, `procs`, `swap`, `ssh`) qui n'existent plus. +serveur_icingaweb2_bpm_retires: [supervision] +# Le nom de l'ecosysteme en tete de chaque vue. +serveur_icingaweb2_bpm_nom: "{{ organisation | default(domaine_interne) }}" + # LES CODES QU'UNE CONSOLE SAINE PEUT RENDRE A UNE REQUETE NON AUTHENTIFIEE. # # 200 quand la racine se sert, 302 quand elle renvoie vers le formulaire de connexion, diff --git a/roles/serveur_icingaweb2/meta/supervision.yml b/roles/serveur_icingaweb2/meta/supervision.yml index e36ab03..2c7bc49 100644 --- a/roles/serveur_icingaweb2/meta/supervision.yml +++ b/roles/serveur_icingaweb2/meta/supervision.yml @@ -27,6 +27,7 @@ # dans les plans (`vigie.`). sondes: - nom: vigie + metier: supervision ttl: 5400 raison: 'La vigie (Icinga Web 2) repond-elle, et lit-elle ce qu''elle doit montrer (base du moteur, annuaire ou base des comptes, Redis) ? Si elle meurt, ou si elle diff --git a/roles/serveur_icingaweb2/tasks/main.yml b/roles/serveur_icingaweb2/tasks/main.yml index 9f601e8..2cfb9c3 100644 --- a/roles/serveur_icingaweb2/tasks/main.yml +++ b/roles/serveur_icingaweb2/tasks/main.yml @@ -322,6 +322,101 @@ label: "{{ item.key }}" when: serveur_icingaweb2_bpm_processes | length > 0 +# --- LES VUES METIER, DERIVEES (2026-10-04) — voir defaults/main.yml ------------------- +# +# Meme lecture que `serveur_icinga` : les `meta/supervision.yml` de tous les roles, sur le +# controleur. Les vues ne nomment ainsi que ce qu'Icinga surveille vraiment. +- name: Vues métier — relever les sondes que les rôles déclarent + ansible.builtin.find: + paths: "{{ role_path }}/.." + patterns: supervision.yml + recurse: true + depth: 3 + delegate_to: localhost + become: false + register: serveur_icingaweb2_metas_supervision + when: "'businessprocess' in serveur_icingaweb2_modules" + +- name: Vues métier — lire chaque déclaration + ansible.builtin.slurp: + src: "{{ item.path }}" + delegate_to: localhost + become: false + loop: "{{ serveur_icingaweb2_metas_supervision.files | default([]) }}" + loop_control: + label: "{{ item.path | dirname | dirname | basename }}" + register: serveur_icingaweb2_supervision_brute + when: "'businessprocess' in serveur_icingaweb2_modules" + +# Les detenteurs d'etat appartiennent a `client_backup` : on les LIT chez lui, comme +# `serveur_icinga` — deux listes divergeraient, et la vue nommerait des sauvegardes +# qu'Icinga n'attend pas. +- name: Vues métier — lire la liste des détenteurs d'état chez client_backup + ansible.builtin.include_vars: + file: "{{ role_path }}/../client_backup/vars/main.yml" + name: serveur_icingaweb2_catalogue_sauvegarde + when: "'businessprocess' in serveur_icingaweb2_modules" + +- name: Vues métier — assembler le registre des sondes et les sauvegardes attendues + ansible.builtin.set_fact: + serveur_icingaweb2_sondes: >- + {{ dict(serveur_icingaweb2_supervision_brute.results + | map(attribute='item.path') | map('dirname') | map('dirname') | map('basename') + | zip(serveur_icingaweb2_supervision_brute.results + | map(attribute='content') | map('b64decode') | map('from_yaml') + | map(attribute='sondes'))) }} + serveur_icingaweb2_bpm_hote_sauvegarde: "{{ (groups['serveur_backup'] | default([]) | first) | default('') }}" + serveur_icingaweb2_bpm_sauvegarde_attendue: >- + {{ (serveur_icingaweb2_catalogue_sauvegarde.client_backup_groupes_etat | default([]) + | map('extract', groups) | select('defined') | flatten | unique | list) + | intersect(groups['client_backup'] | default([])) }} + when: "'businessprocess' in serveur_icingaweb2_modules" + +- name: Vues métier — calculer les contrôles de chaque service + ansible.builtin.set_fact: + serveur_icingaweb2_bpm_membres: "{{ lookup('ansible.builtin.template', 'bpm-membres.json.j2') | from_json }}" + when: "'businessprocess' in serveur_icingaweb2_modules" + +- name: Vues métier — retenir les vues qui ont au moins un service + ansible.builtin.set_fact: + serveur_icingaweb2_bpm_vues_posees: >- + {{ serveur_icingaweb2_bpm_vues | dict2items + | selectattr('key', 'in', serveur_icingaweb2_bpm_services + | selectattr('cle', 'in', serveur_icingaweb2_bpm_membres.keys() | list) + | map(attribute='vues') | flatten | unique | list) + | rejectattr('value.requiert', 'defined') + | map(attribute='key') | list + + (serveur_icingaweb2_bpm_vues | dict2items + | selectattr('value.requiert', 'defined') + | selectattr('value.requiert', 'in', serveur_icingaweb2_bpm_membres.keys() | list) + | map(attribute='key') | list) }} + when: "'businessprocess' in serveur_icingaweb2_modules" + +- name: Vues métier — poser chaque vue + ansible.builtin.template: + src: bpm-vue.conf.j2 + dest: "{{ serveur_icingaweb2_config_dir }}/modules/businessprocess/processes/setops-{{ bpm_vue }}.conf" + owner: root + group: icingaweb2 + mode: "0660" + loop: "{{ serveur_icingaweb2_bpm_vues_posees }}" + loop_control: + loop_var: bpm_vue + when: "'businessprocess' in serveur_icingaweb2_modules" + +# UNE VUE QUI N'A PLUS DE SERVICE SE RETIRE, et l'ancien exemple avec elle. Seuls les +# fichiers que ce role a poses sont concernes : un processus cree dans l'interface garde +# son nom, et le role n'y touche jamais. +- name: Vues métier — retirer les vues vides et les processus abandonnés + ansible.builtin.file: + path: "{{ serveur_icingaweb2_config_dir }}/modules/businessprocess/processes/{{ item }}.conf" + state: absent + loop: >- + {{ (serveur_icingaweb2_bpm_vues.keys() | reject('in', serveur_icingaweb2_bpm_vues_posees | default([])) + | map('regex_replace', '^', 'setops-') | list) + + serveur_icingaweb2_bpm_retires }} + when: "'businessprocess' in serveur_icingaweb2_modules" + - name: Déployer le vhost nginx local d'Icinga Web 2 ansible.builtin.template: src: nginx.conf.j2 diff --git a/roles/serveur_icingaweb2/templates/bpm-membres.json.j2 b/roles/serveur_icingaweb2/templates/bpm-membres.json.j2 new file mode 100644 index 0000000..31e9d21 --- /dev/null +++ b/roles/serveur_icingaweb2/templates/bpm-membres.json.j2 @@ -0,0 +1,53 @@ +{#- LES CONTROLES DE CHAQUE SERVICE METIER (2026-10-04) — rendu en JSON, lu par les taches. + + Meme derivation que `serveur_icinga/templates/setops-sondes.conf.j2`, a la ligne pres : + chaque role, ses hotes (`groups[role]` et `client_sante`), ses sondes, et la condition + `seulement_si` lue dans l'inventaire ou dans les defauts du role qui la definit. Une vue + ne doit nommer que des services qu'Icinga a REELLEMENT : un noeud absent s'afficherait + « manquant », et une vue qui ment est pire qu'une vue absente. + + Les sauvegardes ne viennent pas des roles mais de `setops-sauvegardes.conf.j2`, et leur + nom change avec le modele : `sauvegarde: ` sur le depot local (site), `sauvegarde` + sur chaque noeud (locataire). On reprend ses deux variables, calculees dans les taches. +-#} +{%- set m = namespace(d={}) -%} +{%- for role, sondes in (serveur_icingaweb2_sondes | default({})) | dictsort -%} +{%- for hote in ((groups[role] | default([])) | intersect(groups['client_sante'] | default([]))) | sort -%} +{%- for sonde in sondes if sonde.metier is defined -%} +{%- set condition = sonde.seulement_si | default('') -%} +{%- set ns = namespace(ok=true) -%} +{%- if condition -%} +{%- set defauts = lookup('file', role_path ~ '/../' ~ (sonde.defini_par | default(role)) ~ '/defaults/main.yml') | from_yaml -%} +{#- LE MEME TEST QU'ICINGA, pas `| bool` : une valeur comme « frontiere » est vraie + pour lui (non vide) et fausse pour `bool` — la sonde existait, la vue l'omettait. -#} +{%- set ns.ok = (hostvars[hote][condition] if hostvars[hote][condition] is defined else defauts.get(condition)) and true -%} +{%- endif -%} +{%- if ns.ok -%} +{%- set _ = m.d.setdefault(sonde.metier, []).append([hote, sonde.nom]) -%} +{%- endif -%} +{%- endfor -%} +{%- endfor -%} +{%- endfor -%} +{%- for noeud in serveur_icingaweb2_bpm_sauvegarde_attendue | sort -%} +{#- `sauvegarde` existe TOUJOURS sur le noeud ; `sauvegarde: ` S'Y AJOUTE sur le + depot quand l'ecosysteme en a un (le site) — les deux, pas l'un ou l'autre. -#} +{%- if serveur_icingaweb2_bpm_hote_sauvegarde -%} +{%- set _ = m.d.setdefault("donnees", []).append([serveur_icingaweb2_bpm_hote_sauvegarde, "sauvegarde: " ~ noeud]) -%} +{%- endif -%} +{%- set _ = m.d.setdefault("donnees", []).append([noeud, "sauvegarde"]) -%} +{%- set _ = m.d.setdefault("donnees", []).append([noeud, "restauration"]) -%} +{%- endfor -%} +{#- LE SOCLE COMPLET DE CHAQUE MACHINE : `sante` (unites en echec, `setops-sante.conf.j2`, + sur tout le socle `serveur_debian`) et `ping4` (chaque hote supervise) ne viennent pas des + roles ; au site, le `materiel` des hyperviseurs et de la frontiere (`setops_materiel_hotes`). -#} +{%- for noeud in groups['serveur_debian'] | default([]) | sort -%} +{%- set _ = m.d.setdefault("socle", []).extend([[noeud, "sante"], [noeud, "ping4"]]) -%} +{%- endfor -%} +{%- for h in setops_materiel_hotes | default([]) -%} +{%- set _ = m.d.setdefault("socle", []).extend([[h.nom, "materiel"], [h.nom, "ping4"]]) -%} +{%- endfor -%} +{#- LES PATTES DE LA FRONTIERE (site) : une par zone, que Icinga joint par `ping4`. -#} +{%- for f in serveur_icinga_fabric | default([]) -%} +{%- set _ = m.d.setdefault("frontiere", []).append([f.nom, "ping4"]) -%} +{%- endfor -%} +{{ m.d | to_json }} diff --git a/roles/serveur_icingaweb2/templates/bpm-vue.conf.j2 b/roles/serveur_icingaweb2/templates/bpm-vue.conf.j2 new file mode 100644 index 0000000..0fe9a62 --- /dev/null +++ b/roles/serveur_icingaweb2/templates/bpm-vue.conf.j2 @@ -0,0 +1,44 @@ +{#- UNE VUE METIER (2026-10-04) — `bpm_vue` (cle), sur les controles calcules par + `bpm-membres.json.j2`. Syntaxe : module businessprocess 2.5 (parseur « legacy ») — + `noeud = a & b`, `display ;;` (priorite 0 : libelle seul, pas + a la racine). -#} +{%- set vue = serveur_icingaweb2_bpm_vues[bpm_vue] -%} +{%- set membres = serveur_icingaweb2_bpm_membres -%} +{%- set services = serveur_icingaweb2_bpm_services | selectattr("vues", "contains", bpm_vue) + | selectattr("cle", "in", membres.keys() | list) | list -%} +{%- set regrouper = bpm_vue == "direction" -%} +### Business Process Config File ### +# +# Title : {{ serveur_icingaweb2_bpm_nom }} — {{ vue.titre }} +# Description : {{ vue.description }} +# Statetype : hard +# +# GENERE par Set-OPS (role serveur_icingaweb2, vue « {{ bpm_vue }} »). Ne pas editer : +# modifier le catalogue (serveur_icingaweb2_bpm_services) ou le `metier:` des sondes. +################################### + +{% set rang = namespace(v=0) -%} +{% for s in services -%} +{% set controles = membres[s.cle] -%} +{% if s.par_machine | default(false) -%} +{% for hote in controles | map("first") | unique | sort -%} +machine_{{ s.cle }}_{{ hote }} = {{ controles | selectattr("0", "equalto", hote) | map("join", ";") | join(" & ") }} +display 0;machine_{{ s.cle }}_{{ hote }};{{ hote }} +{% endfor -%} +svc_{{ s.cle }} = {% for hote in controles | map("first") | unique | sort %}machine_{{ s.cle }}_{{ hote }}{{ " & " if not loop.last }}{% endfor %} + +{% else -%} +svc_{{ s.cle }} = {{ controles | map("join", ";") | join(" & ") }} +{% endif -%} +{% if regrouper and s.fondation | default(false) -%} +display 0;svc_{{ s.cle }};{{ s.titre }} +{% else -%} +{% set rang.v = rang.v + 1 -%} +display {{ rang.v }};svc_{{ s.cle }};{{ s.titre }} +{% endif %} +{% endfor -%} +{% set fondations = services | selectattr("fondation", "defined") | selectattr("fondation") | list -%} +{% if regrouper and fondations | length > 0 -%} +fondations = {{ fondations | map(attribute="cle") | map("regex_replace", "^", "svc_") | join(" & ") }} +display {{ rang.v + 1 }};fondations;Fondations techniques +{% endif -%} diff --git a/roles/serveur_keycloak/meta/supervision.yml b/roles/serveur_keycloak/meta/supervision.yml index 5ded295..c7c5da8 100644 --- a/roles/serveur_keycloak/meta/supervision.yml +++ b/roles/serveur_keycloak/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: identite + metier: connexion ttl: 5400 raison: Le realm sert-il sa decouverte OIDC, et Keycloak ATTEINT-IL l'annuaire ? La decouverte est la porte par laquelle tout le SSO entre ; la federation LDAP est ce qui la rend utile. Un Keycloak dont diff --git a/roles/serveur_loki/meta/supervision.yml b/roles/serveur_loki/meta/supervision.yml index 3e5092a..dd8fb94 100644 --- a/roles/serveur_loki/meta/supervision.yml +++ b/roles/serveur_loki/meta/supervision.yml @@ -2,12 +2,14 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: ingestion + metier: supervision ttl: 5400 raison: Loki est-il PRET a ingerer ? Un Loki qui ecoute mais dont l'ingesteur n'est pas pret accepte les connexions et perd les journaux — la panne se voit des semaines plus tard, quand on cherche une trace qui n'a jamais ete ecrite. - nom: journaux-frontiere + metier: supervision ttl: 5400 # Posee seulement la ou une frontiere est ecoutee : au SITE, pas chez un locataire, # dont la frontiere appartient a l'hebergeur. Sans cette ligne, Icinga l'attendait diff --git a/roles/serveur_nextcloud/meta/supervision.yml b/roles/serveur_nextcloud/meta/supervision.yml index 59dd4fd..547926d 100644 --- a/roles/serveur_nextcloud/meta/supervision.yml +++ b/roles/serveur_nextcloud/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: collaboration + metier: fichiers ttl: 5400 raison: Nextcloud est-il installe, hors maintenance et sans migration en attente ? Ces trois etats se lisent d'un coup dans `status.php`, et chacun rend le service inutilisable sans que la page d'accueil diff --git a/roles/serveur_nginx/meta/supervision.yml b/roles/serveur_nginx/meta/supervision.yml index 4537424..c42b988 100644 --- a/roles/serveur_nginx/meta/supervision.yml +++ b/roles/serveur_nginx/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: edge + metier: acces ttl: 5400 raison: 'L''edge ecoute-t-il, et sa configuration est-elle encore valide ? Un nginx dont la configuration est cassee continue de servir l''ANCIENNE tant qu''on ne le recharge pas : il fonctionne, et le diff --git a/roles/serveur_oauth2_proxy/meta/supervision.yml b/roles/serveur_oauth2_proxy/meta/supervision.yml index 04259aa..8328ddd 100644 --- a/roles/serveur_oauth2_proxy/meta/supervision.yml +++ b/roles/serveur_oauth2_proxy/meta/supervision.yml @@ -14,6 +14,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: passerelle + metier: connexion ttl: 5400 raison: 'La passerelle d''authentification repond-elle, et mene-t-elle vraiment a la page de connexion de l''IdP pour son client ? Elle porte l''acces aux applications sans SSO natif — la vigie, la console. Quand elle meurt, les services derriere restent diff --git a/roles/serveur_openldap/meta/supervision.yml b/roles/serveur_openldap/meta/supervision.yml index 0a3430c..84dd6f3 100644 --- a/roles/serveur_openldap/meta/supervision.yml +++ b/roles/serveur_openldap/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: annuaire + metier: connexion ttl: 5400 raison: L'annuaire repond-il, et contient-il encore ses entrees ? Un annuaire vide repond parfaitement a toutes les requetes — et plus personne ne s'authentifie nulle part. C'est le meme mensonge qu'une diff --git a/roles/serveur_ops/meta/supervision.yml b/roles/serveur_ops/meta/supervision.yml index 2e73878..468bd6a 100644 --- a/roles/serveur_ops/meta/supervision.yml +++ b/roles/serveur_ops/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: runner + metier: pilotage ttl: 5400 raison: 'Le poste d''exploitation peut-il encore agir ? Deux choses : ses depots sont-ils PROPRES et sur leur branche (une modification locale fait diverger le runner du depot que tout le monde @@ -17,6 +18,7 @@ sondes: # authentifier ne fait echouer personne — il ouvre la fabric. La sonde exige donc un # REFUS sur une requete anonyme : c'est la seule facon de mesurer une serrure. - nom: console-ops + metier: pilotage ttl: 5400 # Posee seulement si le GUI est actif (voir `setops-sondes.conf.j2`, 2026-09-28). seulement_si: serveur_ops_gui_actif diff --git a/roles/serveur_ops_site/meta/supervision.yml b/roles/serveur_ops_site/meta/supervision.yml index b8188ff..1fdb4c3 100644 --- a/roles/serveur_ops_site/meta/supervision.yml +++ b/roles/serveur_ops_site/meta/supervision.yml @@ -28,6 +28,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: pouvoir-materialiser + metier: machines ttl: 5400 raison: 'Le runner du site peut-il encore materialiser, et son secret est-il toujours protege ? La carte de la fabric, la voute du site et sa cle ne font tomber aucun @@ -35,12 +36,14 @@ sondes: voute dechiffree en transit ne fait echouer aucun deploiement : Ansible la lit tres bien, elle expose simplement tout.' - nom: fabric + metier: machines ttl: 5400 raison: >- Le pare-feu Proxmox, le SDN, la frontiere et les acces WireGuard disent-ils encore ce que le plan dit ? Le 2026-09-28, aucune VM des locataires n'avait son pare-feu actif et rien ne le signalait ; les plans existaient, personne ne les jouait sans raison. - nom: genome-a-jour + metier: pilotage ttl: 5400 raison: >- La forge du site porte-t-elle ce que le poste a publie ? Elle fait autorite, mais un diff --git a/roles/serveur_ops_tenant/meta/supervision.yml b/roles/serveur_ops_tenant/meta/supervision.yml index 897ff2a..866182e 100644 --- a/roles/serveur_ops_tenant/meta/supervision.yml +++ b/roles/serveur_ops_tenant/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: voute + metier: pilotage ttl: 5400 raison: 'La voute de l''ecosysteme est-elle presente ET CHIFFREE la ou le runner la lit ? Une voute en clair sur un runner est la fuite la plus discrete qui soit : rien ne casse, tout continue de diff --git a/roles/serveur_postfix/meta/supervision.yml b/roles/serveur_postfix/meta/supervision.yml index 7530aa5..459f2b7 100644 --- a/roles/serveur_postfix/meta/supervision.yml +++ b/roles/serveur_postfix/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: file-courriel + metier: courriel ttl: 5400 raison: Combien de courriels attendent dans la file ? Une file qui monte est le premier signe d'une remise qui ne se fait plus — et c'est un signe qu'on voit AVANT que quiconque se plaigne de ne rien diff --git a/roles/serveur_postgresql/meta/supervision.yml b/roles/serveur_postgresql/meta/supervision.yml index affd762..24824f2 100644 --- a/roles/serveur_postgresql/meta/supervision.yml +++ b/roles/serveur_postgresql/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: base + metier: base ttl: 5400 raison: 'La base repond-elle a une VRAIE requete, et lui reste-t-il des connexions ? Un PostgreSQL a court de connexions accepte encore le port et refuse tout le monde : chaque application tombe diff --git a/roles/serveur_powerdns/meta/supervision.yml b/roles/serveur_powerdns/meta/supervision.yml index 55463e4..98209d0 100644 --- a/roles/serveur_powerdns/meta/supervision.yml +++ b/roles/serveur_powerdns/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: zones + metier: noms ttl: 5400 raison: 'L''autoritatif repond-il, et sert-il encore ses zones ? Un PowerDNS qui a perdu ses zones repond NXDOMAIN a tout : la resolution interne s''effondre pendant que le service a l''air parfaitement diff --git a/roles/serveur_prometheus/meta/supervision.yml b/roles/serveur_prometheus/meta/supervision.yml index 495b09c..f0f128c 100644 --- a/roles/serveur_prometheus/meta/supervision.yml +++ b/roles/serveur_prometheus/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: collecte + metier: supervision ttl: 5400 raison: 'Toutes les cibles declarees sont-elles reellement collectees ? C''est la seule sonde qui voit le cas SILENCIEUX : un noeud qui a cesse d''etre scrape ne peut pas s''en plaindre lui-meme, diff --git a/roles/serveur_redis/meta/supervision.yml b/roles/serveur_redis/meta/supervision.yml index fadd42b..80f76d3 100644 --- a/roles/serveur_redis/meta/supervision.yml +++ b/roles/serveur_redis/meta/supervision.yml @@ -17,6 +17,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: cache + metier: base ttl: 5400 raison: 'Le cache repond-il, et sert-il encore ? Un Redis borne ne tombe pas quand il est plein — il evicte. Les sessions se perdent une a une, les gens sont deconnectes diff --git a/roles/serveur_resolveur/meta/supervision.yml b/roles/serveur_resolveur/meta/supervision.yml index 8cea477..b5f28f6 100644 --- a/roles/serveur_resolveur/meta/supervision.yml +++ b/roles/serveur_resolveur/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: resolution + metier: noms ttl: 5400 raison: 'Le resolveur repond-il POUR LA ZONE INTERNE ET pour un nom de l''Internet ? Les deux voies sont distinctes : la zone interne vient de l''autoritatif local, le reste de la recursion. Une seule diff --git a/roles/serveur_resolveur_site/meta/supervision.yml b/roles/serveur_resolveur_site/meta/supervision.yml index d27020e..86a94b6 100644 --- a/roles/serveur_resolveur_site/meta/supervision.yml +++ b/roles/serveur_resolveur_site/meta/supervision.yml @@ -26,6 +26,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: resolution-locataires + metier: noms ttl: 5400 raison: 'Les locataires du site sont-ils toujours admis a resoudre ici ? Un supernet absent de la liste d''autorisation ne provoque pas un refus : Unbound laisse tomber diff --git a/roles/serveur_rspamd/meta/supervision.yml b/roles/serveur_rspamd/meta/supervision.yml index 7384f8d..5cef487 100644 --- a/roles/serveur_rspamd/meta/supervision.yml +++ b/roles/serveur_rspamd/meta/supervision.yml @@ -14,6 +14,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: filtrage + metier: courriel ttl: 5400 raison: 'Le filtrage du courrier repond-il, et ANALYSE-T-IL (GTUBE rejete) ? Un filtre muet ne bloque pas le courrier, il le laisse passer : Postfix sans verdict delivre sans filtrer ou differe, et le service de diff --git a/roles/serveur_step_ca/meta/supervision.yml b/roles/serveur_step_ca/meta/supervision.yml index 7e6e46b..bb9bda8 100644 --- a/roles/serveur_step_ca/meta/supervision.yml +++ b/roles/serveur_step_ca/meta/supervision.yml @@ -2,6 +2,7 @@ # Supervision derivee du role. Voir docs/supervision-conception.md. sondes: - nom: autorite + metier: confiance ttl: 5400 raison: 'L''autorite de certification repond-elle ? C''est la sonde la plus urgente de l''ecosysteme : nos certificats vivent 24 h. Une AC muette ne casse rien aujourd''hui — elle casse TOUT demain, diff --git a/roles/serveur_web_dorsal/meta/supervision.yml b/roles/serveur_web_dorsal/meta/supervision.yml index eae5181..bf4729a 100644 --- a/roles/serveur_web_dorsal/meta/supervision.yml +++ b/roles/serveur_web_dorsal/meta/supervision.yml @@ -23,6 +23,7 @@ # peremption. Le silence alerte autant que l'echec. sondes: - nom: apps-servies + metier: web ttl: 5400 raison: 'Chacune des webapps declarees repond-elle encore ? Une app ne tombe presque jamais en « failed » — elle se coince : le processus vit, systemd la dit active, le @@ -30,6 +31,7 @@ sondes: verra jamais ca.' # SUR LE DORSAL DEPUIS LE 2026-09-29 : c'est lui qui porte les sites ; le frontal les relaie. - nom: sites-servis + metier: web ttl: 5400 raison: 'Chacun des sites statiques declares se sert-il encore ? Le contenu vient d''un depot git : une branche renommee, un sous-dossier deplace ou un clone vide diff --git a/roles/serveur_web_frontal/meta/supervision.yml b/roles/serveur_web_frontal/meta/supervision.yml index 6a33f5a..870557c 100644 --- a/roles/serveur_web_frontal/meta/supervision.yml +++ b/roles/serveur_web_frontal/meta/supervision.yml @@ -7,6 +7,7 @@ # `sites-servis` a suivi les sites sur le dorsal le 2026-09-29. sondes: - nom: frontal + metier: web ttl: 5400 raison: 'Le reverse proxy public tient-il, son WAF (ModSecurity + OWASP CRS) est-il vraiment dans le chemin, et chaque exposition publique repond-elle a travers lui ?