Skip to content

Instantly share code, notes, and snippets.

@senz
Last active May 5, 2024 11:23
Show Gist options
  • Save senz/e60ce68e560f09cb1999d6d3ede1f5cc to your computer and use it in GitHub Desktop.
Save senz/e60ce68e560f09cb1999d6d3ede1f5cc to your computer and use it in GitHub Desktop.
Snapper snapshots clone tool to mountable attached storage
[Unit]
Description=Snapper Clone Service
[Service]
ExecStart=/bin/bash -c 'chmod +x /home/senz/bin/snapper-clone.sh && /home/senz/b
in/snapper-clone.sh'
User=root
Group=root
Type=simple
[Install]
WantedBy=multi-user.target
#!/usr/bin/zsh
# This script is used to clone snapper snapshots from one subvolume to another
# Incremental backups are supported, the first snapshot will be a full backup
# Mountpoint of the backup drive
BACKUP_MOUNTPOINT=/mnt/fw1tb
# List of snapper configs to clone
# Opposite backup-<config> needs to exist before running this script. Disable timeline for the backup-<config> config
CONFIGS=(
root
)
VERBOSE=0
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
if mountpoint -q "$BACKUP_MOUNTPOINT"; then
echo "Backup already mounted"
else
echo "Mounting Backup"
mount "$BACKUP_MOUNTPOINT"
if mountpoint -q /backup; then
echo "Backup now mounted"
else
echo "Still can't find Backup"
exit
fi
fi
# Clone snapshots from source to target
# Supports seeding the first snapshot (full backup)
backup_snapshots() {
local source=$1
local target=$2
local source_snapshots=$(snapper -c $source list --disable-used-space --columns number | tr -d " " | grep "^[0-9]")
local target_snapshots=$(snapper -c $target list --disable-used-space --columns number | tr -d " " | grep "^[0-9]")
echo -n "Snapshots in $source: "
echo $source_snapshots | wc -w
echo -n "Snapshots in $target: "
echo $target_snapshots | wc -w
if [[ $(echo $target_snapshots | wc -w) -eq 0 ]]; then
# Send the full first snapshot
first_snapshot=$(echo $source_snapshots | awk '{print $1}')
mkdir -p $BACKUP_MOUNTPOINT/.snapshots/$first_snapshot
cp /home/.snapshots/$first_snapshot/info.xml $BACKUP_MOUNTPOINT/.snapshots/$first_snapshot/
btrfs send /home/.snapshots/$first_snapshot/snapshot | btrfs receive $BACKUP_MOUNTPOINT/.snapshots/$first_snapshot
fi
local y=0
for x in $(diff -u <(echo $source_snapshots) <(echo $target_snapshots) | grep -B 1 -E "^-[0-9]" | tr -d "-"); do
if [[ $y -gt 0 ]]; then
# TODO support different subvolumes
mkdir -p $BACKUP_MOUNTPOINT/.snapshots/$x
# FIXME this is a hack for my current layout
cp /home/.snapshots/$x/info.xml $BACKUP_MOUNTPOINT/.snapshots/$x/
echo "Sending $x"
local receive_opts=""
if [[ $VERBOSE -eq 1 ]]; then
receive_opts="-v"
fi
btrfs send -p /home/.snapshots/$y/snapshot /home/.snapshots/$x/snapshot | btrfs $receive_opts receive $BACKUP_MOUNTPOINT/.snapshots/$x
fi
y=$x
done
}
for config in $CONFIGS; do
backup_snapshots $config backup-$config
done
[Unit]
Description=Run snapper clone every hour
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment