Compare commits

..

No commits in common. "010ab1dcebbd38e17ddf08b7659d0ab3854afd5b" and "e4cd29fd42e9f89b5a3c3525e0cfa47f3bb4f602" have entirely different histories.

View File

@ -43,31 +43,10 @@ consoleError() {
} }
exitError() { exitError() {
printf "%s[%s] --- %s execution completed with error ---\n%s" "$err" "$(stamp)" "$scriptName" "$norm" >> "$logfile" printf "%s[%s] --- %s execution completed with error ---\n%s" "$err" "$(stamp)" "$scriptName" "$norm" >>"$logfile"
exit "$1" exit "$1"
} }
doRestore() {
sourceFiles=$(find "${backupLocation}" -iname "${1}" -type d)
if [ -n "$sourceFiles" ]; then
if [ "$verbose" -eq 1 ]; then
if (! (cd "$sourceFiles/_data" && tar -cf - .) | (cd "${2}" && tar xvf -) >> "$logfile" ); then
return 1
else
return 0
fi
else
if (! (cd "$sourceFiles/_data" && tar -cf - .) | (cd "${3}" && tar xvf -) ); then
return 1
else
return 0
fi
fi
else
return 2
fi
}
scriptHelp() { scriptHelp() {
textNewline textNewline
printf "%sUsage: %s [parameters]%s\n\n" "$bold" "$scriptName" "$norm" printf "%sUsage: %s [parameters]%s\n\n" "$bold" "$scriptName" "$norm"
@ -104,30 +83,31 @@ textNewline() {
} }
trapExit() { trapExit() {
printf "%s[%s] -- [ERROR] 99: Caught signal --%s\n" "$err" "$(stamp)" "$norm" >> "$logfile" printf "%s[%s] -- [ERROR] 99: Caught signal --%s\n" "$err" "$(stamp)" "$norm" >>"$logfile"
printf "%s[%s] --- %s execution terminated via signal ---\n%s" "$err" "$(stamp)" "$scriptName" "$norm" >> "$logfile" cleanup
printf "%s[%s] --- %s execution terminated via signal ---\n%s" "$err" "$(stamp)" "$scriptName" "$norm" >>"$logfile"
exit 99 exit 99
} }
writeLog() { writeLog() {
if [ "$1" = "task" ]; then if [ "$1" = "task" ]; then
printf "%s[%s] -- [INFO] %s... " "$info" "$(stamp)" "$2" >> "$logfile" printf "%s[%s] -- [INFO] %s... " "$info" "$(stamp)" "$2" >>"$logfile"
elif [ "$1" = "done" ]; then elif [ "$1" = "done" ]; then
if [ -z "$2" ]; then if [ -z "$2" ]; then
printf "%sdone%s --\n%s" "$ok" "$info" "$norm" >> "$logfile" printf "%sdone%s --\n%s" "$ok" "$info" "$norm" >>"$logfile"
elif [ "$2" = "error" ]; then elif [ "$2" = "error" ]; then
printf "%sERROR%s --\n%s" "$err" "$info" "$norm" >> "$logfile" printf "%sERROR%s --\n%s" "$err" "$info" "$norm" >>"$logfile"
elif [ "$2" = "warn" ]; then elif [ "$2" = "warn" ]; then
printf "%swarning%s --\n%s" "$yellow" "$info" "$norm" >> "$logfile" printf "%swarning%s --\n%s" "$yellow" "$info" "$norm" >>"$logfile"
fi fi
elif [ "$1" = "error" ]; then elif [ "$1" = "error" ]; then
printf "%s[%s] -- [ERROR] %s: %s --\n%s" "$err" "$(stamp)" "$2" "$3" "$norm" >> "$logfile" printf "%s[%s] -- [ERROR] %s: %s --\n%s" "$err" "$(stamp)" "$2" "$3" "$norm" >>"$logfile"
elif [ "$1" = "warn" ]; then elif [ "$1" = "warn" ]; then
printf "%s[%s] -- [WARNING] %s --\n%s" "$yellow" "$(stamp)" "$2" "$norm" >> "$logfile" printf "%s[%s] -- [WARNING] %s --\n%s" "$yellow" "$(stamp)" "$2" "$norm" >>"$logfile"
elif [ "$1" = "info" ]; then elif [ "$1" = "info" ]; then
printf "%s[%s] -- [INFO] %s --\n%s" "$info" "$(stamp)" "$2" "$norm" >> "$logfile" printf "%s[%s] -- [INFO] %s --\n%s" "$info" "$(stamp)" "$2" "$norm" >>"$logfile"
elif [ "$1" = "success" ]; then elif [ "$1" = "success" ]; then
printf "%s[%s] -- [SUCCESS] %s --\n%s" "$ok" "$(stamp)" "$2" "$norm" >> "$logfile" printf "%s[%s] -- [SUCCESS] %s --\n%s" "$ok" "$(stamp)" "$2" "$norm" >>"$logfile"
fi fi
} }
@ -222,7 +202,7 @@ while [ $# -gt 0 ]; do
-b|--backup-location) -b|--backup-location)
if [ -n "$2" ]; then if [ -n "$2" ]; then
if [ -d "$2" ] && [ -n "$( ls -A "$2" )" ]; then if [ -d "$2" ] && [ -n "$( ls -A "$2" )" ]; then
backupLocation="${2%/}" backupLocation="$2"
shift shift
else else
consoleError '1' "$1: cannot find specified backup location directory or it is empty." consoleError '1' "$1: cannot find specified backup location directory or it is empty."
@ -247,7 +227,7 @@ while [ $# -gt 0 ]; do
restoreRspamd=0 restoreRspamd=0
;; ;;
*) *)
printf "\n%sUnknown option: %s\n" "$err" "$1" printf "\n%Unknown option: %s\n" "$err" "$1"
printf "Use '--help' for valid options.%s\n\n" "$norm" printf "Use '--help' for valid options.%s\n\n" "$norm"
exit 1 exit 1
;; ;;
@ -256,13 +236,9 @@ while [ $# -gt 0 ]; do
done done
### pre-flight checks ### pre-flight checks
# ensure there's something to do
if [ "$restoreMail" -eq 0 ] && [ "$restoreSQL" -eq 0 ] && [ "$restorePostfix" -eq 0 ] && [ "$restoreRedis" -eq 0 ] && [ "$restoreRedis" -eq 0 ]; then
printf "\n%sAll restore operations skipped -- nothing to do!%s\n\n" "$yellow" "$norm"
exit 0
fi
# set path so checks are valid for this script environment # set path so checks are valid for this script environment
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
# docker installed? # docker installed?
if ! command -v docker >/dev/null; then if ! command -v docker >/dev/null; then
consoleError '3' 'docker does not seem to be installed!' consoleError '3' 'docker does not seem to be installed!'
@ -275,12 +251,8 @@ fi
if [ ! -f "$mcDockerCompose" ]; then if [ ! -f "$mcDockerCompose" ]; then
consoleError '1' "docker-compose configuration ($mcDockerCompose) cannot be found." consoleError '1' "docker-compose configuration ($mcDockerCompose) cannot be found."
fi fi
# forgot to set backup location?
if [ -z "$backupLocation" ]; then
consoleError '1' "'--backup-location' cannot be unspecified or null/empty."
fi
# change to mailcow directory so commands execute properly # change to mailcow directory so commands execute properly
\cd "${mcConfig%/*}" || consoleError '4' 'Cannot change to mailcow directory as determined from mailcow.conf location.' \cd ${mcConfig%/*} || consoleError '4' 'Cannot change to mailcow directory as determined from mailcow.conf location.'
### read mailcow.conf and import vars ### read mailcow.conf and import vars
# shellcheck source=./mailcow.conf.shellcheck # shellcheck source=./mailcow.conf.shellcheck
@ -311,7 +283,7 @@ else
fi fi
fi fi
# write initial log entries # write initial log entries
if ! printf "%s[%s] --- Start %s execution ---\n%s" "$magenta" "$(stamp)" "$scriptName" "$norm" 2>/dev/null >> "$logfile"; then if ! printf "%s[%s] --- Start %s execution ---\n%s" "$magenta" "$(stamp)" "$scriptName" "$norm" 2>/dev/null >>"$logfile"; then
consoleError '1' "Unable to write to log file ($logfile)" consoleError '1' "Unable to write to log file ($logfile)"
fi fi
writeLog 'info' "Log located at $logfile" writeLog 'info' "Log located at $logfile"
@ -342,7 +314,7 @@ if [ "$restoreSQL" -eq 1 ]; then
if [ -n "$sqlBackup" ]; then if [ -n "$sqlBackup" ]; then
# start mysql container if not already running # start mysql container if not already running
if ! docker container inspect -f '{{ .State.Running }}' ${COMPOSE_PROJECT_NAME}_mysql-mailcow_1 > /dev/null 2>&1; then if ! docker container inspect -f '{{ .State.Running }}' ${COMPOSE_PROJECT_NAME}_mysql-mailcow_1 > /dev/null 2>&1; then
docker-compose up -d mysql-mailcow > /dev/null 2>&1 docker-compose up -d mysql-mailcow
if docker container inspect -f '{{ .State.Running }}' ${COMPOSE_PROJECT_NAME}_mysql-mailcow_1 > /dev/null 2>&1; then if docker container inspect -f '{{ .State.Running }}' ${COMPOSE_PROJECT_NAME}_mysql-mailcow_1 > /dev/null 2>&1; then
sqlRunning=1 sqlRunning=1
else else
@ -366,223 +338,27 @@ if [ "$restoreSQL" -eq 1 ]; then
else else
writeLog 'done' 'error' writeLog 'done' 'error'
writeLog 'error' '13' "Something went wrong while trying to restore SQL database. Perhaps try again?" writeLog 'error' '13' "Something went wrong while trying to restore SQL database. Perhaps try again?"
errorCount=$((errorCount+1))
fi fi
fi fi
fi fi
### stop containers (necessary for all restore operations except SQL) #TODO: stop containers
writeLog 'task' "Stopping mailcow" #TODO: copy backups to correct docker volumes
if ! docker-compose down --timeout "${dockerStopTimeout}" > /dev/null 2>&1; then #TODO: restart docker containers
writeLog 'done' 'error' #TODO: optionally reindex dovecot (parameter)
writeLog 'error' '20' "Unable to bring mailcow containers down -- cannot reliably restore. Aborting."
exitError 20
fi
if [ "$( docker ps --filter "name=${COMPOSE_PROJECT_NAME}" -q | wc -l )" -gt 0 ]; then
writeLog 'done' 'error'
writeLog 'error' '20' "Unable to bring mailcow containers down -- cannot reliably restore. Aborting."
exitError 20
fi
writeLog 'done'
### restore mail and encryption key
if [ "$restoreMail" -eq 1 ]; then
if [ "$verbose" -eq 1 ]; then
writeLog 'info' "Restoring email"
else
writeLog 'task' "Restoring email"
fi
# restore email messages
doRestore "${COMPOSE_PROJECT_NAME}_vmail-vol-1" "$dockerVolumeMail"; ec="$?"
case "$ec" in
0)
if [ "$verbose" -eq 1 ]; then
writeLog 'success' "Email messages restored"
else
writeLog 'done'
fi
;;
1)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '52' "There was an error restoring one or more email messages."
else
writeLog 'done' 'error'
writeLog 'error' '52' "There was an error restoring one or more email messages."
fi
;;
2)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '51' "Cannot locate email message backups!"
else
writeLog 'done' 'error'
writeLog 'error' '51' "Cannot locate email message backups!"
fi
;;
esac
# restore encryption key
doRestore "${COMPOSE_PROJECT_NAME}_crypt-vol-1" "$dockerVolumeCrypt"; ec="$?"
case "$ec" in
0)
if [ "$verbose" -eq 1 ]; then
writeLog 'success' "Encryption key restored"
else
writeLog 'done'
fi
;;
1)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '52' "There was an error restoring the encryption key! Any restored messages are likely *not* readable!"
else
writeLog 'done' 'error'
writeLog 'error' '52' "There was an error restoring the encryption key! Any restored messages are likely *not* readable!"
fi
;;
2)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '51' "Cannot locate encryption key backup!"
else
writeLog 'done' 'error'
writeLog 'error' '51' "Cannot locate encryption key backup!"
fi
;;
esac
fi
### restore postfix
if [ "$restorePostfix" -eq 1 ]; then
if [ "$verbose" -eq 1 ]; then
writeLog 'info' "Restoring postfix files"
else
writeLog 'task' "Restoring postfix files"
fi
# restore email messages
doRestore "${COMPOSE_PROJECT_NAME}_postfix-vol-1" "$dockerVolumePostfix"; ec="$?"
case "$ec" in
0)
if [ "$verbose" -eq 1 ]; then
writeLog 'success' "Postfix files restored"
else
writeLog 'done'
fi
;;
1)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '52' "There was an error restoring one or more postfix files."
else
writeLog 'done' 'error'
writeLog 'error' '52' "There was an error restoring one or more postfix files."
fi
;;
2)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '51' "Cannot locate postfix backups!"
else
writeLog 'done' 'error'
writeLog 'error' '51' "Cannot locate postfix backups!"
fi
;;
esac
fi
### restore rspamd
if [ "$restoreRspamd" -eq 1 ]; then
if [ "$verbose" -eq 1 ]; then
writeLog 'info' "Restoring Rspamd files"
else
writeLog 'task' "Restoring Rspamd files"
fi
# restore email messages
doRestore "${COMPOSE_PROJECT_NAME}_rspamd-vol-1" "$dockerVolumeRspamd"; ec="$?"
case "$ec" in
0)
if [ "$verbose" -eq 1 ]; then
writeLog 'success' "Rspamd files restored"
else
writeLog 'done'
fi
;;
1)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '52' "There was an error restoring one or more Rspamd files."
else
writeLog 'done' 'error'
writeLog 'error' '52' "There was an error restoring one or more Rspamd files."
fi
;;
2)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '51' "Cannot locate Rspamd backups!"
else
writeLog 'done' 'error'
writeLog 'error' '51' "Cannot locate Rspamd backups!"
fi
;;
esac
fi
### restore redis
if [ "$restoreRedis" -eq 1 ]; then
if [ "$verbose" -eq 1 ]; then
writeLog 'info' "Restoring redis database"
else
writeLog 'task' "Restoring redis database"
fi
# restore email messages
doRestore "${COMPOSE_PROJECT_NAME}_redis-vol-1" "$dockerVolumeRedis"; ec="$?"
case "$ec" in
0)
if [ "$verbose" -eq 1 ]; then
writeLog 'success' "Redis database restored"
else
writeLog 'done'
fi
;;
1)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '52' "There was an error restoring the redis database. This is usually *not* a serious issue."
else
writeLog 'done' 'error'
writeLog 'error' '52' "There was an error restoring the redis database. This is usually *not* a serious issue."
fi
;;
2)
if [ "$verbose" -eq 1 ]; then
writeLog 'error' '51' "Cannot locate redis database backups!"
else
writeLog 'done' 'error'
writeLog 'error' '51' "Cannot locate redis database backups!"
fi
;;
esac
fi
### restart mailcow
writeLog 'task' "Starting mailcow"
if ! docker-compose up -d > /dev/null 2>&1; then
writeLog 'done' 'warn'
writeLog 'warn' '21' "Unable to automatically start mailcow containers. Please attempt a manual start and note any errors."
warnCount=$((warnCount+1))
fi
writeLog 'done'
### exit gracefully ### exit gracefully
writeLog 'success' "All processes completed"
printf "%s[%s] --- %s execution completed ---\n%s" "$magenta" "$(stamp)" "$scriptName" "$norm" >>"$logfile"
# note non-terminating errors
if [ "$errorCount" -gt 0 ]; then if [ "$errorCount" -gt 0 ]; then
# note non-terminating errors printf "%s%s errors encountered!%s\n" "$err" "$errorCount" "$norm" >>"$logfile"
printf "%s[%s] --- %s execution completed with %s error(s) ---\n%s" "$err" "$(stamp)" "$scriptName" "$errorCount" "$norm" >> "$logfile"
exit 98
elif [ "$warnCount" -gt 0 ]; then
printf "%s[%s] --- %s execution completed with %s warning(s) ---\n%s" "$yellow" "$(stamp)" "$scriptName" "$warnCount" "$norm" >> "$logfile"
exit 97
else
writeLog 'success' "All processes completed"
printf "%s[%s] --- %s execution completed ---\n%s" "$magenta" "$(stamp)" "$scriptName" "$norm" >> "$logfile"
exit 0
fi fi
# note warnings
if [ "$warnCount" -gt 0 ]; then
printf "%s%s warnings issued!%s\n" "$yellow" "$warnCount" "$norm" >>"$logfile"
fi
exit 0
### error codes: ### error codes:
# 1: parameter error # 1: parameter error
@ -594,14 +370,9 @@ fi
# 11: cannot locate SQL dump in backup directory # 11: cannot locate SQL dump in backup directory
# 12: cannot start mysql-mailcow container # 12: cannot start mysql-mailcow container
# 13: restoring SQL dump was unsuccessful # 13: restoring SQL dump was unsuccessful
# 2x: Docker/Docker-Compose errors
# 20: cannot bring docker container(s) down successfully
# 21: cannot bring docker container(s) up successfully
# 5x: File restore errors
# 51: cannot locate source files in backup directory
# 52: error restoring one or more files
# 97: script completed with 1 or more warnings
# 98: script completed with 1 or more non-terminating errors
# 99: TERM signal trapped # 99: TERM signal trapped
# 100: could not change to mailcow-dockerized directory
# 101: could not stop container(s)
# 102: could not start container(s)
#EOF #EOF