Clients deleted every auto-backup_ snapshot on the server except the newest, so the backup held one state only. prune-snapshots now keeps the newest per day, week and month (14/8/24 by default) independent of the source, and the clients call it after each receive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RywMtsL8qXG7GDY3MHq9Uh
64 lines
2.4 KiB
Bash
64 lines
2.4 KiB
Bash
#!/bin/bash
|
|
|
|
set -eu
|
|
|
|
path=$1
|
|
uuid=$(jq -r .client_uuid < /etc/backup/config.json)
|
|
server=$(jq -r .server_hostname < /etc/backup/config.json)
|
|
ssh="ssh -o ConnectTimeout=5 backup-receiver@$server"
|
|
|
|
source_dataset=$(zfs list -H -o mountpoint,name | grep -P "^$path\t" | cut -d $'\t' -f 2)
|
|
target_dataset="tank/$uuid/$source_dataset"
|
|
target_dataset_parent=$(echo $target_dataset | rev | cut -d / -f 2- | rev)
|
|
bookmark_prefix="auto-backup_"
|
|
new_bookmark="$bookmark_prefix$(date +"%Y-%m-%d_%H:%M:%S")"
|
|
|
|
for var in path uuid server ssh source_dataset target_dataset target_dataset_parent new_bookmark
|
|
do
|
|
[[ -z "${!var}" ]] && echo "ERROR - $var is empty" && exit 96
|
|
done
|
|
|
|
$ssh true || (echo "ERROR - cant ssh connect to $server" && exit 97)
|
|
|
|
echo "BACKUP ZFS DATASET - PATH: $path, SERVER: $server, UUID: $uuid, SOURCE_DATASET: $source_dataset, TARGET_DATASET: $target_dataset"
|
|
|
|
if ! $ssh sudo zfs list -t filesystem -H -o name | grep -q "^$target_dataset_parent$"
|
|
then
|
|
echo "CREATING PARENT DATASET..."
|
|
$ssh sudo zfs create -p -o mountpoint=none "$target_dataset_parent"
|
|
fi
|
|
|
|
zfs snap "$source_dataset@$new_bookmark"
|
|
|
|
if zfs list -t bookmark -H -o name | grep "^$source_dataset#$bookmark_prefix" | wc -l | grep -q "^0$"
|
|
then
|
|
echo "INITIAL BACKUP"
|
|
# do in subshell, otherwise ctr+c will lead to 0 exitcode
|
|
$(zfs send -v "$source_dataset@$new_bookmark" | $ssh sudo zfs recv -F "$target_dataset")
|
|
else
|
|
echo "INCREMENTAL BACKUP"
|
|
last_bookmark=$(zfs list -t bookmark -H -o name | grep "^$source_dataset#$bookmark_prefix" | sort | tail -1 | cut -d '#' -f 2)
|
|
[[ -z "$last_bookmark" ]] && echo "ERROR - last_bookmark is empty" && exit 98
|
|
$(zfs send -v -L -i "#$last_bookmark" "$source_dataset@$new_bookmark" | $ssh sudo zfs recv "$target_dataset")
|
|
fi
|
|
|
|
if [[ "$?" == "0" ]]
|
|
then
|
|
|
|
# delete old local bookmarks
|
|
for destroyable_bookmark in $(zfs list -t bookmark -H -o name "$source_dataset" | grep "^$source_dataset#$bookmark_prefix")
|
|
do
|
|
zfs destroy "$destroyable_bookmark"
|
|
done
|
|
|
|
# the backup server thins out its snapshots by its own retention
|
|
$ssh sudo /opt/backup-server/prune-snapshots "$target_dataset" || echo "WARNING - pruning snapshots of $target_dataset failed"
|
|
|
|
zfs bookmark "$source_dataset@$new_bookmark" "$source_dataset#$new_bookmark"
|
|
zfs destroy "$source_dataset@$new_bookmark" # keep snapshots?
|
|
echo "SUCCESS"
|
|
else
|
|
zfs destroy "$source_dataset@$new_bookmark"
|
|
echo "ERROR"
|
|
exit 99
|
|
fi
|