2
0
mirror of https://github.com/deajan/osync synced 2024-11-15 12:12:56 +00:00
osync/osync-batch.sh

326 lines
10 KiB
Bash
Raw Normal View History

2014-11-24 21:24:37 +00:00
#!/usr/bin/env bash
2015-11-12 00:37:43 +00:00
SUBPROGRAM=osync
PROGRAM="$SUBPROGRAM-batch" # Batch program to run osync / obackup instances sequentially and rerun failed ones
2018-10-02 08:52:25 +00:00
AUTHOR="(L) 2013-2018 by Orsiris de Jong"
2015-11-12 00:37:43 +00:00
CONTACT="http://www.netpower.fr - ozy@netpower.fr"
2018-10-02 16:14:07 +00:00
PROGRAM_BUILD=2018100201
2014-11-24 21:24:37 +00:00
2015-11-12 00:37:43 +00:00
## Runs an osync /obackup instance for every conf file found
2014-11-24 21:24:37 +00:00
## If an instance fails, run it again if time permits
2016-08-18 21:30:10 +00:00
if ! type "$BASH" > /dev/null; then
2016-12-13 08:19:14 +00:00
echo "Please run this script only with bash shell. Tested on bash >= 3.2"
exit 127
2016-08-18 21:30:10 +00:00
fi
2014-11-24 21:24:37 +00:00
## If maximum execution time is not reached, failed instances will be rerun. Max exec time is in seconds. Example is set to 10 hours.
MAX_EXECUTION_TIME=36000
2016-08-18 21:30:10 +00:00
## Specifies the number of total runs an instance may get
MAX_RUNS=3
2014-11-24 21:24:37 +00:00
## Log file path
2015-09-08 14:08:14 +00:00
if [ -w /var/log ]; then
2015-11-12 00:37:43 +00:00
LOG_FILE=/var/log/$SUBPROGRAM-batch.log
2014-11-24 21:24:37 +00:00
else
2015-11-12 00:37:43 +00:00
LOG_FILE=./$SUBPROGRAM-batch.log
2014-11-24 21:24:37 +00:00
fi
2018-10-02 08:52:25 +00:00
## Default directory where to store temporary run files
if [ -w /tmp ]; then
RUN_DIR=/tmp
elif [ -w /var/tmp ]; then
RUN_DIR=/var/tmp
else
RUN_DIR=.
fi
2018-10-02 16:14:07 +00:00
trap TrapQuit TERM EXIT HUP QUIT
2014-11-24 21:24:37 +00:00
# No need to edit under this line ##############################################################
2018-10-02 08:52:25 +00:00
#### RemoteLogger SUBSET ####
# Array to string converter, see http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array
# usage: joinString separaratorChar Array
function joinString {
local IFS="$1"; shift; echo "$*";
}
# Sub function of Logger
function _Logger {
local logValue="${1}" # Log to file
local stdValue="${2}" # Log to screeen
local toStdErr="${3:-false}" # Log to stderr instead of stdout
if [ "$logValue" != "" ]; then
echo -e "$logValue" >> "$LOG_FILE"
# Build current log file for alerts if we have a sufficient environment
if [ "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID.$TSTAMP" != "" ]; then
echo -e "$logValue" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID.$TSTAMP"
fi
fi
if [ "$stdValue" != "" ] && [ "$_LOGGER_SILENT" != true ]; then
if [ $toStdErr == true ]; then
# Force stderr color in subshell
(>&2 echo -e "$stdValue")
else
echo -e "$stdValue"
fi
fi
}
# Remote logger similar to below Logger, without log to file and alert flags
function RemoteLogger {
local value="${1}" # Sentence to log (in double quotes)
local level="${2}" # Log level
local retval="${3:-undef}" # optional return value of command
if [ "$_LOGGER_PREFIX" == "time" ]; then
prefix="TIME: $SECONDS - "
elif [ "$_LOGGER_PREFIX" == "date" ]; then
prefix="R $(date) - "
else
prefix=""
fi
if [ "$level" == "CRITICAL" ]; then
_Logger "" "$prefix\e[1;33;41m$value\e[0m" true
if [ $_DEBUG == "yes" ]; then
_Logger -e "" "[$retval] in [$(joinString , ${FUNCNAME[@]})] SP=$SCRIPT_PID P=$$" true
fi
return
elif [ "$level" == "ERROR" ]; then
_Logger "" "$prefix\e[31m$value\e[0m" true
if [ $_DEBUG == "yes" ]; then
_Logger -e "" "[$retval] in [$(joinString , ${FUNCNAME[@]})] SP=$SCRIPT_PID P=$$" true
fi
return
elif [ "$level" == "WARN" ]; then
_Logger "" "$prefix\e[33m$value\e[0m" true
if [ $_DEBUG == "yes" ]; then
_Logger -e "" "[$retval] in [$(joinString , ${FUNCNAME[@]})] SP=$SCRIPT_PID P=$$" true
fi
return
elif [ "$level" == "NOTICE" ]; then
if [ $_LOGGER_ERR_ONLY != true ]; then
_Logger "" "$prefix$value"
fi
return
elif [ "$level" == "VERBOSE" ]; then
if [ $_LOGGER_VERBOSE == true ]; then
_Logger "" "$prefix$value"
fi
return
elif [ "$level" == "ALWAYS" ]; then
_Logger "" "$prefix$value"
return
elif [ "$level" == "DEBUG" ]; then
if [ "$_DEBUG" == "yes" ]; then
_Logger "" "$prefix$value"
return
fi
else
_Logger "" "\e[41mLogger function called without proper loglevel [$level].\e[0m" true
_Logger "" "Value was: $prefix$value" true
fi
2015-09-08 14:16:22 +00:00
}
2018-10-02 08:52:25 +00:00
#### RemoteLogger SUBSET END ####
# General log function with log levels:
# Environment variables
# _LOGGER_SILENT: Disables any output to stdout & stderr
# _LOGGER_ERR_ONLY: Disables any output to stdout except for ALWAYS loglevel
# _LOGGER_VERBOSE: Allows VERBOSE loglevel messages to be sent to stdout
2015-09-08 14:16:22 +00:00
2018-10-02 08:52:25 +00:00
# Loglevels
# Except for VERBOSE, all loglevels are ALWAYS sent to log file
# CRITICAL, ERROR, WARN sent to stderr, color depending on level, level also logged
# NOTICE sent to stdout
# VERBOSE sent to stdout if _LOGGER_VERBOSE = true
# ALWAYS is sent to stdout unless _LOGGER_SILENT = true
# DEBUG & PARANOIA_DEBUG are only sent to stdout if _DEBUG=yes
# SIMPLE is a wrapper for QuickLogger that does not use advanced functionality
2015-09-08 14:16:22 +00:00
function Logger {
2018-10-02 08:52:25 +00:00
local value="${1}" # Sentence to log (in double quotes)
local level="${2}" # Log level
local retval="${3:-undef}" # optional return value of command
if [ "$_LOGGER_PREFIX" == "time" ]; then
prefix="TIME: $SECONDS - "
elif [ "$_LOGGER_PREFIX" == "date" ]; then
prefix="$(date '+%Y-%m-%d %H:%M:%S') - "
else
prefix=""
fi
2015-09-08 14:16:22 +00:00
2018-10-02 08:52:25 +00:00
## Obfuscate _REMOTE_TOKEN in logs (for ssh_filter usage only in osync and obackup)
value="${value/env _REMOTE_TOKEN=$_REMOTE_TOKEN/__(o_O)__}"
value="${value/env _REMOTE_TOKEN=\$_REMOTE_TOKEN/__(o_O)__}"
2015-09-08 14:16:22 +00:00
if [ "$level" == "CRITICAL" ]; then
2018-10-02 08:52:25 +00:00
_Logger "$prefix($level):$value" "$prefix\e[1;33;41m$value\e[0m" true
ERROR_ALERT=true
# ERROR_ALERT / WARN_ALERT is not set in main when Logger is called from a subprocess. Need to keep this flag.
echo -e "[$retval] in [$(joinString , ${FUNCNAME[@]})] SP=$SCRIPT_PID P=$$\n$prefix($level):$value" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID.$TSTAMP"
return
2015-09-08 14:16:22 +00:00
elif [ "$level" == "ERROR" ]; then
2018-10-02 08:52:25 +00:00
_Logger "$prefix($level):$value" "$prefix\e[91m$value\e[0m" true
ERROR_ALERT=true
echo -e "[$retval] in [$(joinString , ${FUNCNAME[@]})] SP=$SCRIPT_PID P=$$\n$prefix($level):$value" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID.$TSTAMP"
return
2015-09-08 14:16:22 +00:00
elif [ "$level" == "WARN" ]; then
2018-10-02 08:52:25 +00:00
_Logger "$prefix($level):$value" "$prefix\e[33m$value\e[0m" true
WARN_ALERT=true
echo -e "[$retval] in [$(joinString , ${FUNCNAME[@]})] SP=$SCRIPT_PID P=$$\n$prefix($level):$value" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.warn.$SCRIPT_PID.$TSTAMP"
return
2015-09-08 14:16:22 +00:00
elif [ "$level" == "NOTICE" ]; then
2018-10-02 08:52:25 +00:00
if [ "$_LOGGER_ERR_ONLY" != true ]; then
_Logger "$prefix$value" "$prefix$value"
fi
return
elif [ "$level" == "VERBOSE" ]; then
if [ $_LOGGER_VERBOSE == true ]; then
_Logger "$prefix($level):$value" "$prefix$value"
fi
return
elif [ "$level" == "ALWAYS" ]; then
_Logger "$prefix$value" "$prefix$value"
return
2015-09-08 14:16:22 +00:00
elif [ "$level" == "DEBUG" ]; then
2018-10-02 08:52:25 +00:00
if [ "$_DEBUG" == "yes" ]; then
_Logger "$prefix$value" "$prefix$value"
return
fi
elif [ "$level" == "SIMPLE" ]; then
if [ "$_LOGGER_SILENT" == true ]; then
_Logger "$preix$value"
else
_Logger "$preix$value" "$prefix$value"
2015-09-08 14:16:22 +00:00
fi
2018-10-02 08:52:25 +00:00
return
2015-09-08 14:16:22 +00:00
else
2018-10-02 08:52:25 +00:00
_Logger "\e[41mLogger function called without proper loglevel [$level].\e[0m" "\e[41mLogger function called without proper loglevel [$level].\e[0m" true
_Logger "Value was: $prefix$value" "Value was: $prefix$value" true
2015-09-08 14:16:22 +00:00
fi
2014-11-24 21:24:37 +00:00
}
2015-09-08 14:08:14 +00:00
function CheckEnvironment {
2015-11-12 00:37:43 +00:00
## osync / obackup executable full path can be set here if it cannot be found on the system
2016-03-14 20:51:29 +00:00
if ! type $SUBPROGRAM.sh > /dev/null 2>&1
2015-09-08 14:16:22 +00:00
then
2015-11-12 00:37:43 +00:00
if [ -f /usr/local/bin/$SUBPROGRAM.sh ]
2015-09-08 14:16:22 +00:00
then
2015-11-12 00:37:43 +00:00
SUBPROGRAM_EXECUTABLE=/usr/local/bin/$SUBPROGRAM.sh
2015-09-08 14:16:22 +00:00
else
2016-08-30 09:57:39 +00:00
Logger "Could not find [/usr/local/bin/$SUBPROGRAM.sh]" "CRITICAL"
2016-12-04 10:15:57 +00:00
( >&2 echo "Could not find [/usr/local/bin/$SUBPROGRAM.sh]" )
2015-09-08 14:16:22 +00:00
exit 1
fi
else
2015-11-12 00:37:43 +00:00
SUBPROGRAM_EXECUTABLE=$(type -p $SUBPROGRAM.sh)
2015-09-08 14:16:22 +00:00
fi
2016-11-24 13:50:48 +00:00
if [ "$CONF_FILE_PATH" == "" ]; then
Usage
fi
2016-08-18 21:30:10 +00:00
}
function Batch {
2016-12-04 10:15:57 +00:00
local runs=1 # Number of batch runs
2016-08-18 21:30:10 +00:00
local runList # Actual conf file list to run
local runAgainList # List of failed conf files sto run again
local confFile
local result
2015-07-19 10:39:44 +00:00
2016-12-04 10:15:57 +00:00
local i
2014-11-24 21:24:37 +00:00
2016-12-04 10:15:57 +00:00
# Using -e because find will accept directories or files
if [ ! -e "$CONF_FILE_PATH" ]; then
2016-08-18 21:30:10 +00:00
Logger "Cannot find conf file path [$CONF_FILE_PATH]." "CRITICAL"
Usage
2016-12-04 10:15:57 +00:00
else
# Ugly hack to read files into an array while preserving special characters
runList=()
while IFS= read -d $'\0' -r file; do runList+=("$file"); done < <(find "$CONF_FILE_PATH" -maxdepth 1 -iname "*.conf" -print0)
while ([ $MAX_EXECUTION_TIME -gt $SECONDS ] || [ $MAX_EXECUTION_TIME -eq 0 ]) && [ "${#runList[@]}" -gt 0 ] && [ $runs -le $MAX_RUNS ]; do
runAgainList=()
Logger "Sequential run n°$runs of $SUBPROGRAM instances for:" "NOTICE"
for confFile in "${runList[@]}"; do
Logger "$(basename $confFile)" "NOTICE"
done
for confFile in "${runList[@]}"; do
$SUBPROGRAM_EXECUTABLE "$confFile" --silent $opts &
wait $!
result=$?
if [ $result != 0 ]; then
if [ $result == 1 ] || [ $result == 128 ]; then # Do not handle exit code 128 because it is already handled here
Logger "Instance $(basename $confFile) failed with exit code [$result]." "ERROR"
runAgainList+=("$confFile")
elif [ $result == 2 ]; then
Logger "Instance $(basename $confFile) finished with warnings." "WARN"
2016-08-18 21:30:10 +00:00
fi
2016-12-04 10:15:57 +00:00
else
Logger "Instance $(basename $confFile) succeed." "NOTICE"
2014-11-24 21:24:37 +00:00
fi
2016-12-04 10:15:57 +00:00
done
runList=("${runAgainList[@]}")
2017-02-08 07:39:59 +00:00
runs=$((runs + 1))
2014-11-24 21:24:37 +00:00
done
2016-12-04 10:15:57 +00:00
fi
2014-11-24 21:24:37 +00:00
}
2015-09-08 14:08:14 +00:00
function Usage {
2015-09-08 14:16:22 +00:00
echo "$PROGRAM $PROGRAM_BUILD"
2017-02-08 07:39:59 +00:00
echo "$AUTHOR"
echo "$CONTACT"
2015-09-08 14:16:22 +00:00
echo ""
2015-11-12 00:37:43 +00:00
echo "Batch script to sequentially run osync or obackup instances and rerun failed ones."
2016-11-24 13:50:48 +00:00
echo "Usage: $PROGRAM.sh [OPTIONS] [$SUBPROGRAM OPTIONS]"
2015-09-08 14:16:22 +00:00
echo ""
echo "[OPTIONS]"
2015-11-12 00:37:43 +00:00
echo "--path=/path/to/conf Path to osync / obackup conf files, defaults to /etc/osync or /etc/obackup"
2016-08-18 21:30:10 +00:00
echo "--max-runs=X Number of max runs per instance, (defaults to 3)"
echo "--max-exec-time=X Retry failed instances only if max execution time not reached (defaults to 36000 seconds). Set to 0 to bypass execution time check"
2016-11-24 13:50:48 +00:00
echo "[$SUBPROGRAM OPTIONS]"
echo "Specify whatever options $PROGRAM accepts. Example"
echo "$PROGRAM.sh --path=/etc/$SUBPROGRAM --no-maxtime"
echo ""
echo "No output will be written to stdout/stderr."
echo "Verify log file in [$LOG_FILE]."
2015-09-08 14:16:22 +00:00
exit 128
2014-11-24 21:43:50 +00:00
}
opts=""
2014-11-24 21:24:37 +00:00
for i in "$@"
do
2015-09-08 14:16:22 +00:00
case $i in
2014-11-24 21:51:59 +00:00
--path=*)
CONF_FILE_PATH=${i##*=}
2014-11-24 21:43:50 +00:00
;;
2016-08-18 21:30:10 +00:00
--max-runs=*)
MAX_RUNS=${i##*=}
2014-11-24 21:43:50 +00:00
;;
2014-11-24 21:51:59 +00:00
--max-exec-time=*)
2014-11-24 21:54:15 +00:00
MAX_EXECUTION_TIME=${i##*=}
2014-11-24 21:43:50 +00:00
;;
2015-08-25 13:40:22 +00:00
--help|-h|-?)
2014-11-24 21:43:50 +00:00
Usage
2015-03-29 15:57:06 +00:00
;;
*)
2016-12-04 10:31:18 +00:00
opts="$opts$i "
2014-11-24 21:43:50 +00:00
;;
2014-11-24 21:24:37 +00:00
esac
done
CheckEnvironment
2015-11-12 00:37:43 +00:00
Logger "$(date) $SUBPROGRAM batch run" "NOTICE"
2014-11-24 21:24:37 +00:00
Batch