Skip to content

Instantly share code, notes, and snippets.

@laurentdinclaux
Created November 3, 2016 00:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laurentdinclaux/4242d18b7f16cd78b789ad9794d8bbba to your computer and use it in GitHub Desktop.
Save laurentdinclaux/4242d18b7f16cd78b789ad9794d8bbba to your computer and use it in GitHub Desktop.
#!/bin/bash
zfs="zfs"
zfsDest=${zfs}
keep=3
prefix=zfs-auto-snap
recursive=false
usage() { echo "Usage: $0 -r [-k <int>] source destination" 1>&2; exit 1; }
filesystem_exists() {
if [ -z "$1" ] || [ -z "$2" ]; then
return 1
fi
if [ `${2} list -H -t filesystem -o name ${1} 2> /dev/null` ]; then
return 0
fi
return 1
}
while getopts ":rp:k:" o; do
case "${o}" in
k)
if echo "${OPTARG}" | grep -qE -v ^[1-9]+[0-9]*$; then usage; fi
keep=${OPTARG}
;;
r)
recursive=true
;;
p)
prefix=${OPTARG}
;;
esac
done
shift $(expr $OPTIND - 1)
source="$1"; shift
dest="$1"; shift
if [ -z "$source" ] || [ -z "$dest" ]; then
usage
fi
# verify filesystems exists
if ! filesystem_exists ${source} ${zfs}; then
echo "The file system '${source}' doesn't exists."
exit 1
fi
# verify filesystems exists
if ! filesystem_exists ${dest} ${zfsDest}; then
echo "The file system '${dest}' doesn't exists."
exit 1
fi
filesystems=${source}
if ${recursive}; then
filesystems=`${zfs} list -H -r -o name -t filesystem ${source} 2> /dev/null`
fi
for filesystem in ${filesystems}
do
echo -e "\033[0;34mBacking up ${filesystem}\033[0m"
# incremental ?
incremental=true
base_snapshot=
# lookup for destination filesystem
if [ ! -z ${zfsDest} list -H -t filesystem -o name ${dest}/${filesystem} 2> /dev/null ]; then
echo "Destination filesystem doesn't exists, doing full backup."
incremental=false
else
# lookup for destination snapshot
dest_snapshots=`${zfsDest} list -H -t snapshot -o name -S creation | grep ^${dest}/${filesystem}@${prefix} 2> /dev/null`
if [ -z "${dest_snapshots}" ]; then
echo "Destination filesystem has no snapshot, doing full backup."
incremental=false
else
for snap in ${dest_snapshots}
do
_base_snapshot=`echo ${snap} | sed -n "s/^.*\@\s*\(\S*\).*$/\1/p"`
if ${zfs} list -H ${filesystem}@${_base_snapshot} &> /dev/null; then
base_snapshot=${_base_snapshot}
break
fi
done
if [ -z "$base_snapshot" ]; then
echo "No base snapshot can be used for the incremental backup of ${filesystem}. Destroy the destination filsesystem and relaunch to start over with a full backup."
echo
continue
incremental=false
fi
fi
fi
# full/initial backup
if ! $incremental; then
latest=`${zfs} list -H -t snapshot -o name -S creation 2> /dev/null | grep ^${filesystem}@${prefix} | head -n 1`
if [ -z ${latest} ]; then
echo "No snapshot to use"
echo
continue
fi
${zfs} send ${latest} | ${zfsDest} receive -Fv ${dest}/${filesystem}
echo
continue
fi
echo Doing incremental backup of ${filesystem}.
latest=`${zfs} list -H -r -t snapshot -o name -S creation ${filesystem} 2> /dev/null | grep ^${filesystem}@${prefix} | head -n 1`
#roll back destination
${zfsDest} rollback -r ${dest}/${filesystem}@${base_snapshot}
${zfs} send -i $base_snapshot $latest | ${zfsDest} receive -v ${dest}/${filesystem}
# if [ $? -eq 0 ]; then
# delete old backup snapshots
# adjust retention to work with tail i.e. increase by one
retention=$keep
let retention+=1
old_snapshots=`${zfsDest} list -H -t snapshot -o name -S creation | grep ^${dest}/${filesystem}@${prefix} | tail -n +${retention}`
if [ ! -z "${old_snapshots}" ]; then
echo Deleting old snap shots
for snapshot in ${old_snapshots}
do
echo - destroying ${snapshot}
${zfsDest} destroy ${snapshot}
done
fi
# fi
echo
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment