134 lines
3.9 KiB
Bash
Executable File
134 lines
3.9 KiB
Bash
Executable File
#! /bin/sh
|
|
|
|
# change this to the name of your ZFS pool. Or set ZPOOL envvar at runtime
|
|
zpool=${ZPOOL:-"zroot"}
|
|
|
|
# name of backup to take
|
|
bkname=${1:-"default"}
|
|
# make a backup collection having 1 full and N-1 incremental backups.
|
|
# set to 1 to avoid incrementals and always take full dumps.
|
|
max_incremental=${2:-"4"}
|
|
|
|
usage () {
|
|
echo "Usage:"
|
|
echo "zfsbk.sh <bkname> [numincr]"
|
|
echo "Takes & sends backup with given name. If snapshots with"
|
|
echo "this name exist, backup incrementally. Limit incremental"
|
|
echo "backup sequences to 'numincr' steps (default 1 = alw. full)."
|
|
echo
|
|
echo "Optional envvars:"
|
|
echo "UPLOAD_PATH upload generated backup to this path. scp:// or rsync://"
|
|
echo "CLEAR_BKFILE remove local backup file at the end of the process."
|
|
}
|
|
|
|
failmsg () {
|
|
echo $*
|
|
echo
|
|
usage
|
|
exit 1
|
|
}
|
|
|
|
verify_zpool () {
|
|
zpool status $zpool >/dev/null 2>&1 || failmsg "ZFS pool '$zpool' not found. Fix your \$ZPOOL envvar."
|
|
}
|
|
|
|
verify_zpool
|
|
|
|
echo $bkname | grep -qiE '^[a-z0-9]+$' || failmsg "Given bkname is invalid. Want alphanumeric."
|
|
echo "$max_incremental" | grep -qE '^[1-9][0-9]*$' || failmsg "Invalid number of backups sequence steps, want positive integer."
|
|
|
|
export PATH=$PATH:/usr/local/bin
|
|
|
|
# list snapshots by decreasing time. Arguments: [name] restrict listing to this tag
|
|
list_named_snaps () {
|
|
local bkname=$1
|
|
snapdir="/.zfs/snapshot"
|
|
for i in $snapdir/zbk-$bkname-*
|
|
do
|
|
test -e "$i" && (echo $i |sed "s@^$snapdir/@@")
|
|
done | sort -r
|
|
}
|
|
|
|
# remove all datasets for a given tag. Arguments: $1 -> bkname
|
|
reset_sequence () {
|
|
local bkname=$1
|
|
list_named_snaps $bkname | while read snapname
|
|
do
|
|
zfs destroy -r $zpool@$snapname
|
|
done
|
|
}
|
|
|
|
# take snapshot
|
|
#echo ./zfssnap.sh $bkname $max_incremental
|
|
if ! ./zfssnap.sh $bkname $max_incremental
|
|
then
|
|
echo "Error creating snapshot! Code $?"
|
|
exit 1
|
|
fi
|
|
|
|
# get label
|
|
num_snaps=`list_named_snaps $bkname | awk 'END {print NR}'`
|
|
label_latest=`list_named_snaps $bkname | awk NR==1`
|
|
|
|
# decide what to do based on how many snapshots were found
|
|
if [ $num_snaps -eq 0 ]
|
|
then
|
|
# no snapshots. Something's wrong
|
|
echo "Error, no snapshots found for $bkname!"
|
|
list_named_snaps $bkname
|
|
exit 1
|
|
elif [ $num_snaps -eq 1 ]
|
|
then
|
|
# first snapshot. Send full
|
|
bkfile="/backups/${label_latest}.dump"
|
|
#echo zfs send -R $zpool@$label_latest
|
|
zfs send -R $zpool@$label_latest 2>/dev/null > $bkfile
|
|
else
|
|
# n-th snapshot. Send incrementally
|
|
label_2ndlatest=`list_named_snaps $bkname | awk NR==2`
|
|
bkfile="/backups/${label_latest}--${label_2ndlatest}.dump"
|
|
#echo zfs send -i $label_2ndlatest -R $zpool@$label_latest
|
|
zfs send -i $label_2ndlatest -R $zpool@$label_latest 2>/dev/null > $bkfile
|
|
fi
|
|
|
|
if [ $num_snaps -eq $max_incremental ]
|
|
then
|
|
# finished the incremental sequence. Take full backup next time
|
|
echo "Sequence of $max_incremental increm steps complete. Resetting."
|
|
reset_sequence $bkname
|
|
fi
|
|
|
|
|
|
# upload backup to remote location
|
|
if [ "x$UPLOAD_PATH" != x ]
|
|
then
|
|
upload_excode=1 # assume failure, override with actual outcome
|
|
#echo "Archiving $bkfile remotely..."
|
|
if echo "$UPLOAD_PATH" | grep -qE '^rsync://'
|
|
then
|
|
rsync -qz $bkfile ${UPLOAD_PATH#rsync://}
|
|
upload_excode=$?
|
|
elif echo "$UPLOAD_PATH" | grep -qE '^scp://'
|
|
then
|
|
SCP_PATH=${UPLOAD_PATH#scp://}
|
|
if [ "$num_snaps" -eq 1 -a "x$DELETE_OUTDATED" != x ]
|
|
then
|
|
echo "Clearing old zbk-${bkname}* sequence remotely..."
|
|
echo "rm zbk-${bkname}*" | sftp -q -b- $SCP_PATH
|
|
fi
|
|
scp -BCq $bkfile "$SCP_PATH"
|
|
upload_excode=$?
|
|
else
|
|
echo "UPLOAD_PATH not understood! '$UPLOAD_PATH'"
|
|
echo "Expecting rsync://.. or scp://.."
|
|
exit 1
|
|
fi
|
|
# remove local backup if requested & upload was successful
|
|
if [ $upload_excode -eq 0 -a "x$CLEAR_BKFILE" != x ]
|
|
then
|
|
# remove backup file if requested
|
|
rm -f $bkfile
|
|
fi
|
|
fi
|
|
|