Set-OPS-Public/roles/client_backup/templates/sauvegarder.sh.j2
Daniel Allaire f8a84b78d5 reconstruction from-zero : sept defauts, tous invisibles sur une flotte debout
Chezlepro reconstruit depuis zero en 10.17.x.x. Sept defauts sont tombes, et
AUCUN n'etait detectable autrement — c'est tout l'argument de la reconstruction
comme preuve.

  1. aucune route vers le tenant sur le poste (posee a la main, jamais persistee)
  2. backup-01 exigeait l'AC d'Icinga — dependance non declaree
  3. ma correction inversait les couches : REFUSEE PAR P08 avant d'entrer
  4. base Forgejo a moitie initialisee (sequelle de l'arret du n°2)
  5. /etc/hosts : nom court avant le FQDN -> hostname -f faux sur les 14 machines
  6. API Icinga jamais activee (garde `creates:` d'api setup)
  7. restic refuse tout le lot si un chemin declare manque

LE CINQUIEME DEPASSAIT ICINGA. hostname -f rend le PREMIER nom : toute la flotte
se croyait appelee « mon-01 ». Visible sur le certificat d'Icinga, mais le meme
piege attendait Postfix (myhostname), les journaux, les certificats. FQDN d'abord.

CE QU'ON NE CORRIGE PAS : icinga2 api setup REECRIT NodeName d'apres le nom court
et nomme ses certificats d'apres lui. Aligne avant, il est ecrase ; aligne apres,
les certificats portent le mauvais nom. On adopte sa convention : le depot appelle
l'API par le nom court, celui que le certificat porte.

serveur_icinga_node_name derive desormais de l'INVENTAIRE, pas d'ansible_fqdn —
un fait qui depend du resolveur et rendait « mon-01 » alors que le FQDN etait bon.

Le commentaire ecrit pour avertir qu'une sequence accolade-diese casse les
gabarits Jinja contenait cette sequence, et cassait le gabarit. Neuf hotes en
echec pour un avertissement mal redige.

Sept devis CONFORME, prouver 36/36, make test 0. Neuf sauvegardes reussies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 03:36:56 -04:00

53 lines
2 KiB
Django/Jinja

#!/bin/bash
# Géré par Set-OPS (rôle client_backup). Ne pas éditer à la main.
# Sauvegarde applicative du nœud -> dépôt restic hors-nœud (chiffré, dédupliqué).
set -euo pipefail
export RESTIC_REPOSITORY="{{ client_backup_repo }}"
export RESTIC_PASSWORD_FILE="/etc/setops/restic.pass"
# 1. Dumps applicatifs (pg_dump, slapcat, forgejo dump...) vers le staging.
{% for job in client_backup_jobs %}
{% if job.commande is defined %}
install -d -m 0700 "{{ client_backup_staging }}/{{ job.nom }}"
{{ job.commande }}
{% endif %}
{% endfor %}
# 2. Initialiser le dépôt s'il n'existe pas encore.
restic snapshots >/dev/null 2>&1 || restic init
# 3. Snapshot de tous les chemins déclarés.
CHEMINS=(
{% for job in client_backup_jobs %}
{% for c in job.chemins %}
"{{ c }}"
{% endfor %}
{% endfor %}
)
# Un chemin DECLARE peut ne pas exister encore : `/srv/web` avant la premiere webapp,
# le stockage de Nextcloud avant son installation. Restic refuse alors TOUT le lot
# (« all source directories/files do not exist ») et la sauvegarde entiere echoue —
# constate le 2026-08-13 sur trois hotes d'une flotte neuve.
# On ne sauvegarde donc que ce qui existe, et on le DIT quand il n'y a rien : c'est a la
# supervision de signaler un depot vide, pas au script de mourir.
# NOTE : ne JAMAIS ecrire la longueur d'un tableau bash dans ce gabarit — la sequence
# accolade-diese y ouvre un commentaire Jinja et casse le rendu. On compte a la main.
# (Ce commentaire a lui-meme casse le gabarit une fois, en citant la sequence.)
PRESENTS=()
N_PRESENTS=0
for c in "${CHEMINS[@]}"; do
if [[ -e "$c" ]]; then
PRESENTS+=("$c")
N_PRESENTS=$((N_PRESENTS + 1))
else
echo "absent, ignore : $c" >&2
fi
done
if (( N_PRESENTS == 0 )); then
echo "aucun chemin declare n'existe encore sur cet hote — rien a sauvegarder." >&2
exit 0
fi
restic backup --host "{{ inventory_hostname }}" --tag setops "${PRESENTS[@]}"
# 4. Rétention.
restic forget {{ client_backup_retention }} --prune