808 lines
29 KiB
Bash
Executable File
808 lines
29 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
|
|
### Text formatting presets
|
|
normal="\e[0m"
|
|
bold="\e[1m"
|
|
default="\e[39m"
|
|
err="\e[1;31m"
|
|
warn="\e[1;93m"
|
|
ok="\e[32m"
|
|
lit="\e[93m"
|
|
op="\e[39m"
|
|
info="\e[96m"
|
|
note="\e[95m"
|
|
|
|
|
|
### Functions ###
|
|
|
|
function checkExist {
|
|
if [ "$1" = "ff" ]; then
|
|
# find file
|
|
if [ -f "$2" ]; then
|
|
# found
|
|
return 0
|
|
else
|
|
# not found
|
|
return 1
|
|
fi
|
|
elif [ "$1" = "fd" ]; then
|
|
# find directory
|
|
if [ -d "$2" ]; then
|
|
# found
|
|
return 0
|
|
else
|
|
# not found
|
|
return 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
### cleanup - cleanup files and directories created by this script
|
|
function cleanup {
|
|
## remove SQL dump file and directory
|
|
rm -rf "$sqlDumpDir" >> "$logFile" 2>&1
|
|
# verify directory is gone
|
|
checkExist fd "$sqlDumpDir"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = "0" ]; then
|
|
# directory still exists
|
|
exitWarn+=("[$(stamp)]_111")
|
|
else
|
|
# directory removed
|
|
echo -e "${op}[$(stamp)] Removed SQL temp directory${normal}" \
|
|
>> "$logFile"
|
|
fi
|
|
|
|
## remove 503 error page
|
|
# 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"
|
|
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")
|
|
else
|
|
# file removed
|
|
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," \
|
|
"nothing to cleanup" >> "$logFile"
|
|
fi
|
|
|
|
## Restart Seafile services
|
|
svcSeafile start
|
|
}
|
|
|
|
### scriptHelp -- display usage information for this script
|
|
function scriptHelp {
|
|
echo -e "${bold}${note}\n${scriptName} usage instructions:\n${normal}"
|
|
echo -e "${default}This script performs a backup of your Seafile system" \
|
|
"assuming a fairly standard"
|
|
echo -e "baremetal set up such as outlined at${lit}" \
|
|
"https://mytechiethoughts.com${default}."
|
|
echo -e "Details about this script can be found at that site."
|
|
echo -e "${bold}\nThe script performs the following tasks:" \
|
|
"${normal}${default}"
|
|
echo -e "1. Stops Seafile services and copies a 503 error page to" \
|
|
"your webroot to"
|
|
echo -e "\tprevent access to Seafile during the backup."
|
|
echo -e "2. Dumps Seafile SQL database to a temporary directory."
|
|
echo -e "3. Invokes borgbackup to backup your SQL data, Seafile program" \
|
|
"and data files,"
|
|
echo -e "\tand any other files you specify."
|
|
echo -e "3. Prunes old backups from borgbackup repo."
|
|
echo -e "4. Removes 503 error page, if necessary, and cleans up."
|
|
echo -e "\nThe readme file included in this script's git repo contains" \
|
|
"detailed usage"
|
|
echo -e "information. The following is a brief summary:\n"
|
|
echo -e "${bold}${note}Mandatory parameters:${normal}${default}"
|
|
echo -e "${lit}\n-d, Seafile data directory${default}"
|
|
echo -e "This is the physical location of your Seafile data."
|
|
echo -e "${lit}\n-u, Seafile system user account${default}"
|
|
echo -e "The system account Seafile is running under. Some actions must" \
|
|
"run as this"
|
|
echo -e "user due to file ownership restrictions."
|
|
echo -e "${bold}${note}\nOptional parameters:${normal}${default}"
|
|
echo -e "${lit}\n-5, Location of 503 error page file${default}"
|
|
echo -e "FULL PATH to the 503 error page HTML file you want copied to" \
|
|
"your webroot to"
|
|
echo -e "inform users the server is down during the backup. If you don't" \
|
|
"specify a path/"
|
|
echo -e "file, the default will be used. If the default cannot be found," \
|
|
"a warning will"
|
|
echo -e "be logged and the script will continue."
|
|
echo -e "${info}Default: ScriptPath/503.html${default}"
|
|
echo -e "${lit}\n-b, Location of file with borg repo details${default}"
|
|
echo -e "FULL PATH to the plain text file containing all information" \
|
|
"needed to connect"
|
|
echo -e "and process your borg repo. Details on the structure of this" \
|
|
"file are in the"
|
|
echo -e "readme and on ${lit}https://mytechiethoughts.com${default}"
|
|
echo -e "${info}Default: ScriptPath/nc_borg.details${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 structured in"
|
|
echo -e "a way easy for log parsers (like Logwatch) to read."
|
|
echo -e "${info}Default: ScriptPath/ScriptName.log${default}"
|
|
echo -e "${lit}\n-s, Location of file with mySQL details${default}"
|
|
echo -e "FULL PATH to the plain text file containing all information" \
|
|
"needed to connect"
|
|
echo -e "to your mySQL (mariaDB) server and Seafile database. Details" \
|
|
"on the structure"
|
|
echo -e "of this file are in the readme and on${lit}" \
|
|
"https://mytechiethoughts.com${default}"
|
|
echo -e "${info}Default: ScriptPath/nc_sql.details${default}"
|
|
echo -e "${lit}\n-v, Verbose output from borgbackup${default}"
|
|
echo -e "By default, this script will only log summary data from borg." \
|
|
"If you need/want"
|
|
echo -e "more detailed information, the verbose setting will list every" \
|
|
"file processed"
|
|
echo -e "along with their status. Note: Your log file can quickly get" \
|
|
"very very large"
|
|
echo -e "using this option!"
|
|
echo -e "${info}Default: NOT activated (standard logging)${default}"
|
|
echo -e "${lit}\n-w, webserver's webroot directory${default}"
|
|
echo -e "This is the location from which your webserver (NGINX, Apache," \
|
|
"etc.) physically"
|
|
echo -e "stores files to be served. This is NOT the configuration" \
|
|
"directory for your"
|
|
echo -e "webserver! It is the place where the actual" \
|
|
"HTML/PHP/CSS/JS/etc. files are"
|
|
echo -e "stored. NOTE: If you omit this option, then the entire 503 copy" \
|
|
"process will"
|
|
echo -e "be skipped regardless of the presence of a 503.html file. If" \
|
|
"you don't want to"
|
|
echo -e "use the 503 feature, omitting this is an easy way to skip it!"
|
|
echo -e "${info}Default: NONE${default}"
|
|
echo -e "${lit}\n-?, This help screen${default}\n"
|
|
echo -e "${bold}Please refer to the readme file and/or ${lit}https://mytechiethoughts.com${default}"
|
|
echo -e "for more information on this script.${normal}\n"
|
|
# exit with code 1 -- there is no use logging this
|
|
exit 1
|
|
}
|
|
|
|
### start and stop seafile services
|
|
function svcSeafile {
|
|
if [ "$1" = "start" ]; then
|
|
# start services
|
|
systemctl start seafile.service
|
|
statusSeaf=$?
|
|
systemctl start seahub.service
|
|
statusShub=$?
|
|
# check for errors
|
|
if [ $statusSeaf -eq 0 ] && [ $statusShub -eq 0 ]; then
|
|
echo -e "${info}[$(stamp)] -- [INFO] Seafile services started" \
|
|
"successfully --${normal}" >> "$logFile"
|
|
else
|
|
exitError+=("[$(stamp)] 100")
|
|
quit
|
|
fi
|
|
elif [ "$1" = "stop" ]; then
|
|
# stop services
|
|
systemctl stop seahub.service
|
|
statusShub=$?
|
|
systemctl stop seafile.service
|
|
statusSeaf=$?
|
|
# check for errors
|
|
if [ $statusSeaf -eq 0 ] && [ $statusShub -eq 0 ]; then
|
|
echo -e "${info}[$(stamp)] -- [INFO] Seafile services stopped" \
|
|
"successfully --${normal}" >> "$logFile"
|
|
else
|
|
# verify services are still actually running
|
|
pidShub=$(pgrep -f "seahub")
|
|
pidSeaf=$(pgrep -f seafile-controller)
|
|
# force stop seahub
|
|
if [ $pidShub ]; then
|
|
pkill -f "seahub"
|
|
exitWarn+=("[$(stamp)]_101")
|
|
fi
|
|
# force stop seafile
|
|
if [ $pidSeaf ]; then
|
|
pkill -f seafile-controller
|
|
exitWarn+=("[$(stamp)]_101")
|
|
fi
|
|
echo -e "${info}[$(stamp)] -- [INFO] Seafile services stopped" \
|
|
"successfully --${normal}" >> "$logFile"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
### generate dynamic timestamps
|
|
function stamp {
|
|
(date +%F" "%T)
|
|
}
|
|
|
|
### quit -- exit the script after logging any errors, warnings, etc.
|
|
function quit {
|
|
# list generated warnings, if any
|
|
if [ ${#exitWarn[@]} -gt 0 ]; then
|
|
echo -e "${warn}${scriptName} generated the following warnings:" \
|
|
"${normal}" >> "$logFile"
|
|
for warnCode in "${exitWarn[@]}"; do
|
|
warnStamp="${warnCode%%_*}"
|
|
warnValue="${warnCode##*_}"
|
|
echo -e "${warn}${warnStamp} -- [WARNING]" \
|
|
"${warningExplain[$warnValue]} (code: ${warnValue}) --" \
|
|
"${normal}" >> "$logFile"
|
|
done
|
|
fi
|
|
if [ -z "${exitError}" ]; then
|
|
# exit cleanly
|
|
echo -e "${note}[$(stamp)] --- ${scriptName} completed" \
|
|
"---${normal}" >> "$logFile"
|
|
exit 0
|
|
else
|
|
# list generated errors and explanations then exit script with code 2
|
|
echo -e "${err}${scriptName} generated the following errors:" \
|
|
"${normal}" >> "$logFile"
|
|
for errCode in "${exitError[@]}"; do
|
|
errStamp="${errCode%%_*}"
|
|
errValue="${errCode##*_}"
|
|
echo -e "${err}${errStamp} -- [ERROR] ${errorExplain[$errValue]}" \
|
|
"(code: ${errValue}) --${normal}" >> "$logFile"
|
|
done
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
### End of Functions ###
|
|
|
|
|
|
### Default parameters
|
|
|
|
# store the logfile in the same directory as this script using the script's name
|
|
# with the extension .log
|
|
scriptPath="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
scriptName="$( basename ${0} )"
|
|
logFile="$scriptPath/${scriptName%.*}.log"
|
|
|
|
# set default 503 error page name and location in scriptPath
|
|
err503Path="$scriptPath/503.html"
|
|
err503File="${err503Path##*/}"
|
|
|
|
# set default sqlDetails path to scriptPath
|
|
sqlDetails="$scriptPath/seaf_sql.details"
|
|
|
|
# set default borgDetails path to scriptPath
|
|
borgDetails="$scriptPath/seaf_borg.details"
|
|
|
|
# set borg parameters to 'normal' verbosity
|
|
borgCreateParams='--stats'
|
|
borgPruneParams='--list'
|
|
|
|
|
|
### initialize array variables
|
|
exitError=()
|
|
errorExplain=()
|
|
exitWarn=()
|
|
warningExplain=()
|
|
borgConfig=()
|
|
xtraFiles=()
|
|
|
|
### Error codes
|
|
errorExplain[100]="Could not start Seafile service(s)"
|
|
errorExplain[200]="Could not dump Seafile SQL databases"
|
|
errorExplain[210]="Invalid or non-existant borg base directory specified (borg backup details file)"
|
|
errorExplain[211]="Invalid or non-existant path to borg SSH keyfile (borg backup details file)"
|
|
errorExplain[212]="Name of borg repo was not specified (borg backup details file)"
|
|
errorExplain[215]="Could not find/create 'tmp' directory within borg base directory. Please manually create it and ensure it's writable"
|
|
errorExplain[220]="Borg exited with a critical error. Please check this script's logfile for details"
|
|
errorExplain[221]="Borg prune exited with ERRORS. Please check this script's logfile for details"
|
|
|
|
### Warning codes & messages
|
|
warningExplain[101]="Could not stop Seafile service(s) normally, had to force"
|
|
warningExplain[111]="Could not remove SQL dump file and directory, please remove manually"
|
|
warningExplain[5030]="Could not remove 503 error page. This MUST be removed manually before NGINX will serve webclients!"
|
|
warningExplain[5031]="No webroot path was specified (-w parameter missing)"
|
|
warningExplain[5032]="The specified webroot (-w parameter) could not be found"
|
|
warningExplain[5033]="No 503 error page could be found. If not using the default located in the script directory, then check your -5 parameter"
|
|
warningExplain[5035]="Error copying 503 error page to webroot"
|
|
warn503="Web users will NOT be informed the server is down!"
|
|
warningExplain[2111]="No password used for access to remote borg repo. This is an insecure configuration"
|
|
warningExplain[2112]="No remote borg instance specified. Operations will be slower in this configuration"
|
|
warningExplain[2113]="The specified file containing extra files for inclusion in borgbackup could not be found"
|
|
warningExplain[2114]="The specified file containing exclusion patterns for borgbackup could not be found. Backup was performed as though NO exclusions were defined"
|
|
warningExplain[2115]="No paramters provided for borg prune. No repo pruning has taken place. You should reconsider this decision to control the size/history of your backups"
|
|
warningExplain[2116]="No additional locations are specified for inclusion in backup. ONLY Seafile DATA will be backed up (no configuration, etc). If this is unintentional, check the inclusion file referenced in your borgbackup settings"
|
|
warningExplain[2200]="Borg completed with warnings. Please check this script's logfile for details"
|
|
warningExplain[2201]="Borg exited with an unknown return-code. Please check this script's logfile for details"
|
|
warningExplain[2210]="Borg prune exited with warnings. Please check this script's logfile for details"
|
|
warningExplain[2212]="Borg prune exited with an unknown return-code. Please check this script's logfile for details"
|
|
|
|
|
|
### Process script parameters
|
|
|
|
# If parameters are provided but don't start with '-' then show the help page
|
|
# and exit with an error
|
|
if [ -n "$1" ] && [[ ! "$1" =~ ^- ]]; then
|
|
# show script help page
|
|
scriptHelp
|
|
fi
|
|
|
|
# use GetOpts to process parameters
|
|
while getopts ':5:b:d:l:p:s:u:v:w:' PARAMS; do
|
|
case "$PARAMS" in
|
|
5)
|
|
# Full path to 503 error page
|
|
err503Path="${OPTARG%/}"
|
|
err503File="${err503Path##*/}"
|
|
;;
|
|
b)
|
|
# path to file containing borgbackup settings and details
|
|
borgDetails="${OPTARG%/}"
|
|
;;
|
|
d)
|
|
# Seafile data directory
|
|
dataDir="${OPTARG%/}"
|
|
;;
|
|
l)
|
|
# use provided location for logFile
|
|
logFile="${OPTARG%/}"
|
|
;;
|
|
p)
|
|
# Seafile program directory
|
|
seafDir="${OPTARG%/}"
|
|
;;
|
|
s)
|
|
# path to file containing SQL login details
|
|
sqlDetails="${OPTARG%/}"
|
|
;;
|
|
u)
|
|
# Seafile system user
|
|
seafUser="${OPTARG}"
|
|
;;
|
|
v)
|
|
# verbose output from Borg
|
|
borgCreateParams='--list --stats'
|
|
borgPruneParams='--list'
|
|
;;
|
|
w)
|
|
# path to webserver webroot to copy 503 error page
|
|
webroot="${OPTARG%/}"
|
|
;;
|
|
?)
|
|
# unrecognized parameters trigger scriptHelp
|
|
scriptHelp
|
|
;;
|
|
esac
|
|
done
|
|
|
|
|
|
### Verify script pre-requisites
|
|
|
|
## If not running as root, display error on console and exit
|
|
if [ $(id -u) -ne 0 ]; then
|
|
echo -e "\n${err}This script MUST be run as ROOT. Exiting.${normal}"
|
|
exit 3
|
|
fi
|
|
|
|
## Check Seafile program directory
|
|
# Ensure Seafile program directory is provided
|
|
if [ -z "$seafDir" ]; then
|
|
echo -e "\n${err}The Seafile program directory must be specified" \
|
|
"(-p parameter)${normal}\n"
|
|
exit 1
|
|
# Ensure Seafile program directory exists
|
|
else
|
|
checkExist fd "$seafDir"
|
|
checkResult="$?"
|
|
if [ "$checkResult" -eq 1 ]; then
|
|
# Specified Seafile program directory could not be found
|
|
echo -e "\n${err}The provided Seafile program directory" \
|
|
"(-p parameter) does not exist.${normal}\n"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
## Check Seafile user account
|
|
# Ensure Seafile user account is provided
|
|
if [ -z "$seafUser" ]; then
|
|
echo -e "\n${err}The user account running Seafile must be provided" \
|
|
"(-u parameter)${normal}\n"
|
|
exit 1
|
|
# Check if supplied seafUser account exists
|
|
else
|
|
user_exists=$(id -u "$seafUser" > /dev/null 2>&1; echo $?)
|
|
if [ "$user_exists" -ne 0 ]; then
|
|
echo -e "\n${err}The supplied user account (-u parameter) does not" \
|
|
"exist.${normal}\n"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
## Ensure sqlDetails file exists
|
|
checkExist ff "$sqlDetails"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = "1" ]; then
|
|
# sqlDetails file cannot be found
|
|
echo -e "\n${err}The file containing your SQL details does not exist" \
|
|
"(-s parameter)${normal}\n"
|
|
exit 1
|
|
fi
|
|
|
|
## Ensure borgDetails file exists
|
|
checkExist ff "$borgDetails"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = "1" ]; then
|
|
# borgDetails file cannot be found
|
|
echo -e "\n${err}The file containing your borgbackup details does not" \
|
|
"exist (-b parameter)${normal}\n"
|
|
exit 1
|
|
fi
|
|
|
|
## Check Seafile data directory
|
|
# Ensure Seafile data directory is provided
|
|
if [ -z "$dataDir" ]; then
|
|
echo -e "\n${err}The Seafile data directory must be specified" \
|
|
"(-d parameter)${normal}\n"
|
|
exit 1
|
|
# Ensure Seafile data directory exists
|
|
else
|
|
checkExist fd "$dataDir"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = "1" ]; then
|
|
# Specified Seafile data directory could not be found
|
|
echo -e "\n${err}The provided Seafile data directory" \
|
|
"(-d parameter) does not exist.${normal}\n"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
|
|
### Log start of script operations
|
|
echo -e "${note}[$(stamp)] --- Start $scriptName execution ---${normal}" \
|
|
>> "$logFile"
|
|
echo -e "${info}[$(stamp)] -- [INFO] Log file located at ${lit}${logFile}" \
|
|
"${info}--${normal}" >> "$logFile"
|
|
|
|
|
|
### Export logFile variable for use by Borg
|
|
export logFile="$logFile"
|
|
|
|
|
|
### Create sqlDump temporary directory and sqlDumpFilenames
|
|
sqlDumpDir=$( mktemp -d )
|
|
sqlDump_ccnet="backup-$(date +%Y%m%d_%H%M%S)_ccnet-db.sql"
|
|
sqlDump_seafile="backup-$(date +%Y%m%d_%H%M%S)_seafile-db.sql"
|
|
sqlDump_seahub="backup-$(date +%Y%m%d_%H%M%S)_seahub-db.sql"
|
|
echo -e "${info}[$(stamp)] -- [INFO] mySQL dump files will be temporarily" \
|
|
"stored at: ${lit}${sqlDumpDir}/${sqlDumpFile}${normal}" >> "$logFile"
|
|
|
|
|
|
### 503 error page: If you don't plan on using the auto-copied 503 then comment
|
|
### this entire section starting with '--- Begin 503 section ---' until
|
|
### '--- End 503 section ---' to suppress generated warnings
|
|
|
|
### --- Begin 503 section ---
|
|
|
|
## 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}" \
|
|
>> "$logFile"
|
|
exitWarn+=("[$(stamp)]_5031")
|
|
clean503=0
|
|
else
|
|
# verify webroot actually exists
|
|
checkExist fd "$webroot"
|
|
checkResult="$?"
|
|
if [ "$checkResult" -eq 1 ]; then
|
|
# webroot directory specified could not be found
|
|
echo -e "${info}[$(stamp)] -- [INFO] ${warn503} --${normal}" \
|
|
>> "$logFile"
|
|
exitWarn+=("{$stamp}_5032")
|
|
clean503=0
|
|
else
|
|
# webroot exists
|
|
echo -e "${op}[$(stamp)] Using webroot: ${lit}${webroot}${normal}" \
|
|
>> "$logFile"
|
|
# Verify 503 file existence at given path
|
|
checkExist ff "$err503Path"
|
|
checkResult="$?"
|
|
if [ "$checkResult" -eq 1 ]; then
|
|
# 503 file could not be found
|
|
echo -e "${info}[$(stamp)] -- [INFO] ${warn503} --${normal}" \
|
|
>> "$logFile"
|
|
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}${normal}" >> "$logFile"
|
|
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" -eq 1 ]; then
|
|
# copy was unsuccessful
|
|
echo -e "${info}[$(stamp)] -- [INFO] ${warn503} --" \
|
|
"${normal}" >> "$logFile"
|
|
exitWarn+=("[$(stamp)]_5035")
|
|
clean503=0
|
|
else
|
|
# copy was successful
|
|
echo -e "${info}[$(stamp)] -- [INFO] 503 error page" \
|
|
"successfully copied to webroot --${normal}" >> "$logFile"
|
|
clean503=1
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
### --- End 503 section ---
|
|
|
|
|
|
### Stop Seafile services
|
|
svcSeafile stop
|
|
|
|
|
|
### Get SQL info from sqlDetails
|
|
mapfile -t sqlParams < "$sqlDetails"
|
|
|
|
|
|
### Dump SQL
|
|
echo -e "${op}[$(stamp)] Dumping Seafile SQL databases...${normal}" \
|
|
>> "$logFile"
|
|
mysqldump -h"${sqlParams[0]}" -u"${sqlParams[1]}" -p"${sqlParams[2]}" --opt \
|
|
ccnet-db > "${sqlDumpDir}/${sqlDump_ccnet}" 2>> "$logFile"
|
|
dumpResult_ccnet=$?
|
|
mysqldump -h"${sqlParams[0]}" -u"${sqlParams[1]}" -p"${sqlParams[2]}" --opt \
|
|
seafile-db > "${sqlDumpDir}/${sqlDump_seafile}" 2>> "$logFile"
|
|
dumpResult_seafile=$?
|
|
mysqldump -h"${sqlParams[0]}" -u"${sqlParams[1]}" -p"${sqlParams[2]}" --opt \
|
|
seahub-db > "${sqlDumpDir}/${sqlDump_seahub}" 2>> "$logFile"
|
|
dumpResult_seahub=$?
|
|
# verify
|
|
if [ "$dumpResult_ccnet" -eq 0 ] && [ "$dumpResult_seafile" -eq 0 ] && \
|
|
[ "$dumpResult_seahub" -eq 0 ]; then
|
|
echo -e "${ok}[$(stamp)] -- [SUCCESS] SQL dumped successfully --${normal}" \
|
|
>> "$logFile"
|
|
else
|
|
exitError+=("[$(stamp)]_200")
|
|
cleanup
|
|
quit
|
|
fi
|
|
|
|
### Call borgbackup to copy actual files
|
|
echo -e "${op}[$(stamp)] Pre-backup tasks completed, calling borgbackup..." \
|
|
"${normal}" >> "$logFile"
|
|
|
|
## Get borgbackup settings and repo details
|
|
# read definition file and map to array variable
|
|
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..." \
|
|
"${normal}" >> "$logFile"
|
|
if [ -z "${borgConfig[0]}" ]; then
|
|
exitError+=("[$(stamp)]_210")
|
|
cleanup
|
|
quit
|
|
else
|
|
# verify the path actually exists
|
|
checkExist fd "${borgConfig[0]}"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = "1" ]; then
|
|
# borg base directory specified could not be found
|
|
exitError+=("[$(stamp)]_210")
|
|
cleanup
|
|
quit
|
|
fi
|
|
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")
|
|
cleanup
|
|
quit
|
|
else
|
|
checkExist ff "${borgConfig[1]}"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = 1 ]; then
|
|
# SSH keyfile specified could not be found
|
|
exitError+=("[$(stamp)]_211")
|
|
cleanup
|
|
quit
|
|
fi
|
|
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")
|
|
cleanup
|
|
quit
|
|
else
|
|
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 REPO password... OK${normal}" >> "$logFile"
|
|
export BORG_PASSPHRASE="${borgConfig[3]}"
|
|
else
|
|
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"
|
|
fi
|
|
# additional files to be backed up
|
|
borgXtra="${borgConfig[4]}"
|
|
# file with pattern definition for excluded files
|
|
borgExclude="${borgConfig[5]}"
|
|
# parameters for borg prune
|
|
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"
|
|
export BORG_REMOTE_PATH="${borgConfig[7]}"
|
|
else
|
|
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" \
|
|
"borgbackup to include in backup${normal}" >> "$logFile"
|
|
checkExist ff "$borgXtra"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = "0" ]; then
|
|
echo -e "${op}[$(stamp)] Found ${lit}${borgXtra}${normal}" >> "$logFile"
|
|
mapfile -t xtraFiles < "$borgXtra"
|
|
echo -e "${op}[$(stamp)] Processed extra files list for inclusion in" \
|
|
"borgbackup${normal}" >> "$logFile"
|
|
else
|
|
exitWarn+=("[$(stamp)]_2113")
|
|
fi
|
|
else
|
|
# no extra locations specified
|
|
echo -e "${op}[$(stamp)] No additional locations specified for backup." \
|
|
"Only Seafile data files will be backed up${normal}" >> "$logFile"
|
|
exitWarn+=("[$(stamp)]_2116")
|
|
fi
|
|
|
|
## Check if borgExclude exists since borg will throw an error if it's missing
|
|
if [ -n "$borgExclude" ]; then
|
|
checkExist ff "$borgExclude"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = "0" ]; then
|
|
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")
|
|
fi
|
|
else
|
|
echo -e "${op}[$(stamp)] Exclusion pattern file not specified." \
|
|
"No exclusions will be processed${normal}" >> "$logFile"
|
|
fi
|
|
|
|
|
|
## Export TMPDIR environment variable for borg via python
|
|
## Python requires a writable temporary directory when unpacking borg and
|
|
## executing commands. This defaults to /tmp but many systems mount /tmp with
|
|
## 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}" \
|
|
"${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}" \
|
|
"${BORG_BASE_DIR}/tmp${normal}" >> "$logFile"
|
|
mkdir "$BORG_BASE_DIR/tmp" 2>> "$logFile"
|
|
# verify folder created
|
|
checkExist fd "$BORG_BASE_DIR/tmp"
|
|
checkResult="$?"
|
|
if [ "$checkResult" = "0" ]; then
|
|
# folder exists
|
|
echo -e "${op}[$(stamp)] tmp folder created within borg base directory" \
|
|
"${normal}" >> "$logFile"
|
|
else
|
|
# problem creating folder and script will exit
|
|
exitError+=("[$(stamp)]_215")
|
|
cleanup
|
|
quit
|
|
fi
|
|
else
|
|
# folder found
|
|
echo -e "${op}[$(stamp)] tmp folder found within borg base directory" \
|
|
"${normal}" >> "$logFile"
|
|
fi
|
|
# export TMPDIR environment variable
|
|
export TMPDIR="${BORG_BASE_DIR}/tmp"
|
|
|
|
|
|
## Generate and execute borg
|
|
# commandline depends on whether borgExclude is empty or not
|
|
if [ -z "$borgExclude" ]; then
|
|
# borgExclude is empty
|
|
echo -e "${info}[$(stamp)] --[INFO] Executing borg without exclusions --" \
|
|
"${normal}" >> "$logFile"
|
|
borg --show-rc create ${borgCreateParams} ::`date +%Y-%m-%d_%H%M%S` \
|
|
"${xtraFiles[@]}" \
|
|
"${sqlDumpDir}" "${dataDir}" \
|
|
2>> "$logFile"
|
|
else
|
|
# borgExclude is not empty
|
|
echo -e "${info}[$(stamp)] --[INFO] Executing borg with exclusions --" \
|
|
"${normal}" >> "$logFile"
|
|
borg --show-rc create ${borgCreateParams} --exclude-from "${borgExclude}" \
|
|
::`date +%Y-%m-%d_%H%M%S` \
|
|
"${xtraFiles[@]}" \
|
|
"${sqlDumpDir}" "${dataDir}" \
|
|
2>> "$logFile"
|
|
fi
|
|
|
|
## Check status of borg operation
|
|
borgResult="$?"
|
|
if [ "$borgResult" -eq 0 ]; then
|
|
echo -e "${ok}[$(stamp)] -- [SUCCESS] Borg backup completed successfully --" \
|
|
"${normal}" >> "$logFile"
|
|
elif [ "$borgResult" -eq 1 ]; then
|
|
exitWarn+=("[$(stamp)]_2200")
|
|
elif [ "$borgResult" -ge 2 ]; then
|
|
exitError+=("[$(stamp)]_220")
|
|
cleanup
|
|
quit
|
|
else
|
|
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 "${info}[$(stamp)] --[INFO] 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" \
|
|
"--${normal}" >> "$logFile"
|
|
elif [ "$pruneResult" -eq 1 ]; then
|
|
exitWarn+=("[$(stamp)]_2210")
|
|
elif [ "$pruneResult" -ge 2 ]; then
|
|
exitError+=("[$(stamp)]_221")
|
|
else
|
|
exitWarn+=("[$(stamp)]_2212")
|
|
fi
|
|
else
|
|
# parameters not defined... skip pruning
|
|
exitWarn+=("[$(stamp)]_2115")
|
|
fi
|
|
|
|
|
|
### borgbackup completed
|
|
echo -e "${op}[$(stamp)] Borgbackup completed... begin cleanup" \
|
|
"${normal}" >> "$logFile"
|
|
|
|
|
|
### Exit script
|
|
echo -e "${bold}${op}[$(stamp)] ***Normal exit process***${normal}" \
|
|
>> "$logFile"
|
|
cleanup
|
|
echo -e "${bold}${ok}[$(stamp)] -- [SUCCESS] All processes completed" \
|
|
"successfully --${normal}" >> "$logFile"
|
|
quit
|
|
|
|
# This code should not be executed since the 'quit' function should terminate
|
|
# this script. Therefore, exit with code 99 if we get to this point.
|
|
exit 99
|