Skip to content

Instantly share code, notes, and snippets.

@fclairamb
Created September 30, 2013 21:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fclairamb/6770356 to your computer and use it in GitHub Desktop.
Save fclairamb/6770356 to your computer and use it in GitHub Desktop.
This backup script uses btrfs for snapshots and delete oldest snapshots when we reach a certain level of disk usage. Note: The most important difference with tools like rsnapshot is that it can calculate differences at a block level (whereas hardlinks only allow such a thing at a file level). Putting the snapshotting logic on the filesystem laye…
#!/bin/sh -x
# === ARGUMENTS PARSING ===
# We don't want to define a default period
PERIOD=
while echo $1 | grep ^- > /dev/null; do
if [ "$1" = "--daily" ]; then
PERIOD=daily
fi
if [ "$1" = "--monthly" ]; then
PERIOD=monthly
fi
if [ "$1" = "--period" ]; then
PERIOD=$2
shift
fi
shift
done
LOCK=/var/run/backup-servers-$PERIOD.lock
if [ "${PERIOD}" = "" ]; then
echo "You have to define a period with the --period arg !" >&2
exit 1
fi
if [ -f $LOCK ]; then
PID=`cat $LOCK`
echo "Other backup locked by process $PID"
kill -s 0 $PID
rc=$?
if [ "$rc" = "0" ] ; then
echo "Other backup running, stopping right here..."
exit 1
else
echo "Other backup stalled, we can continue"
fi
fi
echo $$ >$LOCK
# === END OF ARGUMENTS PARSING ===
# === PARAMETERS ===
# * Device we will use
DISK=/mnt/fs5
# * Subvolume used for the backup
SUBVOLUME=${DISK}/servers
# * Current date (you could limit the date to +%Y-%m-%d)
DATE=`/bin/date +%Y-%m-%d_%H-%M-%S`
# * snapshot directory that will be used
SNAPDIR=${DISK}/snap/servers
# * snapshot volume that will be used
SNAPVOL=${SNAPDIR}/${PERIOD}-${DATE}
# * max days to keep daily backups
MAX_DAYLY=60
# * max days to keep monthly backups
MAX_MONTHLY=365
# * Alert limit
LIMIT_ALERT=95
# * High limit
LIMIT_HIGH=90
# * Low limit
LIMIT_LOW=85
# === END OF PARAMETERS ===
# We get the space used over the total allocated space and the total percentage use.
# This is NOT the device total size but it's a lot more reliable than "df -h"
# DISK_USED=`/sbin/btrfs filesystem df ${DISK}|grep Data|grep -Po "used=([0-9]*)"|cut -d= -f2`
# DISK_TOTAL=`/sbin/btrfs filesystem df ${DISK}|grep Data|grep -Po "total=([0-9]*)"|cut -d= -f2`
# DISK_PERC=`echo 100*${DISK_USED}/${DISK_TOTAL}|bc`
DISK_PERC=`df ${DISK} |grep -E -o "([0-9]+)\%"|cut -d% -f1`
#echo DISK_PERC=${DISK_PERC}
mount -a
# We create the snapshot dir if it doesn't exist
if [ ! -d ${SNAPDIR} ]; then
mkdir -p ${SNAPDIR}
fi
cd ${SNAPDIR}
# If we are over the low free space limit,
# we delete two days of daily backup.
if [ $DISK_PERC -gt $LIMIT_LOW ]; then
echo "LOW LIMIT reached: $DISK_PERC > $LIMIT_LOW : Deleting 2 days" >&2
OLDEST_FILES=`ls --sort=time -r|grep "daily-.*"|head -2`
for file in $OLDEST_FILES; do
/sbin/btrfs subvolume delete $file;
done
fi
# If we are over the high free space limit,
# we delete a month of monthly backup
if [ $DISK_PERC -gt $LIMIT_HIGH ]; then
echo "HIGH LIMIT reached: $DISK_PERC > $LIMIT_HIGH : Deleting 1 month" >&2
OLDEST_FILES=`ls --sort=time -r|grep "monthly-.*"|head -1`
for file in $OLDEST_FILES; do
/sbin/btrfs subvolume delete $file;
done
fi
# If we are over the alert free space limit,
# we delete the first two oldest files we can find
if [ $DISK_PERC -gt $LIMIT_ALERT ]; then
echo "ALERT LIMIT reached: $DISK_PERC > $LIMIT_ALERT : Deleting the 2 oldest" >&2
OLDEST_FILES=`ls --sort=time -r|head -2`
for file in $OLDEST_FILES; do
/sbin/btrfs subvolume delete $file;
done
fi
# We touch the subvolume to change the modification date
touch ${SUBVOLUME}
# We do a snapshot of the subvolume
if [ ! -d "${SNAPVOL}" ]; then
/sbin/btrfs subvolume snapshot ${SUBVOLUME} ${SNAPVOL}
fi
# We delete the backups older than MAX_DAYLY
find ${SNAPDIR} -mindepth 1 -maxdepth 1 -mtime +${MAX_DAYLY} -name "daily-*" -exec /sbin/btrfs subvolume delete {} \;
# We delete the backups older than MAX_MONTHLY
find ${SNAPDIR} -mindepth 1 -maxdepth 1 -mtime +${MAX_MONTHLY} -name "monthly-*" -exec /sbin/btrfs subvolume delete {} \;
# This is the actual backup code
# You need to save your data into the ${SUBVOLUME} directory
# We will only do this backup for the daily task
if [ "${PERIOD}" = "daily" ]; then
RSYNC_ARGS="-auvz --delete --partial --partial-dir=.part --exclude /proc --exclude /sys --exclude /dev --exclude swapfile --exclude /home/nginx --exclude /home/var_lib_php5"
RSYNC_POST="grep -v vanished"
date
echo "=== OVH1 ==="
rsync ${RSYNC_ARGS} --password-file=/etc/rsync.pass.ovh1 rsync://root@ovh1.webingenia.com/root ${SUBVOLUME}/ovh1 | ${RSYNC_POST}
#rsync ${RSYNC_ARGS} --password-file=/etc/rsync.pass.ovh2 rsync://root@ovh2.webingenia.com/root ${SUBVOLUME}/ovh2 | ${RSYNC_POST}
date
echo "=== OVH3 ==="
rsync ${RSYNC_ARGS} --password-file=/etc/rsync.pass.ovh3 rsync://root@ovh3.webingenia.com/root ${SUBVOLUME}/ovh3 | ${RSYNC_POST}
date
echo "=== LOCALHOST ==="
rsync ${RSYNC_ARGS} /etc ${SUBVOLUME}/localhost | ${RSYNC_POST}
date
rsync ${RSYNC_ARGS} / --exclude /mnt ${SUBVOLUME}/localhost/ | ${RSYNC_POST}
date
fi
rm $LOCK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment