From 8de50b5fe06886c600aec15ca45b5863cae535a8 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 13 Jul 2014 12:39:45 +0200 Subject: [PATCH] added new btrfs backup scripts --- bash/backup-btrfs | 93 +++++++++++++++++++++++++++++++++++++ bash/backup-mysql | 113 +++++++++++++++++++++++++++++++++++++++++++++ bash/backup-remote | 92 ++++++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+) create mode 100755 bash/backup-btrfs create mode 100755 bash/backup-mysql create mode 100755 bash/backup-remote diff --git a/bash/backup-btrfs b/bash/backup-btrfs new file mode 100755 index 0000000..48fc98a --- /dev/null +++ b/bash/backup-btrfs @@ -0,0 +1,93 @@ +#!/bin/bash +## + # Incremental backups with Btrfs snapshots + # + # This script does incremental backups of Btrfs subvolumes + # across filesystem boundaries as proposed in the Btrfs wiki: + # https://btrfs.wiki.kernel.org/index.php/Incremental_Backup + # + # It uses the 'btrfs send' and 'btrfs receive' commands. + # Its not intended for simple snapshots in a single filesystem enviroment. + # + # @copyright 2013 Steffen Vogel + # @license http://www.gnu.org/licenses/gpl.txt GNU Public License + # @author Steffen Vogel + # @link http://www.steffenvogel.de + ## +## + # This script 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 + # any later version. + # + # This script is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this script. If not, see . + ## + +# TODO: delete old snapshots in destination fs +# TODO: print statistics of send | receive pipe (speed & size) + +function usage { + echo "Usage: $(basename $0) SOURCE [DEST]" + echo + echo " SOURCE a path to the subvolume to backup" + echo " DEST an optional path to the backup destination" + echo " only required for initialization" + exit 1 +} + +set -e + +if [ $# -lt 1 ]; then + echo -e "missing source" + echo + usage +fi + +SRC=$(readlink -f "$1") + +if [ -h "$SRC/.backup/destination" ]; then + DEST=$(readlink -f "$SRC/.backup/destination") +elif [ $# -ne 2 ] ; then + echo -e "missing destination" + echo + usage +else + DEST=$(readlink -f $2) + + mkdir -p "$SRC/.backup/" + mkdir -p "$DEST" + + ln -sf "$DEST" "$SRC/.backup/destination" + ln -sf "$SRC" "$DEST/source" +fi + +# name for the new snapshot +SNAPSHOT=$(date +%F_%H-%M-%S) +LATEST="$SRC/.backup/$SNAPSHOT" + +# snapshot the current state +btrfs subvolume snapshot -r "$SRC" "$LATEST" + +# send changes +if [ -h "$DEST/latest-source" ]; then + PREVIOUS=$(readlink -f "$DEST/latest-source") + btrfs send -p "$PREVIOUS" "$LATEST" | btrfs receive "$DEST" +else + btrfs send "$LATEST" | btrfs receive "$DEST" +fi + +# delete old snapshot in source fs +if [ -n "$PREVIOUS" ]; then + btrfs subvolume delete "$PREVIOUS" +fi + +# update links to last backup +ln -rsfT "$DEST/$SNAPSHOT" "$DEST/latest" +ln -sfT "$LATEST" "$DEST/latest-source" + diff --git a/bash/backup-mysql b/bash/backup-mysql new file mode 100755 index 0000000..2163067 --- /dev/null +++ b/bash/backup-mysql @@ -0,0 +1,113 @@ +#!/bin/bash +## + # Backup mySQL databases in separate sql dumps + # + # @copyright 2013 Steffen Vogel + # @license http://www.gnu.org/licenses/gpl.txt GNU Public License + # @author Steffen Vogel + # @link http://www.steffenvogel.de + ## +## + # This script 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 + # any later version. + # + # This script is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this script. If not, see . + ## + +set -e + +function usage { + cat <<-EOF + Usage: $(basename $0) [-u USER] [-p PASSWORD] DIR + + DIR is the directory for the backups (defaults to cwd) + + Options: + -u mysql username + -p mysql password + -h show this help + -d enable verbose output + + written by Steffen Vogel + EOF +} + +function deps() { + FAILED=0 + for DEP in $*; do + if ! which ${DEP} &>/dev/null; then + echo -e "This script requires ${DEP} to run but it is not installed." + ((FAILED++)) + fi + done + return ${FAILED} +} + +if ! deps mysql mysqldump; then + echo -e "mysql tools missing!" + echo + usage + exit 1 +fi + +# parse arguments +while getopts "u:p:hd" OPT; do + case ${OPT} in + p) MYSQL_PASS=${OPTARG} ;; + u) MYSQL_USER=${OPTARG} ;; + d) V=1 ;; + h) + usage + exit 0 ;; + *) + usage + exit 1 + esac +done + +# clear all options and reset the command line +shift $((OPTIND-1)) + +# parsing backup directory +if [ -n "$1" ]; then + DIR=$(readlink -f $1) +else + DIR=$(pwd) +fi + +# mySQL options +OPTS="" +if [ -n "$MYSQL_USER" ]; then + OPTS+=" -u$MYSQL_USER" +fi + +if [ -n "$MYSQL_PASS" ]; then + OPTS+=" -p$MYSQL_PASS" +fi + +# get all databases +DATABASES=`mysql $OPTS -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema)"` +DATE=$(date +%F_%H-%M-%S) + +mkdir -p $DIR/$DATE +ln -rsfT $DIR/$DATE/ $DIR/latest + +[ -z "$V" ] || echo "Starting mySQL backup: $(date)" +[ -z "$V" ] || echo "$(echo '$DATABASES' | wc -l) databases" +[ -z "$V" ] || echo "Backup directory: $DIR/$DATE" +for db in $DATABASES; do + [ -z "$V" ] || echo -n "Dumping $db ..." + mysqldump $OPTS --force --opt --events --databases $db | gzip > "$DIR/$DATE/$db.sql.gz" + [ -z "$V" ] || echo -e "\b\b\binto $DIR/$DATE/$db.sql.gz ($(du -h $DIR/$DATE/$db.sql.gz | cut -f1))" +done +[ -z "$V" ] || echo "Finished mySQL backup: $(date) ($(du -hs $DIR/$DATE/ | cut -f1))" + + diff --git a/bash/backup-remote b/bash/backup-remote new file mode 100755 index 0000000..b3d088c --- /dev/null +++ b/bash/backup-remote @@ -0,0 +1,92 @@ +#!/bin/bash +## + # Sync with remote server and create Btrfs snapshots + # + # This scripts uses rsync to sync remote directories with a local copy + # After every successful sync a readonly Btrfs snapshot of this copy is + # created + # + # This script requires root privileges for creating Btrfs snapshots. + # Consider using public key authentification with SSH to allow root + # logins on remote machines: + # + # On remote side: + # echo "PermitRootLogin without-password" >> /etc/ssh/sshd_config: + # + # On local side: + # sudo ssh-keygen + # sudo cat /root/.ssh/id_dsa.pub | ssh user@remote 'cat >> /root/.ssh/authorized_keys' + # + # @copyright 2013 Steffen Vogel + # @license http://www.gnu.org/licenses/gpl.txt GNU Public License + # @author Steffen Vogel + # @link http://www.steffenvogel.de + ## +## + # This script 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 + # any later version. + # + # This script is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this script. If not, see . + ## + +function usage { + echo "Usage: $(basename $0) SOURCE DEST" + echo + echo " SOURCE a path to the subvolume to backup" + echo " DEST a path to the backup destination" + exit 1 +} + +set -e + +if [ $# -ne 2 ]; then + echo -e "invalid args!" + echo + usage +fi + +DATE=$(date +%F_%H-%M-%S) + +SRC=$1 +DEST=$(readlink -f $2) + +if ! btrfs sub show $DEST/.current &> /dev/null; then + if [ -d $DEST/.current ]; then + echo -e "destination directory exists and is not a valid btrfs subvolume!" + echo + usage + else + btrfs sub create $DEST/.current + fi +fi + +# rsync options +OPTS="--archive --acls --xattrs" +#OPTS+=" --progress --human-readable" +OPTS+=" --delete --delete-excluded" +OPTS+=" --exclude /dev/" +OPTS+=" --exclude /proc/" +OPTS+=" --exclude /sys/" +OPTS+=" --exclude /tmp/" +OPTS+=" --exclude /run/" +OPTS+=" --exclude /mnt/" +OPTS+=" --exclude /media/" +OPTS+=" --exclude /lost+found/" + +# sync with remote +rsync $OPTS $SRC $DEST/.current/ + +# create new readonly snapshot +btrfs subvolume snapshot -r $DEST/.current $DEST/$DATE + +# create symlink to latest snapshot +ln -rsfT $DEST/$DATE $DEST/latest +