1
0
mirror of https://github.com/deajan/obackup.git synced 2026-02-12 01:50:55 +01:00

15 Commits

Author SHA1 Message Date
deajan
e0ebd12742 Fixed wrong ofunctions ver 2016-08-07 23:21:58 +02:00
deajan
63b82025ff Rebuilt target 2016-08-06 16:18:43 +02:00
deajan
759621c045 Renewed install info 2016-08-06 13:45:41 +02:00
deajan
200b0a8685 Bumped version to 2.0 2016-08-06 13:42:25 +02:00
deajan
7f99fd6c67 Fixed double pattern declaration 2016-08-06 13:16:45 +02:00
deajan
af8e220e33 Updated changelog 2016-08-05 23:57:10 +02:00
deajan
b1c6aeb6fc Fixed mysqldump error codes not honored 2016-07-19 13:28:16 +02:00
deajan
fcab617c0d Code cleanup 2016-07-19 13:26:16 +02:00
deajan
557738a5e5 Code cleanup 2016-07-19 12:58:05 +02:00
deajan
f2d121f38f Rebuild after osync fix #52 2016-07-19 10:53:55 +02:00
deajan
2488f9f654 Fix for osync bug #52 2016-07-19 10:53:33 +02:00
deajan
48c178ed6b Updated ofunctions 2016-05-26 22:34:08 +02:00
deajan
82e1b68398 Minor additions to ofunctions 2016-05-26 22:33:47 +02:00
deajan
22cc71c9e3 Vastly improved installer script 2016-05-26 11:11:56 +02:00
deajan
7a7a7c08bc Fixed regression for Mac/BSD 2016-05-26 11:11:43 +02:00
8 changed files with 518 additions and 219 deletions

View File

@@ -4,13 +4,17 @@ KNOWN ISSUES
- Backup size check does not honor rsync exclude patterns - Backup size check does not honor rsync exclude patterns
- Bandwidth parameter is ignored for SQL backups - Bandwidth parameter is ignored for SQL backups
- Missing symlink support when run from MSYS environment - Missing symlink support when run from MSYS environment
- Mysqldump errors aren't taken in account
CHANGELOG CHANGELOG
--------- ---------
README: FreeBSD execution needs mailer (not found), sudo missing, bash needed, sed missing (see if StripQuotes mandatory) README: FreeBSD execution needs mailer (not found), sudo missing, bash needed, sed missing (see if StripQuotes mandatory)
! XX Mar 2016: obackup v2.0 released 06 Aug 2016: obackup v2.0 released
- Made logging begin before remote checks for sanity purposes
- RunAfterCommands can get executed when trapquit
- Improved process killing and process time control
- Added optional statistics for installer - Added optional statistics for installer
- Added an option to ignore knownhosts for ssh connections (use with caution, this can lead to a security issue) - Added an option to ignore knownhosts for ssh connections (use with caution, this can lead to a security issue)
- Improved mail fallback - Improved mail fallback

View File

@@ -1,12 +1,11 @@
obackup obackup
======= =======
A small robust file & database backup script for local to local or remote to local backups via ssh. A robust file & database backup script that works for local and remote push or pull backups via ssh.
Works especially well for multiple virtualhost backups with 'backup divide task' functionnality.
## About ## About
OBackup is designed from ground to make the backup process as reliable as possible. obackup is designed to make the backup process as reliable as possible.
It divides the whole backup process into tasks, allowing each task to execute for a certain amount of time. It divides the whole backup process into tasks, allowing each task to execute for a certain amount of time.
If a task doesn't finish in time, it's stopped and the next task in list is processed. If a task doesn't finish in time, it's stopped and the next task in list is processed.
Before a task gets stopped, a first warning message is generated telling the task takes too long. Before a task gets stopped, a first warning message is generated telling the task takes too long.
@@ -14,22 +13,19 @@ Every action gets logged, and if a warning has been generated, a task gets stopp
Remote backups are initiated from the backup server instead of the production server, so hacked servers won't get ssh access to the backup server. Remote backups are initiated from the backup server instead of the production server, so hacked servers won't get ssh access to the backup server.
OBackup can enumerate and backup all MariaDB / MySQL databases present on a server. obackup can enumerate and backup all MariaDB / MySQL databases present on a server.
It can also enumarate all subdirectories of a given path and process them as separate tasks (usefull for multiple vhosts). It can also enumarate all subdirectories of a given path and process them as separate tasks (usefull for multiple vhosts).
It will do several checks before launching a backup like execution checks, dryruns, checking backup size and available local disk space. It will do several checks before launching a backup like execution checks, dryruns, checking backup size and available local disk space.
Obackup can execute local and remote commands before and after backup execution, obackup can execute local and remote commands before and after backup execution,
thus providing an easy way to handle snapshots (see https://github.com/deajan/zsnap for a zfs snapshot management script). thus providing an easy way to handle snapshots (see https://github.com/deajan/zsnap for a zfs snapshot management script).
It may also rotate backups for you. It may also rotate backups for you.
As of today, obackup has been tested successfully on RHEL / CentOS 5, CentOS 6, Debian 6.0.7 and Linux Mint 14. As of today, obackup has been tested successfully on RHEL / CentOS 5, 6 and 7, Debian 6 and 7, Linux Mint 14 and 17, FreeBSD 8.3 and 10.3.
Currently, Obackup also runs on FreeBSD and Windows MSYS environment, altough it is not fully tested yet. Currently, obackup also runs on MacOSX and Windows MSYS environment.
Feel free to drop me a mail for limited support in my free time.
## Warning ## Warning
Starting with Obackup 1.84RC4, the default behavior is modified.
Obackup now follows symlinks and treats them as the referent files / dirs, following symlinks even outside the backup root, which IMHO is more secure in terms of backups. Obackup now follows symlinks and treats them as the referent files / dirs, following symlinks even outside the backup root, which IMHO is more secure in terms of backups.
You may disable this behavior in the config file. You may disable this behavior in the config file.
@@ -38,10 +34,11 @@ You may disable this behavior in the config file.
You can download the latest obackup script from authors website. You can download the latest obackup script from authors website.
You may also clone the following git which will maybe have some more recent builds. You may also clone the following git which will maybe have some more recent builds.
$ git clone git://github.com/deajan/obackup.git $ git clone -b "v2.0" git://github.com/deajan/obackup.git
$ chmod +x ./obackup.sh $ cd obackup
$ ./install.sh
Obackup needs to run with bash shell, using any other shell will most probably fail. obackup needs to run with bash shell, using any other shell will most probably fail.
Once you have grabbed a copy, just edit the config file with your favorite text editor to setup your environment and you're ready to run. Once you have grabbed a copy, just edit the config file with your favorite text editor to setup your environment and you're ready to run.
A detailled documentation can be found on the author's site. A detailled documentation can be found on the author's site.
You can run multiple instances of obackup scripts with different backup environments. Just create another configuration file, You can run multiple instances of obackup scripts with different backup environments. Just create another configuration file,
@@ -75,7 +72,7 @@ You may mix "--silent" and "--verbose" parameters to output verbose input only i
## Final words ## Final words
Backup tasks aren't always reliable, connectivity loss, insufficient disk space, hacked servers with tons of unusefull stuff to backup... Anything can happen. Backup tasks aren't always reliable, connectivity loss, insufficient disk space, hacked servers with tons of unusefull stuff to backup... Anything can happen.
Obackup will sent your a warning email for every issue it can handle. obackup will sent your a warning email for every issue it can handle.
Nevertheless, you should assure yourself that your backup tasks will get done the way you meant it. Also, a backup isn't valuable until you're sure Nevertheless, you should assure yourself that your backup tasks will get done the way you meant it. Also, a backup isn't valuable until you're sure
you can successfully restore. Try to restore your backups to check whether everything is okay. Backups will keep file permissions and owners, you can successfully restore. Try to restore your backups to check whether everything is okay. Backups will keep file permissions and owners,
but may loose ACLs if destination file system won't handle them. but may loose ACLs if destination file system won't handle them.
@@ -83,7 +80,4 @@ but may loose ACLs if destination file system won't handle them.
## Author ## Author
Feel free to mail me for limited support in my free time :) Feel free to mail me for limited support in my free time :)
Orsiris "Ozy" de Jong | ozy@netpower.fr Orsiris de Jong | ozy@netpower.fr

View File

@@ -4,11 +4,11 @@
PROGRAM="obackup" PROGRAM="obackup"
AUTHOR="(C) 2013-2016 by Orsiris de Jong" AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr" CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr"
PROGRAM_VERSION=2.0-RC1 PROGRAM_VERSION=2.0
PROGRAM_BUILD=2016041201 PROGRAM_BUILD=2016080601
IS_STABLE=yes IS_STABLE=yes
## FUNC_BUILD=2016052502 ## FUNC_BUILD=2016071902-b
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr ## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode ## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
@@ -93,6 +93,7 @@ function Dummy {
sleep .1 sleep .1
} }
# Sub function of Logger
function _Logger { function _Logger {
local svalue="${1}" # What to log to stdout local svalue="${1}" # What to log to stdout
local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value
@@ -107,6 +108,7 @@ function _Logger {
fi fi
} }
# General log function with log levels
function Logger { function Logger {
local value="${1}" # Sentence to log (in double quotes) 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, NOTICE, WARN, ERROR, CRITIAL
@@ -150,6 +152,29 @@ function Logger {
fi fi
} }
# QuickLogger subfunction, can be called directly
function _QuickLogger {
local value="${1}"
local destination="${2}" # Destination: stdout, log, both
if ([ "$destination" == "log" ] || [ "$destination" == "both" ]); then
echo -e "$(date) - $value" >> "$LOG_FILE"
elif ([ "$destination" == "stdout" ] || [ "$destination" == "both" ]); then
echo -e "$value"
fi
}
# Generic quick logging function
function QuickLogger {
local value="${1}"
if [ "$_SILENT" -eq 1 ]; then
_QuickLogger "$value" "log"
else
_QuickLogger "$value" "stdout"
fi
}
# Portable child (and grandchild) kill function tester under Linux, BSD and MacOS X # Portable child (and grandchild) kill function tester under Linux, BSD and MacOS X
function KillChilds { function KillChilds {
local pid="${1}" local pid="${1}"
@@ -339,7 +364,7 @@ function SendAlert {
# smtp_server.domain.tld is mandatory, as is smtp_port (should be 25, 465 or 587) # smtp_server.domain.tld is mandatory, as is smtp_port (should be 25, 465 or 587)
# encryption can be set to tls, ssl or none # encryption can be set to tls, ssl or none
# smtp_user and smtp_password are optional # smtp_user and smtp_password are optional
# SendEmail "subject" "Body text" "receiver@example.com receiver2@otherdomain.com" "/path/to/attachment.file" "sender_email@example.com" "smtp_server.domain.tld" "smtp_port" "encrpytion" "smtp_user" "smtp_password" # SendEmail "subject" "Body text" "receiver@example.com receiver2@otherdomain.com" "/path/to/attachment.file" "sender_email@example.com" "smtp_server.domain.tld" "smtp_port" "encryption" "smtp_user" "smtp_password"
function SendEmail { function SendEmail {
local subject="${1}" local subject="${1}"
local message="${2}" local message="${2}"
@@ -348,7 +373,7 @@ function SendEmail {
local sender_email="${5}" local sender_email="${5}"
local smtp_server="${6}" local smtp_server="${6}"
local smtp_port="${7}" local smtp_port="${7}"
local encrpytion="${8}" local encryption="${8}"
local smtp_user="${9}" local smtp_user="${9}"
local smtp_password="${10}" local smtp_password="${10}"
@@ -567,11 +592,37 @@ function IsNumeric {
fi fi
} }
## from https://gist.github.com/cdown/1163649
function urlEncode {
local length="${#1}"
local LANG=C
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-])
printf "$c"
;;
*)
printf '%%%02X' "'$c"
;;
esac
done
}
function urlDecode {
local url_encoded="${1//+/ }"
printf '%b' "${url_encoded//%/\\x}"
}
function CleanUp { function CleanUp {
__CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
if [ "$_DEBUG" != "yes" ]; then if [ "$_DEBUG" != "yes" ]; then
rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID" rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID"
# Fix for sed -i requiring backup extension for BSD & Mac (see all sed -i statements)
rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID.tmp"
fi fi
} }
@@ -693,6 +744,8 @@ function WaitForTaskCompletion {
local seconds_begin=$SECONDS # Seconds since the beginning of the script local seconds_begin=$SECONDS # Seconds since the beginning of the script
local exec_time=0 # Seconds since the beginning of this function local exec_time=0 # Seconds since the beginning of this function
local retval=0 # return value of monitored pid process
while eval "$PROCESS_TEST_CMD" > /dev/null while eval "$PROCESS_TEST_CMD" > /dev/null
do do
Spinner Spinner
@@ -724,7 +777,7 @@ function WaitForTaskCompletion {
sleep $SLEEP_TIME sleep $SLEEP_TIME
done done
wait $pid wait $pid
local retval=$? retval=$?
Logger "${FUNCNAME[0]} ended for [$caller_name] with status $retval." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG Logger "${FUNCNAME[0]} ended for [$caller_name] with status $retval." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG
return $retval return $retval
} }
@@ -738,11 +791,13 @@ function WaitForCompletion {
__CheckArguments 4 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG __CheckArguments 4 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once
local log_ttime=0 # local time instance for comparaison local log_time=0 # local time instance for comparaison
local seconds_begin=$SECONDS # Seconds since the beginning of the script local seconds_begin=$SECONDS # Seconds since the beginning of the script
local exec_time=0 # Seconds since the beginning of this function local exec_time=0 # Seconds since the beginning of this function
local retval=0 # return value of monitored pid process
while eval "$PROCESS_TEST_CMD" > /dev/null while eval "$PROCESS_TEST_CMD" > /dev/null
do do
Spinner Spinner
@@ -987,8 +1042,6 @@ function RsyncPatternsFromAdd {
local pattern_from="${2}" local pattern_from="${2}"
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
local pattern_from=
## Check if the exclude list has a full path, and if not, add the config file path if there is one ## Check if the exclude list has a full path, and if not, add the config file path if there is one
if [ "$(basename $pattern_from)" == "$pattern_from" ]; then if [ "$(basename $pattern_from)" == "$pattern_from" ]; then
pattern_from="$(dirname $CONFIG_FILE)/$pattern_from" pattern_from="$(dirname $CONFIG_FILE)/$pattern_from"
@@ -1683,7 +1736,7 @@ function _CreateDirectoryLocal {
if [ ! -d "$dir_to_create" ]; then if [ ! -d "$dir_to_create" ]; then
# No sudo, you should have all necessary rights # No sudo, you should have all necessary rights
mkdir --parents "$dir_to_create" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 mkdir -p "$dir_to_create" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1
if [ $? != 0 ]; then if [ $? != 0 ]; then
Logger "Cannot create directory [$dir_to_create]" "CRITICAL" Logger "Cannot create directory [$dir_to_create]" "CRITICAL"
if [ -f $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID ]; then if [ -f $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID ]; then
@@ -1702,7 +1755,7 @@ function _CreateDirectoryRemote {
CheckConnectivity3rdPartyHosts CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost CheckConnectivityRemoteHost
cmd=$SSH_CMD' "if ! [ -d \"'$dir_to_create'\" ]; then '$COMMAND_SUDO' mkdir --parents \"'$dir_to_create'\"; fi" > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2>&1' cmd=$SSH_CMD' "if ! [ -d \"'$dir_to_create'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$dir_to_create'\"; fi" > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2>&1'
Logger "cmd: $cmd" "DEBUG" Logger "cmd: $cmd" "DEBUG"
eval "$cmd" & eval "$cmd" &
WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]} WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
@@ -1882,6 +1935,7 @@ function _BackupDatabaseLocalToLocal {
local dry_sql_cmd local dry_sql_cmd
local sql_cmd local sql_cmd
local retval
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
@@ -1896,9 +1950,11 @@ function _BackupDatabaseLocalToLocal {
eval "$dry_sql_cmd" & eval "$dry_sql_cmd" &
fi fi
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]} WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]}
local retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }
@@ -1911,6 +1967,7 @@ function _BackupDatabaseLocalToRemote {
local dry_sql_cmd local dry_sql_cmd
local sql_cmd local sql_cmd
local retval
CheckConnectivity3rdPartyHosts CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost CheckConnectivityRemoteHost
@@ -1927,9 +1984,11 @@ function _BackupDatabaseLocalToRemote {
eval "$dry_sql_cmd" & eval "$dry_sql_cmd" &
fi fi
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]} WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]}
local retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }
@@ -1961,6 +2020,8 @@ function _BackupDatabaseRemoteToLocal {
retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }

View File

@@ -1,26 +1,38 @@
#!/usr/bin/env bash #!/usr/bin/env bash
## Merges ofunctions.sh and n_osync.sh into osync.sh ## MERGE 2016080601
## Merges ofunctions.sh and n_program.sh into program.sh
## Adds installer
PROGRAM=obackup PROGRAM=obackup
VERSION=$(grep "PROGRAM_VERSION=" n_$PROGRAM.sh) VERSION=$(grep "PROGRAM_VERSION=" n_$PROGRAM.sh)
VERSION=${VERSION#*=} VERSION=${VERSION#*=}
FUNC_PATH=/home/git/common
PARANOIA_DEBUG_LINE="__WITH_PARANOIA_DEBUG" PARANOIA_DEBUG_LINE="__WITH_PARANOIA_DEBUG"
PARANOIA_DEBUG_BEGIN="#__BEGIN_WITH_PARANOIA_DEBUG" PARANOIA_DEBUG_BEGIN="#__BEGIN_WITH_PARANOIA_DEBUG"
PARANOIA_DEBUG_END="#__END_WITH_PARANOIA_DEBUG" PARANOIA_DEBUG_END="#__END_WITH_PARANOIA_DEBUG"
MINIMUM_FUNCTION_BEGIN="#### MINIMAL-FUNCTION-SET BEGIN ####"
MINIMUM_FUNCTION_END="#### MINIMAL-FUNCTION-SET END ####"
function Unexpand { function Unexpand {
unexpand n_$PROGRAM.sh > tmp_$PROGRAM.sh unexpand n_$PROGRAM.sh > tmp_$PROGRAM.sh
} }
function Merge { function MergeAll {
sed "/source \"\.\/ofunctions.sh\"/r /home/git/common/ofunctions.sh" tmp_$PROGRAM.sh | grep -v 'source "./ofunctions.sh"' > debug_$PROGRAM.sh sed "/source \"\.\/ofunctions.sh\"/r ofunctions.sh" tmp_$PROGRAM.sh | grep -v 'source "./ofunctions.sh"' > debug_$PROGRAM.sh
chmod +x debug_$PROGRAM.sh chmod +x debug_$PROGRAM.sh
} }
function MergeMinimum {
sed -n "/$MINIMUM_FUNCTION_BEGIN/,/$MINIMUM_FUNCTION_END/p" ofunctions.sh > tmp_minimal.sh
sed "/source \"\.\/ofunctions.sh\"/r tmp_minimal.sh" tmp_$PROGRAM.sh | grep -v 'source "./ofunctions.sh"' | grep -v "$PARANOIA_DEBUG_LINE" > debug_$PROGRAM.sh
rm -f tmp_minimal.sh
chmod +x debug_$PROGRAM.sh
}
function CleanDebug { function CleanDebug {
# sed explanation # sed explanation
@@ -38,16 +50,22 @@ function CleanDebug {
} }
function CopyCommons { function CopyCommons {
sed "s/\[prgname\]/$PROGRAM/g" /home/git/common/common_install.sh > ../tmp_install.sh sed "s/\[prgname\]/$PROGRAM/g" common_install.sh > ../tmp_install.sh
sed "s/\[version\]/$VERSION/g" ../tmp_install.sh > ../install.sh sed "s/\[version\]/$VERSION/g" ../tmp_install.sh > ../install.sh
sed "s/\[prgname\]/$PROGRAM/g" /home/git/common/common_batch.sh > ../$PROGRAM-batch.sh if [ -f "common_batch.sh" ]; then
sed "s/\[prgname\]/$PROGRAM/g" common_batch.sh > ../$PROGRAM-batch.sh
fi
chmod +x ../install.sh chmod +x ../install.sh
chmod +x ../obackup-batch.sh chmod +x ../$PROGRAM-batch.sh
rm -f ../tmp_install.sh
} }
Unexpand Unexpand
Merge if [ "$PROGRAM" == "osync" ] || [ "$PROGRAM" == "obackup" ]; then
MergeAll
else
MergeMinimum
fi
CleanDebug CleanDebug
rm -f tmp_$PROGRAM.sh
rm -f ../tmp_install.sh
CopyCommons CopyCommons
rm -f tmp_$PROGRAM.sh

View File

@@ -4,8 +4,8 @@
PROGRAM="obackup" PROGRAM="obackup"
AUTHOR="(C) 2013-2016 by Orsiris de Jong" AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr" CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr"
PROGRAM_VERSION=2.0-RC1 PROGRAM_VERSION=2.0
PROGRAM_BUILD=2016041201 PROGRAM_BUILD=2016080601
IS_STABLE=yes IS_STABLE=yes
source "./ofunctions.sh" source "./ofunctions.sh"
@@ -490,7 +490,7 @@ function _CreateDirectoryLocal {
if [ ! -d "$dir_to_create" ]; then if [ ! -d "$dir_to_create" ]; then
# No sudo, you should have all necessary rights # No sudo, you should have all necessary rights
mkdir --parents "$dir_to_create" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 mkdir -p "$dir_to_create" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1
if [ $? != 0 ]; then if [ $? != 0 ]; then
Logger "Cannot create directory [$dir_to_create]" "CRITICAL" Logger "Cannot create directory [$dir_to_create]" "CRITICAL"
if [ -f $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID ]; then if [ -f $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID ]; then
@@ -509,7 +509,7 @@ function _CreateDirectoryRemote {
CheckConnectivity3rdPartyHosts CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost CheckConnectivityRemoteHost
cmd=$SSH_CMD' "if ! [ -d \"'$dir_to_create'\" ]; then '$COMMAND_SUDO' mkdir --parents \"'$dir_to_create'\"; fi" > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2>&1' cmd=$SSH_CMD' "if ! [ -d \"'$dir_to_create'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$dir_to_create'\"; fi" > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2>&1'
Logger "cmd: $cmd" "DEBUG" Logger "cmd: $cmd" "DEBUG"
eval "$cmd" & eval "$cmd" &
WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]} WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
@@ -689,6 +689,7 @@ function _BackupDatabaseLocalToLocal {
local dry_sql_cmd local dry_sql_cmd
local sql_cmd local sql_cmd
local retval
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
@@ -703,9 +704,11 @@ function _BackupDatabaseLocalToLocal {
eval "$dry_sql_cmd" & eval "$dry_sql_cmd" &
fi fi
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]} WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]}
local retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }
@@ -718,6 +721,7 @@ function _BackupDatabaseLocalToRemote {
local dry_sql_cmd local dry_sql_cmd
local sql_cmd local sql_cmd
local retval
CheckConnectivity3rdPartyHosts CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost CheckConnectivityRemoteHost
@@ -734,9 +738,11 @@ function _BackupDatabaseLocalToRemote {
eval "$dry_sql_cmd" & eval "$dry_sql_cmd" &
fi fi
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]} WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]}
local retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }
@@ -768,6 +774,8 @@ function _BackupDatabaseRemoteToLocal {
retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }

View File

@@ -1,4 +1,4 @@
## FUNC_BUILD=2016052502 ## FUNC_BUILD=2016071902-b
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr ## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode ## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
@@ -83,6 +83,7 @@ function Dummy {
sleep .1 sleep .1
} }
# Sub function of Logger
function _Logger { function _Logger {
local svalue="${1}" # What to log to stdout local svalue="${1}" # What to log to stdout
local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value
@@ -97,6 +98,7 @@ function _Logger {
fi fi
} }
# General log function with log levels
function Logger { function Logger {
local value="${1}" # Sentence to log (in double quotes) 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, NOTICE, WARN, ERROR, CRITIAL
@@ -140,6 +142,29 @@ function Logger {
fi fi
} }
# QuickLogger subfunction, can be called directly
function _QuickLogger {
local value="${1}"
local destination="${2}" # Destination: stdout, log, both
if ([ "$destination" == "log" ] || [ "$destination" == "both" ]); then
echo -e "$(date) - $value" >> "$LOG_FILE"
elif ([ "$destination" == "stdout" ] || [ "$destination" == "both" ]); then
echo -e "$value"
fi
}
# Generic quick logging function
function QuickLogger {
local value="${1}"
if [ "$_SILENT" -eq 1 ]; then
_QuickLogger "$value" "log"
else
_QuickLogger "$value" "stdout"
fi
}
# Portable child (and grandchild) kill function tester under Linux, BSD and MacOS X # Portable child (and grandchild) kill function tester under Linux, BSD and MacOS X
function KillChilds { function KillChilds {
local pid="${1}" local pid="${1}"
@@ -329,7 +354,7 @@ function SendAlert {
# smtp_server.domain.tld is mandatory, as is smtp_port (should be 25, 465 or 587) # smtp_server.domain.tld is mandatory, as is smtp_port (should be 25, 465 or 587)
# encryption can be set to tls, ssl or none # encryption can be set to tls, ssl or none
# smtp_user and smtp_password are optional # smtp_user and smtp_password are optional
# SendEmail "subject" "Body text" "receiver@example.com receiver2@otherdomain.com" "/path/to/attachment.file" "sender_email@example.com" "smtp_server.domain.tld" "smtp_port" "encrpytion" "smtp_user" "smtp_password" # SendEmail "subject" "Body text" "receiver@example.com receiver2@otherdomain.com" "/path/to/attachment.file" "sender_email@example.com" "smtp_server.domain.tld" "smtp_port" "encryption" "smtp_user" "smtp_password"
function SendEmail { function SendEmail {
local subject="${1}" local subject="${1}"
local message="${2}" local message="${2}"
@@ -338,7 +363,7 @@ function SendEmail {
local sender_email="${5}" local sender_email="${5}"
local smtp_server="${6}" local smtp_server="${6}"
local smtp_port="${7}" local smtp_port="${7}"
local encrpytion="${8}" local encryption="${8}"
local smtp_user="${9}" local smtp_user="${9}"
local smtp_password="${10}" local smtp_password="${10}"
@@ -557,11 +582,37 @@ function IsNumeric {
fi fi
} }
## from https://gist.github.com/cdown/1163649
function urlEncode {
local length="${#1}"
local LANG=C
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-])
printf "$c"
;;
*)
printf '%%%02X' "'$c"
;;
esac
done
}
function urlDecode {
local url_encoded="${1//+/ }"
printf '%b' "${url_encoded//%/\\x}"
}
function CleanUp { function CleanUp {
__CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
if [ "$_DEBUG" != "yes" ]; then if [ "$_DEBUG" != "yes" ]; then
rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID" rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID"
# Fix for sed -i requiring backup extension for BSD & Mac (see all sed -i statements)
rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID.tmp"
fi fi
} }
@@ -683,6 +734,8 @@ function WaitForTaskCompletion {
local seconds_begin=$SECONDS # Seconds since the beginning of the script local seconds_begin=$SECONDS # Seconds since the beginning of the script
local exec_time=0 # Seconds since the beginning of this function local exec_time=0 # Seconds since the beginning of this function
local retval=0 # return value of monitored pid process
while eval "$PROCESS_TEST_CMD" > /dev/null while eval "$PROCESS_TEST_CMD" > /dev/null
do do
Spinner Spinner
@@ -714,7 +767,7 @@ function WaitForTaskCompletion {
sleep $SLEEP_TIME sleep $SLEEP_TIME
done done
wait $pid wait $pid
local retval=$? retval=$?
Logger "${FUNCNAME[0]} ended for [$caller_name] with status $retval." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG Logger "${FUNCNAME[0]} ended for [$caller_name] with status $retval." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG
return $retval return $retval
} }
@@ -728,11 +781,13 @@ function WaitForCompletion {
__CheckArguments 4 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG __CheckArguments 4 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once
local log_ttime=0 # local time instance for comparaison local log_time=0 # local time instance for comparaison
local seconds_begin=$SECONDS # Seconds since the beginning of the script local seconds_begin=$SECONDS # Seconds since the beginning of the script
local exec_time=0 # Seconds since the beginning of this function local exec_time=0 # Seconds since the beginning of this function
local retval=0 # return value of monitored pid process
while eval "$PROCESS_TEST_CMD" > /dev/null while eval "$PROCESS_TEST_CMD" > /dev/null
do do
Spinner Spinner
@@ -977,8 +1032,6 @@ function RsyncPatternsFromAdd {
local pattern_from="${2}" local pattern_from="${2}"
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
local pattern_from=
## Check if the exclude list has a full path, and if not, add the config file path if there is one ## Check if the exclude list has a full path, and if not, add the config file path if there is one
if [ "$(basename $pattern_from)" == "$pattern_from" ]; then if [ "$(basename $pattern_from)" == "$pattern_from" ]; then
pattern_from="$(dirname $CONFIG_FILE)/$pattern_from" pattern_from="$(dirname $CONFIG_FILE)/$pattern_from"

View File

@@ -1,15 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
PROGRAM=obackup PROGRAM=obackup
PROGRAM_VERSION=2.0-RC1 PROGRAM_VERSION=2.0
PROGRAM_BINARY=$PROGRAM".sh" PROGRAM_BINARY=$PROGRAM".sh"
PROGRAM_BATCH=$PROGRAM"-batch.sh" PROGRAM_BATCH=$PROGRAM"-batch.sh"
SCRIPT_BUILD=2016052501 SCRIPT_BUILD=2016052601
## osync / obackup / pmocr / zsnap install script ## osync / obackup / pmocr / zsnap install script
## Tested on RHEL / CentOS 6 & 7, Fedora 23, Debian 7 & 8, Mint 17 and FreeBSD 8 & 10 ## Tested on RHEL / CentOS 6 & 7, Fedora 23, Debian 7 & 8, Mint 17 and FreeBSD 8 & 10
## Please adapt this to fit your distro needs ## Please adapt this to fit your distro needs
#TODO: silent mode and no stats mode
CONF_DIR=/etc/$PROGRAM CONF_DIR=/etc/$PROGRAM
BIN_DIR=/usr/local/bin BIN_DIR=/usr/local/bin
SERVICE_DIR_INIT=/etc/init.d SERVICE_DIR_INIT=/etc/init.d
@@ -28,8 +30,56 @@ PMOCR_SERVICE_FILE_SYSTEMD_SYSTEM="pmocr-srv.service"
## Generic code ## Generic code
## Default log file
if [ -w /var/log ]; then
LOG_FILE="/var/log/$PROGRAM-install.log"
elif ([ "$HOME" != "" ] && [ -w "$HOME" ]); then
LOG_FILE="$HOME/$PROGRAM-install.log"
else
LOG_FILE="./$PROGRAM-install.log"
fi
# Generic quick logging function
function _QuickLogger {
local value="${1}"
local destination="${2}" # Destination: stdout, log, both
if ([ "$destination" == "log" ] || [ "$destination" == "both" ]); then
echo -e "$(date) - $value" >> "$LOG_FILE"
elif ([ "$destination" == "stdout" ] || [ "$destination" == "both" ]); then
echo -e "$value"
fi
}
function QuickLogger {
local value="${1}"
if [ "$_SILENT" -eq 1 ]; then
_QuickLogger "$value" "log"
else
_QuickLogger "$value" "stdout"
fi
}
function urlencode() {
# urlencode <string>
local LANG=C
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
}
function SetOSSettings {
USER=root USER=root
local local_os_var
local_os_var="$(uname -spio 2>&1)" local_os_var="$(uname -spio 2>&1)"
if [ $? != 0 ]; then if [ $? != 0 ]; then
local_os_var="$(uname -v 2>&1)" local_os_var="$(uname -v 2>&1)"
@@ -55,10 +105,14 @@ case $local_os_var in
esac esac
if ([ "$USER" != "" ] && [ "$(whoami)" != "$USER" ]); then if ([ "$USER" != "" ] && [ "$(whoami)" != "$USER" ]); then
echo "Must be run as $USER." QuickLogger "Must be run as $USER."
exit 1 exit 1
fi fi
OS=$(urlencode "$local_os_var")
}
function GetInit {
if [ -f /sbin/init ]; then if [ -f /sbin/init ]; then
if file /sbin/init | grep systemd > /dev/null; then if file /sbin/init | grep systemd > /dev/null; then
init="systemd" init="systemd"
@@ -66,22 +120,26 @@ if [ -f /sbin/init ]; then
init="initV" init="initV"
fi fi
else else
echo "Can't detect initV or systemd. Service files won't be installed. You can still run $PROGRAM manually or via cron." QuickLogger "Can't detect initV or systemd. Service files won't be installed. You can still run $PROGRAM manually or via cron."
init=none init="none"
fi fi
}
function CreateConfDir {
if [ ! -d "$CONF_DIR" ]; then if [ ! -d "$CONF_DIR" ]; then
mkdir "$CONF_DIR" mkdir "$CONF_DIR"
if [ $? == 0 ]; then if [ $? == 0 ]; then
echo "Created directory [$CONF_DIR]." QuickLogger "Created directory [$CONF_DIR]."
else else
echo "Cannot create directory [$CONF_DIR]." QuickLogger "Cannot create directory [$CONF_DIR]."
exit 1 exit 1
fi fi
else else
echo "Config directory [$CONF_DIR] exists." QuickLogger "Config directory [$CONF_DIR] exists."
fi fi
}
function CopyExampleFiles {
if [ -f "./sync.conf.example" ]; then if [ -f "./sync.conf.example" ]; then
cp "./sync.conf.example" "/etc/$PROGRAM/sync.conf.example" cp "./sync.conf.example" "/etc/$PROGRAM/sync.conf.example"
fi fi
@@ -97,59 +155,64 @@ fi
if [ -f "./snapshot.conf.example" ]; then if [ -f "./snapshot.conf.example" ]; then
cp "./snapshot.conf.example" "/etc/$PROGRAM/snapshot.conf.example" cp "./snapshot.conf.example" "/etc/$PROGRAM/snapshot.conf.example"
fi fi
}
function CopyProgram {
cp "./$PROGRAM_BINARY" "$BIN_DIR" cp "./$PROGRAM_BINARY" "$BIN_DIR"
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "Cannot copy $PROGRAM_BINARY to [$BIN_DIR]." QuickLogger "Cannot copy $PROGRAM_BINARY to [$BIN_DIR]. Make sure to run install script in the directory containing all other files."
QuickLogger "Also make sure you have permissions to write to [$BIN_DIR]."
exit 1
else else
chmod 755 "$BIN_DIR/$PROGRAM_BINARY" chmod 755 "$BIN_DIR/$PROGRAM_BINARY"
echo "Copied $PROGRAM_BINARY to [$BIN_DIR]." QuickLogger "Copied $PROGRAM_BINARY to [$BIN_DIR]."
fi fi
if [ -f "./$PROGRAM_BATCH" ]; then if [ -f "./$PROGRAM_BATCH" ]; then
cp "./$PROGRAM_BATCH" "$BIN_DIR" cp "./$PROGRAM_BATCH" "$BIN_DIR"
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "Cannot copy $PROGRAM_BATCH to [$BIN_DIR]." QuickLogger "Cannot copy $PROGRAM_BATCH to [$BIN_DIR]."
else else
chmod 755 "$BIN_DIR/$PROGRAM_BATCH" chmod 755 "$BIN_DIR/$PROGRAM_BATCH"
echo "Copied $PROGRAM_BATCH to [$BIN_DIR]." QuickLogger "Copied $PROGRAM_BATCH to [$BIN_DIR]."
fi fi
fi fi
if [ -f "./ssh_filter.sh" ]; then if [ -f "./ssh_filter.sh" ]; then
cp "./ssh_filter.sh" "$BIN_DIR" cp "./ssh_filter.sh" "$BIN_DIR"
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "Cannot copy ssh_filter.sh to [$BIN_DIR]." QuickLogger "Cannot copy ssh_filter.sh to [$BIN_DIR]."
else else
chmod 755 "$BIN_DIR/ssh_filter.sh" chmod 755 "$BIN_DIR/ssh_filter.sh"
if ([ "$USER" != "" ] && [ "$GROUP" != "" ]); then if ([ "$USER" != "" ] && [ "$GROUP" != "" ]); then
chown $USER:$GROUP "$BIN_DIR/ssh_filter.sh" chown $USER:$GROUP "$BIN_DIR/ssh_filter.sh"
fi fi
echo "Copied ssh_filter.sh to [$BIN_DIR]." QuickLogger "Copied ssh_filter.sh to [$BIN_DIR]."
fi fi
fi fi
}
function CopyServiceFiles {
# OSYNC SPECIFIC # OSYNC SPECIFIC
if ([ "$init" == "systemd" ] && [ -f "./$OSYNC_SERVICE_FILE_SYSTEMD_SYSTEM" ]); then if ([ "$init" == "systemd" ] && [ -f "./$OSYNC_SERVICE_FILE_SYSTEMD_SYSTEM" ]); then
cp "./$OSYNC_SERVICE_FILE_SYSTEMD_SYSTEM" "$SERVICE_DIR_SYSTEMD_SYSTEM" && cp "./$OSYNC_SERVICE_FILE_SYSTEMD_USER" "$SERVICE_DIR_SYSTEMD_USER/$SERVICE_FILE_SYSTEMD_SYSTEM" cp "./$OSYNC_SERVICE_FILE_SYSTEMD_SYSTEM" "$SERVICE_DIR_SYSTEMD_SYSTEM" && cp "./$OSYNC_SERVICE_FILE_SYSTEMD_USER" "$SERVICE_DIR_SYSTEMD_USER/$SERVICE_FILE_SYSTEMD_SYSTEM"
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "Cannot copy the systemd file to [$SERVICE_DIR_SYSTEMD_SYSTEM] or [$SERVICE_DIR_SYSTEMD_USER]." QuickLogger "Cannot copy the systemd file to [$SERVICE_DIR_SYSTEMD_SYSTEM] or [$SERVICE_DIR_SYSTEMD_USER]."
else else
echo "Created osync-srv service in [$SERVICE_DIR_SYSTEMD_SYSTEM] and [$SERVICE_DIR_SYSTEMD_USER]." QuickLogger "Created osync-srv service in [$SERVICE_DIR_SYSTEMD_SYSTEM] and [$SERVICE_DIR_SYSTEMD_USER]."
echo "Can be activated with [systemctl start osync-srv@instance.conf] where instance.conf is the name of the config file in /etc/osync." QuickLogger "Can be activated with [systemctl start osync-srv@instance.conf] where instance.conf is the name of the config file in /etc/osync."
echo "Can be enabled on boot with [systemctl enable osync-srv@instance.conf]." QuickLogger "Can be enabled on boot with [systemctl enable osync-srv@instance.conf]."
echo "In userland, active with [systemctl --user start osync-srv@instance.conf]." QuickLogger "In userland, active with [systemctl --user start osync-srv@instance.conf]."
fi fi
elif ( "$init" == "initV" ] && [ -f "./$OSYNC_SERVICE_FILE_INIT" ]); then elif ([ "$init" == "initV" ] && [ -f "./$OSYNC_SERVICE_FILE_INIT" ]); then
cp "./$OSYNC_SERVICE_FILE_INIT" "$SERVICE_DIR_INIT" cp "./$OSYNC_SERVICE_FILE_INIT" "$SERVICE_DIR_INIT"
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "Cannot copy osync-srv to [$SERVICE_DIR_INIT]." QuickLogger "Cannot copy osync-srv to [$SERVICE_DIR_INIT]."
else else
chmod 755 "$SERVICE_DIR_INIT/$OSYNC_SERVICE_FILE_INIT" chmod 755 "$SERVICE_DIR_INIT/$OSYNC_SERVICE_FILE_INIT"
echo "Created osync-srv service in [$SERVICE_DIR_INIT]." QuickLogger "Created osync-srv service in [$SERVICE_DIR_INIT]."
echo "Can be activated with [service $OSYNC_SERVICE_FILE_INIT start]." QuickLogger "Can be activated with [service $OSYNC_SERVICE_FILE_INIT start]."
echo "Can be enabled on boot with [chkconfig $OSYNC_SERVICE_FILE_INIT on]." QuickLogger "Can be enabled on boot with [chkconfig $OSYNC_SERVICE_FILE_INIT on]."
fi fi
fi fi
@@ -157,48 +220,83 @@ fi
if ([ "$init" == "systemd" ] && [ -f "./$PMOCR_SERVICE_FILE_SYSTEMD_SYSTEM" ]); then if ([ "$init" == "systemd" ] && [ -f "./$PMOCR_SERVICE_FILE_SYSTEMD_SYSTEM" ]); then
cp "./$PMOCR_SERVICE_FILE_SYSTEMD_SYSTEM" "$SERVICE_DIR_SYSTEMD_SYSTEM" cp "./$PMOCR_SERVICE_FILE_SYSTEMD_SYSTEM" "$SERVICE_DIR_SYSTEMD_SYSTEM"
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "Cannot copy the systemd file to [$SERVICE_DIR_SYSTEMD_SYSTEM] or [$SERVICE_DIR_SYSTEMD_USER]." QuickLogger "Cannot copy the systemd file to [$SERVICE_DIR_SYSTEMD_SYSTEM] or [$SERVICE_DIR_SYSTEMD_USER]."
else else
echo "Created pmocr-srv service in [$SERVICE_DIR_SYSTEMD_SYSTEM] and [$SERVICE_DIR_SYSTEMD_USER]." QuickLogger "Created pmocr-srv service in [$SERVICE_DIR_SYSTEMD_SYSTEM] and [$SERVICE_DIR_SYSTEMD_USER]."
echo "Can be activated with [systemctl start pmocr-srv] after configuring file options in [$BIN_DIR/$PROGRAM]." QuickLogger "Can be activated with [systemctl start pmocr-srv] after configuring file options in [$BIN_DIR/$PROGRAM]."
echo "Can be enabled on boot with [systemctl enable pmocr-srv]." QuickLogger "Can be enabled on boot with [systemctl enable pmocr-srv]."
fi fi
elif ([ "$init" == "initV" ] && [ -f "./$PMOCR_SERVICE_FILE_INIT" ]); then elif ([ "$init" == "initV" ] && [ -f "./$PMOCR_SERVICE_FILE_INIT" ]); then
cp "./$PMOCR_SERVICE_FILE_INIT" "$SERVICE_DIR_INIT" cp "./$PMOCR_SERVICE_FILE_INIT" "$SERVICE_DIR_INIT"
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "Cannot copy pmoct-srv to [$SERVICE_DIR_INIT]." QuickLogger "Cannot copy pmoct-srv to [$SERVICE_DIR_INIT]."
else else
chmod 755 "$SERVICE_DIR_INIT/$PMOCR_SERVICE_FILE_INIT" chmod 755 "$SERVICE_DIR_INIT/$PMOCR_SERVICE_FILE_INIT"
echo "Created osync-srv service in [$SERVICE_DIR_INIT]." QuickLogger "Created osync-srv service in [$SERVICE_DIR_INIT]."
echo "Can be activated with [service $PMOCR_SERVICE_FILE_INIT start]." QuickLogger "Can be activated with [service $PMOCR_SERVICE_FILE_INIT start]."
echo "Can be enabled on boot with [chkconfig $PMOCR_SERVICE_FILE_INIT on]." QuickLogger "Can be enabled on boot with [chkconfig $PMOCR_SERVICE_FILE_INIT on]."
fi fi
fi fi
}
function Statistics { function Statistics {
local link="http://instcount.netpower.fr?program=$PROGRAM&version=$PROGRAM_VERSION&os=$local_os_var"
if type wget > /dev/null; then if type wget > /dev/null; then
wget -qO- $link > /dev/null 2>&1 wget -qO- "$STATS_LINK" > /dev/null 2>&1
if [ $? == 0 ]; then if [ $? == 0 ]; then
return 0 return 0
fi fi
fi fi
if type curl > /dev/null; then if type curl > /dev/null; then
curl -o /dev/null $link > /dev/null 2>&1 curl "$STATS_LINK" -o /dev/null > /dev/null 2>&1
if [ $? == 0 ]; then if [ $? == 0 ]; then
return 0 return 0
fi fi
fi fi
echo "Neiter wget nor curl could be used for. Cannot run statistics. Use the provided link please." QuickLogger "Neiter wget nor curl could be used for. Cannot run statistics. Use the provided link please."
retun 1 return 1
} }
echo "$PROGRAM installed. Use with $BIN_DIR/$PROGRAM" function Usage {
echo "" echo "Installs $PROGRAM into $BIN_DIR"
echo "In order to make install statistics, the script would like to connect to http://instcount.netpower.fr?program=$PROGRAM&version=$PROGRAM_VERSION" echo "options:"
echo "--silent Will log and bypass user interaction."
echo "--no-stats Used with --silent in order to refuse sending anonymous install stats."
exit 127
}
_SILENT=0
_STATS=1
for i in "$@"
do
case $i in
--silent)
_SILENT=1
;;
--no-stats)
_STATS=0
;;
--help|-h|-?)
Usage
esac
done
SetOSSettings
CreateConfDir
CopyExampleFiles
CopyProgram
GetInit
CopyServiceFiles
STATS_LINK="http://instcount.netpower.fr?program=$PROGRAM&version=$PROGRAM_VERSION&os=$OS"
QuickLogger "$PROGRAM installed. Use with $BIN_DIR/$PROGRAM"
if [ $_STATS -eq 1 ]; then
if [ $_SILENT -eq 1 ]; then
Statistics
else
QuickLogger "In order to make install statistics, the script would like to connect to $STATS_LINK"
read -r -p "No data except those in the url will be send. Allow [Y/n]" response read -r -p "No data except those in the url will be send. Allow [Y/n]" response
case $response in case $response in
[nN]) [nN])
@@ -209,3 +307,5 @@ case $response in
exit $? exit $?
;; ;;
esac esac
fi
fi

View File

@@ -4,11 +4,11 @@
PROGRAM="obackup" PROGRAM="obackup"
AUTHOR="(C) 2013-2016 by Orsiris de Jong" AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr" CONTACT="http://www.netpower.fr/obackup - ozy@netpower.fr"
PROGRAM_VERSION=2.0-RC1 PROGRAM_VERSION=2.0
PROGRAM_BUILD=2016041201 PROGRAM_BUILD=2016080601
IS_STABLE=yes IS_STABLE=yes
## FUNC_BUILD=2016052502 ## FUNC_BUILD=2016071902-b
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr ## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode ## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
@@ -88,6 +88,7 @@ function Dummy {
sleep .1 sleep .1
} }
# Sub function of Logger
function _Logger { function _Logger {
local svalue="${1}" # What to log to stdout local svalue="${1}" # What to log to stdout
local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value
@@ -102,6 +103,7 @@ function _Logger {
fi fi
} }
# General log function with log levels
function Logger { function Logger {
local value="${1}" # Sentence to log (in double quotes) 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, NOTICE, WARN, ERROR, CRITIAL
@@ -140,6 +142,29 @@ function Logger {
fi fi
} }
# QuickLogger subfunction, can be called directly
function _QuickLogger {
local value="${1}"
local destination="${2}" # Destination: stdout, log, both
if ([ "$destination" == "log" ] || [ "$destination" == "both" ]); then
echo -e "$(date) - $value" >> "$LOG_FILE"
elif ([ "$destination" == "stdout" ] || [ "$destination" == "both" ]); then
echo -e "$value"
fi
}
# Generic quick logging function
function QuickLogger {
local value="${1}"
if [ "$_SILENT" -eq 1 ]; then
_QuickLogger "$value" "log"
else
_QuickLogger "$value" "stdout"
fi
}
# Portable child (and grandchild) kill function tester under Linux, BSD and MacOS X # Portable child (and grandchild) kill function tester under Linux, BSD and MacOS X
function KillChilds { function KillChilds {
local pid="${1}" local pid="${1}"
@@ -327,7 +352,7 @@ function SendAlert {
# smtp_server.domain.tld is mandatory, as is smtp_port (should be 25, 465 or 587) # smtp_server.domain.tld is mandatory, as is smtp_port (should be 25, 465 or 587)
# encryption can be set to tls, ssl or none # encryption can be set to tls, ssl or none
# smtp_user and smtp_password are optional # smtp_user and smtp_password are optional
# SendEmail "subject" "Body text" "receiver@example.com receiver2@otherdomain.com" "/path/to/attachment.file" "sender_email@example.com" "smtp_server.domain.tld" "smtp_port" "encrpytion" "smtp_user" "smtp_password" # SendEmail "subject" "Body text" "receiver@example.com receiver2@otherdomain.com" "/path/to/attachment.file" "sender_email@example.com" "smtp_server.domain.tld" "smtp_port" "encryption" "smtp_user" "smtp_password"
function SendEmail { function SendEmail {
local subject="${1}" local subject="${1}"
local message="${2}" local message="${2}"
@@ -336,7 +361,7 @@ function SendEmail {
local sender_email="${5}" local sender_email="${5}"
local smtp_server="${6}" local smtp_server="${6}"
local smtp_port="${7}" local smtp_port="${7}"
local encrpytion="${8}" local encryption="${8}"
local smtp_user="${9}" local smtp_user="${9}"
local smtp_password="${10}" local smtp_password="${10}"
@@ -553,10 +578,36 @@ function IsNumeric {
fi fi
} }
## from https://gist.github.com/cdown/1163649
function urlEncode {
local length="${#1}"
local LANG=C
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-])
printf "$c"
;;
*)
printf '%%%02X' "'$c"
;;
esac
done
}
function urlDecode {
local url_encoded="${1//+/ }"
printf '%b' "${url_encoded//%/\\x}"
}
function CleanUp { function CleanUp {
if [ "$_DEBUG" != "yes" ]; then if [ "$_DEBUG" != "yes" ]; then
rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID" rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID"
# Fix for sed -i requiring backup extension for BSD & Mac (see all sed -i statements)
rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID.tmp"
fi fi
} }
@@ -674,6 +725,8 @@ function WaitForTaskCompletion {
local seconds_begin=$SECONDS # Seconds since the beginning of the script local seconds_begin=$SECONDS # Seconds since the beginning of the script
local exec_time=0 # Seconds since the beginning of this function local exec_time=0 # Seconds since the beginning of this function
local retval=0 # return value of monitored pid process
while eval "$PROCESS_TEST_CMD" > /dev/null while eval "$PROCESS_TEST_CMD" > /dev/null
do do
Spinner Spinner
@@ -705,7 +758,7 @@ function WaitForTaskCompletion {
sleep $SLEEP_TIME sleep $SLEEP_TIME
done done
wait $pid wait $pid
local retval=$? retval=$?
return $retval return $retval
} }
@@ -716,11 +769,13 @@ function WaitForCompletion {
local caller_name="${4}" # Who called this function local caller_name="${4}" # Who called this function
local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once
local log_ttime=0 # local time instance for comparaison local log_time=0 # local time instance for comparaison
local seconds_begin=$SECONDS # Seconds since the beginning of the script local seconds_begin=$SECONDS # Seconds since the beginning of the script
local exec_time=0 # Seconds since the beginning of this function local exec_time=0 # Seconds since the beginning of this function
local retval=0 # return value of monitored pid process
while eval "$PROCESS_TEST_CMD" > /dev/null while eval "$PROCESS_TEST_CMD" > /dev/null
do do
Spinner Spinner
@@ -918,8 +973,6 @@ function RsyncPatternsFromAdd {
local pattern_type="${1}" local pattern_type="${1}"
local pattern_from="${2}" local pattern_from="${2}"
local pattern_from=
## Check if the exclude list has a full path, and if not, add the config file path if there is one ## Check if the exclude list has a full path, and if not, add the config file path if there is one
if [ "$(basename $pattern_from)" == "$pattern_from" ]; then if [ "$(basename $pattern_from)" == "$pattern_from" ]; then
pattern_from="$(dirname $CONFIG_FILE)/$pattern_from" pattern_from="$(dirname $CONFIG_FILE)/$pattern_from"
@@ -1596,7 +1649,7 @@ function _CreateDirectoryLocal {
if [ ! -d "$dir_to_create" ]; then if [ ! -d "$dir_to_create" ]; then
# No sudo, you should have all necessary rights # No sudo, you should have all necessary rights
mkdir --parents "$dir_to_create" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 mkdir -p "$dir_to_create" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1
if [ $? != 0 ]; then if [ $? != 0 ]; then
Logger "Cannot create directory [$dir_to_create]" "CRITICAL" Logger "Cannot create directory [$dir_to_create]" "CRITICAL"
if [ -f $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID ]; then if [ -f $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID ]; then
@@ -1614,7 +1667,7 @@ function _CreateDirectoryRemote {
CheckConnectivity3rdPartyHosts CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost CheckConnectivityRemoteHost
cmd=$SSH_CMD' "if ! [ -d \"'$dir_to_create'\" ]; then '$COMMAND_SUDO' mkdir --parents \"'$dir_to_create'\"; fi" > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2>&1' cmd=$SSH_CMD' "if ! [ -d \"'$dir_to_create'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$dir_to_create'\"; fi" > '$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID' 2>&1'
Logger "cmd: $cmd" "DEBUG" Logger "cmd: $cmd" "DEBUG"
eval "$cmd" & eval "$cmd" &
WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]} WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
@@ -1790,6 +1843,7 @@ function _BackupDatabaseLocalToLocal {
local dry_sql_cmd local dry_sql_cmd
local sql_cmd local sql_cmd
local retval
local dry_sql_cmd="mysqldump -u $SQL_USER $export_options --database $database $COMPRESSION_PROGRAM $COMPRESSION_OPTIONS > /dev/null 2> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" local dry_sql_cmd="mysqldump -u $SQL_USER $export_options --database $database $COMPRESSION_PROGRAM $COMPRESSION_OPTIONS > /dev/null 2> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID"
@@ -1803,9 +1857,11 @@ function _BackupDatabaseLocalToLocal {
eval "$dry_sql_cmd" & eval "$dry_sql_cmd" &
fi fi
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]} WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]}
local retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }
@@ -1817,6 +1873,7 @@ function _BackupDatabaseLocalToRemote {
local dry_sql_cmd local dry_sql_cmd
local sql_cmd local sql_cmd
local retval
CheckConnectivity3rdPartyHosts CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost CheckConnectivityRemoteHost
@@ -1833,9 +1890,11 @@ function _BackupDatabaseLocalToRemote {
eval "$dry_sql_cmd" & eval "$dry_sql_cmd" &
fi fi
WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]} WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK ${FUNCNAME[0]}
local retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }
@@ -1866,6 +1925,8 @@ function _BackupDatabaseRemoteToLocal {
retval=$? retval=$?
if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" ]; then
Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR" Logger "Error output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID)" "ERROR"
# Dirty fix for mysqldump return code not honored
retval=1
fi fi
return $retval return $retval
} }