Initial commit
authorBernie Innocenti <bernie@codewiz.org>
Mon, 25 Jul 2011 19:00:05 +0000 (15:00 -0400)
committerroot <root@monolith.office.fsf.org>
Mon, 25 Jul 2011 19:58:34 +0000 (15:58 -0400)
wizbackup [new file with mode: 0755]
wizbackup-driver [new file with mode: 0755]

diff --git a/wizbackup b/wizbackup
new file mode 100755 (executable)
index 0000000..e2c7729
--- /dev/null
+++ b/wizbackup
@@ -0,0 +1,146 @@
+#!/bin/bash
+#
+# wizbackup 2.0 - Simple rsync backup
+# Based on incremental-backup 0.1 by Matteo Mattei
+#
+# Copyright 2006 Matteo Mattei <matteo.mattei@gmail.com>
+# Copyright 2007, 2008, 2009, 2010, 2011 Bernie Innocenti <bernie@codewiz.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License,
+# or (at your option) any later version.
+
+
+if [ $# -lt 2 ]
+then
+       echo "Usage: $0 SOURCE DEST [RSYNC_OPTS]"
+       exit 1
+fi
+
+# Fail on any error; Treat undefined variables as errors
+set -e -u
+
+#####################################################################
+# CONFIGURATION
+#####################################################################
+
+# Source path
+SRC=$1; shift
+
+# DESTINATION DIRECTORY (must exists)
+DEST=$1; shift
+
+# NOTE: --timeout needs to be large enough: if a large dir tree don't change a lot of time can pass without I/O
+# NOTE: --inplace will clobber linked files in older snapshots. DON'T USE IT!
+RSYNC_OPTIONS="-HAXa --stats --timeout 1800 --numeric-ids --delete --delete-excluded --ignore-errors $@"
+# NUMBER OF SAVED ARCHIVES
+N_SNAPSHOT=45
+RESULT=500
+
+DATE=`date +"%Y%m%d"`
+DEST="`echo $DEST | sed -e 's/\/$//'`"
+
+
+# Use "backup" ssh key with ssh protocol, or password file for rsync protocol
+if [ "${SRC%:*}" == "rsync" ]; then
+       RSYNC_PWD="--password-file=/etc/wizbackup.pwd --contimeout 10"
+else
+       export RSYNC_RSH="ssh -i /root/.ssh/id_backup -c arcfour -x -o VerifyHostKeyDNS=yes"
+       RSYNC_PWD=""
+fi
+
+# Error tolerant grep
+tgrep()
+{
+       grep "$@"
+       return 0
+}
+
+do_backup()
+{
+       set -o pipefail
+       echo "$(date): Starting rsync: rsync $RSYNC_PWD $RSYNC_OPTIONS $SRC $DEST/$DATE/"
+       rsync $RSYNC_PWD $RSYNC_OPTIONS "$SRC" "$DEST/tmp/" 2>&1 | tgrep -v -E 'vanished|some files'
+       RESULT=$?
+       case "$RESULT" in
+       0|24)
+               RESULT=0 # Ignore error 24 (Partial transfer due to vanished source files)
+               # Cleanup old incomplete backups
+               if [ -d "$DEST/$DATE" ]; then
+                       echo "$(date): Removing existing backup $DEST/$DATE"
+                       rm -rf "$DEST/$DATE"
+               fi
+               mv "$DEST/tmp" "$DEST/$DATE"
+               ;;
+       *)
+               echo "$(date): rsync failed: $RESULT"
+               echo "$(date): Leaving incomplete backup in $DEST/tmp"
+               ;;
+       esac
+       set +o pipefail
+}
+
+do_link()
+{
+       # Safety net (4 slashes just in case)
+       case "$DEST" in
+               /|//|///|////) exit 666 ;;
+       esac
+
+       if [ ! -d "$DEST" ]; then
+               echo "$(date): Creating missing destination directory $DEST."
+               mkdir -p "$DEST" || exit 667
+       fi
+
+       pushd "$DEST" >/dev/null || exit 668
+
+       # Remove old backups
+       local old="`ls | head -n -$N_SNAPSHOT`"
+       if [ ! -z "$old" ]; then
+               echo "$(date): Removing oldest snapshot(s): $old..."
+               rm -rf "$old" || exit 669
+       fi
+
+       local newest=`ls | tail -n 1`
+       if [ -z "$newest" ]; then
+               echo "$(date): No previous snapshot found, performing a full backup!"
+       elif [ -d "$DEST/tmp" ]; then
+               echo "$(date): Continuing with preexisting snapshot $DEST/tmp"
+       else
+               echo "$(date): Linking snapshot $DEST/$newest to $DEST/tmp"
+               # TODO: Creating the hardlinks takes a lot of time.
+               # Perhaps we could save time by recycling the oldest snapshot
+               cp -lR "$DEST/$newest" "$DEST/tmp" || exit 670
+       fi
+
+       popd >/dev/null
+}
+
+do_test()
+{
+       # Avoid clobbering the latest snapshot if the remote host does
+       # not allow us to connect
+       # --contimeout: sometimes hangs on connection...
+       rsync $RSYNC_PWD $RSYNC_OPTIONS --dry-run --no-recursive "$SRC" >/dev/null
+       RESULT=$?
+       if [ $RESULT -ne 0 ]; then
+               echo "$(date): rsync test failed: $RESULT.  Aborting."
+               exit $RESULT
+       fi
+}
+
+######################
+# MAIN
+######################
+
+# make sure to be root
+if (( `id -u` != 0 )); then { echo "Sorry, must be root.  Exiting..."; exit; } fi
+
+echo "$(date): START backup: $SRC -> $DEST"
+do_test
+do_link
+do_backup
+echo "$(date): END backup: $SRC -> $DEST"
+
+exit $RESULT
diff --git a/wizbackup-driver b/wizbackup-driver
new file mode 100755 (executable)
index 0000000..10090c9
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/bash
+#
+# WizBackup Driver 1.0
+# Copyleft 2011 Bernie Innocenti <bernie@codewiz.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License,
+# or (at your option) any later version.
+
+if [ $# -lt 1 ]
+then
+       echo "Usage: $0 [MACHINE-TAB]"
+       echo
+       echo "The MACHINE-TAB file contains hostnames of machines to be backed up, one per line."
+       echo "Empty lines and lines starting with '#' are ignored."
+       exit 1
+fi
+
+HOSTS=`cat $1 | egrep -v '^#|^ *$'`
+
+LOGGROUP=`basename $1`
+LOGDIR=/var/log/wizbackup
+LOCKDIR=/var/lock/wizbackup
+EXCLUDES_DIR=/root/rsync-backups/exclude
+DEST=/backup
+
+today=`date +"%Y%m%d"`
+mkdir -p $LOGDIR
+mkdir -p $LOCKDIR
+
+if [ "`tty`" = "not a tty" ]; then
+       OUTLOGFILE="$LOGDIR/$LOGGROUP-$today.log"
+else
+       LOGFILE=/dev/stdout
+fi
+
+for host in $HOSTS; do
+       opts="--exclude-from $EXCLUDES_DIR/ALWAYS"
+       if [ -f "$EXCLUDES_DIR/$host" ]; then
+               opts="$opts --exclude-from $EXCLUDES_DIR/$host"
+       fi
+
+       start_time=$(date +%s)
+       flock $LOCKDIR/$host wizbackup "$host:/" "$DEST/$host/" $opts >>$LOGFILE 2>&1
+       result=$?
+       end_time=$(date +%s)
+
+       report="$(date):$host:$(($end_time-$start_time)):$result"
+       echo $report >>$LOGDIR/$LOGGROUP-report-$today.log
+       [ $result != 0 ] && echo "$report" >>$LOGDIR/$LOGGROUP-fail-$today.log
+done
+
+# TODO: send fail log email report
+# TODO: delete logs older than 45 days