sauvegarde : la verification suit la cle, pas le depot
Some checks are pending
verifier / verifier (push) Waiting to run

serveur_backup verifiait pour tout le monde — juste tant que le depot vivait
dans l ecosysteme. Depuis qu ils deposent chez leur hebergeur, le site heberge
des octets chiffres COTE CLIENT : il ne peut ni les lire ni dire s ils valent
quelque chose. La verification revient donc au seul qui detient la cle, le noeud.

client_backup verifie SON depot distant — pas le fait d avoir lance sa
sauvegarde. Une unite verte sur un depot vide est ce qui a menti un mois.

serveur_icinga n exige plus un hote serveur_backup et se branche sur deux
modeles : depot local (services sur son hote, nommes sauvegarde: <noeud>) ou
pas de depot (services sur chaque noeud, nommes sauvegarde).

Le 404 qui n etait pas une absence : les noeuds recevaient  No objects found
alors que icinga2 object list montrait le service charge. Le filtre du compte
d API ne portait que la premiere forme de nom — c est la PERMISSION qui
refusait, avec les mots d une absence.

Aussi : ingress 5665 depuis client_backup, le pair ne nommait que
serveur_backup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
This commit is contained in:
Daniel Allaire 2026-09-02 18:53:44 -04:00
parent cccb4e5b43
commit 6653f49f2e
12 changed files with 408 additions and 6 deletions

View file

@ -1,5 +1,83 @@
# CHANGELOG — Set-OPS
## 2026-09-02 (5) — La verification suit la cle : chaque noeud constate SON depot
**56 preuves. `make valider` : 0 echec sur 13 hotes**, test de restitution compris.
`backup-01` est retire du plan de Chezlepro et sa VM detruite. Elle ne gardait plus rien :
son `/srv/restic` ne contenait que les fichiers de demarrage du compte `restic`, aucun
depot, aucun instantane — et sa verification rapportait consciencieusement « tout va
bien ». **Une supervision creuse est pire qu'aucune : elle est verte.**
### Pourquoi la verification a change de main
`serveur_backup` verifiait pour tout le monde, et c'etait juste : un noeud sait qu'il a
LANCE sa sauvegarde, il ne sait pas qu'elle a ABOUTI — le depot etait le seul a voir ce
qui arrivait vraiment.
Depuis que les ecosystemes deposent chez leur HEBERGEUR, ce n'est plus vrai. Le site
heberge des octets chiffres COTE CLIENT, avec un mot de passe qui ne quitte pas la voute
du locataire : il ne peut ni les lire, ni les ouvrir, ni dire s'ils valent quelque chose.
C'est la propriete qui rend la mutualisation acceptable, et elle deplace la verification
chez le seul qui detient la cle — **le noeud lui-meme**.
Il verifie donc SON depot distant, pas le fait d'avoir lance sa sauvegarde. La nuance est
tout : une unite verte sur un depot vide est exactement ce qui a menti pendant un mois
(2026-07-03 -> 2026-08-11).
### Deux modeles, et le role sait desormais dans lequel il est
`serveur_icinga` exigeait un hote `serveur_backup` dans l'ecosysteme et attachait les
services `sauvegarde: <noeud>` a cet hote. Sans depot local, il refusait de se deployer.
Il se branche maintenant :
- **depot local** — il rapporte pour tous, les services vivent sur SON hote, et leur nom
dit de quel noeud on parle : `sauvegarde: idm-01` ;
- **pas de depot** — chaque noeud rapporte le sien, le service vit SUR LUI, et s'appelle
simplement `sauvegarde`. Repeter le nom donnerait « idm-01 / sauvegarde: idm-01 ». Et
c'est plus juste : la sauvegarde d'`idm-01` est un attribut d'`idm-01`.
Ce qui reste exige, c'est le secret d'API — sans lui, personne ne peut rien rapporter.
### Le 404 qui n'etait pas une absence
Les noeuds recevaient `{"error":404,"status":"No objects found."}` — le message d'un objet
ABSENT. `icinga2 object list` montrait pourtant `idm-01!sauvegarde` charge et vivant.
Le filtre du compte d'API portait `match("sauvegarde: *", service.name)` : la premiere
forme de nom seulement. C'etait la PERMISSION qui refusait, et elle le disait avec les
mots d'une absence. Le filtre accepte desormais les deux formes, sans s'elargir au-dela :
ce compte ne peut poser un resultat que sur un service de sauvegarde.
`serveur_icinga` declare aussi `ingress 5665` depuis `client_backup` — le pair ne
nommait que `serveur_backup`, qui n'existe plus chez ce locataire.
### Ce que la supervision dit maintenant, chez le locataire
collab-01 OK : instantane il y a 20 h, 108 fichier(s)
data-sql-01 OK : instantane il y a 20 h, 1 fichier(s)
edge-mta-01 OK : instantane il y a 20 h, 138 fichier(s)
forge-01 OK : instantane il y a 20 h, 29 fichier(s)
idm-01 OK : instantane il y a 20 h, 1 fichier(s)
infra-mail-01 OK : instantane il y a 20 h, 7 fichier(s)
infra-pki-01 OK : instantane il y a 20 h, 12 fichier(s)
web-dorsal-01 N'EMPORTE RIEN : instantane sans aucun fichier — a confirmer
web-frontal-01 N'EMPORTE RIEN : instantane sans aucun fichier — a confirmer
Les deux avertissements sont honnetes : ces repertoires sont reellement vides, aucune
webapp n'est deployee. La machine ne peut pas distinguer « les donnees ont disparu » de
« il n'y en a pas encore » — c'est a un humain de trancher, mais il doit le VOIR.
### Constat non corrige
Retirer une VM du plan ne la detruit pas : `make raser` ne connait que les hotes DU plan,
donc plus celle-ci. Il a fallu la detruire a la main sur l'hyperviseur. Un hote retire du
plan devient un orphelin qu'aucune cible ne ramasse.
Et Prometheus a continue de scruter son exportateur jusqu'a ce que `serveur_prometheus`
soit rejoue — `make valider` l'a attrape, ce qui est exactement son role.
## 2026-09-02 (4) — Le site a un temoin ; et une panne dormait depuis des semaines dans un mot
**56 preuves.** L'hebergeur a desormais sa propre supervision : `site-mon-01` (VLAN 36,

View file

@ -44,6 +44,7 @@
| `serveur_grafana` | ingress | 3000 | tcp | edge | clair | Interface web servie via l'edge (TLS terminé à l'edge). |
| `serveur_grafana` | egress | 443 | tcp | edge | tls-requis | Authentification OIDC auprès de Keycloak (via son FQDN publié à l'edge). |
| `serveur_icinga` | ingress | 5665 | tcp | localhost | clair | API Icinga 2 consommée en local par Icinga Web 2 co-localisé. |
| `serveur_icinga` | ingress | 5665 | tcp | client_backup | tls-requis | Rapport passif de chaque detenteur d'etat sur SON depot distant : le depot du site heberge du chiffre et ne peut pas le juger. |
| `serveur_icinga` | ingress | 5665 | tcp | serveur_backup | tls-requis | Le depot de sauvegarde depose ses resultats passifs (portee : process-check-result sur « sauvegarde: * »). |
| `serveur_icinga` | egress | 5432 | tcp | serveur_postgresql | tls-requis | Base relationnelle du moteur Icinga (verify-full). |
| `serveur_icingaweb2` | ingress | 8080 | tcp | edge | clair | Interface web servie via l'edge (TLS terminé à l'edge ; SSO possible via oauth2-proxy). |
@ -113,4 +114,4 @@
- **starttls** : 6 flux
- **tls** : 9 flux
- **tls-cible** : 2 flux
- **tls-requis** : 33 flux
- **tls-requis** : 34 flux

View file

@ -89,3 +89,34 @@ client_backup_jobs: >-
# La liste EN CLAIR des memes groupes vit dans `vars/main.yml` — sans Jinja, pour que la
# supervision et P36 puissent la lire par `include_vars` sans rendre ce catalogue.
# --- LE NOEUD VERIFIE SON PROPRE DEPOT ----------------------------------------
#
# POURQUOI ICI, ALORS QUE `serveur_backup` LE FAISAIT DEJA.
#
# Le depot etait le seul a voir ce qui etait REELLEMENT arrive : un noeud sait qu'il a
# lance sa sauvegarde, il ne sait pas qu'elle a abouti. C'etait juste tant que le depot
# appartenait au meme ecosysteme.
#
# Depuis que les ecosystemes deposent chez leur HEBERGEUR, ca ne l'est plus : le site
# heberge des octets chiffres par restic COTE CLIENT, avec un mot de passe qui ne quitte
# pas la voute du locataire. Il ne peut ni les lire, ni les ouvrir, ni dire s'ils valent
# quelque chose. C'est la propriete qui rend la mutualisation acceptable — et elle
# deplace la verification chez le seul qui detient la cle : le noeud lui-meme.
#
# Il verifie donc SON depot distant, pas le fait d'avoir lance sa sauvegarde. La nuance
# est tout : une unite systemd verte sur un depot vide est exactement ce qui a menti
# pendant un mois (2026-07-03 -> 2026-08-11).
client_backup_icinga_hote: "{{ (groups['serveur_icinga'] | default([]) | first) | default('') }}"
client_backup_icinga_utilisateur: "setops-depot"
client_backup_icinga_motdepasse: "{{ vault_icinga_api_depot | default('') }}"
client_backup_ca_verification: "/etc/setops/icinga-ca.crt"
client_backup_icinga_ca_source: "/var/lib/icinga2/ca/ca.crt"
# `ttl` du resultat passif : au-dela, Icinga perime le service de lui-meme — c'est ce qui
# fait que le SILENCE alerte. Memes valeurs que cote depot : une verification toutes les
# 4 h, une execution peut etre manquee sans fausse alerte, deux ne le peuvent pas.
client_backup_verification_horaire: "*-*-* 01/4:00:00"
client_backup_ttl_icinga: 21600
client_backup_age_warn_h: 26
client_backup_age_crit_h: 50

View file

@ -150,3 +150,29 @@
- /etc/systemd/system/setops-sauvegarde.service
- /etc/systemd/system/setops-sauvegarde.timer
notify: Recharger systemd
# --- LE NOEUD VERIFIE SON PROPRE DEPOT ----------------------------------------
#
# Conditionne a l'existence d'un `serveur_icinga` : sans destinataire, le rapport
# n'irait nulle part, et un timer qui echoue chaque nuit apprend a ignorer le rouge.
#
# Et conditionne a `client_backup_jobs` : un noeud qui n'emporte rien n'a pas de depot
# a verifier — c'est la meme liste qui decide des deux, pour qu'elles ne divergent pas.
- name: Vérifier mon dépôt distant, et le dire à Icinga
ansible.builtin.include_tasks: verifier.yml
when:
- client_backup_jobs | length > 0
- client_backup_icinga_hote | length > 0
# DIRE CE QU'ON NE FAIT PAS. Sans supervision dans l'ecosysteme, la sauvegarde tourne et
# personne ne constate jamais qu'elle a abouti. Ce n'est pas une erreur — c'est une dette
# qui doit se voir au deploiement plutot que le jour de la restauration.
- name: Dire que personne ne constatera cette sauvegarde
ansible.builtin.debug:
msg: >-
Aucun `serveur_icinga` dans cet écosystème : la sauvegarde de {{ inventory_hostname }}
tournera sans que personne ne constate qu'elle aboutit. Une unité verte sur un dépôt
vide est exactement ce qui a menti pendant un mois.
when:
- client_backup_jobs | length > 0
- client_backup_icinga_hote | length == 0

View file

@ -0,0 +1,78 @@
---
# CE NOEUD VERIFIE SON PROPRE DEPOT DISTANT.
#
# Inclus seulement quand un `serveur_icinga` existe dans l'ecosysteme : sans destinataire,
# le rapport n'irait nulle part, et poser un timer qui echoue chaque nuit apprendrait aux
# gens a ignorer une unite rouge.
- name: Exiger de quoi rapporter à Icinga
ansible.builtin.assert:
that:
- client_backup_icinga_motdepasse | length > 0
fail_msg: >-
`vault_icinga_api_depot` requis : un hôte `serveur_icinga` existe, mais aucun
secret d'API. Le nœud verrait l'état de son dépôt sans pouvoir le dire.
- name: Déposer le mot de passe d'API Icinga
ansible.builtin.copy:
content: "{{ client_backup_icinga_motdepasse }}\n"
dest: /etc/setops/icinga-api.pass
owner: root
group: root
mode: "0600"
no_log: true
# L'AC d'ICINGA, PAS CELLE DE step-ca : Icinga refuse de servir un certificat qu'il n'a
# pas émis (il renouvelle tout ce qui expire sous 30 jours, nos certificats vivent 24 h).
# Domaine de confiance fermé, pair authentifié malgré tout — ce qui était le vrai enjeu.
- name: L'AC d'Icinga est-elle déjà disponible ?
ansible.builtin.stat:
path: "{{ client_backup_icinga_ca_source }}"
delegate_to: "{{ client_backup_icinga_hote }}"
register: client_backup_ca_presente
- name: Récupérer l'AC d'Icinga depuis l'hôte de supervision
when: client_backup_ca_presente.stat.exists
ansible.builtin.slurp:
src: "{{ client_backup_icinga_ca_source }}"
delegate_to: "{{ client_backup_icinga_hote }}"
register: client_backup_ca_icinga
- name: Déposer l'AC d'Icinga pour la vérification du pair
when: client_backup_ca_presente.stat.exists
ansible.builtin.copy:
content: "{{ client_backup_ca_icinga.content | b64decode }}"
dest: "{{ client_backup_ca_verification }}"
owner: root
group: root
mode: "0644"
- name: Installer curl pour le rapport passif
ansible.builtin.apt:
name: curl
state: present
- name: Déployer le contrôle de mon dépôt
ansible.builtin.template:
src: verifier-mon-depot.sh.j2
dest: /usr/local/sbin/setops-verifier-mon-depot.sh
owner: root
group: root
mode: "0700"
- name: Déployer l'unité et le timer de vérification
ansible.builtin.template:
src: "{{ item.s }}"
dest: "/etc/systemd/system/{{ item.d }}"
owner: root
group: root
mode: "0644"
loop:
- { s: setops-verification-depot.service.j2, d: setops-verification-depot.service }
- { s: setops-verification-depot.timer.j2, d: setops-verification-depot.timer }
- name: Activer le timer de vérification
ansible.builtin.systemd_service:
name: setops-verification-depot.timer
enabled: true
state: started
daemon_reload: true

View file

@ -0,0 +1,11 @@
# Géré par Set-OPS (rôle client_backup). Ne pas éditer à la main.
[Unit]
Description=Vérification de MON dépôt distant et rapport passif vers Icinga
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/setops-verifier-mon-depot.sh
Nice=10
IOSchedulingClass=idle

View file

@ -0,0 +1,15 @@
# Géré par Set-OPS (rôle client_backup). Ne pas éditer à la main.
#
# DÉCALÉ D'UNE HEURE APRÈS LA SAUVEGARDE (02:30) : vérifier avant que l'instantané du
# jour ne soit déposé rendrait un « EN RETARD » chaque matin, sur une sauvegarde qui se
# porte bien. Une alerte qui crie tous les jours cesse d'être lue.
[Unit]
Description=Planification de la vérification du dépôt distant
[Timer]
OnCalendar={{ client_backup_verification_horaire }}
RandomizedDelaySec=300
Persistent=true
[Install]
WantedBy=timers.target

View file

@ -0,0 +1,81 @@
#!/bin/bash
# GENERE par Set-OPS (role client_backup). Ne pas editer a la main.
#
# CE NOEUD VERIFIE SON PROPRE DEPOT, ET PAS SON PROPRE TIMER.
#
# Un noeud sait qu'il a LANCE sa sauvegarde ; il ne sait pas qu'elle a ABOUTI. La
# difference n'est pas theorique : onze machines ont lance chaque nuit un timer vert
# pendant un mois sur des depots qui n'emportaient rien (2026-07-03 -> 2026-08-11).
#
# Ce controle interroge donc le DEPOT DISTANT — l'instantane existe-t-il, est-il RECENT,
# n'est-il pas VIDE. Le noeud est desormais le seul a pouvoir le faire : le depot vit
# chez l'hebergeur, qui heberge des octets chiffres cote client et ne detient aucune de
# nos cles.
set -uo pipefail
export RESTIC_PASSWORD_FILE="/etc/setops/restic.pass"
export RESTIC_REPOSITORY="{{ client_backup_repo }}"
API="https://{{ client_backup_icinga_hote }}.{{ domaine_interne }}:5665"
TTL={{ client_backup_ttl_icinga }}
AGE_WARN={{ client_backup_age_warn_h }}
AGE_CRIT={{ client_backup_age_crit_h }}
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}!sauvegarde" "$1" "$2" "${TTL}")
reponse=$(curl -sS --cacert "{{ client_backup_ca_verification }}" --max-time 20 \
-u "{{ client_backup_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
}
maintenant=$(date +%s)
json=$(restic snapshots --latest 1 --json 2>/dev/null)
horodatage=$(printf '%s' "${json}" | python3 -c \
'import sys,json;d=json.load(sys.stdin);print(d[0]["time"] if d else "")' 2>/dev/null)
if [[ -z "${horodatage}" ]]; then
# ON NE DISTINGUE PAS ICI « depot vide » de « depot injoignable », et c'est voulu :
# dans les deux cas il n'y a PAS de sauvegarde exploitable, et c'est ce qui compte.
# Le detail est dans le journal du noeud, pas dans un verdict qui se voudrait plus
# precis qu'il ne peut l'etre.
rapporter 2 "AUCUN INSTANTANE lisible dans ${RESTIC_REPOSITORY} — depot vide ou injoignable."
exit 0
fi
secondes=$(date -d "$(printf '%s' "${horodatage}" | sed -E 's/\.[0-9]+//')" +%s 2>/dev/null || echo 0)
age_h=$(( (maintenant - secondes) / 3600 ))
taille=$(restic stats latest --mode raw-data --json 2>/dev/null | python3 -c \
'import sys,json;print(json.load(sys.stdin).get("total_size",0))' 2>/dev/null || echo 0)
fichiers=$(restic ls latest --json 2>/dev/null | python3 -c \
'import sys,json
n=0
for l in sys.stdin:
try: d=json.loads(l)
except ValueError: continue
if d.get("struct_type")=="node" and d.get("type")=="file": n+=1
print(n)' 2>/dev/null || echo 0)
if (( fichiers == 0 )); then
# AVERTISSEMENT et non CRITIQUE : la machine ne peut pas distinguer « les donnees ont
# disparu » de « il n'y en a pas encore » (un /srv/web sans webapp). C'est a un humain
# de trancher — mais il doit le VOIR.
rapporter 1 "N'EMPORTE RIEN : instantane sans aucun fichier (${taille} octets). Legitime si ce noeud n'a pas encore de donnees — a confirmer."
elif (( age_h >= AGE_CRIT )); then
rapporter 2 "PERIME : dernier instantane il y a ${age_h} h (seuil ${AGE_CRIT} h), ${fichiers} fichier(s)."
elif (( age_h >= AGE_WARN )); then
rapporter 1 "EN RETARD : dernier instantane il y a ${age_h} h (seuil ${AGE_WARN} h), ${fichiers} fichier(s)."
else
rapporter 0 "OK : instantane il y a ${age_h} h, ${fichiers} fichier(s), ${taille} octets."
fi

View file

@ -8,6 +8,21 @@ flux:
pair: localhost
chiffrement: clair
raison: "API Icinga 2 consommée en local par Icinga Web 2 co-localisé."
# LES NOEUDS RAPPORTENT EUX-MEMES DEPUIS LE 2026-09-02.
#
# Tant que le depot vivait dans l'ecosysteme, il rapportait pour tout le monde et
# `serveur_backup` suffisait comme pair. Depuis que les ecosystemes deposent chez leur
# HEBERGEUR — qui heberge du chiffre et ne peut rien juger — c'est chaque detenteur
# d'etat qui verifie SON depot et le rapporte. Le pair, c'est donc `client_backup`.
#
# Les deux coexistent : un ecosysteme qui garde son propre depot continue de le laisser
# rapporter. `serveur_backup` reste declare juste en dessous.
- sens: ingress
port: 5665
protocole: tcp
pair: client_backup
chiffrement: tls-requis
raison: "Rapport passif de chaque detenteur d'etat sur SON depot distant : le depot du site heberge du chiffre et ne peut pas le juger."
- sens: ingress
port: 5665
protocole: tcp

View file

@ -135,14 +135,24 @@
ansible.builtin.set_fact:
client_backup_groupes_etat: "{{ _catalogue_sauvegarde.client_backup_groupes_etat }}"
- name: Exiger le secret d'API du depot (Vault)
# UN ECOSYSTEME PEUT N'AVOIR AUCUN DEPOT A LUI, ET C'EST LE CAS NORMAL DEPUIS QU'ILS
# DEPOSENT CHEZ LEUR HEBERGEUR (2026-09-02).
#
# Cette assertion exigeait un hote `serveur_backup` dans l'ecosysteme. C'etait juste tant
# que le depot y vivait : il etait le seul a voir ce qui arrivait vraiment, et il
# rapportait pour tout le monde.
#
# Depuis la bascule vers le depot du SITE, l'ecosysteme n'en a plus. Le site, lui, ne
# peut pas ouvrir ces depots — restic chiffre chez le client. C'est donc chaque NOEUD qui
# verifie le sien (`client_backup/tasks/verifier.yml`) et rapporte ici. Ce qui reste
# exige, c'est le secret d'API : sans lui, personne ne peut rien rapporter.
- name: Exiger le secret d'API pour les rapports passifs (Vault)
ansible.builtin.assert:
that:
- serveur_icinga_api_motdepasse | length > 0
- serveur_icinga_hote_sauvegarde | length > 0
fail_msg: >-
vault_icinga_api_depot requis, et un hote du groupe `serveur_backup` doit exister :
sans l'un ou l'autre, les sauvegardes ne seraient surveillees par personne.
vault_icinga_api_depot requis : sans lui, ni le depot ni les noeuds ne peuvent
rapporter l'etat de leurs sauvegardes, et personne ne les surveille.
- name: Deployer le compte d'API du depot de sauvegarde
ansible.builtin.template:

View file

@ -10,7 +10,26 @@ object ApiUser "{{ serveur_icinga_api_utilisateur }}" {
permissions = [
{
permission = "actions/process-check-result"
filter = {{ '{{' }} match("sauvegarde: *", service.name) {{ '}}' }}
{#
DEUX FORMES DE NOM, PARCE QU'IL Y A DEUX MODELES (2026-09-02).
« sauvegarde: <noeud> » — l'ecosysteme a son propre depot, qui rapporte pour
tout le monde : les services vivent sur SON hote, le nom doit donc dire de quel
noeud on parle.
« sauvegarde » — l'ecosysteme depose chez son hebergeur, qui heberge du chiffre
et ne peut rien juger. Chaque noeud verifie le sien : le service vit SUR LUI, et
repeter son nom donnerait « idm-01 / sauvegarde: idm-01 ».
Le filtre n'acceptait que la premiere forme. Les noeuds recevaient
`{"error":404,"status":"No objects found."}` — le message d'un objet ABSENT,
alors qu'il existait et que c'etait la PERMISSION qui refusait. Une heure a
chercher un objet qui etait la.
La portee reste etroite : ce compte ne peut poser un resultat que sur un service
de sauvegarde, jamais ailleurs.
#}
filter = {{ '{{' }} match("sauvegarde: *", service.name) || service.name == "sauvegarde" {{ '}}' }}
}
]
}

View file

@ -17,6 +17,11 @@ object CheckCommand "setops-passif" {
command = [ "/bin/true" ]
}
{% if serveur_icinga_hote_sauvegarde %}
{#
L'ECOSYSTEME A SON PROPRE DEPOT : c'est LUI qui rapporte, parce qu'il est le seul a
voir ce qui est reellement arrive. Les services s'attachent donc a son hote.
#}
object Host "{{ serveur_icinga_hote_sauvegarde }}" {
check_command = "hostalive"
address = "{{ serveur_icinga_hote_sauvegarde }}.{{ domaine_interne }}"
@ -34,3 +39,35 @@ object Service "sauvegarde: {{ noeud }}" {
vars.setops_source = "{{ noeud }}"
}
{% endfor %}
{% else %}
{#
AUCUN DEPOT DANS CET ECOSYSTEME — le cas normal depuis qu'ils deposent chez leur
HEBERGEUR (2026-09-02).
Le site heberge des octets chiffres COTE CLIENT : il ne peut ni les lire, ni dire
s'ils valent quelque chose. La verification revient donc au seul qui detient la cle,
le NOEUD lui-meme — 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 n'est plus nomme « sauvegarde: <noeud> » mais simplement « sauvegarde » :
le nom du noeud est desormais 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 Host "{{ noeud }}" {
check_command = "hostalive"
address = "{{ noeud }}.{{ domaine_interne }}"
vars.role = "detenteur d etat"
}
object Service "sauvegarde" {
host_name = "{{ noeud }}"
check_command = "setops-passif"
enable_active_checks = false
enable_passive_checks = true
volatile = false
max_check_attempts = 1
vars.setops_source = "{{ noeud }}"
}
{% endfor %}
{% endif %}