Skip to content

Instantly share code, notes, and snippets.

@bleleve
Forked from dalecaru/innobackupex-restore.sh
Last active February 9, 2018 08:34
Show Gist options
  • Save bleleve/5605430 to your computer and use it in GitHub Desktop.
Save bleleve/5605430 to your computer and use it in GitHub Desktop.
#!/bin/sh
#
# Script to prepare and restore full and incremental backups created with innobackupex-runner.
#
# (C)2010 Owen Carter @ Mirabeau BV
# This script is provided as-is; no liability can be accepted for use.
# You are free to modify and reproduce so long as this attribution is preserved.
#
# (C)2013 Benoît LELEVÉ @ Exsellium (www.exsellium.com)
# Adding parameters in order to execute the script in a multiple MySQL instances environment
#
INNOBACKUPEX=innobackupex
INNOBACKUPEXFULL=/usr/bin/$INNOBACKUPEX
TMPFILE="/tmp/innobackupex-restore.$$.tmp"
MEMORY=1024M # Amount of memory to use when preparing the backup
SCRIPTNAME=$(basename "$0")
#############################################################################
# Display usage message and exit
#############################################################################
usage() {
cat <<EOF
Usage: $SCRIPTNAME [-d backdir] [-f config] [-g group] /absolute/path/to/backup/to/restore
-d Directory used to store database backup
-f Path to my.cnf database config file
-g Group to read from the config file
-h Display basic help
EOF
exit 0
}
# Parse parameters
while getopts ":d:f:g:h" opt; do
case $opt in
d ) BACKUPDIR=$OPTARG ;;
f ) MYCNF=$OPTARG ;;
g ) MYGROUP=$OPTARG ;;
h ) usage ;;
\?) echo "Invalid option: -$OPTARG"
echo "For help, type: $SCRIPTNAME -h"
exit 1 ;;
: ) echo "Option -$OPTARG requires an argument"
echo "For help, type: $SCRIPTNAME -h"
exit 1 ;;
esac
done
shift $(($OPTIND - 1))
# Check required parameters
if [ -z "$BACKUPDIR" ]; then
echo "Backup directory is required"
echo "For help, type: $SCRIPTNAME -h"
exit 1
fi
if [ -z "$MYCNF" ]; then MYCNF=/etc/mysql/my.cnf; fi
if [ ! -z "$MYGROUP" ]; then DEFGROUP="--defaults-group=$MYGROUP"; fi
# Full and incremental backup directories
FULLBACKUPDIR=$BACKUPDIR/full
INCRBACKUPDIR=$BACKUPDIR/incr
#############################################################################
# Display error message and exit
#############################################################################
error() {
echo "$1" 1>&2
exit 1
}
#############################################################################
# Check for errors in innobackupex output
#############################################################################
check_innobackupex_error() {
if [ -z "`tail -1 $TMPFILE | grep 'completed OK!'`" ]; then
echo "$INNOBACKUPEX failed:"; echo
echo "---------- ERROR OUTPUT from $INNOBACKUPEX ----------"
cat $TMPFILE
rm -f $TMPFILE
exit 1
fi
}
# Check options before proceeding
if [ ! -x $INNOBACKUPEXFULL ]; then
error "$INNOBACKUPEXFULL does not exist."
fi
if [ ! -d $BACKUPDIR ]; then
error "Backup destination folder: $BACKUPDIR does not exist."
fi
if [ ! -d $1 ]; then
error "Backup to restore: $1 does not exist."
fi
# Some info output
echo "----------------------------"
echo
echo "$SCRIPTNAME: MySQL backup script"
echo "started: `date`"
echo
PARENT_DIR=`dirname $1`
if [ $PARENT_DIR = $FULLBACKUPDIR ]; then
FULLBACKUP=$1
echo "Restore `basename $FULLBACKUP`"
echo
else
if [ `dirname $PARENT_DIR` = $INCRBACKUPDIR ]; then
INCR=`basename $1`
FULL=`basename $PARENT_DIR`
FULLBACKUP=$FULLBACKUPDIR/$FULL
if [ ! -d $FULLBACKUP ]; then
error "Full backup: $FULLBACKUP does not exist."
fi
echo "Restore $FULL up to incremental $INCR"
echo
echo "Replay committed transactions on full backup"
$INNOBACKUPEXFULL --defaults-file=$MYCNF $DEFGROUP --apply-log --redo-only --use-memory=$MEMORY $FULLBACKUP > $TMPFILE 2>&1
check_innobackupex_error
# Apply incrementals to base backup
for i in `find $PARENT_DIR -mindepth 1 -maxdepth 1 -type d -printf "%P\n" | sort -n`; do
echo "Applying $i to full ..."
$INNOBACKUPEXFULL --defaults-file=$MYCNF $DEFGROUP --apply-log --redo-only --use-memory=$MEMORY $FULLBACKUP --incremental-dir=$PARENT_DIR/$i > $TMPFILE 2>&1
check_innobackupex_error
if [ $INCR = $i ]; then
break # break. we are restoring up to this incremental.
fi
done
else
error "unknown backup type"
fi
fi
echo "Preparing ..."
$INNOBACKUPEXFULL --defaults-file=$MYCNF $DEFGROUP --apply-log --use-memory=$MEMORY $FULLBACKUP > $TMPFILE 2>&1
check_innobackupex_error
echo
echo "Restoring ..."
$INNOBACKUPEXFULL --defaults-file=$MYCNF $DEFGROUP --copy-back $FULLBACKUP > $TMPFILE 2>&1
check_innobackupex_error
rm -f $TMPFILE
echo "Backup restored successfully. You are able to start mysql now."
echo "Verify files ownership in mysql data dir."
echo "Run 'chown -R mysql:mysql /path/to/data/dir' if necessary."
echo
echo "completed: `date`"
exit 0
#!/bin/sh
#
# Script to create full and incremental backups (for all databases on server) using innobackupex from Percona.
# http://www.percona.com/doc/percona-xtrabackup/innobackupex/innobackupex_script.html
#
# Every time it runs will generate an incremental backup except for the first time (full backup).
# FULLBACKUPLIFE variable will define your full backups schedule.
#
# (C)2010 Owen Carter @ Mirabeau BV
# This script is provided as-is; no liability can be accepted for use.
# You are free to modify and reproduce so long as this attribution is preserved.
#
# (C)2013 Benoît LELEVÉ @ Exsellium (www.exsellium.com)
# Adding parameters in order to execute the script in a multiple MySQL instances environment
#
INNOBACKUPEX=innobackupex
INNOBACKUPEXFULL=/usr/bin/$INNOBACKUPEX
TMPFILE="/tmp/innobackupex-runner.$$.tmp"
MYSQL=/usr/bin/mysql
MYSQLADMIN=/usr/bin/mysqladmin
FULLBACKUPLIFE=604800 # Lifetime of the latest full backup in seconds
KEEP=1 # Number of full backups (and its incrementals) to keep
SCRIPTNAME=$(basename "$0")
# Grab start time
STARTED_AT=`date +%s`
#############################################################################
# Display usage message and exit
#############################################################################
usage() {
cat <<EOF
Usage: $SCRIPTNAME [-d backdir] [-f config] [-g group] [-u username] [-p password] [-H host] [-P port] [-S socket]
-d Directory used to store database backup
-f Path to my.cnf database config file
-g Group to read from the config file
-u Username used when connecting to the database
-p Password used when connecting to the database
-H Host used when connecting to the database
-P Port number used when connecting to the database
-S Socket used when connecting to the database
-h Display basic help
EOF
exit 0
}
# Parse parameters
while getopts ":d:f:g:u:p:H:P:S:h" opt; do
case $opt in
d ) BACKUPDIR=$OPTARG ;;
f ) MYCNF=$OPTARG ;;
g ) MYGROUP=$OPTARG ;;
u ) MYUSER=$OPTARG ;;
p ) MYPASSWD=$OPTARG ;;
H ) MYHOST=$OPTARG ;;
P ) MYPORT=$OPTARG ;;
S ) MYSOCKET=$OPTARG ;;
h ) usage ;;
\?) echo "Invalid option: -$OPTARG"
echo "For help, type: $SCRIPTNAME -h"
exit 1 ;;
: ) echo "Option -$OPTARG requires an argument"
echo "For help, type: $SCRIPTNAME -h"
exit 1 ;;
esac
done
# Check required parameters
if [ -z "$BACKUPDIR" ]; then
echo "Backup directory is required"
echo "For help, type: $SCRIPTNAME -h"
exit 1
fi
if [ -z "$MYUSER" ]; then
echo "Database username is required"
echo "For help, type: $SCRIPTNAME -h"
exit 1
fi
if [ -z "$MYCNF" ]; then MYCNF=/etc/mysql/my.cnf; fi
if [ ! -z "$MYGROUP" ]; then DEFGROUP="--defaults-group=$MYGROUP"; fi
# Concatenate parameters into innobackupex ones
USEROPTIONS="--user=$MYUSER"
if [ ! -z "$MYPASSWD" ]; then USEROPTIONS="$USEROPTIONS --password=$MYPASSWD"; fi
if [ ! -z "$MYHOST" ]; then USEROPTIONS="$USEROPTIONS --host=$MYHOST"; fi
if [ ! -z "$MYPORT" ]; then USEROPTIONS="$USEROPTIONS --port=$MYPORT"; fi
if [ ! -z "$MYSOCKET" ]; then USEROPTIONS="$USEROPTIONS --socket=$MYSOCKET"; fi
# Full and incremental backups directories
FULLBACKUPDIR=$BACKUPDIR/full
INCRBACKUPDIR=$BACKUPDIR/incr
#############################################################################
# Display error message and exit
#############################################################################
error() {
echo "$1" 1>&2
exit 1
}
# Check options before proceeding
if [ ! -x $INNOBACKUPEXFULL ]; then
error "$INNOBACKUPEXFULL does not exist."
fi
if [ ! -d $BACKUPDIR ]; then
error "Backup destination folder: $BACKUPDIR does not exist."
fi
if [ -z "`$MYSQLADMIN $USEROPTIONS status | grep 'Uptime'`" ] ; then
error "HALTED: MySQL does not appear to be running."
fi
if ! `echo 'exit' | $MYSQL -s $USEROPTIONS` ; then
error "HALTED: Supplied mysql username or password appears to be incorrect (not copied here for security, see script)."
fi
# Some info output
echo "----------------------------"
echo
echo "$SCRIPTNAME: MySQL backup script"
echo "started: `date`"
echo
# Create full and incr backup directories if they not exist.
mkdir -p $FULLBACKUPDIR
mkdir -p $INCRBACKUPDIR
# Find latest full backup
LATEST_FULL=`find $FULLBACKUPDIR -mindepth 1 -maxdepth 1 -type d -printf "%P\n" | sort -nr | head -1`
# Get latest backup last modification time
LATEST_FULL_CREATED_AT=`stat -c %Y $FULLBACKUPDIR/$LATEST_FULL`
# Run an incremental backup if latest full is still valid. Otherwise, run a new full one.
if [ "$LATEST_FULL" -a `expr $LATEST_FULL_CREATED_AT + $FULLBACKUPLIFE + 5` -ge $STARTED_AT ] ; then
# Create incremental backups dir if not exists.
TMPINCRDIR=$INCRBACKUPDIR/$LATEST_FULL
mkdir -p $TMPINCRDIR
# Find latest incremental backup.
LATEST_INCR=`find $TMPINCRDIR -mindepth 1 -maxdepth 1 -type d | sort -nr | head -1`
# If this is the first incremental, use the full as base. Otherwise, use the latest incremental as base.
if [ ! $LATEST_INCR ] ; then
INCRBASEDIR=$FULLBACKUPDIR/$LATEST_FULL
else
INCRBASEDIR=$LATEST_INCR
fi
echo "Running new incremental backup using $INCRBASEDIR as base."
$INNOBACKUPEXFULL --defaults-file=$MYCNF $DEFGROUP $USEROPTIONS --incremental $TMPINCRDIR --incremental-basedir $INCRBASEDIR > $TMPFILE 2>&1
else
echo "Running new full backup."
$INNOBACKUPEXFULL --defaults-file=$MYCNF $DEFGROUP $USEROPTIONS $FULLBACKUPDIR > $TMPFILE 2>&1
fi
if [ -z "`tail -1 $TMPFILE | grep 'completed OK!'`" ] ; then
echo "$INNOBACKUPEX failed:"; echo
echo "---------- ERROR OUTPUT from $INNOBACKUPEX ----------"
cat $TMPFILE
rm -f $TMPFILE
exit 1
fi
THISBACKUP=`awk -- "/Backup created in directory/ { split( \\\$0, p, \"'\" ) ; print p[2] }" $TMPFILE`
rm -f $TMPFILE
echo "Databases backed up successfully to: $THISBACKUP"
echo
# Cleanup
echo "Cleanup. Keeping only $KEEP full backups and its incrementals."
AGE=$(($FULLBACKUPLIFE * $KEEP / 60))
find $FULLBACKUPDIR -maxdepth 1 -type d -mmin +$AGE -execdir echo "removing: "$FULLBACKUPDIR/{} \; -execdir rm -rf $FULLBACKUPDIR/{} \; -execdir echo "removing: "$INCRBACKUPDIR/{} \; -execdir rm -rf $INCRBACKUPDIR/{} \;
echo
echo "completed: `date`"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment