diff --git a/database/mybackup.sh b/database/mybackup.sh new file mode 100755 index 0000000000000000000000000000000000000000..ff0665ba34ff0e195c4db884c87b1a19c6cc0faf --- /dev/null +++ b/database/mybackup.sh @@ -0,0 +1,243 @@ +#!/bin/bash +# +# mybackup.sh +# +# Copyright (C) 2010, Branko Majic <branko@majic.rs> +# +# 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. +# +# This program 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 program. If not, see <http://www.gnu.org/licenses/>. +# + +program="mybackup.sh" +version="0.1" + +function usage() { + cat <<EOF +$program $version, a non-interactive utility for backing-up the MySQL datbase +with mysqldump. + +Usage: $program -D dir [-c (bz2|gz)] [-M mail] [-t (e|w|a)] [-l logfile] [database[ database2...]] + +$program is a non-interactive utility for backing-up the MySQL database using +the mysqldump utility. If no databases are specified, the utility will back-up +all the databases. Database backups are named in the pattern: + +database.YYYYMMDD_HHmmSS[.gz|bz2] + +YYYY stands for year, MM for month, DD for day, HH for hour, mm for minutes, and +SS for seconds. Compression suffix is added in case the compression was +requested. If the file by the same name already exists, it is not overwritten, +and a warning is issued. + +User and password for the script must be specified using the \$HOME/.my.cnf +file. The user used for backup must have the select permissions for the +databases it will backup. + +$program accepts the following options: + + -d dir Directory where the backups should reside. + -c (bz2|gz) Compress the MySQL database dumps using either bzip2 or gzip. + -m mail Mail the report about performed back-up to the specified e-mail + address. (optional) + -t level Set the threshold for when sending mails. Supported thresholds + are ERROR, WARN, or INFO. + -l logfile Log the activity in the specified log file. Default is + /var/log/mybackup/mybackup.log. + + -v show script version and licensing information + -h show usage help + + +Please report bugs and send feature requests to <branko@majic.rs>. +EOF +} + +function version() { + cat <<EOF +$program, version $version + ++-----------------------------------------------------------------------+ +| Copyright (C) 2010, Branko Majic <branko@majic.rs> | +| | +| 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. | +| | +| This program 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 program. If not, see <http://www.gnu.org/licenses/>. | ++-----------------------------------------------------------------------+ + +EOF +} + +# +# Helper function that generates a timestamp for the log. Current date is used +# for the timestmap. +# +# Outputs: +# Current date in format 'YYYY-MM-DD HH:mm:SS'. +# +function timestamp() { + date '+%Y-%m-%d %H:%M:%S' +} + +# +# Helper function for logging the events. The events are logged into a file and +# into a variable "logCache". This variable can be used later on for sending +# mail notifications etc. Entries in logCache are generated taking the threshold +# into account. +# +# Arguments: +# $1 - Event level, INFO, WARN, or ERROR. +# $2 - Message which should be written to log. +# +function logMessage() { + local level="$1" + local message="$2" + local logEntry + + if [[ $level == "INFO" || $level == "WARN" || $level == "ERROR" ]]; then + logEntry="$(timestamp) $level $message" + echo "$logEntry" >> "$logFile" + if [[ $level == INFO && $mailThreshold == INFO ]]; then + logCache[${#logCache[@]}]="$logEntry" + elif [[ $level == WARN && ($mailThreshold == WARN || $mailThreshold == INFO) ]]; then + logCache[${#logCache[@]}]="$logEntry" + elif [[ $level == ERROR ]]; then + logCache[${#logCache[@]}]="$logEntry" + fi + fi +} + +# If no arguments were given, just show usage help. +if [[ -z $1 ]]; then + usage + exit 0 +fi + +# Setup static variables +dateFormat="+%Y%m%d_%H%M%S" + +# Setup default argument values +mailThreshold="WARN" +logFile="/var/log/mybackup/mybackup.log" + +# Parse the arguments +while getopts "d:c:m:t:l:vh" opt; do + case "$opt" in + d) backupDirectory="$OPTARG";; + c) compression="$OPTARG";; + m) mail="$OPTARG";; + t) mailThreshold="$OPTARG";; + l) logFile="$OPTARG";; + v) version + exit 0;; + h) usage + exit 0;; + *) usage + exit 1;; + esac +done +i=$OPTIND +shift $(($i-1)) + +# Verify parameters +if [[ -z $backupDirectory ]]; then + echo "No backup directory was supplied." >&2 + exit 2 +fi +if [[ ($compression != "bz2" && $compression != "gz") && -n $compression ]]; then + echo "Compression type '$compression' is not supported." >&2 + exit 3 +fi +if [[ $mailThreshold != "INFO" && $mailThreshold != "WARN" && $mailThreshold != "ERROR" ]]; then + echo "Unrecognised threshold '$mailThreshold'" >&2 + exit 3 +fi + +# Setup the compression command +if [[ $compression == "bz2" ]]; then + compressionCommand="bzip2" +elif [[ $compression == "gz" ]]; then + compressionCommand="gzip" +else + compressionCommand="cat" +fi + +# Retrieve a list of all the databases provided at the command line +databases=() +while [[ -n $1 ]]; do + databases=(${databases[@]} $1) + shift +done + +# If no databases were specified, back-up all the MySQL databases +if [[ ${#databases[@]} == 0 ]]; then + if ! databases=($(mysql --batch --skip-column-names -e 'SHOW DATABASES')); then + logMessage ERROR "Could not retrieve the list of databases. Aborting backup." + exit 4 + fi +fi + +# Add a dot to the compression so it's easier to build-up extensions +if [[ -n $compression ]]; then + compression=".$compression" +fi + +# Create the backup directory if it doesn't exist +mkdir -p "$backupDirectory" + +logMessage INFO "Starting the back-up of databases to $backupDirectory" + +for db in ${databases[@]}; do + outputFile="$db.$(date $dateFormat)${compression:-}" + if [[ -e $outputFile ]]; then + logMessage WARN "File already exists ($outputFile), skipping" + else + logMessage INFO "Starting the back-up of database $db" + mysqldump --single-transaction "$db" | "$compressionCommand" > "$backupDirectory/$outputFile" + exitCodes=(${PIPESTATUS[@]}) + if [[ ${exitCodes[0]} != 0 ]]; then + logMessage ERROR "Failed to back-up $db. Command 'mysqldump' exited with error code ${exitCodes[0]}" + fi + if [[ ${exitCodes[1]} != 0 ]]; then + logMessage ERROR "Failed to back-up $db. Compression command '$compressionCommand' exited with error code ${exitCodes[1]}" + fi + if [[ ${exitCodes[0]} == 0 && ${exitCodes[1]} == 0 ]]; then + logMessage INFO "Finished the back-up of database $db" + fi + fi + +done + +logMessage INFO "Finished the back-up of databases to $backupDirectory" + +if [[ -n $mail && ${logCache[@]} != 0 ]]; then + { + cat <<EOF +During backup of MySQL databases, the following messages of threshold +$mailThreshold have been logged: + +EOF + for line in "${logCache[@]}"; do + echo "$line"; + done + } | mail -s "mybackup report for $(hostname -f)" -e "$mail" +fi +