Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a26bb36f17 | |||
| bbbdf38dcc | |||
| 43f1bb0021 | |||
| b371e18ab0 | |||
| fb8091ecce | |||
| 25c6b407a6 | |||
| 3ddc2c5d4a | |||
| 82f80d0f83 | |||
| 0597127cbf | |||
| e23feddb1b | |||
| 12bc49a59e | |||
| a14d0ba4a5 | |||
| ed9db22534 | |||
| 7e92495c94 | |||
| 0808888030 |
@@ -0,0 +1,75 @@
|
||||
# Common settings that generally should always be used with your language specific settings
|
||||
|
||||
# Auto detect text files and perform LF normalization
|
||||
# https://www.davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
|
||||
* text=auto
|
||||
|
||||
#
|
||||
# The above will handle all files NOT found below
|
||||
#
|
||||
|
||||
# Documents
|
||||
*.bibtex text diff=bibtex
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
*.md text
|
||||
*.tex text diff=tex
|
||||
*.adoc text
|
||||
*.textile text
|
||||
*.mustache text
|
||||
*.csv text
|
||||
*.tab text
|
||||
*.tsv text
|
||||
*.txt text
|
||||
*.sql text
|
||||
|
||||
# Graphics
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.tif binary
|
||||
*.tiff binary
|
||||
*.ico binary
|
||||
# SVG treated as an asset (binary) by default.
|
||||
*.svg text
|
||||
# If you want to treat it as binary,
|
||||
# use the following line instead.
|
||||
# *.svg binary
|
||||
*.eps binary
|
||||
|
||||
# Scripts
|
||||
*.bash text eol=lf
|
||||
*.sh text eol=lf
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.ps1 text eol=crlf
|
||||
|
||||
# Serialisation
|
||||
*.json text
|
||||
*.toml text
|
||||
*.xml text
|
||||
*.yaml text
|
||||
*.yml text
|
||||
|
||||
# Archives
|
||||
*.7z binary
|
||||
*.gz binary
|
||||
*.tar binary
|
||||
*.zip binary
|
||||
|
||||
#
|
||||
# Exclude files from exporting
|
||||
#
|
||||
|
||||
.gitattributes export-ignore
|
||||
.gitignore export-ignore
|
||||
+6
-1
@@ -1,5 +1,10 @@
|
||||
# ignore all vscode config files
|
||||
.vscode/
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/numbered-bookmarks.json
|
||||
|
||||
# ignore all generated logfiles
|
||||
*.log
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"bookmarks": []
|
||||
}
|
||||
@@ -25,33 +25,37 @@ This script automates the following tasks:
|
||||
- [Environment notes](#environment-notes)
|
||||
- [Why this script must be run as root](#why-this-script-must-be-run-as-root)
|
||||
- [Script parameters](#script-parameters)
|
||||
- [Optional parameters](#optional-parameters)
|
||||
- [Docker container STOP timeout before error: -1 _number_](#docker-container-stop-timeout-before-error--1-_number_)
|
||||
- [Docker container START timeout before error: -2 _number_](#docker-container-start-timeout-before-error--2-_number_)
|
||||
- [Path to 503 error page: -5 _/path/to/filename.html_](#path-to-503-error-page--5-_pathtofilenamehtml_)
|
||||
- [Path to borg details file: -b _/path/to/filename.file_](#path-to-borg-details-file--b-_pathtofilenamefile_)
|
||||
- [File name of docker-compose configuration file: -d _filename.file_](#file-name-of-docker-compose-configuration-file--d-_filenamefile_)
|
||||
- [Log file location: -l _/path/to/filename.file_](#log-file-location--l-_pathtofilenamefile_)
|
||||
- [File name of Mailcow master configuration file: -m _filename.file_](#file-name-of-mailcow-master-configuration-file--m-_filenamefile_)
|
||||
- [Verbose output from borg: -v (no arguments)](#verbose-output-from-borg--v-no-arguments)
|
||||
- [Path to webroot: -w _/path/to/webroot/_](#path-to-webroot--w-_pathtowebroot_)
|
||||
- [Optional parameters](#optional-parameters)
|
||||
- [Docker container STOP timeout before error: -1 _number_](#docker-container-stop-timeout-before-error--1-number)
|
||||
- [Docker container START timeout before error: -2 _number_](#docker-container-start-timeout-before-error--2-number)
|
||||
- [Path to 503 error page: -5 _/path/to/filename.html_](#path-to-503-error-page--5-pathtofilenamehtml)
|
||||
- [Path to borg details file: -b _/path/to/filename.file_](#path-to-borg-details-file--b-pathtofilenamefile)
|
||||
- [File name of docker-compose configuration file: -d _filename.file_](#file-name-of-docker-compose-configuration-file--d-filenamefile)
|
||||
- [Log file location: -l _/path/to/filename.file_](#log-file-location--l-pathtofilenamefile)
|
||||
- [File name of Mailcow master configuration file: -m _filename.file_](#file-name-of-mailcow-master-configuration-file--m-filenamefile)
|
||||
- [Verbose output from borg: -v (no arguments)](#verbose-output-from-borg--v-no-arguments)
|
||||
- [Path to webroot: -w _/path/to/webroot/_](#path-to-webroot--w-pathtowebroot)
|
||||
- [Borg details file](#borg-details-file)
|
||||
- [Protect your borg details file](#protect-your-borg-details-file)
|
||||
- [borg specific entries (lines 1-4)](#borg-specific-entries-lines-1-4)
|
||||
- [additional files/directories to backup](#additional-filesdirectories-to-backup)
|
||||
- [exclusion patterns](#exclusion-patterns)
|
||||
- [prune timeframe options](#prune-timeframe-options)
|
||||
- [borg remote location](#borg-remote-location)
|
||||
- [Examples](#examples)
|
||||
- [Protect your borg details file](#protect-your-borg-details-file)
|
||||
- [borg specific entries (lines 1-4)](#borg-specific-entries-lines-1-4)
|
||||
- [Line 1: Path to borg base directory](#line-1-path-to-borg-base-directory)
|
||||
- [Line 2: Path to SSH key for remote server](#line-2-path-to-ssh-key-for-remote-server)
|
||||
- [Line 3: Connection string to remote repo](#line-3-connection-string-to-remote-repo)
|
||||
- [Line 4: Password for borg repo/repo key](#line-4-password-for-borg-reporepo-key)
|
||||
- [additional files/directories to backup](#additional-filesdirectories-to-backup)
|
||||
- [exclusion patterns](#exclusion-patterns)
|
||||
- [prune timeframe options](#prune-timeframe-options)
|
||||
- [borg remote location](#borg-remote-location)
|
||||
- [Examples](#examples)
|
||||
- [503 functionality](#503-functionality)
|
||||
- [Conditional forwarding by your webserver](#conditional-forwarding-by-your-webserver)
|
||||
- [NGINX](#nginx)
|
||||
- [Apache](#apache)
|
||||
- [Disabling 503 functionality altogether](#disabling-503-functionality-altogether)
|
||||
- [Conditional forwarding by your webserver](#conditional-forwarding-by-your-webserver)
|
||||
- [NGINX](#nginx)
|
||||
- [Apache](#apache)
|
||||
- [Disabling 503 functionality altogether](#disabling-503-functionality-altogether)
|
||||
- [Scheduling: Cron](#scheduling-cron)
|
||||
- [The log file](#the-log-file)
|
||||
- [Using Logwatch](#using-logwatch)
|
||||
- [Remember to rotate your logs](#remember-to-rotate-your-logs)
|
||||
- [Using Logwatch](#using-logwatch)
|
||||
- [Remember to rotate your logs](#remember-to-rotate-your-logs)
|
||||
- [Final notes](#final-notes)
|
||||
|
||||
## Installation/copying
|
||||
@@ -209,9 +213,9 @@ example entries. The file must have the following information in the following
|
||||
order:
|
||||
|
||||
1. path to borg base directory **(required)**
|
||||
2. path to ssh private key for repo **(required)**
|
||||
2. path to ssh private key for remote server **(required)**
|
||||
3. connection string to remote repo **(required)**
|
||||
4. password for ssh key/repo **(required)**
|
||||
4. password for borg repo/repo key **(required)**
|
||||
5. path to file listing additional files/directories to backup
|
||||
6. path to file containing borg-specific exclusion patterns
|
||||
7. prune timeframe options
|
||||
@@ -234,10 +238,59 @@ chmod 600 mc_borg.details # grant access to root user only (read/write)
|
||||
|
||||
If you need help with these options, then you should consult the borg
|
||||
documentation or search my blog at
|
||||
[https://mytechiethoughts.com](https://mytechiethoughts.com) for borg. This is
|
||||
especially true if you want to understand why an SSH key and passphrase are
|
||||
preferred and why just a passphrase on it's own presents problems automating
|
||||
borg backups.
|
||||
[https://mytechiethoughts.com](https://mytechiethoughts.com) for borg. Here's a
|
||||
very brief overview:
|
||||
|
||||
#### Line 1: Path to borg base directory
|
||||
|
||||
This is primary directory on your local system where your borg configuration is
|
||||
located, **NOT* the path to your borg binary. The base directory contains the
|
||||
borg configuration, cache, security files and keys.
|
||||
|
||||
#### Line 2: Path to SSH key for remote server
|
||||
|
||||
This is the SSH key used to connect to your remote (backup) server where your
|
||||
borg repo is located. **This is NOT your borg repo key!**
|
||||
|
||||
> Please note: If you are planning on executing this script via cron or some
|
||||
> other form of automation, it is *highly recommended* that you use an SSH key
|
||||
> **without** a password! SSH is designed such that passwords cannot simply be
|
||||
> passed to it via environment variables, etc. so this is something not easily
|
||||
> automated by a script such as this for security reasons. As such, your
|
||||
> computer will sit and wait for you to enter the password and will NOT execute
|
||||
> the actual backup portion of the script until the SSH key password is provided.
|
||||
>
|
||||
> If you really want/need to use an SSH key password, you will have to look into
|
||||
> somethign like GNOME keyring or SSH-agent to provide a secure automated way to
|
||||
> provide that password to SSH and allow this script to continue.
|
||||
>
|
||||
> In practice, SSH keys without passwords are still quite safe since the key
|
||||
> must still be known in order to connect and most keys are quite long. In
|
||||
> addition, they key only connects to the remote server, your actual information
|
||||
> within the borg repository is still encrypted and secured with both a key and
|
||||
> password.
|
||||
|
||||
#### Line 3: Connection string to remote repo
|
||||
|
||||
This is the full server and path required to connect to your borg repo on the
|
||||
remote server. Very often it is the in the form of:
|
||||
|
||||
```
|
||||
user@servername.tld:repo-name/
|
||||
```
|
||||
|
||||
for rsync.net it is in the following form:
|
||||
|
||||
```
|
||||
username@server-number.rsync.net:repo-name/
|
||||
```
|
||||
|
||||
#### Line 4: Password for borg repo/repo key
|
||||
|
||||
This is the password needed to access and decrypt your *borg repo*. Assuming
|
||||
you set up your borg repo using recommended practices, this will actually be the
|
||||
password for your *borg repo private key*. **This is NOT your SSH key
|
||||
password!**
|
||||
|
||||
### additional files/directories to backup
|
||||
|
||||
|
||||
Regular → Executable
+178
-152
@@ -12,7 +12,6 @@ lit="\e[93m"
|
||||
op="\e[39m"
|
||||
info="\e[96m"
|
||||
note="\e[95m"
|
||||
stamp="[`date +%Y-%m-%d` `date +%H:%M:%S`]"
|
||||
|
||||
|
||||
### Functions ###
|
||||
@@ -34,10 +33,15 @@ function scriptHelp {
|
||||
echo -e "\tMailcow to operational status."
|
||||
echo -e "\nThe readme file included in this script's git contains detailed"
|
||||
echo -e "usage information. The following is a brief summary:\n"
|
||||
echo -e "${bold}***This script scans for your mailcow configuration file"
|
||||
echo -e "either with the default name or with your provided filename. If"
|
||||
echo -e "multiple files with this name are on your system, the script"
|
||||
echo -e "WILL get confused and exit with errors***${normal}${default}"
|
||||
echo -e "${bold}***You MUST provide the full path to your mailcow"
|
||||
echo -e "configuration file using the '-m' parameter***${normal}${default}"
|
||||
echo -e "${bold}${note}\nMandatory parameters:${normal}${default}"
|
||||
echo -e "${lit}\n-m, File name of the Mailcow build configuration file${default}"
|
||||
echo -e "FULL PATH to your Mailcow master build configuration file containing"
|
||||
echo -e "all variables and configuration info unique to your Mailcow setup."
|
||||
echo -e "The path specified here is also used for all docker-related"
|
||||
echo -e "operations in this script."
|
||||
echo -e "${info}Default: <none>${default}"
|
||||
echo -e "${bold}${note}\nOptional parameters:${normal}${default}"
|
||||
echo -e "${lit}\n-1, Timeout for containers to STOP before error${default}"
|
||||
echo -e "The number of seconds to wait for a docker container to STOP"
|
||||
@@ -64,20 +68,12 @@ function scriptHelp {
|
||||
echo -e "${lit}\n-d, File name of the docker-compose configuration file${default}"
|
||||
echo -e "Name of the docker-compose configuration file that Mailcow uses"
|
||||
echo -e "to build/start/stop all containers. This will only be searched"
|
||||
echo -e "for in the path found to contain your mailcow configuration file."
|
||||
echo -e "for in the path provided for your mailcow configuration file."
|
||||
echo -e "${info}Default: docker-compose.yml${default}"
|
||||
echo -e "${lit}\n-l, Location to save log file${default}"
|
||||
echo -e "This script writes a detailed log file of all activities. It is"
|
||||
echo -e "structured in an way easy for log parsers (like Logwatch) to read."
|
||||
echo -e "${info}Default: ScriptPath/ScriptName.log${default}"
|
||||
echo -e "${lit}\n-m, File name of the Mailcow build configuration file${default}"
|
||||
echo -e "Name of the Mailcow master build configuration file that has all"
|
||||
echo -e "variables and configuration info unique to your Mailcow setup."
|
||||
echo -e "This script will search for any file matching what you specify"
|
||||
echo -e "so please ensure you don't have multiple files laying around with"
|
||||
echo -e "the same name! The path where this file is found is used for all"
|
||||
echo -e "docker-based operations in this script."
|
||||
echo -e "${info}Default: mailcow.conf${default}"
|
||||
echo -e "${lit}\n-v, Verbose output from borgbackup${default}"
|
||||
echo -e "By default, this script will only log summary data from borg."
|
||||
echo -e "If you need/want more detailed information, the verbose setting"
|
||||
@@ -101,6 +97,11 @@ function scriptHelp {
|
||||
exit 1
|
||||
}
|
||||
|
||||
### Generate dynamic timestamp
|
||||
function stamp {
|
||||
echo `date +%F" "%T`
|
||||
}
|
||||
|
||||
### quit -- exit the script after logging any errors, warnings, etc.
|
||||
function quit {
|
||||
# list generated warnings, if any
|
||||
@@ -117,7 +118,7 @@ function quit {
|
||||
fi
|
||||
if [ -z "${exitError}" ]; then
|
||||
# exit cleanly
|
||||
echo -e "${note}${stamp} -- ${scriptName} completed" \
|
||||
echo -e "${note}[$(stamp)] -- ${scriptName} completed" \
|
||||
"--${normal}" >> "$logFile"
|
||||
exit 0
|
||||
else
|
||||
@@ -174,10 +175,10 @@ function cleanup {
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "0" ]; then
|
||||
# directory still exists
|
||||
exitWarn+=("${stamp}_111")
|
||||
exitWarn+=("[$(stamp)]_111")
|
||||
else
|
||||
# directory removed
|
||||
echo -e "${op}${stamp} Removed SQL temp directory${normal}" \
|
||||
echo -e "${op}[$(stamp)] Removed SQL temp directory${normal}" \
|
||||
>> "$logFile"
|
||||
fi
|
||||
|
||||
@@ -185,21 +186,21 @@ function cleanup {
|
||||
# check value of 'clean503' to see if this is necessary (=1) otherwise, skip
|
||||
if [ "$clean503" = "1" ]; then
|
||||
# proceed with cleanup
|
||||
echo -e "${op}${stamp} Removing 503 error page..." >> "$logFile"
|
||||
echo -e "${op}[$(stamp)] Removing 503 error page..." >> "$logFile"
|
||||
rm -f "$webroot/$err503File" >> "$logFile" 2>&1
|
||||
# verify file is actually gone
|
||||
checkExist ff "$webroot/$err503File"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "0" ]; then
|
||||
# file still exists
|
||||
exitWarn+=("${stamp}_5030")
|
||||
exitWarn+=("[$(stamp)]_5030")
|
||||
else
|
||||
# file removed
|
||||
echo -e "${info}${stamp} -- [INFO] 503 page removed from webroot" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] 503 page removed from webroot" \
|
||||
"--${normal}" >> "$logFile"
|
||||
fi
|
||||
else
|
||||
echo -e "${op}${stamp} 503 error page never copied to webroot," \
|
||||
echo -e "${op}[$(stamp)] 503 error page never copied to webroot," \
|
||||
"nothing to cleanup" >> "$logFile"
|
||||
fi
|
||||
|
||||
@@ -207,43 +208,42 @@ function cleanup {
|
||||
# start and verify postfix
|
||||
operateDocker start postfix
|
||||
if [ "$dockerResultState" = "true" ]; then
|
||||
echo -e "${info}${stamp} -- [INFO] Postfix container is running --" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] Postfix container is running --" \
|
||||
"${normal}" >> "$logFile"
|
||||
else
|
||||
exitError+=("${stamp}_103")
|
||||
exitError+=("[$(stamp)]_103")
|
||||
fi
|
||||
# start and verify dovecot
|
||||
operateDocker start dovecot
|
||||
if [ "$dockerResultState" = "true" ]; then
|
||||
echo -e "${info}${stamp} -- [INFO] Dovecot container is running --" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] Dovecot container is running --" \
|
||||
"${normal}" >> "$logFile"
|
||||
else
|
||||
exitError+=("${stamp}_104")
|
||||
exitError+=("[$(stamp)]_104")
|
||||
fi
|
||||
}
|
||||
|
||||
### operate docker containers
|
||||
function operateDocker {
|
||||
# determine action to take
|
||||
if [ "$1" = "stop" ]; then
|
||||
echo -e "${op}${stamp} Stopping ${2}-mailcow container...${normal}" \
|
||||
>> "$logFile"
|
||||
docker-compose stop --timeout ${dockerStopTimeout} ${2}-mailcow \
|
||||
2>> "$logFile"
|
||||
# verify container stopped (should return true)
|
||||
dockerResultState=$(docker inspect -f '{{ .State.Running }}' \
|
||||
${COMPOSE_PROJECT_NAME}_${2}-mailcow_1)
|
||||
# verify clean stop (exit code 0)
|
||||
dockerResultExit=$(docker inspect -f '{{ .State.ExitCode }}' \
|
||||
${COMPOSE_PROJECT_NAME}_${2}-mailcow_1)
|
||||
elif [ "$1" = "start" ]; then
|
||||
echo -e "${op}${stamp} Starting ${2}-mailcow container...${normal}" \
|
||||
>> "$logFile"
|
||||
docker-compose start ${2}-mailcow 2>> "$logFile"
|
||||
# verify
|
||||
dockerResultState=$(docker inspect -f '{{ .State.Running }}' \
|
||||
${COMPOSE_PROJECT_NAME}_${2}-mailcow_1)
|
||||
fi
|
||||
containerName="$(docker ps --format '{{ .Names }}' --filter name=${COMPOSE_PROJECT_NAME}_${2}-mailcow_1)"
|
||||
|
||||
# determine action to take
|
||||
if [ "$1" = "stop" ]; then
|
||||
echo -e "${op}[$(stamp)] Stopping ${2}-mailcow container...${normal}" \
|
||||
>> "$logFile"
|
||||
docker-compose stop --timeout ${dockerStopTimeout} ${2}-mailcow \
|
||||
2>> "$logFile"
|
||||
# verify container stopped (should return true)
|
||||
dockerResultState="$(docker inspect -f '{{ .State.Running }}' $containerName)"
|
||||
# verify clean stop (exit code 0)
|
||||
dockerResultExit="$(docker inspect -f '{{ .State.ExitCode }}' $containerName)"
|
||||
elif [ "$1" = "start" ]; then
|
||||
echo -e "${op}[$(stamp)] Starting ${2}-mailcow container...${normal}" \
|
||||
>> "$logFile"
|
||||
docker-compose start ${2}-mailcow 2>> "$logFile"
|
||||
# verify
|
||||
dockerResultState="$(docker inspect -f '{{ .State.Running }}' $containerName)"
|
||||
fi
|
||||
}
|
||||
|
||||
### End of Functions ###
|
||||
@@ -257,9 +257,6 @@ scriptPath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
scriptName="$( basename ${0} )"
|
||||
logFile="$scriptPath/${scriptName%.*}.log"
|
||||
|
||||
# Set default mailcow configuration filename
|
||||
mailcowConfigFile=mailcow.conf
|
||||
|
||||
# Set default docker-compose filename
|
||||
dockerComposeFile=docker-compose.yml
|
||||
|
||||
@@ -380,8 +377,8 @@ while getopts ':l:v5:w:b:m:d:1:2:' PARAMS; do
|
||||
borgDetails="${OPTARG%/}"
|
||||
;;
|
||||
m)
|
||||
# name of mailcow configuration file
|
||||
mailcowConfigFile="${OPTARG}"
|
||||
# full path to mailcow.conf configuration file
|
||||
mailcowConfigFilePath="${OPTARG%/}"
|
||||
;;
|
||||
d)
|
||||
# name of docker-compose configuration file
|
||||
@@ -411,20 +408,33 @@ if [ $(id -u) -ne 0 ]; then
|
||||
exit 3
|
||||
fi
|
||||
|
||||
## Find mailcow configuration file so additional variables can be read
|
||||
mailcowConfigFilePath=$( find / -mount -name "$mailcowConfigFile" -print )
|
||||
## verify mailcow.conf location provided
|
||||
if [ -z "$mailcowConfigFilePath" ]; then
|
||||
echo -e "\n${err}Could not locate the specified mailcow configuration" \
|
||||
"file: ${lit}${mailcowConfigFile}${normal}"
|
||||
echo -e "\n${err}You MUST provide the full path to your mailcow.conf" \
|
||||
"configuration file. Exiting.${normal}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## Find docker-compose file using mailcow configuration file path as a reference
|
||||
mailcowPath="${mailcowConfigFilePath%/$mailcowConfigFile*}"
|
||||
dockerComposeFilePath="$mailcowPath/$dockerComposeFile"
|
||||
checkExist ff "$dockerComposeFilePath"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = 1 ]; then
|
||||
## verify mailcow.conf and extract path
|
||||
if checkExist ff "$mailcowConfigFilePath"; then
|
||||
# extract directory name
|
||||
case $mailcowConfigFilePath in
|
||||
*/*)
|
||||
mailcowPath=${mailcowConfigFilePath%/*}
|
||||
;;
|
||||
*)
|
||||
mailcowPath="."
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo -e "\n${err}Could not locate the specified mailcow configuration" \
|
||||
"file: ${lit}${mailcowConfigFilePath}${normal}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# verify docker-compose.yml exists at location of mailcow.conf (standard setup)
|
||||
dockerComposeFilePath="${mailcowPath}/${dockerComposeFile}"
|
||||
if ! checkExist ff "$dockerComposeFilePath"; then
|
||||
echo -e "\n${err}Could not locate docker-compose configuration file:" \
|
||||
"${lit}${dockerComposeFilePath}${normal}"
|
||||
exit 1
|
||||
@@ -442,15 +452,16 @@ fi
|
||||
|
||||
|
||||
### Log start of script operations
|
||||
echo -e "${note}${stamp} --- Start $scriptName execution ---${normal}" \
|
||||
echo -e "${note}[$(stamp)] --- Start $scriptName execution ---${normal}" \
|
||||
>> "$logFile"
|
||||
echo -e "${info}${stamp} -- [INFO] using ${lit}${mailcowConfigFilePath}" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] using ${lit}${mailcowConfigFilePath}" \
|
||||
>> "$logFile"
|
||||
echo -e "${info}${stamp} -- [INFO] using ${lit}${dockerComposeFilePath}" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] using ${lit}${dockerComposeFilePath}" \
|
||||
>> "$logFile"
|
||||
|
||||
|
||||
### Import additional variables from mailcow configuration file
|
||||
source "${mailcowConfigFilePath}"
|
||||
source "$mailcowConfigFilePath"
|
||||
|
||||
### Export PATH so this script can access all docker and docker-compose commands
|
||||
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
@@ -472,7 +483,7 @@ dockerVolumeCrypt=$(docker volume inspect -f '{{ .Mountpoint }}' ${COMPOSE_PROJE
|
||||
### Create sqlDump temporary directory and sqlDumpFile name
|
||||
sqlDumpDir=$( mktemp -d )
|
||||
sqlDumpFile="backup-`date +%Y%m%d_%H%M%S`.sql"
|
||||
echo -e "${info}${stamp} -- [INFO] mySQL dump file will be stored" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] mySQL dump file will be stored" \
|
||||
"at: ${lit}${sqlDumpDir}/${sqlDumpFile}${normal}" >> "$logFile"
|
||||
|
||||
|
||||
@@ -485,9 +496,9 @@ echo -e "${info}${stamp} -- [INFO] mySQL dump file will be stored" \
|
||||
## Check if webroot has been specified, if not, skip this entire section since there is nowhere to copy the 503 file.
|
||||
if [ -z "$webroot" ]; then
|
||||
# no webroot path provided
|
||||
echo -e "${info}${stamp} -- [INFO] ${warn503} --${normal}" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] ${warn503} --${normal}" \
|
||||
>> "$logFile"
|
||||
exitWarn+=("${stamp}_5031")
|
||||
exitWarn+=("[$(stamp)]_5031")
|
||||
clean503=0
|
||||
else
|
||||
# verify webroot actually exists
|
||||
@@ -495,41 +506,41 @@ else
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "1" ]; then
|
||||
# webroot directory specified could not be found
|
||||
echo -e "${info}${stamp} -- [INFO] ${warn503} --${normal}" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] ${warn503} --${normal}" \
|
||||
>> "$logFile"
|
||||
exitWarn+=("${stamp}_5032")
|
||||
exitWarn+=("[$(stamp)]_5032")
|
||||
clean503=0
|
||||
else
|
||||
# webroot exists
|
||||
echo -e "${op}${stamp} Using webroot: ${lit}${webroot}${normal}" \
|
||||
echo -e "${op}[$(stamp)] Using webroot: ${lit}${webroot}${normal}" \
|
||||
>> "$logFile"
|
||||
# Verify 503 file existance at given path
|
||||
checkExist ff "$err503Path"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "1" ]; then
|
||||
# 503 file could not be found
|
||||
echo -e "${info}${stamp} -- [INFO] ${warn503} --${normal}" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] ${warn503} --${normal}" \
|
||||
>> "$logFile"
|
||||
exitWarn+=("${stamp}_5033")
|
||||
exitWarn+=("[$(stamp)]_5033")
|
||||
clean503=0
|
||||
else
|
||||
# 503 file exists and webroot is valid. Let's copy it!
|
||||
echo -e "${op}${stamp} ${err503File} found at ${lit}${err503Path}" \
|
||||
echo -e "${op}[$(stamp)] ${err503File} found at ${lit}${err503Path}" \
|
||||
"${normal}" >> "$logFile"
|
||||
echo -e "${op}${stamp} Copying 503 error page to webroot..." \
|
||||
echo -e "${op}[$(stamp)] Copying 503 error page to webroot..." \
|
||||
"${normal}" >> "$logFile"
|
||||
cp "${err503Path}" "$webroot/" >> "$logFile" 2>&1
|
||||
copyResult="$?"
|
||||
# verify copy was successful
|
||||
if [ "$copyResult" = "1" ]; then
|
||||
# copy was unsuccessful
|
||||
echo -e "${info}${stamp} -- [INFO] ${warn503} --${normal}" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] ${warn503} --${normal}" \
|
||||
>> "$logFile"
|
||||
exitWarn+=("${stamp}_5035")
|
||||
exitWarn+=("[$(stamp)]_5035")
|
||||
clean503=0
|
||||
else
|
||||
# copy was successful
|
||||
echo -e "${info}${stamp} -- [INFO] 503 error page" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] 503 error page" \
|
||||
"successfully copied to webroot --${normal}" >> "$logFile"
|
||||
clean503=1
|
||||
fi
|
||||
@@ -549,10 +560,10 @@ cd "$mailcowPath"
|
||||
operateDocker stop postfix
|
||||
# process result
|
||||
if [ "$dockerResultState" = "false" ] && [ "$dockerResultExit" -eq 0 ]; then
|
||||
echo -e "${info}${stamp} -- [INFO] Postfix container stopped --${normal}" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] Postfix container stopped --${normal}" \
|
||||
>> "$logFile"
|
||||
else
|
||||
exitError+=("${stamp}_101")
|
||||
exitError+=("[$(stamp)]_101")
|
||||
cleanup
|
||||
quit
|
||||
fi
|
||||
@@ -560,62 +571,77 @@ fi
|
||||
operateDocker stop dovecot
|
||||
# process result
|
||||
if [ "$dockerResultState" = "false" ] && [ "$dockerResultExit" -eq 0 ]; then
|
||||
echo -e "${info}${stamp} -- [INFO] Dovecot container stopped --${normal}" \
|
||||
echo -e "${info}[$(stamp)] -- [INFO] Dovecot container stopped --${normal}" \
|
||||
>> "$logFile"
|
||||
else
|
||||
exitError+=("${stamp}_102")
|
||||
exitError+=("[$(stamp)]_102")
|
||||
cleanup
|
||||
quit
|
||||
fi
|
||||
|
||||
|
||||
### Dump SQL
|
||||
echo -e "${op}${stamp} Dumping mailcow SQL database...${normal}" >> "$logFile"
|
||||
docker-compose exec mysql-mailcow mysqldump --default-character-set=utf8mb4 -u${DBUSER} -p${DBPASS} ${DBNAME} > "$sqlDumpDir/$sqlDumpFile" 2>> "$logFile"
|
||||
## error checking sqldump within the container in a cron-friendly manner is a
|
||||
## nightmare, so let's just see if a non-empty file with the expected name was
|
||||
## created
|
||||
echo -e "${op}[$(stamp)] Dumping mailcow SQL database...${normal}" >> "$logFile"
|
||||
docker-compose exec -T mysql-mailcow mysqldump --default-character-set=utf8mb4 \
|
||||
-u${DBUSER} -p${DBPASS} ${DBNAME} > "$sqlDumpDir/$sqlDumpFile" \
|
||||
2>> "$logFile"
|
||||
dumpResult=$(docker-compose exec -T mysql-mailcow echo "$?")
|
||||
## very mysqldump completed successfully
|
||||
if [ "$dumpResult" = "0" ]; then
|
||||
echo -e "${info}[$(stamp)] -- [INFO] mySQLdump completed successfully --" \
|
||||
"${normal}" >> "$logFile"
|
||||
else
|
||||
exitError+=("[$(stamp)]_201")
|
||||
fi
|
||||
## verify the dump file was actually written to disk
|
||||
checkExist fs "$sqlDumpDir/$sqlDumpFile"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "0" ]; then
|
||||
echo -e "${ok}${stamp} -- [SUCCESS] SQL successfully dumped --" \
|
||||
echo -e "${ok}[$(stamp)] -- [SUCCESS] SQL successfully dumped --" \
|
||||
"${normal}" >> "$logFile"
|
||||
else
|
||||
exitError+=("${stamp}_201")
|
||||
exitError+=("[$(stamp)]_201")
|
||||
fi
|
||||
|
||||
### Save redis state
|
||||
## Delete any existing redis dump file otherwise our check will be useless
|
||||
echo -e "${op}${stamp} Cleaning up old redis state backup...${normal}" \
|
||||
## Delete any existing redis dump file otherwise our file check will be useless
|
||||
echo -e "${op}[$(stamp)] Cleaning up old redis state backup...${normal}" \
|
||||
>> "$logFile"
|
||||
checkExist ff "$dockerVolumeRedis/dump.rdb"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "0" ]; then
|
||||
echo -e "${lit}${stamp} Old redis backup found.${normal}" >> "$logFile"
|
||||
echo -e "${op}Deleting...${normal}" >> "$logFile"
|
||||
echo -e "${lit}[$(stamp)] Old redis backup found. ${op}Deleting..." \
|
||||
"${normal}" >> "$logFile"
|
||||
rm -f "$dockerVolumeRedis/dump.rdb" 2>> "$logFile"
|
||||
echo -e "${op}${stamp}...done${normal}" >> "$logFile"
|
||||
echo -e "${op}[$(stamp)] ...done${normal}" >> "$logFile"
|
||||
else
|
||||
echo -e "${op}${stamp} No old redis backup found${normal}" \
|
||||
echo -e "${op}[$(stamp)] No old redis backup found${normal}" \
|
||||
>> "$logFile"
|
||||
fi
|
||||
## Export redis
|
||||
echo -e "${op}${stamp} Saving redis state information...${normal}" >> "$logFile"
|
||||
docker-compose exec redis-mailcow redis-cli save >> "$logFile" 2>&1
|
||||
## although redis returns an 'OK' if successful, seemingly nothing can test for
|
||||
## this... so let's just verify the dump file was written to disk
|
||||
echo -e "${op}[$(stamp)] Saving redis state information...${normal}" >> "$logFile"
|
||||
docker-compose exec -T redis-mailcow redis-cli save >> "$logFile" 2>&1
|
||||
saveResult=$(docker-compose exec -T redis-mailcow echo "$?")
|
||||
# verify save operation completed successfully
|
||||
if [ "$saveResult" = "0" ]; then
|
||||
echo -e "${info}[$(stamp)] -- [INFO] redis save-state successful --" \
|
||||
"${normal}" >> "$logFile"
|
||||
else
|
||||
exitError+=("[$(stamp)]_202")
|
||||
fi
|
||||
## verify save-file written to disk
|
||||
checkExist fs "$dockerVolumeRedis/dump.rdb"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "0" ]; then
|
||||
echo -e "${ok}${stamp} -- [SUCCESS] redis state saved --${normal}" \
|
||||
echo -e "${ok}[$(stamp)] -- [SUCCESS] redis state saved --${normal}" \
|
||||
>> "$logFile"
|
||||
else
|
||||
exitError+=("${stamp}_202")
|
||||
exitError+=("[$(stamp)]_202")
|
||||
fi
|
||||
|
||||
|
||||
### Call borgbackup to copy actual files
|
||||
echo -e "${op}${stamp} Pre-backup tasks completed, calling borgbackup..." \
|
||||
echo -e "${op}[$(stamp)] Pre-backup tasks completed, calling borgbackup..." \
|
||||
"${normal}" >> "$logFile"
|
||||
|
||||
## Get borgbackup settings and repo details
|
||||
@@ -624,10 +650,10 @@ mapfile -t borgConfig < "$borgDetails"
|
||||
## check if any required borg configuration variables in defintion file are
|
||||
## empty and exit with error, otherwise, map array items to variables
|
||||
# check: borg base directory
|
||||
echo -e "${op}${stamp} Verifying supplied borg configuration variables..." \
|
||||
echo -e "${op}[$(stamp)] Verifying supplied borg configuration variables..." \
|
||||
"${normal}" >> "$logFile"
|
||||
if [ -z "${borgConfig[0]}" ]; then
|
||||
exitError+=("${stamp}_210")
|
||||
exitError+=("[$(stamp)]_210")
|
||||
cleanup
|
||||
quit
|
||||
else
|
||||
@@ -636,16 +662,16 @@ else
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "1" ]; then
|
||||
# borg base directory specified could not be found
|
||||
exitError+=("${stamp}_210")
|
||||
exitError+=("[$(stamp)]_210")
|
||||
cleanup
|
||||
quit
|
||||
fi
|
||||
echo -e "${op}${stamp} Borg base dir... OK${normal}" >> "$logFile"
|
||||
echo -e "${op}[$(stamp)] Borg base dir... OK${normal}" >> "$logFile"
|
||||
export BORG_BASE_DIR="${borgConfig[0]%/}"
|
||||
fi
|
||||
# check: path to SSH keyfile
|
||||
if [ -z "${borgConfig[1]}" ]; then
|
||||
exitError+=("${stamp}_211")
|
||||
exitError+=("[$(stamp)]_211")
|
||||
cleanup
|
||||
quit
|
||||
else
|
||||
@@ -653,28 +679,28 @@ else
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = 1 ]; then
|
||||
# SSH keyfile specified could not be found
|
||||
exitError+=("${stamp}_211")
|
||||
exitError+=("[$(stamp)]_211")
|
||||
cleanup
|
||||
quit
|
||||
fi
|
||||
echo -e "${op}${stamp} Borg SSH key... OK${normal}" >> "$logFile"
|
||||
echo -e "${op}[$(stamp)] Borg SSH key... OK${normal}" >> "$logFile"
|
||||
export BORG_RSH="ssh -i ${borgConfig[1]}"
|
||||
fi
|
||||
# check: name of borg repo
|
||||
if [ -z "${borgConfig[2]}" ]; then
|
||||
exitError+=("${stamp}_212")
|
||||
exitError+=("[$(stamp)]_212")
|
||||
cleanup
|
||||
quit
|
||||
else
|
||||
echo -e "${op}${stamp} Borg REPO name... OK${normal}" >> "$logFile"
|
||||
echo -e "${op}[$(stamp)] Borg REPO name... OK${normal}" >> "$logFile"
|
||||
export BORG_REPO="${borgConfig[2]}"
|
||||
fi
|
||||
# repo password
|
||||
if [ -n "${borgConfig[3]}" ]; then
|
||||
echo -e "${op}${stamp} Borg SSH/REPO password... OK${normal}" >> "$logFile"
|
||||
echo -e "${op}[$(stamp)] Borg SSH/REPO password... OK${normal}" >> "$logFile"
|
||||
export BORG_PASSPHRASE="${borgConfig[3]}"
|
||||
else
|
||||
exitWarn+=("${stamp}_2111")
|
||||
exitWarn+=("[$(stamp)]_2111")
|
||||
# if the password was omitted by mistake, export a dummy password so borg
|
||||
# fails with an error instead of sitting and waiting for input
|
||||
export BORG_PASSPHRASE="DummyPasswordSoBorgFails"
|
||||
@@ -687,32 +713,32 @@ borgExclude="${borgConfig[5]}"
|
||||
borgPrune="${borgConfig[6]}"
|
||||
# export: borg remote path (if not blank)
|
||||
if [ -n "${borgConfig[7]}" ]; then
|
||||
echo -e "${op}${stamp} Borg REMOTE path... OK${normal}" >> "$logFile"
|
||||
echo -e "${op}[$(stamp)] Borg REMOTE path... OK${normal}" >> "$logFile"
|
||||
export BORG_REMOTE_PATH="${borgConfig[7]}"
|
||||
else
|
||||
exitWarn+=("${stamp}_2112")
|
||||
exitWarn+=("[$(stamp)]_2112")
|
||||
fi
|
||||
|
||||
## If borgXtra exists, map contents to an array variable
|
||||
if [ -n "$borgXtra" ]; then
|
||||
echo -e "${op}${stamp} Processing referenced extra files list for" \
|
||||
echo -e "${op}[$(stamp)] Processing referenced extra files list for" \
|
||||
"borgbackup to include in backup${normal}" >> "$logFile"
|
||||
checkExist ff "$borgXtra"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "0" ]; then
|
||||
echo -e "${op}${stamp} Found ${lit}${borgXtra}${normal}" >> "$logFile"
|
||||
echo -e "${op}[$(stamp)] Found ${lit}${borgXtra}${normal}" >> "$logFile"
|
||||
mapfile -t xtraFiles < "$borgXtra"
|
||||
echo -e "${op}${stamp} Processed extra files list for inclusion in" \
|
||||
echo -e "${op}[$(stamp)] Processed extra files list for inclusion in" \
|
||||
"borgbackup${normal}" >> "$logFile"
|
||||
else
|
||||
exitWarn+=("${stamp}_2113")
|
||||
exitWarn+=("[$(stamp)]_2113")
|
||||
fi
|
||||
else
|
||||
# no extra locations specified
|
||||
echo -e "${op}${stamp} No additional locations specified for backup." \
|
||||
echo -e "${op}[$(stamp)] No additional locations specified for backup." \
|
||||
"Only Mailcow data and config files will be backed up.${normal}" \
|
||||
>> "$logFile"
|
||||
exitWarn+=("${stamp}_2116")
|
||||
exitWarn+=("[$(stamp)]_2116")
|
||||
fi
|
||||
|
||||
## Check if borgExclude exists since borg will throw an error if it's missing
|
||||
@@ -720,16 +746,16 @@ if [ -n "$borgExclude" ]; then
|
||||
checkExist ff "$borgExclude"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "0" ]; then
|
||||
echo -e "${op}${stamp} Found ${lit}${borgExclude}${normal}" \
|
||||
echo -e "${op}[$(stamp)] Found ${lit}${borgExclude}${normal}" \
|
||||
>> "$logFile"
|
||||
else
|
||||
# file not found, unset the variable so it's like it was not specified
|
||||
# in the first place and continue with backup
|
||||
unset borgExclude
|
||||
exitWarn+=("${stamp}_2114")
|
||||
exitWarn+=("[$(stamp)]_2114")
|
||||
fi
|
||||
else
|
||||
echo -e "${op}${stamp} Exclusion pattern file not specified." \
|
||||
echo -e "${op}[$(stamp)] Exclusion pattern file not specified." \
|
||||
"No exclusions will be processed${normal}" >> "$logFile"
|
||||
fi
|
||||
|
||||
@@ -740,13 +766,13 @@ fi
|
||||
## the 'noexec' option for security. Thus, we will use/create a 'tmp' folder
|
||||
## within the BORG_BASE_DIR and instruct python to use that instead of /tmp
|
||||
# check if BORG_BASE_DIR/tmp exists, if not, create it
|
||||
echo -e "${op}${stamp} Checking for tmp directory at ${lit}${BORG_BASE_DIR}" \
|
||||
echo -e "${op}[$(stamp)] Checking for tmp directory at ${lit}${BORG_BASE_DIR}" \
|
||||
"${normal}" >> "$logFile"
|
||||
checkExist fd "$BORG_BASE_DIR/tmp"
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "1" ]; then
|
||||
# folder not found
|
||||
echo -e "${op}${stamp} tmp folder not found... creating${lit}" \
|
||||
echo -e "${op}[$(stamp)] tmp folder not found... creating${lit}" \
|
||||
"${BORG_BASE_DIR}/tmp${normal}" >> "$logFile"
|
||||
mkdir "$BORG_BASE_DIR/tmp" 2>> "$logFile"
|
||||
# verify folder created
|
||||
@@ -754,17 +780,17 @@ if [ "$checkResult" = "1" ]; then
|
||||
checkResult="$?"
|
||||
if [ "$checkResult" = "0" ]; then
|
||||
# folder exists
|
||||
echo -e "${op}${stamp} tmp folder created within borg base directory" \
|
||||
echo -e "${op}[$(stamp)] tmp folder created within borg base directory" \
|
||||
"${normal}" >> "$logFile"
|
||||
else
|
||||
# problem creating folder and script will exit
|
||||
exitError+=("${stamp}_215")
|
||||
exitError+=("[$(stamp)]_215")
|
||||
cleanup
|
||||
quit
|
||||
fi
|
||||
else
|
||||
# folder found
|
||||
echo -e "${op}${stamp} tmp folder found within borg base directory" \
|
||||
echo -e "${op}[$(stamp)] tmp folder found within borg base directory" \
|
||||
"${normal}" >> "$logFile"
|
||||
fi
|
||||
# export TMPDIR environment variable
|
||||
@@ -775,78 +801,78 @@ export TMPDIR="${BORG_BASE_DIR}/tmp"
|
||||
# commandline depends on whether borgExclude is empty or not
|
||||
if [ -z "$borgExclude" ]; then
|
||||
# borgExclude is empty
|
||||
echo -e "${bold}${op}${stamp} Executing borg without exclusions${normal}" \
|
||||
echo -e "${bold}${op}[$(stamp)] Executing borg without exclusions${normal}" \
|
||||
>> "$logFile"
|
||||
borg --show-rc create ${borgCreateParams} ::`date +%Y-%m-%d_%H%M%S` \
|
||||
${xtraFiles[@]} \
|
||||
${sqlDumpDir} \
|
||||
${dockerVolumeMail} ${dockerVolumeRspamd} ${dockerVolumePostfix} \
|
||||
${dockerVolumeRedis} ${dockerVolumeCrypt} \
|
||||
"${xtraFiles[@]}" \
|
||||
"${sqlDumpDir}" \
|
||||
"${dockerVolumeMail}" "${dockerVolumeRspamd}" "${dockerVolumePostfix}" \
|
||||
"${dockerVolumeRedis}" "${dockerVolumeCrypt}" \
|
||||
2>> "$logFile"
|
||||
else
|
||||
# borgExclude is not empty
|
||||
echo -e "${bold}${op}${stamp} Executing borg with exclusions${normal}" \
|
||||
echo -e "${bold}${op}[$(stamp)] Executing borg with exclusions${normal}" \
|
||||
>> "$logFile"
|
||||
borg --show-rc create ${borgCreateParams} --exclude-from ${borgExclude} \
|
||||
borg --show-rc create ${borgCreateParams} --exclude-from "${borgExclude}" \
|
||||
::`date +%Y-%m-%d_%H%M%S` \
|
||||
${xtraFiles[@]} \
|
||||
${sqlDumpDir} \
|
||||
${dockerVolumeMail} ${dockerVolumeRspamd} ${dockerVolumePostfix} \
|
||||
${dockerVolumeRedis} ${dockerVolumeCrypt} \
|
||||
"${xtraFiles[@]}" \
|
||||
"${sqlDumpDir}" \
|
||||
"${dockerVolumeMail}" "${dockerVolumeRspamd}" "${dockerVolumePostfix}" \
|
||||
"${dockerVolumeRedis}" "${dockerVolumeCrypt}" \
|
||||
2>> "$logFile"
|
||||
fi
|
||||
|
||||
## Check status of borg operation
|
||||
borgResult="$?"
|
||||
if [ "$borgResult" -eq 0 ]; then
|
||||
echo -e "${ok}${stamp} -- [SUCCESS] Borg backup completed successfully --" \
|
||||
echo -e "${ok}[$(stamp)] -- [SUCCESS] Borg backup completed successfully --" \
|
||||
"${normal}" >> "$logFile"
|
||||
elif [ "$borgResult" -eq 1 ]; then
|
||||
exitWarn+=("${stamp}_2200")
|
||||
exitWarn+=("[$(stamp)]_2200")
|
||||
elif [ "$borgResult" -ge 2 ]; then
|
||||
exitError+=("${stamp}_220")
|
||||
exitError+=("[$(stamp)]_220")
|
||||
cleanup
|
||||
quit
|
||||
else
|
||||
exitWarn+=("${stamp}_2201")
|
||||
exitWarn+=("[$(stamp)]_2201")
|
||||
fi
|
||||
|
||||
## Generate and execute borg prune
|
||||
# command depends on whether or not parameters have been defined
|
||||
if [ -n "$borgPrune" ]; then
|
||||
# parameters defined
|
||||
echo -e "${bold}${op}${stamp} Executing borg prune operation${normal}" \
|
||||
echo -e "${bold}${op}[$(stamp)] Executing borg prune operation${normal}" \
|
||||
>> "$logFile"
|
||||
borg prune --show-rc -v ${borgPruneParams} ${borgPrune} \
|
||||
2>> "$logFile"
|
||||
# check return-status
|
||||
pruneResult="$?"
|
||||
if [ "$pruneResult" -eq 0 ]; then
|
||||
echo -e "${ok}${stamp} -- [SUCCESS] Borg prune completed successfully" \
|
||||
echo -e "${ok}[$(stamp)] -- [SUCCESS] Borg prune completed successfully" \
|
||||
"--${normal}" >> "$logFile"
|
||||
elif [ "$pruneResult" -eq 1 ]; then
|
||||
exitWarn+=("${stamp}_2210")
|
||||
exitWarn+=("[$(stamp)]_2210")
|
||||
elif [ "$pruneResult" -ge 2 ]; then
|
||||
exitError+=("${stamp}_221")
|
||||
exitError+=("[$(stamp)]_221")
|
||||
else
|
||||
exitWarn+=("${stamp}_2212")
|
||||
exitWarn+=("[$(stamp)]_2212")
|
||||
fi
|
||||
else
|
||||
# parameters not defined... skip pruning
|
||||
exitWarn+=("${stamp}_2115")
|
||||
exitWarn+=("[$(stamp)]_2115")
|
||||
fi
|
||||
|
||||
|
||||
### borgbackup completed
|
||||
echo -e "${op}${stamp} Borgbackup completed... begin cleanup" \
|
||||
echo -e "${op}[$(stamp)] Borgbackup completed... begin cleanup" \
|
||||
"${normal}" >> "$logFile"
|
||||
|
||||
|
||||
### Exit script
|
||||
echo -e "${bold}${op}${stamp} ***Normal exit process***${normal}" \
|
||||
echo -e "${bold}${op}[$(stamp)] ***Normal exit process***${normal}" \
|
||||
>> "$logFile"
|
||||
cleanup
|
||||
echo -e "${bold}${ok}${stamp} -- [SUCCESS] All processes completed" \
|
||||
echo -e "${bold}${ok}[$(stamp)] -- [SUCCESS] All processes completed" \
|
||||
"successfully --${normal}" >> "$logFile"
|
||||
quit
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<path to borgbackup base directory> /var/borgbackup
|
||||
<path to SSH private key for repo> /var/borgbackup/sshPrivate.key
|
||||
<connection string to remote repo> user@server-number.rsync.net:repoName/
|
||||
<password for SSH key/repo> pAsSwOrd
|
||||
<path to file listing extra files> /root/scripts/xtraLocations.borg
|
||||
<path to file with exclusions> /root/scripts/excludeLocations.borg
|
||||
<purge timeframe options> --keep-within=7d --keep-daily=30 --keep-weekly=12 --keep-monthly=-1
|
||||
<location of borg remote instance> borg1
|
||||
<path to borgbackup base directory> /var/borgbackup
|
||||
<path to SSH private key for remote server> /var/borgbackup/sshPrivate.key
|
||||
<connection string to remote repo> user@servername.tld:repoName/
|
||||
<password for repo> pAsSwOrd
|
||||
<path to file listing extra files> /root/scripts/xtraLocations.borg
|
||||
<path to file with exclusions> /root/scripts/excludeLocations.borg
|
||||
<purge timeframe options> --keep-within=7d --keep-daily=30 --keep-weekly=12 --keep-monthly=-1
|
||||
<location of borg remote instance> borg1
|
||||
Reference in New Issue
Block a user