Last active
May 5, 2024 11:23
-
-
Save senz/e60ce68e560f09cb1999d6d3ede1f5cc to your computer and use it in GitHub Desktop.
Snapper snapshots clone tool to mountable attached storage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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