Skip to content

Instantly share code, notes, and snippets.

@MarcusWichelmann
Last active January 21, 2020 23:57
Show Gist options
  • Select an option

  • Save MarcusWichelmann/16d2b9560ad31c99ba8d9c9015ae6e7b to your computer and use it in GitHub Desktop.

Select an option

Save MarcusWichelmann/16d2b9560ad31c99ba8d9c9015ae6e7b to your computer and use it in GitHub Desktop.
Simple script for replication of single datasets over SSH with zfs send/receive
#!/bin/bash
# Source pool or dataset
SOURCE=Storage
# Target location on remote machine
# Note: Ensure all datasets in there are not mounted, otherwise the user on the remote machine needs to have unmount permissions.
TARGET=Storage/Backups/Some-Server
# Datasets to be backed up (relative to source)
DATASETS=(Data)
# Command for ssh connection to remote machine
SSH_COMMAND="ssh -i /some/directory/id_rsa BackupUser@backup.host.example.com"
# Error handling
failure()
{
echo "An error occured. Exiting."
trap : 0
exit 1
}
trap 'failure' 0
set -e
# Backup datasets
for dataset in "${DATASETS[@]}"
do
source_dataset="$SOURCE/$dataset"
target_dataset="$TARGET/$dataset"
# Analyze source dataset
first_source_snap=$(zfs list -t snapshot -o name -s creation -r "$source_dataset" | grep "^$source_dataset@" | head -1 | cut -d '@' -f2 ; exit "${PIPESTATUS[0]}")
last_source_snap=$(zfs list -t snapshot -o name -s creation -r "$source_dataset" | grep "^$source_dataset@" | tail -1 | cut -d '@' -f2 ; exit "${PIPESTATUS[0]}")
# Backups are not possible when no snapshots exist
if [[ -z "$first_source_snap" || -z "$last_source_snap" ]]
then
echo "No snapshots in source '$source_dataset'. Consider setting up zfs-auto-snapshot."
failure
fi
# Analyze remote dataset
first_target_snap=$($SSH_COMMAND zfs list -t snapshot -o name -s creation -r "$target_dataset" | grep "^$target_dataset@" | head -1 | cut -d '@' -f2 ; exit "${PIPESTATUS[0]}")
last_target_snap=$($SSH_COMMAND zfs list -t snapshot -o name -s creation -r "$target_dataset" | grep "^$target_dataset@" | tail -1 | cut -d '@' -f2 ; exit "${PIPESTATUS[0]}")
echo "### Backing up: $source_dataset ($first_source_snap - $last_source_snap) ===> $target_dataset (${first_target_snap:-none} - ${last_target_snap:-none})";
# It's backup time!
if [[ -z "$last_target_snap" ]]
then
# Send first snapshot to initialize the target
echo "### Target dataset has no snapshots. Sending initial snapshot before starting incremental backups..."
zfs send -v "$source_dataset@$first_source_snap" | gzip --fast | mbuffer -s 128k -m 500M -q | $SSH_COMMAND "gzcat | zfs recv -F $target_dataset"
fi
zfs send -vI "${last_target_snap:-$first_source_snap}" "$source_dataset@$last_source_snap" | gzip --fast | mbuffer -s 128k -m 500M -q | $SSH_COMMAND "gzcat | zfs recv -F $target_dataset"
echo "### Done: $source_dataset";
done
trap : 0
echo "Done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment