sondes : quatorze, une par role, derivees en objets Icinga
boites (dovecot) · cache-apt (artefacts) · certificat (client_pki, 14/14)
collaboration (nextcloud) · collecte (prometheus) · file-courriel (postfix)
forge (forgejo) · identite (keycloak) · ingestion (loki) · moteur (icinga)
resolution (resolveur) · runner (serveur_ops) · tableaux (grafana)
voute (ops_tenant) — toutes vertes, sans une ligne ecrite dans Icinga.
DEUX PRINCIPES QUE LA PREMIERE SONDE A IMPOSES.
Une sonde doit pouvoir etre mise en defaut PAR PARAMETRE : cible et seuils
sont des variables du role, on prouve le rouge avec un port ferme ou un
seuil impossible, sans rien casser. Et la sonde vit LA OU VIT LA VERITE :
« ce noeud est-il collecte ? » appartient a prometheus, pas au client —
une seule y voit les N noeuds, et surtout elle voit le cas SILENCIEUX.
ON DEMANDE AU SERVICE CE QU IL PENSE DE LUI-MEME quand il sait le dire
(healthz, /ready, status.php, decouverte OIDC). Quand il ne sait pas, on
va chercher la verite de terrain : « moteur » ne regarde ni le service ni
le port, il demande a la base depuis combien de temps elle n a pas ete
rafraichie — la lecon des sauvegardes appliquee a la supervision.
QUATRE FOIS J AI ECRIT LA SONDE AVANT DE MESURER, QUATRE FOIS ELLE A EU
TORT. La forge : port et chemin des depots inventes, elle ecoute en 3000
derriere l edge et n a legitimement aucun depot. Loki : « panne
persistante » conclue sur deux lectures a quelques secondes d intervalle
juste apres un redemarrage — deux mesures rapprochees ne distinguent pas
un etat d un instant. Keycloak : vise en 8443, il ecoute en 8080. Le
runner : git en root refuse un depot d un autre proprietaire. A chaque
fois le remede est le meme — lire la verite du role, ne pas la supposer.
Et le meme piege Jinja qu avec client_sante : ${#tableau[@]} contient {#.
Le remede etait deja au depot ; je l ai reecrit au lieu de le chercher.
RESTE : client_smtp, client_artefacts, client_journal, icingaweb2 et
ops_site. Ce sont des chemins de report, dont la panne se voit deja par le
silence des sondes qu ils portent.
make prouver : CONFORME, 64 OK, 0 echec, 0 saute (P64 : 14 sondes).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
This commit is contained in:
parent
1832530f29
commit
6120e6f006
30 changed files with 518 additions and 1 deletions
69
CHANGELOG.md
69
CHANGELOG.md
|
|
@ -1,5 +1,74 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 2026-09-10 — Chaque role porte desormais sa sonde
|
||||||
|
|
||||||
|
**Quatorze sondes**, declarees dans `meta/supervision.yml`, deposees par le role qui
|
||||||
|
possede la verite, derivees en objets Icinga sans qu'une ligne soit ecrite a la main :
|
||||||
|
|
||||||
|
boites (dovecot) certificat (client_pki, 14/14) collaboration (nextcloud)
|
||||||
|
cache-apt (artefacts) collecte (prometheus) file-courriel (postfix)
|
||||||
|
forge (forgejo) identite (keycloak) ingestion (loki)
|
||||||
|
moteur (icinga) resolution (resolveur) runner (serveur_ops)
|
||||||
|
tableaux (grafana) voute (ops_tenant)
|
||||||
|
|
||||||
|
Les dix-neuf lignes `surveillance:` ecrites en prose et jamais executees commencent a
|
||||||
|
devenir des mesures.
|
||||||
|
|
||||||
|
### Deux principes que la premiere sonde a imposes
|
||||||
|
|
||||||
|
**Une sonde doit pouvoir etre mise en defaut PAR PARAMETRE.** Cible et seuils sont des
|
||||||
|
variables du role : on prouve le rouge avec un port ferme ou un seuil impossible, sur une
|
||||||
|
machine reelle, sans rien casser, aussi souvent qu'on veut. Une sonde qu'on ne peut
|
||||||
|
prouver qu'en cassant un service ne sera prouvee qu'une fois. Eprouve sur `cache-apt` :
|
||||||
|
vert, CRITIQUE par port ferme, AVERTISSEMENT par seuil, retour au vert.
|
||||||
|
|
||||||
|
**La sonde vit la ou vit la verite.** *« Ce noeud est-il collecte ? »* est une sonde de
|
||||||
|
`serveur_prometheus`, pas de `client_metrique` : une seule y voit les N noeuds, et surtout
|
||||||
|
elle voit le cas **silencieux** — celui qui a cesse d'etre collecte ne peut pas s'en
|
||||||
|
plaindre lui-meme.
|
||||||
|
|
||||||
|
### On demande au service ce qu'il pense de lui-meme
|
||||||
|
|
||||||
|
Quand il sait le dire : `/api/healthz` de Forgejo (base + cache), `/api/health` de Grafana,
|
||||||
|
`/ready` de Loki, `status.php` de Nextcloud, la decouverte OIDC de Keycloak. C'est plus
|
||||||
|
juste que tout critere invente de l'exterieur — une forge dont la base est tombee sert
|
||||||
|
encore ses pages et repond a `/api/v1/version`.
|
||||||
|
|
||||||
|
Et quand il ne sait pas : on va chercher la verite de terrain. `moteur` ne regarde ni le
|
||||||
|
service ni le port — il demande a la base **depuis combien de temps elle n'a pas ete
|
||||||
|
rafraichie**. C'est la lecon des sauvegardes appliquee a la supervision elle-meme : un
|
||||||
|
moteur vert dont la synchronisation est tombee affiche eternellement le dernier etat connu.
|
||||||
|
|
||||||
|
### Quatre fois j'ai ecrit la sonde avant de mesurer, quatre fois elle a eu tort
|
||||||
|
|
||||||
|
**La forge** : port 443 et chemin des depots INVENTES. Elle ecoute en 3000 derriere l'edge
|
||||||
|
et n'a legitimement AUCUN depot — elle est neuve. Deux cris sur un service sain.
|
||||||
|
|
||||||
|
**Loki** : conclu « panne persistante » sur deux lectures prises a quelques secondes
|
||||||
|
d'intervalle, juste apres un redemarrage. L'anneau etait `ACTIVE` et la reponse est passee
|
||||||
|
a `ready` moins d'une minute plus tard. *Deux mesures rapprochees ne distinguent pas un
|
||||||
|
etat d'un instant.* Le delai de stabilisation est desormais un AVERTISSEMENT nomme.
|
||||||
|
|
||||||
|
**Keycloak** : vise en 8443, il ecoute en 8080 derriere l'edge.
|
||||||
|
|
||||||
|
**Le runner** : `git` en root refuse les depots d'un autre proprietaire — la sonde aurait
|
||||||
|
rendu un echec qui parle de git au lieu de parler du depot.
|
||||||
|
|
||||||
|
À chaque fois le remede est le meme : **lire la verite du role, ne pas la supposer**.
|
||||||
|
|
||||||
|
### Et le meme piege Jinja, une seconde fois
|
||||||
|
|
||||||
|
`${#tableau[@]}` contient `{#`. Le remede etait deja au depot depuis `client_sante` ; je
|
||||||
|
l'ai reecrit au lieu de le chercher. La correction balaie desormais tous les gabarits de
|
||||||
|
sonde.
|
||||||
|
|
||||||
|
### Ce qui reste
|
||||||
|
|
||||||
|
`client_smtp`, `client_artefacts`, `client_journal`, `serveur_icingaweb2` et
|
||||||
|
`serveur_ops_site` n'ont pas encore la leur. Le premier lot couvre les services dont la
|
||||||
|
chute arrete l'ecosysteme ; ceux-la sont des chemins de report, dont la panne se voit
|
||||||
|
deja par le silence des sondes qu'ils portent.
|
||||||
|
|
||||||
## 2026-09-09 (9) — La supervision passe juste apres la PKI (D-86)
|
## 2026-09-09 (9) — La supervision passe juste apres la PKI (D-86)
|
||||||
|
|
||||||
*On n'allume pas la lumiere une fois la maison finie.*
|
*On n'allume pas la lumiere une fois la maison finie.*
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@
|
||||||
| P61 | Schema du plan : il decrit tout ce que les plans contiennent | AFF-033 | ✅ OK | Le schema decrit 47 champ(s) sur 6 registres ; il couvre tout ce que les plans reels contiennent, et la FORME de chaque champ (scalaire / objet / table) corresp |
|
| P61 | Schema du plan : il decrit tout ce que les plans contiennent | AFF-033 | ✅ OK | Le schema decrit 47 champ(s) sur 6 registres ; il couvre tout ce que les plans reels contiennent, et la FORME de chaque champ (scalaire / objet / table) corresp |
|
||||||
| P62 | Schema du plan : il decrit tout ce que le MOTEUR accepte | AFF-033 | ✅ OK | Les 4 validateurs n'acceptent aucun champ que le schema ignore (applications:8, bases_donnees:4, domaines_publics:5, serveurs:3 champ(s) lus par validateur). |
|
| P62 | Schema du plan : il decrit tout ce que le MOTEUR accepte | AFF-033 | ✅ OK | Les 4 validateurs n'acceptent aucun champ que le schema ignore (applications:8, bases_donnees:4, domaines_publics:5, serveurs:3 champ(s) lus par validateur). |
|
||||||
| P63 | cloud-init nait avec la VM et ne lui survit pas | — | ✅ OK | cloud-init est au gabarit (la premiere seconde), absent du socle (pas de va-et-vient), et retire par le durcissement — avec la garde qui verifie que le reseau s |
|
| P63 | cloud-init nait avec la VM et ne lui survit pas | — | ✅ OK | cloud-init est au gabarit (la premiere seconde), absent du socle (pas de va-et-vient), et retire par le durcissement — avec la garde qui verifie que le reseau s |
|
||||||
| P64 | Sondes de supervision : declarees ET deposees | — | ✅ OK | 7 sonde(s) declaree(s) ET deposee(s), chacune avec sa raison et son `ttl` : client_pki/certificat, serveur_artefacts/cache-apt, serveur_forgejo/forge, serveur_g |
|
| P64 | Sondes de supervision : declarees ET deposees | — | ✅ OK | 14 sonde(s) declaree(s) ET deposee(s), chacune avec sa raison et son `ttl` : client_pki/certificat, serveur_artefacts/cache-apt, serveur_dovecot/boites, serveur |
|
||||||
|
|
||||||
## Couverture des affirmations ✅ du registre
|
## Couverture des affirmations ✅ du registre
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,3 +50,9 @@ serveur_dovecot_sasl_port: 12345
|
||||||
# cote emetteur : l'un sans l'autre, la livraison interne s'arrete — soit elle part en
|
# cote emetteur : l'un sans l'autre, la livraison interne s'arrete — soit elle part en
|
||||||
# clair, soit elle est differee sans fin.
|
# clair, soit elle est differee sans fin.
|
||||||
serveur_dovecot_lmtp_tls: true
|
serveur_dovecot_lmtp_tls: true
|
||||||
|
|
||||||
|
# --- Sonde de supervision -----------------------------------------------------------
|
||||||
|
# UN COMPTE QUI DOIT EXISTER. Le resoudre prouve la chaine entiere : demon, configuration,
|
||||||
|
# bind LDAP, mappage userdb. Variable, donc mise en defaut avec un nom inexistant sans
|
||||||
|
# toucher a l'annuaire.
|
||||||
|
serveur_dovecot_sonde_utilisateur: "daniel"
|
||||||
|
|
|
||||||
8
roles/serveur_dovecot/meta/supervision.yml
Normal file
8
roles/serveur_dovecot/meta/supervision.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Supervision derivee du role. Voir docs/supervision-conception.md.
|
||||||
|
sondes:
|
||||||
|
- nom: boites
|
||||||
|
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
|
||||||
|
a l''air debout et plus personne n''entre.'
|
||||||
|
|
@ -154,3 +154,22 @@
|
||||||
enabled: true
|
enabled: true
|
||||||
state: started
|
state: started
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
|
|
||||||
|
# --- Sonde de supervision (docs/supervision-conception.md) --------------------------
|
||||||
|
# Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la
|
||||||
|
# fait tourner et pousse le verdict, sans savoir ce qu'elle mesure.
|
||||||
|
- 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 « boites »
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sonde-boites.sh.j2
|
||||||
|
dest: /usr/local/lib/setops/sondes/boites.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
|
||||||
22
roles/serveur_dovecot/templates/sonde-boites.sh.j2
Normal file
22
roles/serveur_dovecot/templates/sonde-boites.sh.j2
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# GENERE par Set-OPS (role serveur_dovecot). Ne pas editer a la main.
|
||||||
|
#
|
||||||
|
# SONDE « boites » — Dovecot repond et resout un utilisateur dans l'annuaire
|
||||||
|
#
|
||||||
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||||
|
# Mise en defaut PAR PARAMETRE : `serveur_dovecot_sonde_utilisateur` (compte inexistant).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
UTILISATEUR={{ serveur_dovecot_sonde_utilisateur }}
|
||||||
|
|
||||||
|
systemctl is-active --quiet dovecot || { echo "Dovecot n'est pas actif."; exit 2; }
|
||||||
|
|
||||||
|
# ON RESOUT UN UTILISATEUR REEL, PAS UN PING DE SERVICE. C'est le bind LDAP qui tombe le
|
||||||
|
# plus souvent, et il ne se voit que quand on demande un compte : le demon reste debout,
|
||||||
|
# le port reste ouvert, et toute authentification echoue.
|
||||||
|
sortie=$(doveadm user "${UTILISATEUR}" 2>&1)
|
||||||
|
if ! printf '%s' "${sortie}" | grep -qE '^uid[[:space:]]'; then
|
||||||
|
echo "Dovecot ne resout pas « ${UTILISATEUR} » — l'annuaire ne repond plus : ${sortie:0:70}"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
echo "Dovecot : « ${UTILISATEUR} » resolu dans l'annuaire, service actif."
|
||||||
|
|
@ -106,3 +106,10 @@ serveur_icinga_sondes: {}
|
||||||
# Vide, aucun destinataire n'est pose et le deploiement le SIGNALE — plutot que de
|
# Vide, aucun destinataire n'est pose et le deploiement le SIGNALE — plutot que de
|
||||||
# laisser croire qu'une alerte partira.
|
# laisser croire qu'une alerte partira.
|
||||||
serveur_icinga_destinataire: ""
|
serveur_icinga_destinataire: ""
|
||||||
|
|
||||||
|
# --- Sonde de supervision -----------------------------------------------------------
|
||||||
|
serveur_icinga_sonde_config_db: /etc/icingadb/config.yml
|
||||||
|
# Les controles passifs ont un `ttl` de 45 min au plus long ; une base qui n'a rien recu
|
||||||
|
# depuis deux fois cela ne reflete plus rien.
|
||||||
|
serveur_icinga_sonde_age_avert: 900
|
||||||
|
serveur_icinga_sonde_age_crit: 5400
|
||||||
|
|
|
||||||
9
roles/serveur_icinga/meta/supervision.yml
Normal file
9
roles/serveur_icinga/meta/supervision.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
# Supervision derivee du role. Voir docs/supervision-conception.md.
|
||||||
|
sondes:
|
||||||
|
- nom: moteur
|
||||||
|
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
|
||||||
|
est tombee affiche eternellement le dernier etat connu — une supervision figee qui a l''air d''aller
|
||||||
|
bien.'
|
||||||
|
|
@ -350,3 +350,22 @@
|
||||||
`root@localhost`, que personne ne lit. La supervision VERRA les defauts sans
|
`root@localhost`, que personne ne lit. La supervision VERRA les defauts sans
|
||||||
pouvoir les dire. Declarer l'adresse au plan.
|
pouvoir les dire. Declarer l'adresse au plan.
|
||||||
when: serveur_icinga_destinataire | length == 0
|
when: serveur_icinga_destinataire | length == 0
|
||||||
|
|
||||||
|
# --- Sonde de supervision (docs/supervision-conception.md) --------------------------
|
||||||
|
# Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la
|
||||||
|
# fait tourner et pousse le verdict, sans savoir ce qu'elle mesure.
|
||||||
|
- 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 « moteur »
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sonde-moteur.sh.j2
|
||||||
|
dest: /usr/local/lib/setops/sondes/moteur.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
|
||||||
39
roles/serveur_icinga/templates/sonde-moteur.sh.j2
Normal file
39
roles/serveur_icinga/templates/sonde-moteur.sh.j2
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# GENERE par Set-OPS (role serveur_icinga). Ne pas editer a la main.
|
||||||
|
#
|
||||||
|
# SONDE « moteur » — l'etat des controles arrive frais jusqu'a IcingaDB
|
||||||
|
#
|
||||||
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||||
|
# Mise en defaut PAR PARAMETRE : `serveur_icinga_sonde_age_crit` (age impossible).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
CONF={{ serveur_icinga_sonde_config_db }}
|
||||||
|
AVERT={{ serveur_icinga_sonde_age_avert }}
|
||||||
|
CRIT={{ serveur_icinga_sonde_age_crit }}
|
||||||
|
|
||||||
|
systemctl is-active --quiet icinga2 || { echo "Le moteur Icinga n'est pas actif."; exit 2; }
|
||||||
|
systemctl is-active --quiet icingadb || { echo "La synchronisation IcingaDB n'est pas active."; exit 2; }
|
||||||
|
|
||||||
|
# ON NE SE FIE PAS A `is-active` SEUL — c'est le mensonge que ce depot a deja paye avec
|
||||||
|
# les sauvegardes : un service vert sur un travail qui n'aboutit pas. On demande a la BASE
|
||||||
|
# depuis combien de temps elle n'a pas ete rafraichie.
|
||||||
|
hote=$(grep -m1 -A5 '^database:' "${CONF}" 2>/dev/null | grep -m1 'host:' | awk '{print $2}')
|
||||||
|
mdp=$(grep -m1 'password:' "${CONF}" 2>/dev/null | awk '{print $2}')
|
||||||
|
base=$(grep -m1 -A5 '^database:' "${CONF}" 2>/dev/null | grep -m1 'database:' | awk '{print $2}')
|
||||||
|
util=$(grep -m1 -A6 '^database:' "${CONF}" 2>/dev/null | grep -m1 'user:' | awk '{print $2}')
|
||||||
|
[[ -n "${hote}" && -n "${mdp}" ]] || { echo "Configuration IcingaDB illisible (${CONF})."; exit 2; }
|
||||||
|
|
||||||
|
age=$(PGPASSWORD="${mdp}" psql -h "${hote}" -U "${util:-icingadb}" -d "${base:-icingadb}" -Atc \
|
||||||
|
"select coalesce(extract(epoch from now()) - max(last_update)/1000, 999999)::bigint from service_state" 2>/dev/null)
|
||||||
|
[[ "${age}" =~ ^-?[0-9]+$ ]] || { echo "La base de supervision ne repond pas (${hote})."; exit 2; }
|
||||||
|
(( age < 0 )) && age=0
|
||||||
|
|
||||||
|
if (( age >= CRIT )); then
|
||||||
|
echo "Etat FIGE : rien de neuf en base depuis ${age} s — la supervision montre le passe.|age=${age}s;${AVERT};${CRIT};0;"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if (( age >= AVERT )); then
|
||||||
|
echo "Etat vieillissant : ${age} s sans mise a jour (seuil ${AVERT}).|age=${age}s;${AVERT};${CRIT};0;"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Moteur et synchronisation vivants : base rafraichie il y a ${age} s.|age=${age}s;${AVERT};${CRIT};0;"
|
||||||
|
|
@ -220,3 +220,9 @@ serveur_keycloak_cache_local: "{{ setops_cache_artefacts | default(lookup('env',
|
||||||
# il exige une relecture humaine, pas un remplacement silencieux.
|
# il exige une relecture humaine, pas un remplacement silencieux.
|
||||||
serveur_keycloak_signature_empreinte: "861AB50E8CC6611FB6BC01A6B8F12EA26FD6EEBA"
|
serveur_keycloak_signature_empreinte: "861AB50E8CC6611FB6BC01A6B8F12EA26FD6EEBA"
|
||||||
serveur_keycloak_signature_url: "{{ serveur_keycloak_url }}.asc"
|
serveur_keycloak_signature_url: "{{ serveur_keycloak_url }}.asc"
|
||||||
|
|
||||||
|
# --- Sonde de supervision -----------------------------------------------------------
|
||||||
|
# Keycloak ecoute EN CLAIR derriere l'edge : viser le port TLS en dur casserait sur toute
|
||||||
|
# installation derriere un proxy (verifie le 2026-09-10 : 8080, pas 8443).
|
||||||
|
serveur_keycloak_sonde_url: "http://127.0.0.1:8080"
|
||||||
|
serveur_keycloak_sonde_realm: "{{ serveur_keycloak_realm }}"
|
||||||
|
|
|
||||||
8
roles/serveur_keycloak/meta/supervision.yml
Normal file
8
roles/serveur_keycloak/meta/supervision.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Supervision derivee du role. Voir docs/supervision-conception.md.
|
||||||
|
sondes:
|
||||||
|
- nom: identite
|
||||||
|
ttl: 5400
|
||||||
|
raison: Le realm sert-il encore sa decouverte OIDC ? C'est la porte par laquelle tout le SSO de l'ecosysteme
|
||||||
|
entre. Un Keycloak debout dont le realm n'a pas charge repond sur son port et refuse toute connexion
|
||||||
|
— sans rien dire.
|
||||||
|
|
@ -324,3 +324,22 @@
|
||||||
when:
|
when:
|
||||||
- serveur_keycloak_account_theme | length > 0
|
- serveur_keycloak_account_theme | length > 0
|
||||||
- not ansible_check_mode
|
- not ansible_check_mode
|
||||||
|
|
||||||
|
# --- Sonde de supervision (docs/supervision-conception.md) --------------------------
|
||||||
|
# Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la
|
||||||
|
# fait tourner et pousse le verdict, sans savoir ce qu'elle mesure.
|
||||||
|
- 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 « identite »
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sonde-identite.sh.j2
|
||||||
|
dest: /usr/local/lib/setops/sondes/identite.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
|
||||||
24
roles/serveur_keycloak/templates/sonde-identite.sh.j2
Normal file
24
roles/serveur_keycloak/templates/sonde-identite.sh.j2
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# GENERE par Set-OPS (role serveur_keycloak). Ne pas editer a la main.
|
||||||
|
#
|
||||||
|
# SONDE « identite » — le realm sert sa decouverte OIDC
|
||||||
|
#
|
||||||
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||||
|
# Mise en defaut PAR PARAMETRE : `serveur_keycloak_sonde_realm` (realm inexistant).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
URL={{ serveur_keycloak_sonde_url }}
|
||||||
|
REALM={{ serveur_keycloak_sonde_realm }}
|
||||||
|
|
||||||
|
s=$(curl -s --max-time 10 "${URL}/realms/${REALM}/.well-known/openid-configuration" 2>/dev/null)
|
||||||
|
[[ -n "${s}" ]] || { echo "Keycloak ne repond pas sur ${URL}."; exit 2; }
|
||||||
|
printf '%s' "${s}" | grep -q '"issuer"' \
|
||||||
|
|| { echo "Le realm « ${REALM} » ne sert pas sa decouverte OIDC : ${s:0:70}"; exit 2; }
|
||||||
|
|
||||||
|
# LES POINTS D'ENTREE QUE LES CLIENTS UTILISENT VRAIMENT. Un document de decouverte
|
||||||
|
# tronque se lit comme du JSON valide et casse chaque client a la premiere redirection.
|
||||||
|
for cle in authorization_endpoint token_endpoint jwks_uri; do
|
||||||
|
printf '%s' "${s}" | grep -q "\"${cle}\"" \
|
||||||
|
|| { echo "Decouverte OIDC incomplete pour « ${REALM} » : ${cle} absent."; exit 2; }
|
||||||
|
done
|
||||||
|
echo "Realm « ${REALM} » : decouverte OIDC complete."
|
||||||
|
|
@ -120,3 +120,6 @@ serveur_nextcloud_marqueur_admin: "/etc/setops-nextcloud-admin-sha256"
|
||||||
# puis pousse par SSH : aucun flux nouveau, et l'artefact devient deployable hors ligne.
|
# puis pousse par SSH : aucun flux nouveau, et l'artefact devient deployable hors ligne.
|
||||||
# Surchargeable par `setops_cache_artefacts` pour partager un cache commun.
|
# Surchargeable par `setops_cache_artefacts` pour partager un cache commun.
|
||||||
serveur_nextcloud_cache_local: "{{ setops_cache_artefacts | default(lookup('env', 'HOME') + '/.cache/setops') }}"
|
serveur_nextcloud_cache_local: "{{ setops_cache_artefacts | default(lookup('env', 'HOME') + '/.cache/setops') }}"
|
||||||
|
|
||||||
|
# --- Sonde de supervision -----------------------------------------------------------
|
||||||
|
serveur_nextcloud_sonde_url: "http://127.0.0.1"
|
||||||
|
|
|
||||||
8
roles/serveur_nextcloud/meta/supervision.yml
Normal file
8
roles/serveur_nextcloud/meta/supervision.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Supervision derivee du role. Voir docs/supervision-conception.md.
|
||||||
|
sondes:
|
||||||
|
- nom: collaboration
|
||||||
|
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
|
||||||
|
cesse de repondre.
|
||||||
|
|
@ -53,3 +53,22 @@
|
||||||
- name: Identite visuelle Alliance Boreale (theme + ciel etoile)
|
- name: Identite visuelle Alliance Boreale (theme + ciel etoile)
|
||||||
ansible.builtin.import_tasks: theme.yml
|
ansible.builtin.import_tasks: theme.yml
|
||||||
when: serveur_nextcloud_branding | bool
|
when: serveur_nextcloud_branding | bool
|
||||||
|
|
||||||
|
# --- Sonde de supervision (docs/supervision-conception.md) --------------------------
|
||||||
|
# Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la
|
||||||
|
# fait tourner et pousse le verdict, sans savoir ce qu'elle mesure.
|
||||||
|
- 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 « collaboration »
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sonde-collaboration.sh.j2
|
||||||
|
dest: /usr/local/lib/setops/sondes/collaboration.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
|
||||||
35
roles/serveur_nextcloud/templates/sonde-collaboration.sh.j2
Normal file
35
roles/serveur_nextcloud/templates/sonde-collaboration.sh.j2
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# GENERE par Set-OPS (role serveur_nextcloud). Ne pas editer a la main.
|
||||||
|
#
|
||||||
|
# SONDE « collaboration » — installe, hors maintenance, sans migration en attente
|
||||||
|
#
|
||||||
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||||
|
# Mise en defaut PAR PARAMETRE : `serveur_nextcloud_sonde_url` (port ferme).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
URL={{ serveur_nextcloud_sonde_url }}
|
||||||
|
|
||||||
|
s=$(curl -sk --max-time 10 "${URL}/status.php" 2>/dev/null)
|
||||||
|
[[ -n "${s}" ]] || { echo "Nextcloud ne repond pas sur ${URL}."; exit 2; }
|
||||||
|
|
||||||
|
verdict=$(printf '%s' "${s}" | python3 -c '
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
d = json.load(sys.stdin)
|
||||||
|
except Exception:
|
||||||
|
print("2|status.php illisible"); raise SystemExit
|
||||||
|
if not d.get("installed"):
|
||||||
|
print("2|instance NON INSTALLEE")
|
||||||
|
elif d.get("maintenance"):
|
||||||
|
print("2|en MODE MAINTENANCE — personne ne peut travailler")
|
||||||
|
elif d.get("needsDbUpgrade"):
|
||||||
|
print("2|migration de base EN ATTENTE — le service tourne sur un schema perime")
|
||||||
|
else:
|
||||||
|
print("0|version " + str(d.get("versionstring") or d.get("version") or "?"))
|
||||||
|
' 2>/dev/null)
|
||||||
|
|
||||||
|
code=${verdict%%|*}; texte=${verdict#*|}
|
||||||
|
[[ -n "${code}" ]] || { echo "Verdict Nextcloud illisible."; exit 2; }
|
||||||
|
[[ "${code}" == "0" ]] && { echo "Nextcloud : ${texte}, installe et disponible."; exit 0; }
|
||||||
|
echo "Nextcloud EN DEFAUT — ${texte}."
|
||||||
|
exit 2
|
||||||
|
|
@ -182,3 +182,8 @@ serveur_ops_cache_roues: >-
|
||||||
{{ (setops_cache_artefacts | default(lookup('env', 'HOME') + '/.cache/setops')) }}/roues-{{
|
{{ (setops_cache_artefacts | default(lookup('env', 'HOME') + '/.cache/setops')) }}/roues-{{
|
||||||
(lookup('file', serveur_ops_roues_source) ~ serveur_ops_ansible) | hash('sha1') | truncate(12, true, '') }}
|
(lookup('file', serveur_ops_roues_source) ~ serveur_ops_ansible) | hash('sha1') | truncate(12, true, '') }}
|
||||||
serveur_ops_roues_depot: "{{ serveur_ops_racine }}/.roues-hors-ligne"
|
serveur_ops_roues_depot: "{{ serveur_ops_racine }}/.roues-hors-ligne"
|
||||||
|
|
||||||
|
# --- Sonde de supervision -----------------------------------------------------------
|
||||||
|
serveur_ops_sonde_racine: /opt/setops
|
||||||
|
serveur_ops_sonde_venv: /opt/setops/venv
|
||||||
|
serveur_ops_sonde_branche: main
|
||||||
|
|
|
||||||
8
roles/serveur_ops/meta/supervision.yml
Normal file
8
roles/serveur_ops/meta/supervision.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Supervision derivee du role. Voir docs/supervision-conception.md.
|
||||||
|
sondes:
|
||||||
|
- nom: runner
|
||||||
|
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
|
||||||
|
lit), et Ansible repond-il dans son venv.'
|
||||||
|
|
@ -520,3 +520,22 @@
|
||||||
owner: "{{ serveur_ops_utilisateur }}"
|
owner: "{{ serveur_ops_utilisateur }}"
|
||||||
group: "{{ serveur_ops_utilisateur }}"
|
group: "{{ serveur_ops_utilisateur }}"
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
|
|
||||||
|
# --- Sonde de supervision (docs/supervision-conception.md) --------------------------
|
||||||
|
# Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la
|
||||||
|
# fait tourner et pousse le verdict, sans savoir ce qu'elle mesure.
|
||||||
|
- 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 « runner »
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sonde-runner.sh.j2
|
||||||
|
dest: /usr/local/lib/setops/sondes/runner.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
|
||||||
43
roles/serveur_ops/templates/sonde-runner.sh.j2
Normal file
43
roles/serveur_ops/templates/sonde-runner.sh.j2
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#jinja2: comment_start_string:'{=#', comment_end_string:'#=}'
|
||||||
|
#!/bin/bash
|
||||||
|
# (Le gabarit redefinit le delimiteur de commentaire Jinja : `${#tableau[@]}` contient
|
||||||
|
# la sequence `{#`, que Jinja lirait comme un debut de commentaire. Le shell en a
|
||||||
|
# besoin ; c'est donc a Jinja de s'ecarter.)
|
||||||
|
# GENERE par Set-OPS (role serveur_ops). Ne pas editer a la main.
|
||||||
|
#
|
||||||
|
# SONDE « runner » — depots propres sur leur branche, et Ansible repond
|
||||||
|
#
|
||||||
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||||
|
# Mise en defaut PAR PARAMETRE : `serveur_ops_sonde_venv` (chemin inexistant).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
VENV={{ serveur_ops_sonde_venv }}
|
||||||
|
BRANCHE={{ serveur_ops_sonde_branche }}
|
||||||
|
RACINE={{ serveur_ops_sonde_racine }}
|
||||||
|
|
||||||
|
# `safe.directory` : les depots appartiennent au compte d'exploitation, la sonde tourne en
|
||||||
|
# root. Sans cela git refuse — « proprietaire douteux » — et la sonde rendrait un echec
|
||||||
|
# qui parle de git au lieu de parler du depot.
|
||||||
|
git_() { git -c safe.directory='*' -C "$1" "${@:2}" 2>/dev/null; }
|
||||||
|
|
||||||
|
ennuis=(); n=0
|
||||||
|
for d in "${RACINE}"/*/; do
|
||||||
|
[[ -d "${d}.git" ]] || continue
|
||||||
|
n=$((n+1)); nom=$(basename "${d}")
|
||||||
|
b=$(git_ "${d}" rev-parse --abbrev-ref HEAD)
|
||||||
|
[[ "${b}" == "${BRANCHE}" ]] || ennuis+=("${nom} sur « ${b:-?} »")
|
||||||
|
# UN DEPOT SALE SUR LE RUNNER EST UNE DIVERGENCE SILENCIEUSE : ce qui s'applique a la
|
||||||
|
# flotte n'est plus ce que le depot contient, et personne ne le sait.
|
||||||
|
[[ -z "$(git_ "${d}" status --porcelain)" ]] || ennuis+=("${nom} MODIFIE localement")
|
||||||
|
done
|
||||||
|
|
||||||
|
(( n > 0 )) || { echo "Aucun depot sous ${RACINE} — le runner n'a rien a appliquer."; exit 2; }
|
||||||
|
|
||||||
|
v=$("${VENV}/bin/ansible" --version 2>/dev/null | head -1)
|
||||||
|
[[ -n "${v}" ]] || { echo "Ansible ne repond pas dans ${VENV} — le runner ne peut rien appliquer."; exit 2; }
|
||||||
|
|
||||||
|
if (( ${#ennuis[@]} > 0 )); then
|
||||||
|
echo "Runner : ${ennuis[*]} — ce qui s'applique diverge du depot.|depots=${n}"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
echo "Runner : ${n} depot(s) propres sur « ${BRANCHE} », ${v}.|depots=${n}"
|
||||||
|
|
@ -79,3 +79,11 @@ serveur_ops_tenant_cle_deposer: false
|
||||||
serveur_ops_tenant_cle_source: ""
|
serveur_ops_tenant_cle_source: ""
|
||||||
serveur_ops_tenant_cle_destination: >-
|
serveur_ops_tenant_cle_destination: >-
|
||||||
{{ serveur_ops_tenant_racine }}/.config/setops-vault-{{ serveur_ops_tenant_depot | lower }}
|
{{ serveur_ops_tenant_racine }}/.config/setops-vault-{{ serveur_ops_tenant_depot | lower }}
|
||||||
|
|
||||||
|
# --- Sonde de supervision -----------------------------------------------------------
|
||||||
|
# Le chemin ou le RUNNER lit la voute de son ecosysteme.
|
||||||
|
# LE DEPOT VIENT DU ROLE, PAS D'UNE SUPPOSITION : `serveur_ops_tenant_depot` designe
|
||||||
|
# deja le dossier clone sur le runner.
|
||||||
|
serveur_ops_tenant_sonde_depot: "{{ serveur_ops_tenant_depot }}"
|
||||||
|
serveur_ops_tenant_sonde_voute: >-
|
||||||
|
/opt/setops/{{ serveur_ops_tenant_sonde_depot }}/inventories/principal/group_vars/all/vault.yml
|
||||||
|
|
|
||||||
8
roles/serveur_ops_tenant/meta/supervision.yml
Normal file
8
roles/serveur_ops_tenant/meta/supervision.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Supervision derivee du role. Voir docs/supervision-conception.md.
|
||||||
|
sondes:
|
||||||
|
- nom: voute
|
||||||
|
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
|
||||||
|
fonctionner, et les secrets sont lisibles par quiconque accede a la machine.'
|
||||||
|
|
@ -177,3 +177,22 @@
|
||||||
when:
|
when:
|
||||||
- serveur_ops_tenant_cle_deposer | bool
|
- serveur_ops_tenant_cle_deposer | bool
|
||||||
- not ansible_check_mode
|
- not ansible_check_mode
|
||||||
|
|
||||||
|
# --- Sonde de supervision (docs/supervision-conception.md) --------------------------
|
||||||
|
# Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la
|
||||||
|
# fait tourner et pousse le verdict, sans savoir ce qu'elle mesure.
|
||||||
|
- 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 « voute »
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sonde-voute.sh.j2
|
||||||
|
dest: /usr/local/lib/setops/sondes/voute.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
|
||||||
24
roles/serveur_ops_tenant/templates/sonde-voute.sh.j2
Normal file
24
roles/serveur_ops_tenant/templates/sonde-voute.sh.j2
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# GENERE par Set-OPS (role serveur_ops_tenant). Ne pas editer a la main.
|
||||||
|
#
|
||||||
|
# SONDE « voute » — la voute est presente et chiffree
|
||||||
|
#
|
||||||
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||||
|
# Mise en defaut PAR PARAMETRE : `serveur_ops_tenant_sonde_voute` (chemin inexistant).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
VOUTE={{ serveur_ops_tenant_sonde_voute }}
|
||||||
|
|
||||||
|
[[ -f "${VOUTE}" ]] || { echo "Aucune voute en ${VOUTE} — le runner ne peut pas deployer."; exit 2; }
|
||||||
|
|
||||||
|
# LA PRESENCE NE SUFFIT PAS, ET C'EST TOUT L'INTERET DE CETTE SONDE. Un fichier existe
|
||||||
|
# aussi bien chiffre qu'en clair ; seul son entete le dit.
|
||||||
|
head -c 20 "${VOUTE}" | grep -q '^\$ANSIBLE_VAULT' \
|
||||||
|
|| { echo "LA VOUTE EST EN CLAIR : ${VOUTE} — secrets lisibles sur ce runner."; exit 2; }
|
||||||
|
|
||||||
|
perm=$(stat -c '%a' "${VOUTE}" 2>/dev/null)
|
||||||
|
if [[ "${perm}" != "600" && "${perm}" != "640" && "${perm}" != "400" ]]; then
|
||||||
|
echo "Voute chiffree mais lisible trop largement (${perm}) : ${VOUTE}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Voute presente et chiffree (${perm})."
|
||||||
|
|
@ -61,3 +61,10 @@ serveur_postfix_tls_dir: "/etc/postfix/tls"
|
||||||
# Zero-confiance : verifier le TLS de la livraison LMTP vers Dovecot (cert step-ca).
|
# Zero-confiance : verifier le TLS de la livraison LMTP vers Dovecot (cert step-ca).
|
||||||
serveur_postfix_lmtp_tls_verify: false
|
serveur_postfix_lmtp_tls_verify: false
|
||||||
serveur_postfix_lmtp_tls_cafile: "/etc/step/certs/root_ca.crt"
|
serveur_postfix_lmtp_tls_cafile: "/etc/step/certs/root_ca.crt"
|
||||||
|
|
||||||
|
# --- Sonde de supervision -----------------------------------------------------------
|
||||||
|
# UN COURRIEL EN ATTENTE N'EST PAS UNE PANNE — un relais distant momentanement muet suffit
|
||||||
|
# a en garder quelques-uns. C'est l'ACCUMULATION qui parle. Les seuils sont bas parce que
|
||||||
|
# cet ecosysteme n'emet presque rien : dix messages en attente y sont deja anormaux.
|
||||||
|
serveur_postfix_sonde_avert: 10
|
||||||
|
serveur_postfix_sonde_crit: 50
|
||||||
|
|
|
||||||
8
roles/serveur_postfix/meta/supervision.yml
Normal file
8
roles/serveur_postfix/meta/supervision.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
# Supervision derivee du role. Voir docs/supervision-conception.md.
|
||||||
|
sondes:
|
||||||
|
- nom: file-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
|
||||||
|
recevoir.
|
||||||
|
|
@ -214,3 +214,22 @@
|
||||||
enabled: true
|
enabled: true
|
||||||
state: started
|
state: started
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
|
|
||||||
|
# --- Sonde de supervision (docs/supervision-conception.md) --------------------------
|
||||||
|
# Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la
|
||||||
|
# fait tourner et pousse le verdict, sans savoir ce qu'elle mesure.
|
||||||
|
- 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 « file-courriel »
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sonde-file-courriel.sh.j2
|
||||||
|
dest: /usr/local/lib/setops/sondes/file-courriel.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0750"
|
||||||
|
|
|
||||||
29
roles/serveur_postfix/templates/sonde-file-courriel.sh.j2
Normal file
29
roles/serveur_postfix/templates/sonde-file-courriel.sh.j2
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# GENERE par Set-OPS (role serveur_postfix). Ne pas editer a la main.
|
||||||
|
#
|
||||||
|
# SONDE « file-courriel » — la file d'attente ne s'accumule pas
|
||||||
|
#
|
||||||
|
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||||
|
# Mise en defaut PAR PARAMETRE : `serveur_postfix_sonde_avert` / `_crit` (seuils impossibles).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
AVERT={{ serveur_postfix_sonde_avert }}
|
||||||
|
CRIT={{ serveur_postfix_sonde_crit }}
|
||||||
|
|
||||||
|
systemctl is-active --quiet postfix || { echo "Postfix n'est pas actif."; exit 2; }
|
||||||
|
|
||||||
|
# `mailq` PLUTOT QUE LE COMPTE DE FICHIERS : la file vit dans plusieurs repertoires
|
||||||
|
# (incoming, active, deferred, hold) et seul Postfix sait ce qu'il compte comme en
|
||||||
|
# attente. Un `find` sur `/var/spool` donnerait un chiffre plausible et faux.
|
||||||
|
n=$(mailq 2>/dev/null | grep -cE '^[0-9A-F]{6,}' || true)
|
||||||
|
diff=$(mailq 2>/dev/null | grep -cE '^[0-9A-F]+\*?[[:space:]]' || true)
|
||||||
|
|
||||||
|
if (( n >= CRIT )); then
|
||||||
|
echo "File de courriel : ${n} message(s) en attente — la remise ne se fait plus.|file=${n};${AVERT};${CRIT};0;"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if (( n >= AVERT )); then
|
||||||
|
echo "File de courriel : ${n} message(s) en attente (seuil ${AVERT}).|file=${n};${AVERT};${CRIT};0;"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "File de courriel : ${n} message(s) en attente.|file=${n};${AVERT};${CRIT};0;"
|
||||||
Loading…
Reference in a new issue