diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f335ca..1bd86e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: ` 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, diff --git a/docs/registre-flux.md b/docs/registre-flux.md index 71d5f1d..d608322 100644 --- a/docs/registre-flux.md +++ b/docs/registre-flux.md @@ -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 diff --git a/roles/client_backup/defaults/main.yml b/roles/client_backup/defaults/main.yml index 17b0380..331f943 100644 --- a/roles/client_backup/defaults/main.yml +++ b/roles/client_backup/defaults/main.yml @@ -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 diff --git a/roles/client_backup/tasks/main.yml b/roles/client_backup/tasks/main.yml index 9d34830..a6351d9 100644 --- a/roles/client_backup/tasks/main.yml +++ b/roles/client_backup/tasks/main.yml @@ -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 diff --git a/roles/client_backup/tasks/verifier.yml b/roles/client_backup/tasks/verifier.yml new file mode 100644 index 0000000..d9ef9c4 --- /dev/null +++ b/roles/client_backup/tasks/verifier.yml @@ -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 diff --git a/roles/client_backup/templates/setops-verification-depot.service.j2 b/roles/client_backup/templates/setops-verification-depot.service.j2 new file mode 100644 index 0000000..16d448a --- /dev/null +++ b/roles/client_backup/templates/setops-verification-depot.service.j2 @@ -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 diff --git a/roles/client_backup/templates/setops-verification-depot.timer.j2 b/roles/client_backup/templates/setops-verification-depot.timer.j2 new file mode 100644 index 0000000..f8eb405 --- /dev/null +++ b/roles/client_backup/templates/setops-verification-depot.timer.j2 @@ -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 diff --git a/roles/client_backup/templates/verifier-mon-depot.sh.j2 b/roles/client_backup/templates/verifier-mon-depot.sh.j2 new file mode 100644 index 0000000..380fdfb --- /dev/null +++ b/roles/client_backup/templates/verifier-mon-depot.sh.j2 @@ -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 diff --git a/roles/serveur_icinga/meta/flux.yml b/roles/serveur_icinga/meta/flux.yml index cc810cf..2f1533a 100644 --- a/roles/serveur_icinga/meta/flux.yml +++ b/roles/serveur_icinga/meta/flux.yml @@ -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 diff --git a/roles/serveur_icinga/tasks/main.yml b/roles/serveur_icinga/tasks/main.yml index 8d811c6..d8ee27a 100644 --- a/roles/serveur_icinga/tasks/main.yml +++ b/roles/serveur_icinga/tasks/main.yml @@ -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: diff --git a/roles/serveur_icinga/templates/setops-api-users.conf.j2 b/roles/serveur_icinga/templates/setops-api-users.conf.j2 index 4267fe0..9388c52 100644 --- a/roles/serveur_icinga/templates/setops-api-users.conf.j2 +++ b/roles/serveur_icinga/templates/setops-api-users.conf.j2 @@ -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: » — 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" {{ '}}' }} } ] } diff --git a/roles/serveur_icinga/templates/setops-sauvegardes.conf.j2 b/roles/serveur_icinga/templates/setops-sauvegardes.conf.j2 index 0ec5def..15c6015 100644 --- a/roles/serveur_icinga/templates/setops-sauvegardes.conf.j2 +++ b/roles/serveur_icinga/templates/setops-sauvegardes.conf.j2 @@ -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: » 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 %}