#!/usr/bin/env bash set -o pipefail PATH="$PATH:/usr/local/bin:/usr/local/sbin" SCRIPT_LOG=/var/log/backup_mysql.log DB_USER="" DB_PASSWORD="" DB_HOST="" DB_LIST=() DUMP_OPTIONS="--single-transaction --quick --no-autocommit --force --add-drop-table --skip-add-locks" DUMP_FOLDER=/backups/tmp ARCHIVE_NAME=archive.tar.gz DESTINATION_FOLDER=/backups function LOG() { local msg="$1" date=$(date '+%Y-%m-%d %H:%M:%S') echo "[$date] $msg" >> $SCRIPT_LOG } function DELETE_TMP_FOLDER() { if [ -d "${DUMP_FOLDER}" ]; then rm -rf "${DUMP_FOLDER}" &> /dev/null if [ $? -ne 0 ]; then LOG "ERROR: Can not delete ${DUMP_FOLDER}" exit 2 else LOG "SUCCESS: Delete ${DUMP_FOLDER}" fi fi } function CREATE_TMP_FOLDER() { if [ -d "${DUMP_FOLDER}" ]; then LOG "ERROR: Dump folder ${DUMP_FOLDER} exists." exit 2 else mkdir -p "${DUMP_FOLDER}" &> /dev/null if [ $? -ne 0 ]; then LOG "ERROR: Create dump folder ${DUMP_FOLDER} failed." DELETE_TMP_FOLDER exit 2 else LOG "SUCCESS: ${DUMP_FOLDER} is created." fi fi } function READ_DBS() { sql="SHOW DATABASES WHERE \`Database\` NOT IN('information_schema', 'performance_schema', 'mysql')" DB_LIST=$(mysql -N --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} -e "$sql") &> /dev/null if [ $? -ne 0 ]; then LOG "ERROR: Getting list of databases failed." DELETE_TMP_FOLDER exit 2 else if [[ -n $DB_LIST ]]; then LOG "SUCCESS: Getting list of databases success." else LOG "ERROR: List of databases is empty." DELETE_TMP_FOLDER exit 2 fi fi } function CHECK_DISK_USAGE() { sql="SELECT table_schema , ROUND(SUM(data_length + index_length) / 1024 / 1024, 0) FROM information_schema.TABLES;" DBS_SIZE=$(mysql -N --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} -e "$sql"| awk '{print $2}') &> /dev/null if [ $? -eq 0 ] ; then LOG "SUCCESS: Determining the size of MySQL databases." else LOG "ERROR: Determining the size of MySQL databases failed." exit 2 fi DST_AVAIL_SIZE=$(df -m ${DESTINATION_FOLDER} | awk 'NR==2{print $4}') &> /dev/null if [ $? -eq 0 ] ; then LOG "SUCCESS: Determining the amount of available disk space on ${DESTINATION_FOLDER} partition." else LOG "ERROR: Determining the amount of available disk space on ${DESTINATION_FOLDER} partition failed." exit 2 fi if [ $DST_AVAIL_SIZE -lt $DBS_SIZE ] ; then LOG "ERROR: There is not ${DESTINATION_FOLDER} enough available disk space." exit 2 else LOG "SUCCESS: There is ${DESTINATION_FOLDER} enough available disk space." fi } function DUMP_DBS() { for DB_NAME in $DB_LIST do LOG "Dumping ${DB_NAME}..." mysqldump --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DUMP_OPTIONS} ${DB_NAME} > ${DUMP_FOLDER}/${DB_NAME}.sql if [ $? -eq 0 ] ; then LOG "SUCCESS: Dump ${DB_NAME} is created." else LOG "ERROR: Dump ${DB_NAME} is failed." DELETE_TMP_FOLDER exit 2 fi done } function COMPRESS_DUMPS() { (cd ${DUMP_FOLDER} && tar cf - *.sql) | gzip -9 > ${DUMP_FOLDER}/${ARCHIVE_NAME} if [ $? -eq 0 ] ; then LOG "SUCCESS: Archive has been created." else LOG "ERROR: Archive creation failed." DELETE_TMP_FOLDER exit 2 fi } function CHECK_ARCHIVE() { tar -tf ${DUMP_FOLDER}/${ARCHIVE_NAME} &> /dev/null; if [ $? -eq 0 ] ; then LOG "SUCCESS: Archive verification completed." else LOG "ERROR: Archive verification failed" DELETE_TMP_FOLDER exit 2 fi } function MOVE_ARCHIVE() { date=$(date '+%Y-%m-%d_%H-%M') mv ${DUMP_FOLDER}/${ARCHIVE_NAME} ${DESTINATION_FOLDER}/${DB_HOST}_${date}.tar.gz &> /dev/null if [ $? -eq 0 ] ; then LOG "SUCCESS: Archive has been moved." else LOG "ERROR: Archive moving failed" DELETE_TMP_FOLDER exit 2 fi } LOG "### Backup mysql started ###" LOG "Checking the amount of available disk space on ${DESTINATION_FOLDER} partition." CHECK_DISK_USAGE LOG "Creatting temporary folder:" CREATE_TMP_FOLDER LOG "Getting list of databases:" READ_DBS LOG "Dump databases:" DUMP_DBS LOG "Compressing dumps:" COMPRESS_DUMPS LOG "Checking archive:" CHECK_ARCHIVE LOG "Moving archive:" MOVE_ARCHIVE DELETE_TMP_FOLDER LOG "### Backup mysql ended ###"