diff --git a/client/CHANGELOG.md b/client/CHANGELOG.md index ad915f4..9b4d387 100644 --- a/client/CHANGELOG.md +++ b/client/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Script now depends on Bash * tolerate absence of mtr or traceroute * Only one loop for all Redis instances +* remodel how we build the rsync command ### Deprecated diff --git a/client/zzz_evobackup b/client/zzz_evobackup index 43566d0..9871b44 100755 --- a/client/zzz_evobackup +++ b/client/zzz_evobackup @@ -48,6 +48,9 @@ PIDFILE="/var/run/${PROGNAME}.pid" # Customize the log path if you have multiple scripts and with separate logs LOGFILE="/var/log/evobackup.log" +# Full Rsync log file, reset each time +RSYNC_LOGFILE="/var/log/${PROGNAME}.rsync.log" + HOSTNAME=$(hostname) DATE_FORMAT="%Y-%m-%d %H:%M:%S" @@ -57,7 +60,71 @@ DATE_FORMAT="%Y-%m-%d %H:%M:%S" # Enable/disable sync tasks (default: enabled) : "${SYNC_TASKS:=1}" -##### SETUP AND FUNCTIONS ############################################# +# Source paths can be customized +# Empty lines, and lines containing # or ; are ignored +RSYNC_INCLUDES=" +/etc +/root +/var +/home +/zzz_evobackup_canary +" + +# Excluded paths can be customized +# Empty lines, and lines beginning with # or ; are ignored +RSYNC_EXCLUDES=" +/dev +/proc +/run +/sys +/tmp +/usr/doc +/usr/obj +/usr/share/doc +/usr/src +/var/apt +/var/cache +/var/db/munin/*.tmp +/var/lib/amavis/amavisd.sock +/var/lib/amavis/tmp +/var/lib/clamav/*.tmp +/var/lib/elasticsearch +/var/lib/metche +/var/lib/mongodb +/var/lib/munin/*tmp* +/var/lib/mysql +/var/lib/php/sessions +/var/lib/php5 +/var/lib/postgres +/var/lib/postgresql +/var/lib/sympa +/var/lock +/var/run +/var/spool/postfix +/var/spool/smtpd +/var/spool/squid +/var/state +/var/tmp +lost+found +.nfs.* +lxc/*/rootfs/tmp +lxc/*/rootfs/usr/doc +lxc/*/rootfs/usr/obj +lxc/*/rootfs/usr/share/doc +lxc/*/rootfs/usr/src +lxc/*/rootfs/var/apt +lxc/*/rootfs/var/cache +lxc/*/rootfs/var/lib/php5 +lxc/*/rootfs/var/lib/php/sessions +lxc/*/rootfs/var/lock +lxc/*/rootfs/var/run +lxc/*/rootfs/var/state +lxc/*/rootfs/var/tmp +/home/mysqltmp +" + + +##### FUNCTIONS ####################################################### local_tasks() { log "START LOCAL_TASKS" @@ -249,7 +316,7 @@ local_tasks() { # else # echo 'Cannot make a snapshot of elasticsearch, at least one node is not mounting the repository.' # fi - ## If you need to keep older snapshot, for example the last 10 daily snapshots, replace the XDELETE and XPUT lines by : + ## If you need to keep older snapshot, for example the last 10 daily snapshots, replace the XDELETE and XPUT lines by : # for snapshot in $(curl -s -XGET "localhost:9200/_snapshot/snaprepo/_all?pretty=true" | grep -Eo 'snapshot_[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -n -10); do # curl -s -XDELETE "localhost:9200/_snapshot/snaprepo/${snapshot}" | grep -v -Fx '{"acknowledged":true}' # done @@ -368,6 +435,62 @@ local_tasks() { log "STOP LOCAL_TASKS" } +build_rsync_cmd() { + ################################################################### + # /!\ WARNING /!\ WARNING /!\ WARNING /!\ WARNING /!\ WARNING /!\ # + ################################################################### + # DO NOT USE COMMENTS in rsync lines # + # DO NOT ADD WHITESPACES AFTER \ in rsync lines # + # It breaks the command and destroys data # + # You should not modify this, unless you are really REALLY sure # + ################################################################### + + # Create a temp file for excludes and includes + includes_file="$(mktemp "${PROGNAME}.includes.XXXXXX")" + excludes_file="$(mktemp "${PROGNAME}.excludes.XXXXXX")" + # … and add them to the list of files to delete at exit + temp_files="${temp_files} ${includes_file} ${excludes_file}" + + # Store includes/excludes in files + # without blank lines of comments (# or ;) + echo "${RSYNC_INCLUDES}" | sed -e 's/\s*\(#\|;\).*//; /^\s*$/d' > "${includes_file}" + echo "${RSYNC_EXCLUDES}" | sed -e 's/\s*\(#\|;\).*//; /^\s*$/d' > "${excludes_file}" + + # Rsync command + cmd="$(command -v rsync)" + + # Rsync main options + cmd="${cmd} --archive" + cmd="${cmd} --itemize-changes" + cmd="${cmd} --quiet" + cmd="${cmd} --stats" + cmd="${cmd} --human-readable" + cmd="${cmd} --relative" + cmd="${cmd} --partial" + cmd="${cmd} --delete" + cmd="${cmd} --delete-excluded" + cmd="${cmd} --force" + cmd="${cmd} --ignore-errors" + cmd="${cmd} --log-file=${RSYNC_LOGFILE}" + cmd="${cmd} --rsh='ssh -p ${SSH_PORT} -o \"ConnectTimeout ${SSH_CONNECT_TIMEOUT}\"'" + + # Rsync excludes + while read line ; do + cmd="${cmd} --exclude ${line}" + done < "${excludes_file}" + + # Rsync local sources + cmd="${cmd} ${default_includes}" + while read line ; do + cmd="${cmd} ${line}" + done < "${includes_file}" + + # Rsync remote destination + cmd="${cmd} root@${SSH_SERVER}:/var/backup/" + + # output final command + echo "${cmd}" +} sync_tasks() { n=0 server="" @@ -392,88 +515,30 @@ sync_tasks() { SSH_SERVER=$(echo "${server}" | cut -d':' -f1) SSH_PORT=$(echo "${server}" | cut -d':' -f2) - if [ "${SYSTEM}" = "linux" ]; then - rep="/bin /boot /lib /opt /sbin /usr" - else - rep="/bsd /bin /sbin /usr" - fi - log "START SYNC_TASKS - server=${server}" - update-evobackup-canary --who "${PROGNAME}" + # default paths, depending on system + if [ "${SYSTEM}" = "linux" ]; then + default_includes="/bin /boot /lib /opt /sbin /usr" + else + default_includes="/bsd /bin /sbin /usr" + fi - # Remote shell command - RSH_COMMAND="ssh -p ${SSH_PORT} -o 'ConnectTimeout ${SSH_CONNECT_TIMEOUT}'" + # reset Rsync log file + if [ -n "$(command -v truncate)" ]; then + truncate -s 0 "${RSYNC_LOGFILE}" + else + printf "" > "${RSYNC_LOGFILE}" + fi - ################################################################### - # /!\ WARNING /!\ WARNING /!\ WARNING /!\ WARNING /!\ WARNING /!\ # - ################################################################### - # DO NOT USE COMMENTS in rsync lines # - # DO NOT ADD WHITESPACES AFTER \ in rsync lines # - # It breaks the command and destroys data # - # => Only remove (or add) lines. # - ################################################################### + # Build the final Rsync command + rsync_cmd=$(build_rsync_cmd) - # ignore check because we want it to split the different arguments to $rep - # shellcheck disable=SC2086 - rsync --archive \ - --itemize-changes --stats --human-readable \ - --relative --partial \ - --delete --delete-excluded --force --ignore-errors \ - --exclude "dev" \ - --exclude "lost+found" \ - --exclude ".nfs.*" \ - --exclude "/usr/doc" \ - --exclude "/usr/obj" \ - --exclude "/usr/share/doc" \ - --exclude "/usr/src" \ - --exclude "/var/apt" \ - --exclude "/var/cache" \ - --exclude "/var/lib/amavis/amavisd.sock" \ - --exclude "/var/lib/amavis/tmp" \ - --exclude "/var/lib/clamav/*.tmp" \ - --exclude "/var/lib/elasticsearch" \ - --exclude "/var/lib/metche" \ - --exclude "/var/lib/munin/*tmp*" \ - --exclude "/var/db/munin/*.tmp" \ - --exclude "/var/lib/mongodb" \ - --exclude "/var/lib/mysql" \ - --exclude "/var/lib/php5" \ - --exclude "/var/lib/php/sessions" \ - --exclude "/var/lib/postgres" \ - --exclude "/var/lib/postgresql" \ - --exclude "/var/lib/sympa" \ - --exclude "/var/lock" \ - --exclude "/var/run" \ - --exclude "/var/spool/postfix" \ - --exclude "/var/spool/smtpd" \ - --exclude "/var/spool/squid" \ - --exclude "/var/state" \ - --exclude "/var/tmp" \ - --exclude "lxc/*/rootfs/tmp" \ - --exclude "lxc/*/rootfs/usr/doc" \ - --exclude "lxc/*/rootfs/usr/obj" \ - --exclude "lxc/*/rootfs/usr/share/doc" \ - --exclude "lxc/*/rootfs/usr/src" \ - --exclude "lxc/*/rootfs/var/apt" \ - --exclude "lxc/*/rootfs/var/cache" \ - --exclude "lxc/*/rootfs/var/lib/php5" \ - --exclude "lxc/*/rootfs/var/lib/php/sessions" \ - --exclude "lxc/*/rootfs/var/lock" \ - --exclude "lxc/*/rootfs/var/log" \ - --exclude "lxc/*/rootfs/var/run" \ - --exclude "lxc/*/rootfs/var/state" \ - --exclude "lxc/*/rootfs/var/tmp" \ - --exclude "/home/mysqltmp" \ - ${rep} \ - /etc \ - /root \ - /var \ - /home \ - /zzz_evobackup_canary \ - -e "${RSH_COMMAND}" \ - "root@${SSH_SERVER}:/var/backup/" \ - | tail -30 >> "${LOGFILE}" + # … log it + log "SYNC_TASKS - Rsync command : ${rsync_cmd}" + + # … execute it + eval "${rsync_cmd}" rsync_rc=$? if [ ${rsync_rc} -ne 0 ]; then @@ -481,6 +546,9 @@ sync_tasks() { rc=201 fi + # Copy last lines of rsync log to the main log + tail -n 30 "${RSYNC_LOGFILE}" >> "${LOGFILE}" + log "STOP SYNC_TASKS - server=${server}" } @@ -582,8 +650,16 @@ main() { fi fi echo "$$" > "${PIDFILE}" + + # Initialize a list of files to delete at exit + # Any file added to the list will also be deleted at exit + temp_files="${PIDFILE}" + # shellcheck disable=SC2064 - trap "rm -f ${PIDFILE}" EXIT + trap "rm -f ${temp_files}" EXIT + + # Update canary to keep track of each run + update-evobackup-canary --who "${PROGNAME}" if [ "${LOCAL_TASKS}" = "1" ]; then local_tasks