From: Bernie Innocenti Date: Mon, 25 Jul 2011 19:00:05 +0000 (-0400) Subject: Initial commit X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=6fa976668baffc519362f6b4e19776491c860670;p=wizbackup.git Initial commit --- 6fa976668baffc519362f6b4e19776491c860670 diff --git a/wizbackup b/wizbackup new file mode 100755 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 +# Copyright 2007, 2008, 2009, 2010, 2011 Bernie Innocenti +# +# 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 index 0000000..10090c9 --- /dev/null +++ b/wizbackup-driver @@ -0,0 +1,55 @@ +#!/bin/bash +# +# WizBackup Driver 1.0 +# Copyleft 2011 Bernie Innocenti +# +# 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