pull/60/head
Shadowigor 8 years ago
commit 88e71f57cd

@ -7,6 +7,8 @@ KNOWN ISSUES
RECENT CHANGES
--------------
- Some more code compliance
- Added more preflight checks
- Logs sent by mail are easier to read
- Better subject (currently running or finished run)
- Fixed bogus double log sent in alert mails

@ -1,4 +1,4 @@
Coding style used for my bash projects (v2.3 Sep 2016)
Coding style used for my bash projects (v2.4 Sep 2016)
++++++ Header
@ -55,6 +55,8 @@ Example: EXEC_TIME
All environment variables (verbose, silent, debug, etc) have prefix _ and are full upercase, separated by _
Example: _PARANOIA_DEBUG
Exec time variables that can take boolean values should use true and false instead of 1 and 0.
++++++ Functions
All function names should begin with an uppercase letter for every word, the other letters should be lowercase

@ -1,12 +1,14 @@
#!/usr/bin/env bash
#TODO(critical): handle conflict prevalance, especially in sync_attrs function
#TODO(high): verbose mode doesn't show files to be softdeleted
#TODO(medium): No remote deletion dir when del dir is present
PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
PROGRAM_VERSION=1.2-dev-parallel
PROGRAM_BUILD=2016082803
PROGRAM_BUILD=2016082901
IS_STABLE=no
# Execution order
@ -47,7 +49,7 @@ IS_STABLE=no
#### MINIMAL-FUNCTION-SET BEGIN ####
## FUNC_BUILD=2016082802
## FUNC_BUILD=2016082901
## BEGIN Generic bash functions written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## To use in a program, define the following variables:
@ -67,19 +69,20 @@ export LC_ALL=C
MAIL_ALERT_MSG="Execution of $PROGRAM instance $INSTANCE_ID on $(date) has warnings/errors."
# Environment variables that can be overriden by programs
_DRYRUN=0
_SILENT=0
_DRYRUN=false
_SILENT=false
_VERBOSE=false
_LOGGER_PREFIX="date"
_LOGGER_STDERR=0
_LOGGER_STDERR=false
if [ "$KEEP_LOGGING" == "" ]; then
KEEP_LOGGING=1801
fi
# Initial error status, logging 'WARN', 'ERROR' or 'CRITICAL' will enable alerts flags
ERROR_ALERT=0
WARN_ALERT=0
ERROR_ALERT=false
WARN_ALERT=false
# Current log
# Log from current run
CURRENT_LOG=
## allow function call checks #__WITH_PARANOIA_DEBUG
@ -91,11 +94,11 @@ fi #__WITH_PARANOIA_DEBUG
if [ ! "$_DEBUG" == "yes" ]; then
_DEBUG=no
SLEEP_TIME=.05 # Tested under linux and FreeBSD bash, #TODO tests on cygwin / msys
_VERBOSE=0
_VERBOSE=false
else
SLEEP_TIME=1
trap 'TrapError ${LINENO} $?' ERR
_VERBOSE=1
_VERBOSE=true
fi
SCRIPT_PID=$$
@ -149,17 +152,21 @@ function _Logger {
echo -e "$lvalue" >> "$LOG_FILE"
CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue"
if [ "$_LOGGER_STDERR" -eq 1 ]; then
if [ $_LOGGER_STDERR == true ]; then
cat <<< "$evalue" 1>&2
elif [ "$_SILENT" -eq 0 ]; then
elif [ "$_SILENT" == false ]; then
echo -e "$svalue"
fi
}
# General log function with log levels
# General log function with log levels:
# CRITICAL, ERROR, WARN are colored in stdout, prefixed in stderr
# NOTICE is standard level
# VERBOSE is only sent to stdout / stderr if _VERBOSE=true
# DEBUG & PARANOIA_DEBUG are only sent if _DEBUG=yes
function Logger {
local value="${1}" # Sentence to log (in double quotes)
local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, NOTICE, WARN, ERROR, CRITIAL
local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, VERBOSE, NOTICE, WARN, ERROR, CRITIAL
if [ "$_LOGGER_PREFIX" == "time" ]; then
prefix="TIME: $SECONDS - "
@ -171,19 +178,22 @@ function Logger {
if [ "$level" == "CRITICAL" ]; then
_Logger "$prefix\e[41m$value\e[0m" "$prefix$level:$value" "$level:$value"
ERROR_ALERT=1
ERROR_ALERT=true
return
elif [ "$level" == "ERROR" ]; then
_Logger "$prefix\e[91m$value\e[0m" "$prefix$level:$value" "$level:$value"
ERROR_ALERT=1
ERROR_ALERT=true
return
elif [ "$level" == "WARN" ]; then
_Logger "$prefix\e[93m$value\e[0m" "$prefix$level:$value" "$level:$value"
WARN_ALERT=1
WARN_ALERT=true
return
elif [ "$level" == "NOTICE" ]; then
_Logger "$prefix$value"
return
elif [ "$level" == "VERBOSE" ] && [ $_VERBOSE == true ]; then
_Logger "$prefix$value"
return
elif [ "$level" == "DEBUG" ]; then
if [ "$_DEBUG" == "yes" ]; then
_Logger "$prefix$value"
@ -220,7 +230,7 @@ function QuickLogger {
__CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
if [ "$_SILENT" -eq 1 ]; then
if [ $_SILENT == true ]; then
_QuickLogger "$value" "log"
else
_QuickLogger "$value" "stdout"
@ -317,9 +327,9 @@ function SendAlert {
fi
body="$MAIL_ALERT_MSG"$'\n\n'"$CURRENT_LOG"
if [ $ERROR_ALERT -eq 1 ]; then
if [ $ERROR_ALERT == true ]; then
subject="Error alert for $INSTANCE_ID"
elif [ $WARN_ALERT -eq 1 ]; then
elif [ $WARN_ALERT == true ]; then
subject="Warning alert for $INSTANCE_ID"
else
subject="Alert for $INSTANCE_ID"
@ -571,7 +581,7 @@ function TrapError {
local job="$0"
local line="$1"
local code="${2:-1}"
if [ $_SILENT -eq 0 ]; then
if [ $_SILENT == false ]; then
echo -e " /!\ ERROR in ${job}: Near line ${line}, exit code ${code}"
fi
}
@ -597,7 +607,7 @@ function LoadConfigFile {
}
function Spinner {
if [ $_SILENT -eq 1 ]; then
if [ $_SILENT == true ]; then
return 0
fi
@ -998,7 +1008,7 @@ function RunLocalCommand {
local hard_max_time="${2}" # Max time to wait for command to compleet
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
if [ $_DRYRUN -ne 0 ]; then
if [ $_DRYRUN == true ]; then
Logger "Dryrun: Local command [$command] not run." "NOTICE"
return 0
fi
@ -1013,7 +1023,7 @@ function RunLocalCommand {
Logger "Command failed." "ERROR"
fi
if [ $_VERBOSE -eq 1 ] || [ $retval -ne 0 ]; then
if [ $_VERBOSE == true ] || [ $retval -ne 0 ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
@ -1031,7 +1041,7 @@ function RunRemoteCommand {
CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost
if [ $_DRYRUN -ne 0 ]; then
if [ $_DRYRUN == true ]; then
Logger "Dryrun: Local command [$command] not run." "NOTICE"
return 0
fi
@ -1048,7 +1058,7 @@ function RunRemoteCommand {
Logger "Command failed." "ERROR"
fi
if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE -eq 1 ] || [ $retval -ne 0 ])
if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE == true ] || [ $retval -ne 0 ])
then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
@ -1122,7 +1132,7 @@ function CheckConnectivity3rdPartyHosts {
if [ "$_PARANOIA_DEBUG" != "yes" ]; then # Do not loose time in paranoia debug
if [ "$REMOTE_3RD_PARTY_HOSTS" != "" ]; then
remote_3rd_party_success=0
remote_3rd_party_success=false
for i in $REMOTE_3RD_PARTY_HOSTS
do
eval "$PING_CMD $i > /dev/null 2>&1" &
@ -1130,11 +1140,11 @@ function CheckConnectivity3rdPartyHosts {
if [ $? != 0 ]; then
Logger "Cannot ping 3rd party host $i" "NOTICE"
else
remote_3rd_party_success=1
remote_3rd_party_success=true
fi
done
if [ $remote_3rd_party_success -ne 1 ]; then
if [ $remote_3rd_party_success == false ]; then
Logger "No remote 3rd party host responded to ping. No internet ?" "ERROR"
return 1
else
@ -1165,14 +1175,14 @@ function __CheckArguments {
# In order to avoid this, we need to iterate over ${4} and count
local iterate=4
local fetchArguments=1
local fetchArguments=true
local argList=""
local countedArguments
while [ $fetchArguments -eq 1 ]; do
while [ $fetchArguments == true ]; do
cmd='argument=${'$iterate'}'
eval $cmd
if [ "$argument" = "" ]; then
fetchArguments=0
fetchArguments=false
else
argList="$arg_list [Argument $(($iterate-3)): $argument]"
iterate=$(($iterate+1))
@ -1314,7 +1324,7 @@ function PreInit {
## Set rsync default arguments
RSYNC_ARGS="-rltD"
if [ "$_DRYRUN" -eq 1 ]; then
if [ "$_DRYRUN" == true ]; then
RSYNC_DRY_ARG="-n"
DRY_WARNING="/!\ DRY RUN"
else
@ -1486,7 +1496,7 @@ function TrapStop {
function TrapQuit {
local exitcode
if [ $ERROR_ALERT -ne 0 ]; then
if [ $ERROR_ALERT == true ]; then
UnlockReplicas
if [ "$_DEBUG" != "yes" ]
then
@ -1500,7 +1510,7 @@ function TrapQuit {
CleanUp
Logger "$PROGRAM finished with errors." "ERROR"
exitcode=1
elif [ $WARN_ALERT -ne 0 ]; then
elif [ $WARN_ALERT == true ]; then
UnlockReplicas
if [ "$_DEBUG" != "yes" ]
then
@ -1867,12 +1877,12 @@ function CheckLocks {
local pids
if [ $_NOLOCKS -eq 1 ]; then
if [ $_NOLOCKS == true ]; then
return 0
fi
# Do not bother checking for locks when FORCE_UNLOCK is set
if [ $FORCE_UNLOCK -eq 1 ]; then
if [ $FORCE_UNLOCK == true ]; then
WriteLockFiles
if [ $? != 0 ]; then
exit 1
@ -2008,7 +2018,7 @@ function UnlockReplicas {
local pids
if [ $_NOLOCKS -eq 1 ]; then
if [ $_NOLOCKS == true ]; then
return 0
fi
@ -2121,6 +2131,14 @@ function _get_file_ctime_mtime_local {
echo -n "" > "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"
while read -r file; do $STAT_CTIME_MTIME_CMD "$replica_path$file" | sort >> "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"; done < "$file_list"
if [ $? != 0 ]; then
Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL"
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID)" "NOTICE"
fi
exit 1
fi
}
function _get_file_ctime_mtime_remote {
@ -2136,7 +2154,7 @@ function _get_file_ctime_mtime_remote {
eval "$cmd"
if [ $? != 0 ]; then
Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID)" "NOTICE"
fi
exit 1
@ -2167,13 +2185,13 @@ function sync_attrs {
eval "$rsync_cmd"
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Getting list of files that need updates failed [$retval]. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP: check why exit $retval was used
@ -2247,13 +2265,13 @@ function sync_attrs {
eval "$rsync_cmd"
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Updating file attributes on $dest_replica [$retval]. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP check why exit $retval was used
@ -2301,13 +2319,13 @@ function sync_update {
Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
eval "$rsync_cmd"
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Updating $destination_replica replica failed. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP exit $retval
@ -2328,21 +2346,24 @@ function _delete_local {
local parentdir
local previous_file=""
if [ -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN -ne 1 ]; then
if [ ! -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN == false ]; then
$COMMAND_SUDO mkdir -p "$replica_dir$deletion_dir"
if [ $? != 0 ]; then
Logger "Cannot create local replica deletion directory in [$replica_dir$deletion_dir]." "ERROR"
exit 1
fi
fi
while read -r files; do
## On every run, check wheter the next item is already deleted because it is included in a directory already deleted
if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then
if [ $_VERBOSE -eq 1 ]; then
Logger "Soft deleting $replica_dir$files" "NOTICE"
fi
if [ "$SOFT_DELETE" != "no" ]; then
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$replica_dir$deletion_dir/$files" ]; then
rm -rf "${replica_dir:?}$deletion_dir/$files"
Logger "Deleting file [$replica_dir$files]." "VERBOSE"
fi
if [ -e "$replica_dir$files" ]; then
@ -2350,18 +2371,20 @@ function _delete_local {
parentdir="$(dirname "$files")"
if [ "$parentdir" != "." ]; then
mkdir -p "$replica_dir$deletion_dir/$parentdir"
Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir/$parentdir]." "VERBOSE"
mv -f "$replica_dir$files" "$replica_dir$deletion_dir/$parentdir"
else
Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir]." "VERBOSE"
mv -f "$replica_dir$files" "$replica_dir$deletion_dir"
fi
if [ $? != 0 ]; then
Logger "Cannot move $replica_dir$files to deletion directory." "ERROR"
Logger "Cannot move [$replica_dir$files] to deletion directory." "ERROR"
echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file"
fi
fi
fi
else
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$replica_dir$files" ]; then
rm -rf "$replica_dir$files"
if [ $? != 0 ]; then
@ -2410,7 +2433,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
local value="${1}" # What to log
echo -e "$value" >&2 #TODO(high): logfile output missing
if [ $_SILENT -eq 0 ]; then
if [ $_SILENT == false ]; then
echo -e "$value"
fi
}
@ -2447,21 +2470,23 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
parentdir=
previous_file=""
if [ -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN -ne 1 ]; then
$COMMAND_SUDO mkdir -p "$replica_dir$deletion_dir"
if [ ! -d "$REPLICA_DIR$DELETE_DIR" ] && [ $_DRYRUN == false ]; then
$COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR"
if [ $? != 0 ]; then
Logger "Cannot create remote replica deletion directory in [$REPLICA_DIR$DELETE_DIR]." "ERROR"
exit 1
fi
fi
while read -r files; do
## On every run, check wheter the next item is already deleted because it is included in a directory already deleted
if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then
if [ $_VERBOSE -eq 1 ]; then
Logger "Soft deleting $REPLICA_DIR$files" "NOTICE"
fi
if [ "$SOFT_DELETE" != "no" ]; then
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$REPLICA_DIR$DELETE_DIR/$files" ]; then
$COMMAND_SUDO rm -rf "$REPLICA_DIR$DELETE_DIR/$files"
Logger "Deleting file [$REPLICA_DIR$files]." "VERBOSE"
fi
if [ -e "$REPLICA_DIR$files" ]; then
@ -2470,17 +2495,19 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
if [ "$parentdir" != "." ]; then
$COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR/$parentdir"
$COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR/$parentdir"
Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_DIR/$parentdir]." "VERBOSE"
else
$COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR"
Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_DIR]." "VERBOSE"
fi
if [ $? != 0 ]; then
Logger "Cannot move $REPLICA_DIR$files to deletion directory." "ERROR"
Logger "Cannot move [$REPLICA_DIR$files] to deletion directory." "ERROR"
echo "$files" >> "$FAILED_DELETE_LIST"
fi
fi
fi
else
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$REPLICA_DIR$files" ]; then
$COMMAND_SUDO rm -rf "$REPLICA_DIR$files"
if [ $? != 0 ]; then
@ -2544,7 +2571,7 @@ function deletion_propagation {
fi
retval=$?
if [ $retval == 0 ]; then
if [ -f "$RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID" ] && [ $_VERBOSE -eq 1 ]; then
if [ -f "$RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID" ] && [ $_VERBOSE == true ]; then
Logger "Remote:\n$(cat $RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID)" "DEBUG"
fi
return $retval
@ -2894,13 +2921,13 @@ function _SoftDeleteLocal {
local retval
if [ -d "$replica_deletion_path" ]; then
if [ $_DRYRUN -eq 1 ]; then
if [ $_DRYRUN == true ]; then
Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE"
else
Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE"
fi
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
# Cannot launch log function from xargs, ugly hack
$COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} echo "Will delete file {}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID"
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
@ -2908,7 +2935,7 @@ function _SoftDeleteLocal {
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
$COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -f "{}" && $COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type d -empty -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -rf "{}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1
else
Dummy
@ -2936,13 +2963,13 @@ function _SoftDeleteRemote {
CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost
if [ $_DRYRUN -eq 1 ]; then
if [ $_DRYRUN == true ]; then
Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE"
else
Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE"
fi
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
# Cannot launch log function from xargs, ugly hack
cmd=$SSH_CMD' "if [ -d \"'$replica_deletion_path'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type f -ctime +'$change_time' -print0 | xargs -0 -I {} echo Will delete file {} && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} echo Will delete directory {}; else echo \"No remote backup/deletion directory.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
Logger "cmd: $cmd" "DEBUG"
@ -2950,7 +2977,7 @@ function _SoftDeleteRemote {
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
cmd=$SSH_CMD' "if [ -d \"'$replica_deletion_path'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type f -ctime +'$change_time' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -f \"{}\" && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -rf \"{}\"; else echo \"No remote backup/deletion directory.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
Logger "cmd: $cmd" "DEBUG"
@ -3011,7 +3038,7 @@ function Init {
set -o errtrace
# Do not use exit and quit traps if osync runs in monitor mode
if [ $sync_on_changes -eq 0 ]; then
if [ $sync_on_changes == false ]; then
trap TrapStop INT HUP TERM QUIT
trap TrapQuit EXIT
else
@ -3081,7 +3108,7 @@ function Init {
local partial_dir="_partial"
local last_action="last-action"
local resume_count="resume-count"
if [ "$_DRYRUN" -eq 1 ]; then
if [ "$_DRYRUN" == true ]; then
local dry_suffix="-dry"
else
local dry_suffix=
@ -3125,11 +3152,11 @@ function Init {
## Set sync only function arguments for rsync
SYNC_OPTS="-u"
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
SYNC_OPTS=$SYNC_OPTS" -i"
fi
if [ $STATS -eq 1 ]; then
if [ $STATS == true ]; then
SYNC_OPTS=$SYNC_OPTS" --stats"
fi
@ -3252,8 +3279,8 @@ function SyncOnChanges {
}
# quicksync mode settings, overriden by config file
STATS=0
PARTIAL=0
STATS=false
PARTIAL=no
if [ "$CONFLICT_PREVALANCE" == "" ]; then
CONFLICT_PREVALANCE=initiator
fi
@ -3261,14 +3288,17 @@ fi
INITIATOR_LOCK_FILE_EXISTS=false
TARGET_LOCK_FILE_EXISTS=false
FORCE_UNLOCK=0
no_maxtime=0
FORCE_UNLOCK=false
no_maxtime=false
opts=""
ERROR_ALERT=0
ERROR_ALERT=false
WARN_ALERT=false
# Number of CTRL+C
SOFT_STOP=0
# Number of given replicas in command line
_QUICK_SYNC=0
sync_on_changes=0
_NOLOCKS=0
sync_on_changes=false
_NOLOCKS=false
osync_cmd=$0
if [ $# -eq 0 ]
@ -3280,7 +3310,7 @@ first=1
for i in "$@"; do
case $i in
--dry)
_DRYRUN=1
_DRYRUN=true
opts=$opts" --dry"
;;
--silent)
@ -3288,11 +3318,11 @@ for i in "$@"; do
opts=$opts" --silent"
;;
--verbose)
_VERBOSE=1
_VERBOSE=true
opts=$opts" --verbose"
;;
--stats)
STATS=1
STATS=true
opts=$opts" --stats"
;;
--partial)
@ -3300,11 +3330,11 @@ for i in "$@"; do
opts=$opts" --partial"
;;
--force-unlock)
FORCE_UNLOCK=1
FORCE_UNLOCK=true
opts=$opts" --force-unlock"
;;
--no-maxtime)
no_maxtime=1
no_maxtime=true
opts=$opts" --no-maxtime"
;;
--help|-h|--version|-v)
@ -3312,15 +3342,15 @@ for i in "$@"; do
;;
--initiator=*)
_QUICK_SYNC=$(($_QUICK_SYNC + 1))
no_maxtime=1
INITIATOR_SYNC_DIR=${i##*=}
opts=$opts" --initiator=\"$INITIATOR_SYNC_DIR\""
no_maxtime=true
;;
--target=*)
_QUICK_SYNC=$(($_QUICK_SYNC + 1))
TARGET_SYNC_DIR=${i##*=}
opts=$opts" --target=\"$TARGET_SYNC_DIR\""
no_maxtime=1
no_maxtime=true
;;
--rsakey=*)
SSH_RSA_PRIVATE_KEY=${i##*=}
@ -3331,13 +3361,13 @@ for i in "$@"; do
opts=$opts" --instance-id=\"$INSTANCE_ID\""
;;
--on-changes)
sync_on_changes=1
_NOLOCKS=1
sync_on_changes=true
_NOLOCKS=true
_LOGGER_PREFIX="date"
_LOGGER_STDERR=1
_LOGGER_STDERR=true
;;
--no-locks)
_NOLOCKS=1
_NOLOCKS=true
;;
*)
if [ $first == "0" ]; then
@ -3426,13 +3456,13 @@ opts="${opts# *}"
Logger "-------------------------------------------------------------" "NOTICE"
Logger "Sync task [$INSTANCE_ID] launched as $LOCAL_USER@$LOCAL_HOST (PID $SCRIPT_PID)" "NOTICE"
if [ $sync_on_changes -eq 1 ]; then
if [ $sync_on_changes == true ]; then
SyncOnChanges
else
GetRemoteOS
InitRemoteOSSettings
if [ $no_maxtime -eq 1 ]; then
if [ $no_maxtime == true ]; then
SOFT_MAX_EXEC_TIME=0
HARD_MAX_EXEC_TIME=0
fi

@ -1,12 +1,14 @@
#!/usr/bin/env bash
#TODO(critical): handle conflict prevalance, especially in sync_attrs function
#TODO(high): verbose mode doesn't show files to be softdeleted
#TODO(medium): No remote deletion dir when del dir is present
PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
PROGRAM_VERSION=1.2-dev-parallel
PROGRAM_BUILD=2016082803
PROGRAM_BUILD=2016082901
IS_STABLE=no
# Execution order
@ -69,7 +71,7 @@ function TrapStop {
function TrapQuit {
local exitcode
if [ $ERROR_ALERT -ne 0 ]; then
if [ $ERROR_ALERT == true ]; then
UnlockReplicas
if [ "$_DEBUG" != "yes" ]
then
@ -83,7 +85,7 @@ function TrapQuit {
CleanUp
Logger "$PROGRAM finished with errors." "ERROR"
exitcode=1
elif [ $WARN_ALERT -ne 0 ]; then
elif [ $WARN_ALERT == true ]; then
UnlockReplicas
if [ "$_DEBUG" != "yes" ]
then
@ -450,12 +452,12 @@ function CheckLocks {
local pids
if [ $_NOLOCKS -eq 1 ]; then
if [ $_NOLOCKS == true ]; then
return 0
fi
# Do not bother checking for locks when FORCE_UNLOCK is set
if [ $FORCE_UNLOCK -eq 1 ]; then
if [ $FORCE_UNLOCK == true ]; then
WriteLockFiles
if [ $? != 0 ]; then
exit 1
@ -591,7 +593,7 @@ function UnlockReplicas {
local pids
if [ $_NOLOCKS -eq 1 ]; then
if [ $_NOLOCKS == true ]; then
return 0
fi
@ -704,6 +706,14 @@ function _get_file_ctime_mtime_local {
echo -n "" > "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"
while read -r file; do $STAT_CTIME_MTIME_CMD "$replica_path$file" | sort >> "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"; done < "$file_list"
if [ $? != 0 ]; then
Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL"
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID)" "NOTICE"
fi
exit 1
fi
}
function _get_file_ctime_mtime_remote {
@ -719,7 +729,7 @@ function _get_file_ctime_mtime_remote {
eval "$cmd"
if [ $? != 0 ]; then
Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID)" "NOTICE"
fi
exit 1
@ -750,13 +760,13 @@ function sync_attrs {
eval "$rsync_cmd"
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Getting list of files that need updates failed [$retval]. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP: check why exit $retval was used
@ -830,13 +840,13 @@ function sync_attrs {
eval "$rsync_cmd"
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Updating file attributes on $dest_replica [$retval]. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP check why exit $retval was used
@ -884,13 +894,13 @@ function sync_update {
Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
eval "$rsync_cmd"
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Updating $destination_replica replica failed. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP exit $retval
@ -911,21 +921,24 @@ function _delete_local {
local parentdir
local previous_file=""
if [ -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN -ne 1 ]; then
if [ ! -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN == false ]; then
$COMMAND_SUDO mkdir -p "$replica_dir$deletion_dir"
if [ $? != 0 ]; then
Logger "Cannot create local replica deletion directory in [$replica_dir$deletion_dir]." "ERROR"
exit 1
fi
fi
while read -r files; do
## On every run, check wheter the next item is already deleted because it is included in a directory already deleted
if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then
if [ $_VERBOSE -eq 1 ]; then
Logger "Soft deleting $replica_dir$files" "NOTICE"
fi
if [ "$SOFT_DELETE" != "no" ]; then
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$replica_dir$deletion_dir/$files" ]; then
rm -rf "${replica_dir:?}$deletion_dir/$files"
Logger "Deleting file [$replica_dir$files]." "VERBOSE"
fi
if [ -e "$replica_dir$files" ]; then
@ -933,18 +946,20 @@ function _delete_local {
parentdir="$(dirname "$files")"
if [ "$parentdir" != "." ]; then
mkdir -p "$replica_dir$deletion_dir/$parentdir"
Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir/$parentdir]." "VERBOSE"
mv -f "$replica_dir$files" "$replica_dir$deletion_dir/$parentdir"
else
Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir]." "VERBOSE"
mv -f "$replica_dir$files" "$replica_dir$deletion_dir"
fi
if [ $? != 0 ]; then
Logger "Cannot move $replica_dir$files to deletion directory." "ERROR"
Logger "Cannot move [$replica_dir$files] to deletion directory." "ERROR"
echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file"
fi
fi
fi
else
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$replica_dir$files" ]; then
rm -rf "$replica_dir$files"
if [ $? != 0 ]; then
@ -993,7 +1008,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
local value="${1}" # What to log
echo -e "$value" >&2 #TODO(high): logfile output missing
if [ $_SILENT -eq 0 ]; then
if [ $_SILENT == false ]; then
echo -e "$value"
fi
}
@ -1030,21 +1045,23 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
parentdir=
previous_file=""
if [ -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN -ne 1 ]; then
$COMMAND_SUDO mkdir -p "$replica_dir$deletion_dir"
if [ ! -d "$REPLICA_DIR$DELETE_DIR" ] && [ $_DRYRUN == false ]; then
$COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR"
if [ $? != 0 ]; then
Logger "Cannot create remote replica deletion directory in [$REPLICA_DIR$DELETE_DIR]." "ERROR"
exit 1
fi
fi
while read -r files; do
## On every run, check wheter the next item is already deleted because it is included in a directory already deleted
if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then
if [ $_VERBOSE -eq 1 ]; then
Logger "Soft deleting $REPLICA_DIR$files" "NOTICE"
fi
if [ "$SOFT_DELETE" != "no" ]; then
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$REPLICA_DIR$DELETE_DIR/$files" ]; then
$COMMAND_SUDO rm -rf "$REPLICA_DIR$DELETE_DIR/$files"
Logger "Deleting file [$REPLICA_DIR$files]." "VERBOSE"
fi
if [ -e "$REPLICA_DIR$files" ]; then
@ -1053,17 +1070,19 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
if [ "$parentdir" != "." ]; then
$COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR/$parentdir"
$COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR/$parentdir"
Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_DIR/$parentdir]." "VERBOSE"
else
$COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR"
Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_DIR]." "VERBOSE"
fi
if [ $? != 0 ]; then
Logger "Cannot move $REPLICA_DIR$files to deletion directory." "ERROR"
Logger "Cannot move [$REPLICA_DIR$files] to deletion directory." "ERROR"
echo "$files" >> "$FAILED_DELETE_LIST"
fi
fi
fi
else
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$REPLICA_DIR$files" ]; then
$COMMAND_SUDO rm -rf "$REPLICA_DIR$files"
if [ $? != 0 ]; then
@ -1127,7 +1146,7 @@ function deletion_propagation {
fi
retval=$?
if [ $retval == 0 ]; then
if [ -f "$RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID" ] && [ $_VERBOSE -eq 1 ]; then
if [ -f "$RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID" ] && [ $_VERBOSE == true ]; then
Logger "Remote:\n$(cat $RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID)" "DEBUG"
fi
return $retval
@ -1477,13 +1496,13 @@ function _SoftDeleteLocal {
local retval
if [ -d "$replica_deletion_path" ]; then
if [ $_DRYRUN -eq 1 ]; then
if [ $_DRYRUN == true ]; then
Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE"
else
Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE"
fi
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
# Cannot launch log function from xargs, ugly hack
$COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} echo "Will delete file {}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID"
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
@ -1491,7 +1510,7 @@ function _SoftDeleteLocal {
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
$COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -f "{}" && $COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type d -empty -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -rf "{}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1
else
Dummy
@ -1519,13 +1538,13 @@ function _SoftDeleteRemote {
CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost
if [ $_DRYRUN -eq 1 ]; then
if [ $_DRYRUN == true ]; then
Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE"
else
Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE"
fi
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
# Cannot launch log function from xargs, ugly hack
cmd=$SSH_CMD' "if [ -d \"'$replica_deletion_path'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type f -ctime +'$change_time' -print0 | xargs -0 -I {} echo Will delete file {} && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} echo Will delete directory {}; else echo \"No remote backup/deletion directory.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
Logger "cmd: $cmd" "DEBUG"
@ -1533,7 +1552,7 @@ function _SoftDeleteRemote {
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
cmd=$SSH_CMD' "if [ -d \"'$replica_deletion_path'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type f -ctime +'$change_time' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -f \"{}\" && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -rf \"{}\"; else echo \"No remote backup/deletion directory.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
Logger "cmd: $cmd" "DEBUG"
@ -1594,7 +1613,7 @@ function Init {
set -o errtrace
# Do not use exit and quit traps if osync runs in monitor mode
if [ $sync_on_changes -eq 0 ]; then
if [ $sync_on_changes == false ]; then
trap TrapStop INT HUP TERM QUIT
trap TrapQuit EXIT
else
@ -1664,7 +1683,7 @@ function Init {
local partial_dir="_partial"
local last_action="last-action"
local resume_count="resume-count"
if [ "$_DRYRUN" -eq 1 ]; then
if [ "$_DRYRUN" == true ]; then
local dry_suffix="-dry"
else
local dry_suffix=
@ -1708,11 +1727,11 @@ function Init {
## Set sync only function arguments for rsync
SYNC_OPTS="-u"
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
SYNC_OPTS=$SYNC_OPTS" -i"
fi
if [ $STATS -eq 1 ]; then
if [ $STATS == true ]; then
SYNC_OPTS=$SYNC_OPTS" --stats"
fi
@ -1835,8 +1854,8 @@ function SyncOnChanges {
}
# quicksync mode settings, overriden by config file
STATS=0
PARTIAL=0
STATS=false
PARTIAL=no
if [ "$CONFLICT_PREVALANCE" == "" ]; then
CONFLICT_PREVALANCE=initiator
fi
@ -1844,14 +1863,17 @@ fi
INITIATOR_LOCK_FILE_EXISTS=false
TARGET_LOCK_FILE_EXISTS=false
FORCE_UNLOCK=0
no_maxtime=0
FORCE_UNLOCK=false
no_maxtime=false
opts=""
ERROR_ALERT=0
ERROR_ALERT=false
WARN_ALERT=false
# Number of CTRL+C
SOFT_STOP=0
# Number of given replicas in command line
_QUICK_SYNC=0
sync_on_changes=0
_NOLOCKS=0
sync_on_changes=false
_NOLOCKS=false
osync_cmd=$0
if [ $# -eq 0 ]
@ -1863,7 +1885,7 @@ first=1
for i in "$@"; do
case $i in
--dry)
_DRYRUN=1
_DRYRUN=true
opts=$opts" --dry"
;;
--silent)
@ -1871,11 +1893,11 @@ for i in "$@"; do
opts=$opts" --silent"
;;
--verbose)
_VERBOSE=1
_VERBOSE=true
opts=$opts" --verbose"
;;
--stats)
STATS=1
STATS=true
opts=$opts" --stats"
;;
--partial)
@ -1883,11 +1905,11 @@ for i in "$@"; do
opts=$opts" --partial"
;;
--force-unlock)
FORCE_UNLOCK=1
FORCE_UNLOCK=true
opts=$opts" --force-unlock"
;;
--no-maxtime)
no_maxtime=1
no_maxtime=true
opts=$opts" --no-maxtime"
;;
--help|-h|--version|-v)
@ -1895,15 +1917,15 @@ for i in "$@"; do
;;
--initiator=*)
_QUICK_SYNC=$(($_QUICK_SYNC + 1))
no_maxtime=1
INITIATOR_SYNC_DIR=${i##*=}
opts=$opts" --initiator=\"$INITIATOR_SYNC_DIR\""
no_maxtime=true
;;
--target=*)
_QUICK_SYNC=$(($_QUICK_SYNC + 1))
TARGET_SYNC_DIR=${i##*=}
opts=$opts" --target=\"$TARGET_SYNC_DIR\""
no_maxtime=1
no_maxtime=true
;;
--rsakey=*)
SSH_RSA_PRIVATE_KEY=${i##*=}
@ -1914,13 +1936,13 @@ for i in "$@"; do
opts=$opts" --instance-id=\"$INSTANCE_ID\""
;;
--on-changes)
sync_on_changes=1
_NOLOCKS=1
sync_on_changes=true
_NOLOCKS=true
_LOGGER_PREFIX="date"
_LOGGER_STDERR=1
_LOGGER_STDERR=true
;;
--no-locks)
_NOLOCKS=1
_NOLOCKS=true
;;
*)
if [ $first == "0" ]; then
@ -2009,13 +2031,13 @@ opts="${opts# *}"
Logger "-------------------------------------------------------------" "NOTICE"
Logger "Sync task [$INSTANCE_ID] launched as $LOCAL_USER@$LOCAL_HOST (PID $SCRIPT_PID)" "NOTICE"
if [ $sync_on_changes -eq 1 ]; then
if [ $sync_on_changes == true ]; then
SyncOnChanges
else
GetRemoteOS
InitRemoteOSSettings
if [ $no_maxtime -eq 1 ]; then
if [ $no_maxtime == true ]; then
SOFT_MAX_EXEC_TIME=0
HARD_MAX_EXEC_TIME=0
fi

@ -1,6 +1,6 @@
#### MINIMAL-FUNCTION-SET BEGIN ####
## FUNC_BUILD=2016082802
## FUNC_BUILD=2016082901
## BEGIN Generic bash functions written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## To use in a program, define the following variables:
@ -20,19 +20,20 @@ export LC_ALL=C
MAIL_ALERT_MSG="Execution of $PROGRAM instance $INSTANCE_ID on $(date) has warnings/errors."
# Environment variables that can be overriden by programs
_DRYRUN=0
_SILENT=0
_DRYRUN=false
_SILENT=false
_VERBOSE=false
_LOGGER_PREFIX="date"
_LOGGER_STDERR=0
_LOGGER_STDERR=false
if [ "$KEEP_LOGGING" == "" ]; then
KEEP_LOGGING=1801
fi
# Initial error status, logging 'WARN', 'ERROR' or 'CRITICAL' will enable alerts flags
ERROR_ALERT=0
WARN_ALERT=0
ERROR_ALERT=false
WARN_ALERT=false
# Current log
# Log from current run
CURRENT_LOG=
## allow function call checks #__WITH_PARANOIA_DEBUG
@ -44,11 +45,11 @@ fi #__WITH_PARANOIA_DEBUG
if [ ! "$_DEBUG" == "yes" ]; then
_DEBUG=no
SLEEP_TIME=.05 # Tested under linux and FreeBSD bash, #TODO tests on cygwin / msys
_VERBOSE=0
_VERBOSE=false
else
SLEEP_TIME=1
trap 'TrapError ${LINENO} $?' ERR
_VERBOSE=1
_VERBOSE=true
fi
SCRIPT_PID=$$
@ -102,17 +103,21 @@ function _Logger {
echo -e "$lvalue" >> "$LOG_FILE"
CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue"
if [ "$_LOGGER_STDERR" -eq 1 ]; then
if [ $_LOGGER_STDERR == true ]; then
cat <<< "$evalue" 1>&2
elif [ "$_SILENT" -eq 0 ]; then
elif [ "$_SILENT" == false ]; then
echo -e "$svalue"
fi
}
# General log function with log levels
# General log function with log levels:
# CRITICAL, ERROR, WARN are colored in stdout, prefixed in stderr
# NOTICE is standard level
# VERBOSE is only sent to stdout / stderr if _VERBOSE=true
# DEBUG & PARANOIA_DEBUG are only sent if _DEBUG=yes
function Logger {
local value="${1}" # Sentence to log (in double quotes)
local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, NOTICE, WARN, ERROR, CRITIAL
local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, VERBOSE, NOTICE, WARN, ERROR, CRITIAL
if [ "$_LOGGER_PREFIX" == "time" ]; then
prefix="TIME: $SECONDS - "
@ -124,19 +129,22 @@ function Logger {
if [ "$level" == "CRITICAL" ]; then
_Logger "$prefix\e[41m$value\e[0m" "$prefix$level:$value" "$level:$value"
ERROR_ALERT=1
ERROR_ALERT=true
return
elif [ "$level" == "ERROR" ]; then
_Logger "$prefix\e[91m$value\e[0m" "$prefix$level:$value" "$level:$value"
ERROR_ALERT=1
ERROR_ALERT=true
return
elif [ "$level" == "WARN" ]; then
_Logger "$prefix\e[93m$value\e[0m" "$prefix$level:$value" "$level:$value"
WARN_ALERT=1
WARN_ALERT=true
return
elif [ "$level" == "NOTICE" ]; then
_Logger "$prefix$value"
return
elif [ "$level" == "VERBOSE" ] && [ $_VERBOSE == true ]; then
_Logger "$prefix$value"
return
elif [ "$level" == "DEBUG" ]; then
if [ "$_DEBUG" == "yes" ]; then
_Logger "$prefix$value"
@ -173,7 +181,7 @@ function QuickLogger {
__CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
if [ "$_SILENT" -eq 1 ]; then
if [ $_SILENT == true ]; then
_QuickLogger "$value" "log"
else
_QuickLogger "$value" "stdout"
@ -270,9 +278,9 @@ function SendAlert {
fi
body="$MAIL_ALERT_MSG"$'\n\n'"$CURRENT_LOG"
if [ $ERROR_ALERT -eq 1 ]; then
if [ $ERROR_ALERT == true ]; then
subject="Error alert for $INSTANCE_ID"
elif [ $WARN_ALERT -eq 1 ]; then
elif [ $WARN_ALERT == true ]; then
subject="Warning alert for $INSTANCE_ID"
else
subject="Alert for $INSTANCE_ID"
@ -524,7 +532,7 @@ function TrapError {
local job="$0"
local line="$1"
local code="${2:-1}"
if [ $_SILENT -eq 0 ]; then
if [ $_SILENT == false ]; then
echo -e " /!\ ERROR in ${job}: Near line ${line}, exit code ${code}"
fi
}
@ -550,7 +558,7 @@ function LoadConfigFile {
}
function Spinner {
if [ $_SILENT -eq 1 ]; then
if [ $_SILENT == true ]; then
return 0
fi
@ -951,7 +959,7 @@ function RunLocalCommand {
local hard_max_time="${2}" # Max time to wait for command to compleet
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
if [ $_DRYRUN -ne 0 ]; then
if [ $_DRYRUN == true ]; then
Logger "Dryrun: Local command [$command] not run." "NOTICE"
return 0
fi
@ -966,7 +974,7 @@ function RunLocalCommand {
Logger "Command failed." "ERROR"
fi
if [ $_VERBOSE -eq 1 ] || [ $retval -ne 0 ]; then
if [ $_VERBOSE == true ] || [ $retval -ne 0 ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
@ -984,7 +992,7 @@ function RunRemoteCommand {
CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost
if [ $_DRYRUN -ne 0 ]; then
if [ $_DRYRUN == true ]; then
Logger "Dryrun: Local command [$command] not run." "NOTICE"
return 0
fi
@ -1001,7 +1009,7 @@ function RunRemoteCommand {
Logger "Command failed." "ERROR"
fi
if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE -eq 1 ] || [ $retval -ne 0 ])
if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE == true ] || [ $retval -ne 0 ])
then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
@ -1075,7 +1083,7 @@ function CheckConnectivity3rdPartyHosts {
if [ "$_PARANOIA_DEBUG" != "yes" ]; then # Do not loose time in paranoia debug
if [ "$REMOTE_3RD_PARTY_HOSTS" != "" ]; then
remote_3rd_party_success=0
remote_3rd_party_success=false
for i in $REMOTE_3RD_PARTY_HOSTS
do
eval "$PING_CMD $i > /dev/null 2>&1" &
@ -1083,11 +1091,11 @@ function CheckConnectivity3rdPartyHosts {
if [ $? != 0 ]; then
Logger "Cannot ping 3rd party host $i" "NOTICE"
else
remote_3rd_party_success=1
remote_3rd_party_success=true
fi
done
if [ $remote_3rd_party_success -ne 1 ]; then
if [ $remote_3rd_party_success == false ]; then
Logger "No remote 3rd party host responded to ping. No internet ?" "ERROR"
return 1
else
@ -1118,14 +1126,14 @@ function __CheckArguments {
# In order to avoid this, we need to iterate over ${4} and count
local iterate=4
local fetchArguments=1
local fetchArguments=true
local argList=""
local countedArguments
while [ $fetchArguments -eq 1 ]; do
while [ $fetchArguments == true ]; do
cmd='argument=${'$iterate'}'
eval $cmd
if [ "$argument" = "" ]; then
fetchArguments=0
fetchArguments=false
else
argList="$arg_list [Argument $(($iterate-3)): $argument]"
iterate=$(($iterate+1))
@ -1267,7 +1275,7 @@ function PreInit {
## Set rsync default arguments
RSYNC_ARGS="-rltD"
if [ "$_DRYRUN" -eq 1 ]; then
if [ "$_DRYRUN" == true ]; then
RSYNC_DRY_ARG="-n"
DRY_WARNING="/!\ DRY RUN"
else

@ -51,4 +51,18 @@ function test_osync_quicksync_local () {
assertEquals "Target state dir exists" "0" $?
}
function test_osync_quicksync_remote () {
CreateReplicas
cd "$DEV_DIR"
./n_osync.sh --initiator="$INITIATOR_DIR" --target="ssh://localhost:49999/$TARGET_DIR" --rsakey=/root/.ssh/id_rsa_local > /dev/null
assertEquals "Return code" "0" $?
[ -d "$INITIATOR_DIR/$OSYNC_STATE_DIR" ]
assertEquals "Initiator state dir exists" "0" $?
[ -d "$TARGET_DIR/$OSYNC_STATE_DIR" ]
assertEquals "Target state dir exists" "0" $?
}
. ./shunit2/shunit2

@ -1,12 +1,14 @@
#!/usr/bin/env bash
#TODO(critical): handle conflict prevalance, especially in sync_attrs function
#TODO(high): verbose mode doesn't show files to be softdeleted
#TODO(medium): No remote deletion dir when del dir is present
PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
PROGRAM_VERSION=1.2-dev-parallel
PROGRAM_BUILD=2016082803
PROGRAM_BUILD=2016082901
IS_STABLE=no
# Execution order
@ -14,7 +16,7 @@ IS_STABLE=no
#### MINIMAL-FUNCTION-SET BEGIN ####
## FUNC_BUILD=2016082802
## FUNC_BUILD=2016082901
## BEGIN Generic bash functions written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## To use in a program, define the following variables:
@ -34,19 +36,20 @@ export LC_ALL=C
MAIL_ALERT_MSG="Execution of $PROGRAM instance $INSTANCE_ID on $(date) has warnings/errors."
# Environment variables that can be overriden by programs
_DRYRUN=0
_SILENT=0
_DRYRUN=false
_SILENT=false
_VERBOSE=false
_LOGGER_PREFIX="date"
_LOGGER_STDERR=0
_LOGGER_STDERR=false
if [ "$KEEP_LOGGING" == "" ]; then
KEEP_LOGGING=1801
fi
# Initial error status, logging 'WARN', 'ERROR' or 'CRITICAL' will enable alerts flags
ERROR_ALERT=0
WARN_ALERT=0
ERROR_ALERT=false
WARN_ALERT=false
# Current log
# Log from current run
CURRENT_LOG=
@ -54,11 +57,11 @@ CURRENT_LOG=
if [ ! "$_DEBUG" == "yes" ]; then
_DEBUG=no
SLEEP_TIME=.05 # Tested under linux and FreeBSD bash, #TODO tests on cygwin / msys
_VERBOSE=0
_VERBOSE=false
else
SLEEP_TIME=1
trap 'TrapError ${LINENO} $?' ERR
_VERBOSE=1
_VERBOSE=true
fi
SCRIPT_PID=$$
@ -111,17 +114,21 @@ function _Logger {
echo -e "$lvalue" >> "$LOG_FILE"
CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue"
if [ "$_LOGGER_STDERR" -eq 1 ]; then
if [ $_LOGGER_STDERR == true ]; then
cat <<< "$evalue" 1>&2
elif [ "$_SILENT" -eq 0 ]; then
elif [ "$_SILENT" == false ]; then
echo -e "$svalue"
fi
}
# General log function with log levels
# General log function with log levels:
# CRITICAL, ERROR, WARN are colored in stdout, prefixed in stderr
# NOTICE is standard level
# VERBOSE is only sent to stdout / stderr if _VERBOSE=true
# DEBUG & PARANOIA_DEBUG are only sent if _DEBUG=yes
function Logger {
local value="${1}" # Sentence to log (in double quotes)
local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, NOTICE, WARN, ERROR, CRITIAL
local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, VERBOSE, NOTICE, WARN, ERROR, CRITIAL
if [ "$_LOGGER_PREFIX" == "time" ]; then
prefix="TIME: $SECONDS - "
@ -133,19 +140,22 @@ function Logger {
if [ "$level" == "CRITICAL" ]; then
_Logger "$prefix\e[41m$value\e[0m" "$prefix$level:$value" "$level:$value"
ERROR_ALERT=1
ERROR_ALERT=true
return
elif [ "$level" == "ERROR" ]; then
_Logger "$prefix\e[91m$value\e[0m" "$prefix$level:$value" "$level:$value"
ERROR_ALERT=1
ERROR_ALERT=true
return
elif [ "$level" == "WARN" ]; then
_Logger "$prefix\e[93m$value\e[0m" "$prefix$level:$value" "$level:$value"
WARN_ALERT=1
WARN_ALERT=true
return
elif [ "$level" == "NOTICE" ]; then
_Logger "$prefix$value"
return
elif [ "$level" == "VERBOSE" ] && [ $_VERBOSE == true ]; then
_Logger "$prefix$value"
return
elif [ "$level" == "DEBUG" ]; then
if [ "$_DEBUG" == "yes" ]; then
_Logger "$prefix$value"
@ -175,7 +185,7 @@ function QuickLogger {
local value="${1}"
if [ "$_SILENT" -eq 1 ]; then
if [ $_SILENT == true ]; then
_QuickLogger "$value" "log"
else
_QuickLogger "$value" "stdout"
@ -269,9 +279,9 @@ function SendAlert {
fi
body="$MAIL_ALERT_MSG"$'\n\n'"$CURRENT_LOG"
if [ $ERROR_ALERT -eq 1 ]; then
if [ $ERROR_ALERT == true ]; then
subject="Error alert for $INSTANCE_ID"
elif [ $WARN_ALERT -eq 1 ]; then
elif [ $WARN_ALERT == true ]; then
subject="Warning alert for $INSTANCE_ID"
else
subject="Alert for $INSTANCE_ID"
@ -522,7 +532,7 @@ function TrapError {
local job="$0"
local line="$1"
local code="${2:-1}"
if [ $_SILENT -eq 0 ]; then
if [ $_SILENT == false ]; then
echo -e " /!\ ERROR in ${job}: Near line ${line}, exit code ${code}"
fi
}
@ -547,7 +557,7 @@ function LoadConfigFile {
}
function Spinner {
if [ $_SILENT -eq 1 ]; then
if [ $_SILENT == true ]; then
return 0
fi
@ -941,7 +951,7 @@ function RunLocalCommand {
local command="${1}" # Command to run
local hard_max_time="${2}" # Max time to wait for command to compleet
if [ $_DRYRUN -ne 0 ]; then
if [ $_DRYRUN == true ]; then
Logger "Dryrun: Local command [$command] not run." "NOTICE"
return 0
fi
@ -956,7 +966,7 @@ function RunLocalCommand {
Logger "Command failed." "ERROR"
fi
if [ $_VERBOSE -eq 1 ] || [ $retval -ne 0 ]; then
if [ $_VERBOSE == true ] || [ $retval -ne 0 ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
@ -973,7 +983,7 @@ function RunRemoteCommand {
CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost
if [ $_DRYRUN -ne 0 ]; then
if [ $_DRYRUN == true ]; then
Logger "Dryrun: Local command [$command] not run." "NOTICE"
return 0
fi
@ -990,7 +1000,7 @@ function RunRemoteCommand {
Logger "Command failed." "ERROR"
fi
if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE -eq 1 ] || [ $retval -ne 0 ])
if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE == true ] || [ $retval -ne 0 ])
then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
@ -1060,7 +1070,7 @@ function CheckConnectivity3rdPartyHosts {
if [ "$_PARANOIA_DEBUG" != "yes" ]; then # Do not loose time in paranoia debug
if [ "$REMOTE_3RD_PARTY_HOSTS" != "" ]; then
remote_3rd_party_success=0
remote_3rd_party_success=false
for i in $REMOTE_3RD_PARTY_HOSTS
do
eval "$PING_CMD $i > /dev/null 2>&1" &
@ -1068,11 +1078,11 @@ function CheckConnectivity3rdPartyHosts {
if [ $? != 0 ]; then
Logger "Cannot ping 3rd party host $i" "NOTICE"
else
remote_3rd_party_success=1
remote_3rd_party_success=true
fi
done
if [ $remote_3rd_party_success -ne 1 ]; then
if [ $remote_3rd_party_success == false ]; then
Logger "No remote 3rd party host responded to ping. No internet ?" "ERROR"
return 1
else
@ -1199,7 +1209,7 @@ function PreInit {
## Set rsync default arguments
RSYNC_ARGS="-rltD"
if [ "$_DRYRUN" -eq 1 ]; then
if [ "$_DRYRUN" == true ]; then
RSYNC_DRY_ARG="-n"
DRY_WARNING="/!\ DRY RUN"
else
@ -1368,7 +1378,7 @@ function TrapStop {
function TrapQuit {
local exitcode
if [ $ERROR_ALERT -ne 0 ]; then
if [ $ERROR_ALERT == true ]; then
UnlockReplicas
if [ "$_DEBUG" != "yes" ]
then
@ -1382,7 +1392,7 @@ function TrapQuit {
CleanUp
Logger "$PROGRAM finished with errors." "ERROR"
exitcode=1
elif [ $WARN_ALERT -ne 0 ]; then
elif [ $WARN_ALERT == true ]; then
UnlockReplicas
if [ "$_DEBUG" != "yes" ]
then
@ -1734,12 +1744,12 @@ function CheckLocks {
local pids
if [ $_NOLOCKS -eq 1 ]; then
if [ $_NOLOCKS == true ]; then
return 0
fi
# Do not bother checking for locks when FORCE_UNLOCK is set
if [ $FORCE_UNLOCK -eq 1 ]; then
if [ $FORCE_UNLOCK == true ]; then
WriteLockFiles
if [ $? != 0 ]; then
exit 1
@ -1869,7 +1879,7 @@ function UnlockReplicas {
local pids
if [ $_NOLOCKS -eq 1 ]; then
if [ $_NOLOCKS == true ]; then
return 0
fi
@ -1979,6 +1989,14 @@ function _get_file_ctime_mtime_local {
echo -n "" > "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"
while read -r file; do $STAT_CTIME_MTIME_CMD "$replica_path$file" | sort >> "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"; done < "$file_list"
if [ $? != 0 ]; then
Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL"
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID)" "NOTICE"
fi
exit 1
fi
}
function _get_file_ctime_mtime_remote {
@ -1993,7 +2011,7 @@ function _get_file_ctime_mtime_remote {
eval "$cmd"
if [ $? != 0 ]; then
Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID)" "NOTICE"
fi
exit 1
@ -2023,13 +2041,13 @@ function sync_attrs {
eval "$rsync_cmd"
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Getting list of files that need updates failed [$retval]. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP: check why exit $retval was used
@ -2103,13 +2121,13 @@ function sync_attrs {
eval "$rsync_cmd"
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Updating file attributes on $dest_replica [$retval]. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP check why exit $retval was used
@ -2156,13 +2174,13 @@ function sync_update {
Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
eval "$rsync_cmd"
retval=$?
if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == true ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
Logger "List:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE"
fi
if [ $retval != 0 ] && [ $retval != 24 ]; then
Logger "Updating $destination_replica replica failed. Stopping execution." "CRITICAL"
if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
if [ $_VERBOSE == false ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE"
fi
exit 1 #WIP exit $retval
@ -2182,21 +2200,24 @@ function _delete_local {
local parentdir
local previous_file=""
if [ -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN -ne 1 ]; then
if [ ! -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN == false ]; then
$COMMAND_SUDO mkdir -p "$replica_dir$deletion_dir"
if [ $? != 0 ]; then
Logger "Cannot create local replica deletion directory in [$replica_dir$deletion_dir]." "ERROR"
exit 1
fi
fi
while read -r files; do
## On every run, check wheter the next item is already deleted because it is included in a directory already deleted
if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then
if [ $_VERBOSE -eq 1 ]; then
Logger "Soft deleting $replica_dir$files" "NOTICE"
fi
if [ "$SOFT_DELETE" != "no" ]; then
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$replica_dir$deletion_dir/$files" ]; then
rm -rf "${replica_dir:?}$deletion_dir/$files"
Logger "Deleting file [$replica_dir$files]." "VERBOSE"
fi
if [ -e "$replica_dir$files" ]; then
@ -2204,18 +2225,20 @@ function _delete_local {
parentdir="$(dirname "$files")"
if [ "$parentdir" != "." ]; then
mkdir -p "$replica_dir$deletion_dir/$parentdir"
Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir/$parentdir]." "VERBOSE"
mv -f "$replica_dir$files" "$replica_dir$deletion_dir/$parentdir"
else
Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir]." "VERBOSE"
mv -f "$replica_dir$files" "$replica_dir$deletion_dir"
fi
if [ $? != 0 ]; then
Logger "Cannot move $replica_dir$files to deletion directory." "ERROR"
Logger "Cannot move [$replica_dir$files] to deletion directory." "ERROR"
echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file"
fi
fi
fi
else
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$replica_dir$files" ]; then
rm -rf "$replica_dir$files"
if [ $? != 0 ]; then
@ -2263,7 +2286,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
local value="${1}" # What to log
echo -e "$value" >&2 #TODO(high): logfile output missing
if [ $_SILENT -eq 0 ]; then
if [ $_SILENT == false ]; then
echo -e "$value"
fi
}
@ -2300,21 +2323,23 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
parentdir=
previous_file=""
if [ -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN -ne 1 ]; then
$COMMAND_SUDO mkdir -p "$replica_dir$deletion_dir"
if [ ! -d "$REPLICA_DIR$DELETE_DIR" ] && [ $_DRYRUN == false ]; then
$COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR"
if [ $? != 0 ]; then
Logger "Cannot create remote replica deletion directory in [$REPLICA_DIR$DELETE_DIR]." "ERROR"
exit 1
fi
fi
while read -r files; do
## On every run, check wheter the next item is already deleted because it is included in a directory already deleted
if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then
if [ $_VERBOSE -eq 1 ]; then
Logger "Soft deleting $REPLICA_DIR$files" "NOTICE"
fi
if [ "$SOFT_DELETE" != "no" ]; then
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$REPLICA_DIR$DELETE_DIR/$files" ]; then
$COMMAND_SUDO rm -rf "$REPLICA_DIR$DELETE_DIR/$files"
Logger "Deleting file [$REPLICA_DIR$files]." "VERBOSE"
fi
if [ -e "$REPLICA_DIR$files" ]; then
@ -2323,17 +2348,19 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=
if [ "$parentdir" != "." ]; then
$COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR/$parentdir"
$COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR/$parentdir"
Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_DIR/$parentdir]." "VERBOSE"
else
$COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR"
Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_DIR]." "VERBOSE"
fi
if [ $? != 0 ]; then
Logger "Cannot move $REPLICA_DIR$files to deletion directory." "ERROR"
Logger "Cannot move [$REPLICA_DIR$files] to deletion directory." "ERROR"
echo "$files" >> "$FAILED_DELETE_LIST"
fi
fi
fi
else
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
if [ -e "$REPLICA_DIR$files" ]; then
$COMMAND_SUDO rm -rf "$REPLICA_DIR$files"
if [ $? != 0 ]; then
@ -2396,7 +2423,7 @@ function deletion_propagation {
fi
retval=$?
if [ $retval == 0 ]; then
if [ -f "$RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID" ] && [ $_VERBOSE -eq 1 ]; then
if [ -f "$RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID" ] && [ $_VERBOSE == true ]; then
Logger "Remote:\n$(cat $RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID)" "DEBUG"
fi
return $retval
@ -2744,13 +2771,13 @@ function _SoftDeleteLocal {
local retval
if [ -d "$replica_deletion_path" ]; then
if [ $_DRYRUN -eq 1 ]; then
if [ $_DRYRUN == true ]; then
Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE"
else
Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE"
fi
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
# Cannot launch log function from xargs, ugly hack
$COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} echo "Will delete file {}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID"
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
@ -2758,7 +2785,7 @@ function _SoftDeleteLocal {
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
$COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -f "{}" && $COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type d -empty -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -rf "{}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1
else
Dummy
@ -2785,13 +2812,13 @@ function _SoftDeleteRemote {
CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost
if [ $_DRYRUN -eq 1 ]; then
if [ $_DRYRUN == true ]; then
Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE"
else
Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE"
fi
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
# Cannot launch log function from xargs, ugly hack
cmd=$SSH_CMD' "if [ -d \"'$replica_deletion_path'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type f -ctime +'$change_time' -print0 | xargs -0 -I {} echo Will delete file {} && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} echo Will delete directory {}; else echo \"No remote backup/deletion directory.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
Logger "cmd: $cmd" "DEBUG"
@ -2799,7 +2826,7 @@ function _SoftDeleteRemote {
Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
fi
if [ $_DRYRUN -ne 1 ]; then
if [ $_DRYRUN == false ]; then
cmd=$SSH_CMD' "if [ -d \"'$replica_deletion_path'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type f -ctime +'$change_time' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -f \"{}\" && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -rf \"{}\"; else echo \"No remote backup/deletion directory.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
Logger "cmd: $cmd" "DEBUG"
@ -2858,7 +2885,7 @@ function Init {
set -o errtrace
# Do not use exit and quit traps if osync runs in monitor mode
if [ $sync_on_changes -eq 0 ]; then
if [ $sync_on_changes == false ]; then
trap TrapStop INT HUP TERM QUIT
trap TrapQuit EXIT
else
@ -2928,7 +2955,7 @@ function Init {
local partial_dir="_partial"
local last_action="last-action"
local resume_count="resume-count"
if [ "$_DRYRUN" -eq 1 ]; then
if [ "$_DRYRUN" == true ]; then
local dry_suffix="-dry"
else
local dry_suffix=
@ -2972,11 +2999,11 @@ function Init {
## Set sync only function arguments for rsync
SYNC_OPTS="-u"
if [ $_VERBOSE -eq 1 ]; then
if [ $_VERBOSE == true ]; then
SYNC_OPTS=$SYNC_OPTS" -i"
fi
if [ $STATS -eq 1 ]; then
if [ $STATS == true ]; then
SYNC_OPTS=$SYNC_OPTS" --stats"
fi
@ -3096,8 +3123,8 @@ function SyncOnChanges {
}
# quicksync mode settings, overriden by config file
STATS=0
PARTIAL=0
STATS=false
PARTIAL=no
if [ "$CONFLICT_PREVALANCE" == "" ]; then
CONFLICT_PREVALANCE=initiator
fi
@ -3105,14 +3132,17 @@ fi
INITIATOR_LOCK_FILE_EXISTS=false
TARGET_LOCK_FILE_EXISTS=false
FORCE_UNLOCK=0
no_maxtime=0
FORCE_UNLOCK=false
no_maxtime=false
opts=""
ERROR_ALERT=0
ERROR_ALERT=false
WARN_ALERT=false
# Number of CTRL+C
SOFT_STOP=0
# Number of given replicas in command line
_QUICK_SYNC=0
sync_on_changes=0
_NOLOCKS=0
sync_on_changes=false
_NOLOCKS=false
osync_cmd=$0
if [ $# -eq 0 ]
@ -3124,7 +3154,7 @@ first=1
for i in "$@"; do
case $i in
--dry)
_DRYRUN=1
_DRYRUN=true
opts=$opts" --dry"
;;
--silent)
@ -3132,11 +3162,11 @@ for i in "$@"; do
opts=$opts" --silent"
;;
--verbose)
_VERBOSE=1
_VERBOSE=true
opts=$opts" --verbose"
;;
--stats)
STATS=1
STATS=true
opts=$opts" --stats"
;;
--partial)
@ -3144,11 +3174,11 @@ for i in "$@"; do
opts=$opts" --partial"
;;
--force-unlock)
FORCE_UNLOCK=1
FORCE_UNLOCK=true
opts=$opts" --force-unlock"
;;
--no-maxtime)
no_maxtime=1
no_maxtime=true
opts=$opts" --no-maxtime"
;;
--help|-h|--version|-v)
@ -3156,15 +3186,15 @@ for i in "$@"; do
;;
--initiator=*)
_QUICK_SYNC=$(($_QUICK_SYNC + 1))
no_maxtime=1
INITIATOR_SYNC_DIR=${i##*=}
opts=$opts" --initiator=\"$INITIATOR_SYNC_DIR\""
no_maxtime=true
;;
--target=*)
_QUICK_SYNC=$(($_QUICK_SYNC + 1))
TARGET_SYNC_DIR=${i##*=}
opts=$opts" --target=\"$TARGET_SYNC_DIR\""
no_maxtime=1
no_maxtime=true
;;
--rsakey=*)
SSH_RSA_PRIVATE_KEY=${i##*=}
@ -3175,13 +3205,13 @@ for i in "$@"; do
opts=$opts" --instance-id=\"$INSTANCE_ID\""
;;
--on-changes)
sync_on_changes=1
_NOLOCKS=1
sync_on_changes=true
_NOLOCKS=true
_LOGGER_PREFIX="date"
_LOGGER_STDERR=1
_LOGGER_STDERR=true
;;
--no-locks)
_NOLOCKS=1
_NOLOCKS=true
;;
*)
if [ $first == "0" ]; then
@ -3270,13 +3300,13 @@ opts="${opts# *}"
Logger "-------------------------------------------------------------" "NOTICE"
Logger "Sync task [$INSTANCE_ID] launched as $LOCAL_USER@$LOCAL_HOST (PID $SCRIPT_PID)" "NOTICE"
if [ $sync_on_changes -eq 1 ]; then
if [ $sync_on_changes == true ]; then
SyncOnChanges
else
GetRemoteOS
InitRemoteOSSettings
if [ $no_maxtime -eq 1 ]; then
if [ $no_maxtime == true ]; then
SOFT_MAX_EXEC_TIME=0
HARD_MAX_EXEC_TIME=0
fi

Loading…
Cancel
Save