Skip to content

Instantly share code, notes, and snippets.

@AaronJackson
Created February 13, 2019 10:51
Show Gist options
  • Save AaronJackson/5455f4119b1e9dc82ce556007e16c46b to your computer and use it in GitHub Desktop.
Save AaronJackson/5455f4119b1e9dc82ce556007e16c46b to your computer and use it in GitHub Desktop.
ZFS incremental backup over SSH
#!/bin/sh
source_pool=$1
first_sync=$2
if [ $first_sync ] ; then
echo "You have asked for an initial sync."
echo "If you didn't mean this, you have five five seconds to cancel it."
sleep 5
fi
if [ ! $source_pool ] ; then exit ; fi
LOCK=/root/mirror.$source_pool.lock
if [ -f $LOCK ] ; then
# We don't want to create another local snapshot before we are
# sure the remote is going to be able to receive it
exit 1
fi
touch $LOCK
# Setup/variables:
snapshot_string=DO_NOT_DELETE_remote_replication_
timestamp=$(/usr/bin/date '+%Y%m%d%H%M%S')
destination_pool=tank/${source_pool}
new_snap="$source_pool"@"$snapshot_string""$timestamp"
destination_host=cvl-store-0
# Ensure that the remote host is UP
ping -c1 $destination_host &>/dev/null || exit 1
# Initial send:
if [ $first_sync ] ; then
zfs snapshot -r "$new_snap"
zfs send -R "$new_snap" | ssh "$destination_host" zfs recv -Fdu "$destination_pool"
rm $LOCK
exit 0
fi
# Incremental sends:
# Get old snapshot name.
old_snap=$(zfs list -H -o name -t snapshot -r "$source_pool" | grep "$source_pool"@"$snapshot_string" | tail --lines=1)
# Let's make sure the name on the remote host matches the local name.
remote_old_snap=$(ssh "$destination_host" zfs list -H -o name -t snapshot -r "$destination_pool" | \
grep "$snapshot_string" | tail -n1)
check_l=$(echo $old_snap | cut -d@ -f2)
check_r=$(echo $remote_old_snap | cut -d@ -f2)
if [ $check_l != $check_r ] ; then
echo "pool $source_pool is out of sync."
echo "Lock file perserved to avoid further attempts."
exit 1
fi
# Create new recursive snapshot of the whole pool.
zfs snapshot -r "$new_snap"
# Incremental replication via SSH.
zfs send -R -I "$old_snap" "$new_snap" | ssh "$destination_host" zfs recv -Fdu "$destination_pool"
# Delete older snaps on the local source
delete_from=$(zfs list -H -o name -t snapshot -r "$source_pool" | grep "$snapshot_string" | grep -v "$timestamp")
for snap in $delete_from; do
zfs destroy "$snap"
done
rm $LOCK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment