From 4017b572627e6a18b18cfa7db893b095d01deea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20L=C3=A9vy?= Date: Thu, 12 Jun 2025 21:43:10 +0200 Subject: [PATCH] Ajout de ZFS-backup --- playbooks/zfsbackup.yml | 5 + roles/zfs-backup/defaults/main.yml | 4 + roles/zfs-backup/handlers/main.yml | 5 + roles/zfs-backup/tasks/main.yml | 32 +++++ .../templates/zfs-backup.service.j2 | 18 +++ .../zfs-backup/templates/zfs-backup.timer.j2 | 8 ++ roles/zfs-backup/templates/zfs-snapshot-nas | 123 ++++++++++++++++++ 7 files changed, 195 insertions(+) create mode 100755 playbooks/zfsbackup.yml create mode 100644 roles/zfs-backup/defaults/main.yml create mode 100644 roles/zfs-backup/handlers/main.yml create mode 100644 roles/zfs-backup/tasks/main.yml create mode 100644 roles/zfs-backup/templates/zfs-backup.service.j2 create mode 100644 roles/zfs-backup/templates/zfs-backup.timer.j2 create mode 100755 roles/zfs-backup/templates/zfs-snapshot-nas diff --git a/playbooks/zfsbackup.yml b/playbooks/zfsbackup.yml new file mode 100755 index 0000000..e501c2a --- /dev/null +++ b/playbooks/zfsbackup.yml @@ -0,0 +1,5 @@ +#!/usr/bin/env ansible-playbook +--- +- hosts: caradoc.adm.auro.re + roles: + - zfs-backup diff --git a/roles/zfs-backup/defaults/main.yml b/roles/zfs-backup/defaults/main.yml new file mode 100644 index 0000000..56b0299 --- /dev/null +++ b/roles/zfs-backup/defaults/main.yml @@ -0,0 +1,4 @@ +--- +zfs_backup: + - scriptpath: /var/zfs-backup-nas +... diff --git a/roles/zfs-backup/handlers/main.yml b/roles/zfs-backup/handlers/main.yml new file mode 100644 index 0000000..60f493a --- /dev/null +++ b/roles/zfs-backup/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Run systemd daemon-reload + systemd: + daemon_reload: true +... diff --git a/roles/zfs-backup/tasks/main.yml b/roles/zfs-backup/tasks/main.yml new file mode 100644 index 0000000..0d27be0 --- /dev/null +++ b/roles/zfs-backup/tasks/main.yml @@ -0,0 +1,32 @@ +--- +- name: Copy files for zfs-backup + template: + src: "{{ item }}.j2" + dest: /etc/systemd/system/{{ item }} + owner: root + group: root + mode: u=rw,g=r,o= + loop: + - zfs-backup.service + - zfs-backup.timer + notify: + - Run systemd daemon-reload + +- name: Copie du script + template: + src: zfs-snapshot-nas + dest: "{{ zfs_backup.scriptpath }}" + owner: root + group: root + mode: u=rx,g=r,o= + +- name: Run systemd deamon-reload + systemd: + daemon_reload: true + +- name: Start and enable ZFS-backup timer + systemd: + name: zfs-backup.timer + state: started + enabled: true +... diff --git a/roles/zfs-backup/templates/zfs-backup.service.j2 b/roles/zfs-backup/templates/zfs-backup.service.j2 new file mode 100644 index 0000000..5bfacdf --- /dev/null +++ b/roles/zfs-backup/templates/zfs-backup.service.j2 @@ -0,0 +1,18 @@ +[Unit] +Description=Service pour ZFS-backup +Wants=network-online.target +After=network-online.target + +[Service] +Type=simple +User=root + +Nice=19 +CPUSchedulingPolicy=batch + +Restart=no + +LogRateLimitIntervalSec=0 + +ExecStartPre=/usr/bin/bash {{ zfs_backup.scriptpath }} nextcloud +ExecStart=/usr/bin/bash {{ zfs_backup.scriptpath }} gitea diff --git a/roles/zfs-backup/templates/zfs-backup.timer.j2 b/roles/zfs-backup/templates/zfs-backup.timer.j2 new file mode 100644 index 0000000..abb0a1a --- /dev/null +++ b/roles/zfs-backup/templates/zfs-backup.timer.j2 @@ -0,0 +1,8 @@ +[Unit] +Description=Timer for ZFS-backup + +[Timer] +OnCalendar=daily + +[Install] +WantedBy=timers.target diff --git a/roles/zfs-backup/templates/zfs-snapshot-nas b/roles/zfs-backup/templates/zfs-snapshot-nas new file mode 100755 index 0000000..e3eeffd --- /dev/null +++ b/roles/zfs-backup/templates/zfs-snapshot-nas @@ -0,0 +1,123 @@ +#!/usr/bin/env bash + +if [ $# -ne 1 ] +then + echo "USAGE: $0 " + exit 1 +fi + +TANK="$1" + +IS_TANK_EXIST=$(zfs list | grep -c "tank/${TANK} ") + +if [ "${IS_TANK_EXIST}" -ne 1 ] +then + echo "${TANK} n'existe pas. Arrêt." + exit 1 +fi + + +TODAY=$(date "+%Y-%m-%d") +TODAY_EPOCH=$(date -d "${TODAY}" +%s) + +# # 1. On fait les snapshots sur le ZFS du NAS. +# /sbin/zfs snapshot "tank/${TANK}@${TODAY}" + + +# 2. On envoie les snapshots sur le ZFS de backup. +while true +do + + # Au préalable, on regarde si un envoi a été interrompu. + TOKEN=$(ssh perceval.adm.auro.re zfs list -o receive_resume_token "tank/${TANK}_backup" | tail -n 1) + + if [ "${#TOKEN}" -gt 15 ] + then + echo "Un envoi a été interrompu. Reprise." + + zfs send -t "${TOKEN}" | pv -trb | ssh perceval.adm.auro.re zfs recv -s -u "tank/${TANK}_backup" + + if [ $? -ne 0 ] + then + echo "La reprise s'est mal déroulée. Arrêt." + exit 1 + fi + fi + + # On récupère les dernières snapshots envoyées sur backup. + LAST_SNAPSHOT=$(ssh perceval.adm.auro.re zfs list -t snapshot \ + | grep "tank/${TANK}_backup" \ + | cut -d' ' -f1 | cut -d'@' -f2 \ + | sort | tail -n1) + + LAST_SNAPSHOT_EPOCH=$(date -d "${LAST_SNAPSHOT}" "+%s") + + # Si la dernière backup envoyée est celle d'aujourd'hui: On sort. + if [ "${LAST_SNAPSHOT_EPOCH}" -ge "${TODAY_EPOCH}" ] + then + echo "La backup distance ${TANK} ${LAST_SNAPSHOT} est suffisament récente. Fin." + break + fi + + # Sinon, on envoie une backup supplémentaire à partir de la dernière snapshot. + NEW_SNAPSHOT=$(date -d "${LAST_SNAPSHOT} +1day" "+%Y-%m-%d") + + echo "Envoi de la backup ${TANK} ${NEW_SNAPSHOT}." + + zfs send -i "tank/${TANK}@${LAST_SNAPSHOT}" "tank/${TANK}@${NEW_SNAPSHOT}" \ + | pv -trb | ssh perceval.adm.auro.re zfs recv -s -u "tank/${TANK}_backup" + + if [ $? -ne 0 ] + then + echo "L'envoi s'est mal déroulé. Arrêt." + exit 1 + fi + +done + + +# # 3. On ne garde que les 15 dernières snapshots ZFS +# LIMIT=$(date -d "${TODAY} -15days" "+%Y-%m-%d") +# LIMIT_EPOCH=$(date -d "${LIMIT}" "+%s") +# +# while true +# do +# +# # On vérifie qu'il existe au moins 15 backups +# COUNT=$(zfs list -t snapshot \ +# | grep -c "tank/${TANK}") +# +# if [ "${COUNT}" -le 15 ] +# then +# echo "Il y a moins de 16 backups. Fin." +# break +# fi +# +# +# # On récupère la plus vieille snapshot +# OLDEST_SNAPSHOT=$(zfs list -t snapshot \ +# | grep "tank/${TANK}" \ +# | cut -d' ' -f1 | cut -d'@' -f2 \ +# | sort | head -n1) +# +# OLDEST_SNAPSHOT_EPOCH=$(date -d "${OLDEST_SNAPSHOT}" "+%s") +# +# # Sanity-check: Si la plus vieille backup est celle d'il y a moins de 15 jours: On sort. +# if [ "${OLDEST_SNAPSHOT_EPOCH}" -ge "${LIMIT_EPOCH}" ] +# then +# echo "La backup locale ${TANK} ${OLDEST_SNAPSHOT} est suffisament récente. Fin." +# break +# fi +# +# # Sinon, on supprime la plus vieille snapshot. +# echo "Suppression de la backup ${TANK} ${OLDEST_SNAPSHOT}." +# +# zfs destroy "tank/${TANK}@${OLDEST_SNAPSHOT}" +# +# if [ $? -ne 0 ] +# then +# echo "La suppression s'est mal déroulée. Arrêt." +# exit 1 +# fi +# +# done