Skip to content

Instantly share code, notes, and snippets.

@simonklee
Created July 2, 2014 09:00
Show Gist options
  • Save simonklee/6680edec8c3bcab9343e to your computer and use it in GitHub Desktop.
Save simonklee/6680edec8c3bcab9343e to your computer and use it in GitHub Desktop.
#!/bin/bash
# takes a backup of node
workdir=null
datavol=""
pidfile="/tmp/backup-node.pid"
declare -A backup_nodes=()
# timings
t0=`date +%s`
t1=`date +%s`
function print_help {
echo "Backup mysql
Usage:
./`basename $0` <volume> [options]
Options are:
-h|--help show this help
"
}
function step {
t1=`date +%s`
printf "INFO: %-30s ... %3d sec - OK\n" "$@" "$[$t1-$t0]"
t0=`date +%s`
}
function error {
echo "ERR: $@" 1>&2
}
function exit_program {
local exit_code=0
if [ ! -z $1 ]; then
exit_code=$1
fi
if [ -e ${pidfile} ]; then
rm $pidfile
fi
exit $exit_code
}
function fail {
error "program terminated"
exit_program 1
}
function trap_sigint {
exit_program 0
}
function trap_sigterm {
exit_program 0
}
function trap_exit {
echo "TRAP"
exit_program 0
}
trap 'trap_sigint' SIGINT
trap 'trap_sigterm' SIGTERM
#trap 'trap_exit' EXIT
function read_config {
# read config file if it is present
[ -r /etc/backup-node/conf ] && . /etc/backup-node/conf || return 1
step "read config"
}
function check_input {
if [ "$1" != "" ] ; then
datavol="$1"
if [ "${datavol}" = "/" ]; then
datavol=""
fi
fi
# set globals
workdir="${datavol}/tmp/mysql-backup"
archivedir="${datavol}/var/lib/mysql-backup"
step "check input"
}
function create_workenv {
# check if workdir exists, del if directory, else fail
if [ -e "${workdir}" ] ; then
if [ ! -d "${workdir}" ] ; then
error "${workdir} exists, but is not a directory"
return 1
else
rm -rf "${workdir}"
fi
fi
# create workdir and extract build
mkdir -p "${workdir}" || return 1
mkdir -p "${archivedir}" || return 1
cd ${workdir} || return 1
step "create workenv"
}
function create_archive {
if [ "$#" -ne 1 ] ; then
error "create_archive <host>"
return 1
fi
cd ${archivedir} || return 1
# 'DAILY'
local d_delete_backup_older_than_days=6
# 'WEEKLY'
local w_delete_backup_older_than_days=30
# Dates format for naming backups
local date_format="%Y-%m-%d"
# Backup folders names
local daily_folder='daily'
local weekly_folder='weekly'
local monthly_folder='monthly'
local dailydir="${archivedir}/${host}/${daily_folder}"
local weeklydir="${archivedir}/${host}/${weekly_folder}"
local monthlydir="${archivedir}/${host}/${monthly_folder}"
for i in $dailydir $weeklydir $monthlydir; do
if [ ! -d $i ]; then
mkdir -p $i || return 1
fi
done
local filename="${workdir}/${host}.tar.gz"
local dailyfile="${dailydir}/${host}_`date +"$date_format"`.tar.gz"
local weeklyfile="${weeklydir}/${host}_`date +"$date_format"`.tar.gz"
local monthlyfile="${monthlydir}/${host}_`date +"$date_format"`.tar.gz"
# Daily backup
if [ ! -e $dailyfile ]; then
cp $filename $dailyfile || return 1
fi
# Weekly backup
if [ "`date +"%u"`" = "7" ]; then
if [ ! -e $weeklyfile ]; then
cp $filename $weeklyfile || return 1
fi
fi
# Monthly backup
if [ "`date +"%d"`" = "01" ]; then
if [ ! -e $monthlyfile ]; then
cp $filename $monthlyfile || return 1
fi
fi
find ${dailydir} -name "*.tar.gz" -mtime +${d_delete_backup_older_than_days} -type f -print -exec rm -f {} \; || return 1
find ${weeklydir} -name "*.tar.gz" -mtime +${w_delete_backup_older_than_days} -type f -print -exec rm -f {} \; || return 1
step "create archive"
}
function create_backup {
if [ "$#" -ne 1 ] ; then
error "create_backup <host>"
return 1
fi
cd ${workdir} || return 1
local backupcmd="innobackupex --safe-slave-backup --stream=tar ./"
local datadir="${host}-datadir"
# create backup and stream it to localhost
ssh -o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
root@${host} -C "${backupcmd}" > "${host}.tar" || return 1
# extract backup and flush transactions
mkdir ${datadir} || return 1
tar xfi "${host}.tar" -C ./${datadir} || return 1
innobackupex --apply-log --use-memory=1G ./${datadir} || return 1
# compress backup and cleanup
tar zcfi "${host}.tar.gz" ./${datadir} || return 1
rm -f "./${host}.tar" || return 1
rm -rf "./${datadir}" || return 1
step "create backup"
}
function create_backups {
cd ${workdir} || return 1
for host in "${backup_nodes[@]}"; do
create_backup "${host}" || return 1
create_archive "${host}" || return 1
done
step "create backups"
}
function cleanup {
rm -rf "${workdir}" || return 1
step "cleanup backups"
}
if [ -e $pidfile ]; then
error "backup-node.sh is already running (pid `cat ${pidfile}`)."
error "if it isn't please delete ${pidfile}"
exit 1
fi
echo $$ > $pidfile
# deploy steps
step "begin backup `date`"
read_config || fail
check_input $@ || fail
create_workenv || fail
create_backups || fail
cleanup || fail
exit_program
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment