Set-OPS-Public/roles/serveur_icinga/templates/setops-sauvegardes.conf.j2
Daniel Allaire b1c4775afe sauvegardes : un controle hebdomadaire de restauration, rapporte a Icinga
restic check en relisant 10 pourcent des donnees, puis restauration reelle du
dernier instantane avec --verify et comptage des fichiers. Service restauration,
fraicheur de 8 jours, filtre du compte d API complete.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 17:04:28 -04:00

115 lines
5.9 KiB
Django/Jinja

/*
* Gere par Set-OPS (role serveur_icinga). Ne pas editer a la main.
*
* Supervision des sauvegardes. Le controle ne porte PAS sur l'unite systemd du noeud
* source : une unite verte sur un depot vide est exactement ce qui a menti pendant un
* mois (2026-07-03 -> 2026-08-11). Il porte sur la VERITE DE TERRAIN, cote depot :
* l'instantane du noeud existe-t-il, est-il RECENT, et n'est-il pas VIDE.
*
* Les HOTES sont definis ailleurs (`setops-hotes.conf`) depuis le 2026-09-09 : deux
* fichiers qui definissent le meme `object Host` font rejeter TOUTE la configuration.
* Ce fichier n'attache que des services.
*
* QUI POUSSE : CHAQUE NOEUD, POUR SON PROPRE DEPOT. Cette ligne a dit le contraire
* jusqu'au 2026-09-14 — elle nommait `backup-01`, « le seul a pouvoir lire ses depots ».
* Or `backup-01` a ete RETIRE le 2026-09-02, et c'est tout le sujet : le site heberge des
* octets chiffres cote client, il ne peut pas les ouvrir, donc pas les juger.
*
* LA VERIFICATION SUIT LA CLE. Chaque noeud verifie SON depot distant et rapporte
* lui-meme, par `client_backup` et son minuteur. Le code de ce fichier avait suivi la
* decision — il attache les services aux vrais noeuds — mais l'en-tete decrivait encore
* un acteur disparu, a celui-la meme qui l'ouvrirait pour comprendre qui pousse.
* C'est le SILENCE qui doit alerter, pas seulement l'echec — le silence est precisement
* ce qui n'a alerte personne. Voir `setops-rapport-attendu` ci-dessous.
*/
/*
* UN RAPPORT ATTENDU, ET NON UN RAPPORT ESPERE (2026-09-28).
*
* Tous les services passifs de Set-OPS (sauvegardes, sante, sondes de role) importent ce
* gabarit. Ils etaient declares `enable_active_checks = false`, avec une commande qui
* executait `/bin/true`. Le `ttl` de chaque envoi couvrait le silence qui SUIT un
* rapport — pas celui d'un noeud qui n'a JAMAIS rapporte : un service passif sans aucun
* resultat reste « en attente », gris, jamais rouge. Dix noeuds de Chezlepro n'ont eu
* aucune sauvegarde du 2026-09-12 au 2026-09-28, et leurs services attendaient.
*
* Le patron documente d'Icinga 2 pour la fraicheur : le service est ACTIF, sa commande est
* `dummy` en CRITIQUE, et son `check_interval` est le seuil. Chaque rapport passif repousse
* l'echeance ; seul le silence la laisse arriver — y compris le silence initial.
*/
template Service "setops-rapport-attendu" {
check_command = "dummy"
enable_active_checks = true
enable_passive_checks = true
volatile = false
max_check_attempts = 1
vars.dummy_state = 2
}
{#
DEUX TEMOINS, ET NON L'UN OU L'AUTRE (2026-09-28).
Ce fichier choisissait : s'il existait un depot dans l'ecosysteme, les services
s'attachaient au DEPOT ; sinon, aux NOEUDS. Or depuis que « la verification suit la
cle », `client_backup` installe sa verification sur CHAQUE noeud, depot ou pas. Au
site, qui a son depot (`site-backup-01`), le rapport des noeuds visait donc un service
que ce fichier n'avait pas cree : `site-forge-01`, `site-mon-01` et `site-pki-01`
ont recu un 404 toutes les quatre heures du 2026-09-20 au 2026-09-28, et leur
verification — la seule qui detienne la cle — n'est arrivee nulle part. Leur unite
echouait ; Icinga, lui, ne voyait que le temoignage du depot, et le croyait complet.
Les deux se completent : le depot dit ce qu'on peut affirmer SANS lire (des octets
arrivent, et quand) ; le noeud dit ce qu'on ne sait qu'AVEC la cle (l'instantane
s'ouvre, il n'est pas vide). Ils ont chacun leur service.
#}
{% if serveur_icinga_hote_sauvegarde %}
{#
LE TEMOIN DU DEPOT : ce que l'hote des depots peut affirmer sans pouvoir lire.
#}
{% for noeud in serveur_icinga_sauvegarde_attendue | sort %}
object Service "sauvegarde: {{ noeud }}" {
import "setops-rapport-attendu"
host_name = "{{ serveur_icinga_hote_sauvegarde }}"
check_interval = {{ serveur_icinga_fraicheur_sauvegarde }}s
retry_interval = {{ serveur_icinga_fraicheur_sauvegarde }}s
vars.dummy_text = "AUCUN RAPPORT depuis {{ (serveur_icinga_fraicheur_sauvegarde / 60) | int }} min : la verification de ce depot ne dit plus rien, ou n a jamais rien dit."
vars.setops_source = "{{ noeud }}"
}
{% endfor %}
{% endif %}
{#
LE TEMOIN DU NOEUD — toujours, qu'il y ait un depot dans l'ecosysteme ou non.
Le depot heberge des octets chiffres COTE CLIENT : il ne peut ni les lire, ni dire
s'ils valent quelque chose. Seul le NOEUD, qui detient la cle, le peut — et le
service s'attache a lui, ce qui est d'ailleurs plus juste : la sauvegarde de `idm-01`
est un attribut de `idm-01`, pas d'une machine tierce.
Le service est nomme simplement « sauvegarde » : le nom du noeud est porte par
l'hote. Repeter le nom dans le service donnerait « idm-01 / sauvegarde: idm-01 ».
#}
{% for noeud in serveur_icinga_sauvegarde_attendue | sort %}
object Service "sauvegarde" {
import "setops-rapport-attendu"
host_name = "{{ noeud }}"
check_interval = {{ serveur_icinga_fraicheur_sauvegarde }}s
retry_interval = {{ serveur_icinga_fraicheur_sauvegarde }}s
vars.dummy_text = "AUCUN RAPPORT depuis {{ (serveur_icinga_fraicheur_sauvegarde / 60) | int }} min : la verification de ce depot ne dit plus rien, ou n a jamais rien dit."
vars.setops_source = "{{ noeud }}"
}
{% endfor %}
{#
LA RESTAURATION, UN SERVICE A PART (2026-09-28). « L'instantane existe, recent, non
vide » (`sauvegarde`) et « il se rouvre, contenu recompare » ne sont pas la meme question.
Controle hebdomadaire : le seuil de fraicheur est de huit jours.
#}
{% for noeud in serveur_icinga_sauvegarde_attendue | sort %}
object Service "restauration" {
import "setops-rapport-attendu"
host_name = "{{ noeud }}"
check_interval = {{ serveur_icinga_fraicheur_restauration }}s
retry_interval = {{ serveur_icinga_fraicheur_restauration }}s
vars.dummy_text = "AUCUN CONTROLE DE RESTAURATION depuis {{ (serveur_icinga_fraicheur_restauration / 86400) | int }} jours : la sauvegarde n'a pas ete rouverte."
vars.setops_source = "{{ noeud }}"
}
{% endfor %}