Paillasse/ansible/roles/sauvegardes/templates/sauvegarde-dedibackup.sh.j2
Adam Belkacemi 3f0b565e1e sauvegarde la base du portail et teste sa restauration chaque semaine
La sauvegarde ne couvrait que /etc, /home et /root : la base MariaDB du
portail et son .env (APP_KEY) en étaient absents. Ajoute aussi le réglage
du quota et du gabarit du projet des labs dans Ansible, la reprise des VM
au démarrage de l'hôte (Nova), et le script du test de capacité.

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

105 lines
4.2 KiB
Django/Jinja

#!/bin/bash
# Géré par Ansible (rôle sauvegardes) — ne pas modifier à la main.
#
# Archive {{ sauvegardes_repertoires | join(', ') }} en tar.zst, chiffre avec age
# (clé publique du serveur — la clé privée ne quitte jamais le serveur, voir
# {{ sauvegardes_age_cle }}), envoie vers Dedibackup en FTP, puis applique la
# rotation ({{ sauvegardes_retention_quotidiennes }} quotidiennes,
# {{ sauvegardes_retention_hebdomadaires }} hebdomadaires).
set -euo pipefail
# Les identifiants ne sont jamais affichés ni journalisés : on désactive
# l'option xtrace pour cette ligne précise, par précaution.
set +x
source /root/.dedibackup
AGE_KEY="{{ sauvegardes_age_cle }}"
AGE_PUB=$(grep -oP '(?<=public key: )age1\S+' "$AGE_KEY")
DATE=$(date +%Y%m%d)
DOW=$(date +%u)
SEMAINE=$(date +%G-W%V)
WORKDIR=$(mktemp -d)
trap 'rm -rf "$WORKDIR"' EXIT
ARCHIVE_QUOT="quotidienne-${DATE}.tar.zst.age"
# Portail (étape 13) : export cohérent de sa base (--single-transaction, sans
# bloquer le site) et ses fichiers d'état. Le mot de passe root est lu dans
# le conteneur : il n'apparaît jamais sur la ligne de commande de l'hôte.
# Absent sur un serveur neuf (la sauvegarde arrive avant le portail) : ignoré.
EN_PLUS=()
if [ "$(docker inspect -f '{% raw %}{{.State.Running}}{% endraw %}' {{ sauvegardes_portail_conteneur }} 2>/dev/null)" = "true" ]; then
docker exec {{ sauvegardes_portail_conteneur }} sh -c \
'MYSQL_PWD="$MARIADB_ROOT_PASSWORD" exec mariadb-dump -uroot --single-transaction --routines --triggers --databases {{ sauvegardes_portail_base }}' \
> "$WORKDIR/portail.sql"
EN_PLUS+=(-C "$WORKDIR" portail.sql)
fi
for chemin in {{ sauvegardes_portail_fichiers | join(' ') }}; do
if [ -e "$chemin" ]; then
EN_PLUS+=("$chemin")
fi
done
tar --exclude="{{ sauvegardes_age_dir }}" --exclude='/root/.dedibackup' \
-I zstd -cf - {{ sauvegardes_repertoires | join(' ') }} "${EN_PLUS[@]}" \
| age -r "$AGE_PUB" -o "$WORKDIR/$ARCHIVE_QUOT"
lftp -u "$DEDIBACKUP_USER,$DEDIBACKUP_PASS" "$DEDIBACKUP_HOST" -e "
set ftp:ssl-allow no
put $WORKDIR/$ARCHIVE_QUOT
quit
"
logger -t sauvegarde-dedibackup "Quotidienne envoyée : $ARCHIVE_QUOT"
# Métrique pour l'alerte Prometheus "SauvegardeAncienne" (étape 7) : écrite
# seulement une fois la sauvegarde confirmée envoyée, de façon atomique
# (fichier temporaire puis renommage) pour que node_exporter ne lise jamais
# un fichier à moitié écrit.
DOSSIER_TEXTFILE="{{ sauvegardes_dossier_textfile | default('/var/lib/node_exporter/textfile') }}"
mkdir -p "$DOSSIER_TEXTFILE"
cat > "$DOSSIER_TEXTFILE/sauvegarde.prom.tmp" << METRIQUE
# HELP syllabus_derniere_sauvegarde_reussie_timestamp Horodatage Unix de la dernière sauvegarde Dedibackup réussie.
# TYPE syllabus_derniere_sauvegarde_reussie_timestamp gauge
syllabus_derniere_sauvegarde_reussie_timestamp $(date +%s)
METRIQUE
mv "$DOSSIER_TEXTFILE/sauvegarde.prom.tmp" "$DOSSIER_TEXTFILE/sauvegarde.prom"
if [ "$DOW" = "{{ sauvegardes_jour_hebdomadaire }}" ]; then
ARCHIVE_HEBDO="hebdomadaire-${SEMAINE}.tar.zst.age"
cp "$WORKDIR/$ARCHIVE_QUOT" "$WORKDIR/$ARCHIVE_HEBDO"
lftp -u "$DEDIBACKUP_USER,$DEDIBACKUP_PASS" "$DEDIBACKUP_HOST" -e "
set ftp:ssl-allow no
put $WORKDIR/$ARCHIVE_HEBDO
quit
"
logger -t sauvegarde-dedibackup "Hebdomadaire envoyée : $ARCHIVE_HEBDO"
fi
# --- Rotation : on ne garde que les N plus récentes de chaque catégorie. ---
rotation() {
local motif="$1" garder="$2"
local liste a_supprimer
liste=$(lftp -u "$DEDIBACKUP_USER,$DEDIBACKUP_PASS" "$DEDIBACKUP_HOST" -e "
set ftp:ssl-allow no
cls -1 ${motif}
quit
" 2>/dev/null | sort)
a_supprimer=$(echo "$liste" | head -n -"$garder")
if [ -n "$a_supprimer" ]; then
local commandes=""
while IFS= read -r fichier; do
[ -n "$fichier" ] && commandes+="rm $fichier;"
done <<< "$a_supprimer"
lftp -u "$DEDIBACKUP_USER,$DEDIBACKUP_PASS" "$DEDIBACKUP_HOST" -e "
set ftp:ssl-allow no
$commandes
quit
"
logger -t sauvegarde-dedibackup "Rotation $motif : supprimé $(echo "$a_supprimer" | wc -l) fichier(s)."
fi
}
rotation "quotidienne-*.tar.zst.age" {{ sauvegardes_retention_quotidiennes }}
rotation "hebdomadaire-*.tar.zst.age" {{ sauvegardes_retention_hebdomadaires }}