Set-OPS-Public/roles/client_sante/templates/setops-sante.sh.j2

90 lines
4.4 KiB
Text
Raw Normal View History

supervision : systemctl --failed entre dans Icinga (role client_sante) CE QU IL FERME. openipmi.service echouait a chaque demarrage sur les quatorze machines depuis le 2026-09-02, et systemctl --failed rendait ZERO partout : non parce qu elles allaient bien, mais parce qu aucune n avait redemarre depuis. Il a fallu qu un humain redemarre une machine pour que le defaut existe aux yeux de quelqu un. Un controle qui ne peut echouer qu au demarrage ne mesure rien tant que rien ne demarre. PASSIF, ET A DUREE DE VIE. Un controle actif ne voit pas la machine MUETTE. Ici c est le noeud qui parle, et le ttl de son envoi fait la fraicheur : sans nouvelle, Icinga perime le service tout seul. Le silence alerte autant que l echec. Le minuteur declenche AU DEMARRAGE autant que toutes les 15 min : les echecs de cette famille naissent au boot. CRITIQUE DES LA PREMIERE UNITE, jamais un seuil — une unite en echec est soit un vrai probleme soit du bruit a retirer, et un seuil ferait vivre le bruit. Les tolerances se nomment une par une, vide par defaut. CONTROLE NEGATIF. Unite factice sur obs-01, etat relu dans IcingaDB : CRITICAL, et le verdict NOMME l unite. Les treize autres OK. Apres nettoyage : 14/14 OK. UN CONFLIT EVITE. setops-sauvegardes.conf definissait les object Host ; un second fichier de controle aurait redefini les memes, et Icinga refuse un objet en double — la configuration entiere aurait ete rejetee, donc AUCUNE supervision, en voulant en ajouter. Les hotes vivent maintenant dans setops-hotes.conf, definis une fois. TROIS OBSTACLES. ${#tableau[@]} contient {# que Jinja lit comme un debut de commentaire (remede : comment_start_string en tete du gabarit). Ma premiere sonde a traduit un 403 « Missing permission: objects/query/service » en « 0 service » — encore un echec qui ecrasait permission ; l etat se lit dans IcingaDB. Et un echec apt transitoire sur mon-01, local et disparu au second essai : mesure avant conclusion. NON FAIT : le SITE n a pas recu client_sante. make prouver : CONFORME, 63 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-09 20:32:08 -04:00
#jinja2: comment_start_string:'{=#', comment_end_string:'#=}'
#!/bin/bash
# GENERE par Set-OPS (role client_sante). Ne pas editer a la main.
#
# (Le gabarit redefinit le delimiteur de commentaire Jinja : `${#tableau[@]}` contient
# la sequence `{#`, que Jinja lirait comme un debut de commentaire — et le rendu
# echouait sur « Missing end of comment tag ». Le shell a besoin de `${#...}` ; c'est
# donc a Jinja de s'ecarter.)
#
# CE NOEUD RAPPORTE SES UNITES EN ECHEC — parce que personne d'autre ne peut le voir.
#
# CE QUI A REVELE LE BESOIN (2026-09-09). `openipmi.service` echouait a CHAQUE demarrage
# sur les quatorze machines depuis le 2026-09-02. `systemctl --failed` rendait pourtant
# ZERO partout — non parce qu'elles allaient bien, mais parce qu'aucune n'avait REDEMARRE
# depuis. Six jours et vingt heures pour la premiere. Il a fallu qu'un humain redemarre
# une machine pour que le defaut existe aux yeux de quelqu'un.
#
# Un controle qui ne peut echouer qu'au demarrage ne mesure rien tant que rien ne demarre.
#
# POURQUOI UN RAPPORT PASSIF, ET PAS UN CONTROLE ACTIF. Un controle actif ne voit pas la
# machine MUETTE : si elle ne repond plus, la sonde echoue et on croit a un probleme de
# reseau. Ici c'est le noeud qui parle, avec un `ttl` : sans nouvelle, Icinga perime le
# service tout seul. Le silence alerte autant que l'echec — et le silence est precisement
# ce qui n'a alerte personne.
set -uo pipefail
API="https://{{ client_sante_icinga_hote }}.{{ domaine_interne }}:5665"
TTL={{ client_sante_ttl_icinga }}
MOI="{{ inventory_hostname }}"
MOTDEPASSE="$(cat /etc/setops/icinga-api.pass)"
rapporter() { # $1=code $2=texte
local charge reponse
charge=$(python3 -c 'import json,sys; print(json.dumps({
"type": "Service", "service": sys.argv[1], "exit_status": int(sys.argv[2]),
"plugin_output": sys.argv[3], "ttl": int(sys.argv[4])}))' \
"${MOI}!sante" "$1" "$2" "${TTL}")
reponse=$(curl -sS --cacert "{{ client_sante_ca_verification }}" --max-time 20 \
-u "{{ client_sante_icinga_utilisateur }}:${MOTDEPASSE}" \
-H 'Accept: application/json' -H 'Content-Type: application/json' \
-X POST "${API}/v1/actions/process-check-result" -d "${charge}" 2>&1)
if ! printf '%s' "${reponse}" | grep -q '"code": *200'; then
echo "ECHEC du rapport Icinga : ${reponse}" >&2
exit 1
fi
}
# `--plain` et `--no-legend` : la sortie doit etre analysable, pas jolie. Sans eux,
# systemd insere une puce « ● » en tete de ligne, qui devient le premier champ.
supervision : le site rapporte aussi — et deux corrections pour que ca MARCHE 7 machines du site deployees, 0 echec au playbook — et CINQ rapports sur sept en TimeoutError. Un playbook vert ne prouve pas qu une chose fonctionne ; seul l essai de bout en bout l a dit. 1. LE PAIR DE LA FRONTIERE. Le role client declarait son egress 5665, la politique de sortie etait accept, la regle d entree de l hote autorisait la source — et les paquets mouraient ENTRE les deux. La frontiere filtre l inter-zones du site et ne resout que les roles que les machines PORTENT AU PLAN ; une integration universelle n y figure pas, elle est derivee. pair: client_sante produisait donc une regle est-ouest correcte et AUCUNE regle a la frontiere. Le pair devient serveur_debian — le vocabulaire du depot pour « tout noeud », que le generateur traite deja comme tel, et exact au sens strict. Six regles creees, zero retiree, une par patte de zone. 2. LE RAPPORTEUR S ACCUSAIT LUI-MEME. Pendant l heure de blocage, setops-sante.service a echoue ; une fois debloque, cinq machines ont rapporte CRITIQUE en citant leur propre rapporteur, et systemd garde l etat failed jusqu a un reset-failed. Sa propre unite est desormais exclue du compte — non par complaisance : sa sante est deja mesuree, et mieux, par la FRAICHEUR de ses envois. S il ne peut plus parler, le ttl perime le service, ce qui se voit precisement quand il ne peut PAS ecrire. ETAT FINAL : 7/7 au site, 14/14 au tenant, tous OK. Controle negatif rejoue sur les deux flottes. make prouver : CONFORME, 63 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-09 20:48:36 -04:00
# SA PROPRE UNITE EST EXCLUE, ET CE N'EST PAS SE MENAGER.
#
# Mesure du 2026-09-09 sur le site : le pare-feu a bloque les rapports pendant une heure,
# `setops-sante.service` a donc echoue, et cinq machines se sont mises a rapporter
# CRITIQUE en citant... leur propre rapporteur. Le blocage corrige, l'accusation restait :
# systemd garde l'etat `failed` jusqu'a un `reset-failed`. Un rapporteur qui trebuche une
# fois s'accuserait indefiniment.
#
# La sante du rapporteur est DEJA mesuree, et mieux : par la FRAICHEUR de ses envois. S'il
# ne peut plus parler, Icinga perime le service tout seul (`ttl`) — ce qui se voit
# precisement quand il ne peut PAS ecrire, alors que sa propre unite en echec ne se voit
# que quand il le peut. Se compter soi-meme, c'est mesurer deux fois la meme chose, dont
# une fois mal.
supervision : systemctl --failed entre dans Icinga (role client_sante) CE QU IL FERME. openipmi.service echouait a chaque demarrage sur les quatorze machines depuis le 2026-09-02, et systemctl --failed rendait ZERO partout : non parce qu elles allaient bien, mais parce qu aucune n avait redemarre depuis. Il a fallu qu un humain redemarre une machine pour que le defaut existe aux yeux de quelqu un. Un controle qui ne peut echouer qu au demarrage ne mesure rien tant que rien ne demarre. PASSIF, ET A DUREE DE VIE. Un controle actif ne voit pas la machine MUETTE. Ici c est le noeud qui parle, et le ttl de son envoi fait la fraicheur : sans nouvelle, Icinga perime le service tout seul. Le silence alerte autant que l echec. Le minuteur declenche AU DEMARRAGE autant que toutes les 15 min : les echecs de cette famille naissent au boot. CRITIQUE DES LA PREMIERE UNITE, jamais un seuil — une unite en echec est soit un vrai probleme soit du bruit a retirer, et un seuil ferait vivre le bruit. Les tolerances se nomment une par une, vide par defaut. CONTROLE NEGATIF. Unite factice sur obs-01, etat relu dans IcingaDB : CRITICAL, et le verdict NOMME l unite. Les treize autres OK. Apres nettoyage : 14/14 OK. UN CONFLIT EVITE. setops-sauvegardes.conf definissait les object Host ; un second fichier de controle aurait redefini les memes, et Icinga refuse un objet en double — la configuration entiere aurait ete rejetee, donc AUCUNE supervision, en voulant en ajouter. Les hotes vivent maintenant dans setops-hotes.conf, definis une fois. TROIS OBSTACLES. ${#tableau[@]} contient {# que Jinja lit comme un debut de commentaire (remede : comment_start_string en tete du gabarit). Ma premiere sonde a traduit un 403 « Missing permission: objects/query/service » en « 0 service » — encore un echec qui ecrasait permission ; l etat se lit dans IcingaDB. Et un echec apt transitoire sur mon-01, local et disparu au second essai : mesure avant conclusion. NON FAIT : le SITE n a pas recu client_sante. make prouver : CONFORME, 63 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-09 20:32:08 -04:00
mapfile -t echecs < <(systemctl list-units --state=failed --plain --no-legend 2>/dev/null \
supervision : le site rapporte aussi — et deux corrections pour que ca MARCHE 7 machines du site deployees, 0 echec au playbook — et CINQ rapports sur sept en TimeoutError. Un playbook vert ne prouve pas qu une chose fonctionne ; seul l essai de bout en bout l a dit. 1. LE PAIR DE LA FRONTIERE. Le role client declarait son egress 5665, la politique de sortie etait accept, la regle d entree de l hote autorisait la source — et les paquets mouraient ENTRE les deux. La frontiere filtre l inter-zones du site et ne resout que les roles que les machines PORTENT AU PLAN ; une integration universelle n y figure pas, elle est derivee. pair: client_sante produisait donc une regle est-ouest correcte et AUCUNE regle a la frontiere. Le pair devient serveur_debian — le vocabulaire du depot pour « tout noeud », que le generateur traite deja comme tel, et exact au sens strict. Six regles creees, zero retiree, une par patte de zone. 2. LE RAPPORTEUR S ACCUSAIT LUI-MEME. Pendant l heure de blocage, setops-sante.service a echoue ; une fois debloque, cinq machines ont rapporte CRITIQUE en citant leur propre rapporteur, et systemd garde l etat failed jusqu a un reset-failed. Sa propre unite est desormais exclue du compte — non par complaisance : sa sante est deja mesuree, et mieux, par la FRAICHEUR de ses envois. S il ne peut plus parler, le ttl perime le service, ce qui se voit precisement quand il ne peut PAS ecrire. ETAT FINAL : 7/7 au site, 14/14 au tenant, tous OK. Controle negatif rejoue sur les deux flottes. make prouver : CONFORME, 63 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-09 20:48:36 -04:00
| awk '{print $1}' | grep -vx 'setops-sante.service')
supervision : systemctl --failed entre dans Icinga (role client_sante) CE QU IL FERME. openipmi.service echouait a chaque demarrage sur les quatorze machines depuis le 2026-09-02, et systemctl --failed rendait ZERO partout : non parce qu elles allaient bien, mais parce qu aucune n avait redemarre depuis. Il a fallu qu un humain redemarre une machine pour que le defaut existe aux yeux de quelqu un. Un controle qui ne peut echouer qu au demarrage ne mesure rien tant que rien ne demarre. PASSIF, ET A DUREE DE VIE. Un controle actif ne voit pas la machine MUETTE. Ici c est le noeud qui parle, et le ttl de son envoi fait la fraicheur : sans nouvelle, Icinga perime le service tout seul. Le silence alerte autant que l echec. Le minuteur declenche AU DEMARRAGE autant que toutes les 15 min : les echecs de cette famille naissent au boot. CRITIQUE DES LA PREMIERE UNITE, jamais un seuil — une unite en echec est soit un vrai probleme soit du bruit a retirer, et un seuil ferait vivre le bruit. Les tolerances se nomment une par une, vide par defaut. CONTROLE NEGATIF. Unite factice sur obs-01, etat relu dans IcingaDB : CRITICAL, et le verdict NOMME l unite. Les treize autres OK. Apres nettoyage : 14/14 OK. UN CONFLIT EVITE. setops-sauvegardes.conf definissait les object Host ; un second fichier de controle aurait redefini les memes, et Icinga refuse un objet en double — la configuration entiere aurait ete rejetee, donc AUCUNE supervision, en voulant en ajouter. Les hotes vivent maintenant dans setops-hotes.conf, definis une fois. TROIS OBSTACLES. ${#tableau[@]} contient {# que Jinja lit comme un debut de commentaire (remede : comment_start_string en tete du gabarit). Ma premiere sonde a traduit un 403 « Missing permission: objects/query/service » en « 0 service » — encore un echec qui ecrasait permission ; l etat se lit dans IcingaDB. Et un echec apt transitoire sur mon-01, local et disparu au second essai : mesure avant conclusion. NON FAIT : le SITE n a pas recu client_sante. make prouver : CONFORME, 63 OK, 0 echec, 0 saute. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-09 20:32:08 -04:00
{% if client_sante_unites_tolerees %}
# UNITES TOLEREES, NOMMEES UNE PAR UNE. Jamais un motif large : un filtre qui cache une
# unite en cache d'autres, et on ne s'en apercoit que le jour ou l'on cherche pourquoi
# rien n'a alerte.
tolerees=({% for u in client_sante_unites_tolerees %}"{{ u }}" {% endfor %})
restantes=()
for u in "${echecs[@]}"; do
garder=1
for t in "${tolerees[@]}"; do [[ "$u" == "$t" ]] && garder=0 && break; done
[[ $garder -eq 1 ]] && restantes+=("$u")
done
echecs=("${restantes[@]}")
{% endif %}
n=${#echecs[@]}
if [[ $n -eq 0 ]]; then
rapporter 0 "Aucune unite systemd en echec."
exit 0
fi
# CRITIQUE des la premiere, et non un seuil. Une unite en echec est soit un vrai
# probleme, soit du bruit qu'il faut retirer : dans les deux cas il faut agir. Un seuil
# ferait vivre le bruit indefiniment, et c'est exactement ce qu'on vient de corriger.
rapporter 2 "$n unite(s) systemd en echec : ${echecs[*]}"