#!/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