From b5f1e13685fe19018561baaaab7535b9d33fa481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:25:33 +0200 Subject: [PATCH 01/14] Add logic to have multiple available servers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SERVERS contains 1 or more servers to send backup files to. Each day a primary backup server is chosen. If it's not available the script falls back to the next server, and the next… --- zzz_evobackup | 68 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index 6e3d2d7..927d26b 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -14,13 +14,11 @@ # Licence: AGPLv3 # # The following variables must be changed: -# SSH_PORT: The Port used for the ssh(1) jail on the backup server # MAIL: The email address to send notifications to. -# SRV: The hostname or IP address of the backup server. -# -# You must then uncomment the various -# examples that best suit your case +# SERVERS: The list of hosts (hostname or IP address) and SSH port +# to send backup files to. # +# You must then uncomment the various examples that best suit your case.# PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin @@ -46,20 +44,62 @@ fi echo "$$" > $PIDFILE trap "rm -f $PIDFILE" EXIT -# port SSH -SSH_PORT=2XXX - # email adress for notifications MAIL=jdoe@example.com # choose "linux" or "bsd" SYSTEM=$(uname | tr '[:upper:]' '[:lower:]') -# Variable to choose different backup server with date -NODE=$(($(date +%e) % 2)) +SERVERS="node0.backup.example.com:2XXX node1.backup.example.com:2XXX" +SSH_CONNECT_TIMEOUT=10 -# serveur address for rsync -SRV="node$NODE.backup.example.com" +test_server() { + item=$1 + host=$(echo ${item} | cut -d':' -f1) + port=$(echo ${item} | cut -d':' -f2) + + # Test if the server is accepting connections + ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" ${host} -p ${port} -t "exit" + + if [ $? = 0 ]; then + return 0 + else + echo "Failed to connect to \`${item}' within ${SSH_CONNECT_TIMEOUT} seconds" >&2 + return 1 + fi +} +pick_server() { + inc=${1:-0} + list_length=$(echo "${SERVERS}" | wc -w) + + if [ "${inc}" -ge "${list_length}" ]; then + echo "No more server available" >&2 + return 1 + fi + + salt=$(hostname | cksum | cut -d' ' -f1) + item=$(echo $(( ($(date +%d) + salt + inc) % list_length ))) + field=$(( item + 1 )) + + echo "${SERVERS}" | cut -d' ' -f${field} +} + +n=0 +SERVER="" +while :; do + server=$(pick_server "${n}") + test $? = 0 || exit 2 + + if test_server "${server}"; then + SERVER="${server}" + break + else + n=$(( n + 1 )) + fi +done + +SSH_SERVER=$(echo $SERVER | cut -d':' -f1) +SSH_PORT=$(echo $SERVER | cut -d':' -f2) ## We use /home/backup : feel free to use your own dir mkdir -p -m 700 /home/backup @@ -249,8 +289,8 @@ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial /var \ /home \ /srv \ - -e "ssh -p $SSH_PORT" \ - "root@$SRV:/var/backup/" \ + -e "ssh -p ${SSH_PORT}" \ + "root@${SSH_SERVER}:/var/backup/" \ | tail -30 >> /var/log/evobackup.log END=$(/bin/date +"%d-%m-%Y ; %H:%M") From ab57f64d93165b1606ce2804d779efd27cf36de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:26:52 +0200 Subject: [PATCH 02/14] Extract a LOCAL_BACKUP_DIR variable --- zzz_evobackup | 58 ++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index 927d26b..1028efe 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -102,16 +102,18 @@ SSH_SERVER=$(echo $SERVER | cut -d':' -f1) SSH_PORT=$(echo $SERVER | cut -d':' -f2) ## We use /home/backup : feel free to use your own dir -mkdir -p -m 700 /home/backup +LOCAL_BACKUP_DIR=/home/backup +# shellcheck disable=SC2174 +mkdir -p -m 700 ${LOCAL_BACKUP_DIR} ## OpenLDAP : example with slapcat -# slapcat -l /home/backup/ldap.bak +# slapcat -l ${LOCAL_BACKUP_DIR}/ldap.bak ### MySQL ## example with global and compressed mysqldump # mysqldump --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \ -# --opt --all-databases --force --events --hex-blob | gzip --best > /home/backup/mysql.bak.gz +# --opt --all-databases --force --events --hex-blob | gzip --best > ${LOCAL_BACKUP_DIR}/mysql.bak.gz ## example with two dumps for each table (.sql/.txt) for all databases # for i in $(echo SHOW DATABASES | mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \ @@ -143,7 +145,7 @@ mkdir -p -m 700 /home/backup # instance=$(echo "$instance"|awk '{ print $3 }') # if [ "$instance" != "3306" ] # then -# mysqldump -P $instance --opt --all-databases --hex-blob -u mysqladmin -p$mysqladminpasswd > /home/backup/mysql.$instance.bak +# mysqldump -P $instance --opt --all-databases --hex-blob -u mysqladmin -p$mysqladminpasswd > ${LOCAL_BACKUP_DIR}/mysql.$instance.bak # fi # done @@ -151,31 +153,31 @@ mkdir -p -m 700 /home/backup ## example with pg_dumpall (warning: you need space in ~postgres) # su - postgres -c "pg_dumpall > ~/pg.dump.bak" -# mv ~postgres/pg.dump.bak /home/backup/ +# mv ~postgres/pg.dump.bak ${LOCAL_BACKUP_DIR}/ ## another method with gzip directly piped # cd /var/lib/postgresql -# sudo -u postgres pg_dumpall | gzip > /home/backup/pg.dump.bak.gz +# sudo -u postgres pg_dumpall | gzip > ${LOCAL_BACKUP_DIR}/pg.dump.bak.gz # cd - > /dev/null ## example with all tables from MYBASE excepts TABLE1 and TABLE2 -# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f /home/backup/pg-backup.tar -t 'TABLE1' -t 'TABLE2' MYBASE +# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -t 'TABLE1' -t 'TABLE2' MYBASE ## example with only TABLE1 and TABLE2 from MYBASE -# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f /home/backup/pg-backup.tar -T 'TABLE1' -T 'TABLE2' MYBASE +# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -T 'TABLE1' -T 'TABLE2' MYBASE ## MongoDB : example with mongodump ## don't forget to create use with read-only access ## > use admin ## > db.createUser( { user: "mongobackup", pwd: "PASS", roles: [ "backup", ] } ) -# test -d /home/backup/mongodump/ && rm -rf /home/backup/mongodump/ -# mkdir -p -m 700 /home/backup/mongodump/ -# mongodump --quiet -u mongobackup -pPASS -o /home/backup/mongodump/ +# test -d ${LOCAL_BACKUP_DIR}/mongodump/ && rm -rf ${LOCAL_BACKUP_DIR}/mongodump/ +# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mongodump/ +# mongodump --quiet -u mongobackup -pPASS -o ${LOCAL_BACKUP_DIR}/mongodump/ # if [ $? -ne 0 ]; then # echo "Error with mongodump!" # fi ## Redis : example with copy .rdb file -# cp /var/lib/redis/dump.rdb /home/backup/ +# cp /var/lib/redis/dump.rdb ${LOCAL_BACKUP_DIR}/ ## ElasticSearch, take a snapshot as a backup. ## Warning: You need to have a path.repo configured. @@ -199,48 +201,48 @@ mkdir -p -m 700 /home/backup # curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot_${date}?wait_for_completion=true" -o /tmp/es_snapshot_${date}.log ## RabbitMQ : export config -#rabbitmqadmin export /home/backup/rabbitmq.config >> /var/log/evobackup.log +#rabbitmqadmin export ${LOCAL_BACKUP_DIR}/rabbitmq.config >> /var/log/evobackup.log ## Dump MBR / table partitions with dd and sfdisk ## Linux #for disk in $(ls /dev/[sv]d[a-z] 2>/dev/null); do # name=$(basename $disk) -# dd if=$disk of=/home/backup/MBR-$name bs=512 count=1 2>&1 | egrep -v "(records in|records out|512 bytes)" -# fdisk -l $disk > /home/backup/partitions-$name +# dd if=$disk of=${LOCAL_BACKUP_DIR}/MBR-$name bs=512 count=1 2>&1 | egrep -v "(records in|records out|512 bytes)" +# fdisk -l $disk > ${LOCAL_BACKUP_DIR}/partitions-$name #done -#cat /home/backup/partitions-* > /home/backup/partitions +#cat ${LOCAL_BACKUP_DIR}/partitions-* > ${LOCAL_BACKUP_DIR}/partitions ## OpenBSD -# disklabel sd0 > /home/backup/partitions +# disklabel sd0 > ${LOCAL_BACKUP_DIR}/partitions # backup MegaCli config -#megacli -CfgSave -f /home/backup/megacli_conf.dump -a0 >/dev/null +#megacli -CfgSave -f ${LOCAL_BACKUP_DIR}/megacli_conf.dump -a0 >/dev/null ## Dump system and kernel versions -uname -a > /home/backup/uname +uname -a > ${LOCAL_BACKUP_DIR}/uname ## Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls) for addr in 8.8.8.8 www.evolix.fr travaux.evolix.net; do - mtr -r $addr > /home/backup/mtr-${addr} - traceroute -n $addr > /home/backup/traceroute-${addr} 2>&1 + mtr -r ${addr} > ${LOCAL_BACKUP_DIR}/mtr-${addr} + traceroute -n ${addr} > ${LOCAL_BACKUP_DIR}/traceroute-${addr} 2>&1 done ## Dump process with ps -ps auwwx >/home/backup/ps.out +ps auwwx >${LOCAL_BACKUP_DIR}/ps.out if [ "$SYSTEM" = "linux" ]; then ## Dump network connections with netstat - netstat -taupen >/home/backup/netstat.out + netstat -taupen > ${LOCAL_BACKUP_DIR}/netstat.out ## List Debian packages - dpkg -l >/home/backup/packages - dpkg --get-selections >/home/backup/packages.getselections - apt-cache dumpavail >/home/backup/packages.available + dpkg -l > ${LOCAL_BACKUP_DIR}/packages + dpkg --get-selections > ${LOCAL_BACKUP_DIR}/packages.getselections + apt-cache dumpavail > ${LOCAL_BACKUP_DIR}/packages.available else ## Dump network connections with netstat - netstat -finet -atn >/home/backup/netstat.out + netstat -finet -atn > ${LOCAL_BACKUP_DIR}/netstat.out ## List OpenBSD packages - pkg_info -m >/home/backup/packages + pkg_info -m > ${LOCAL_BACKUP_DIR}/packages fi HOSTNAME=$(hostname) From b1f46bc86672e19faa6980037374c4bab0cb3020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:27:10 +0200 Subject: [PATCH 03/14] Add braces around variables --- zzz_evobackup | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index 1028efe..dee3cc0 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -229,7 +229,7 @@ done ## Dump process with ps ps auwwx >${LOCAL_BACKUP_DIR}/ps.out -if [ "$SYSTEM" = "linux" ]; then +if [ "${SYSTEM}" = "linux" ]; then ## Dump network connections with netstat netstat -taupen > ${LOCAL_BACKUP_DIR}/netstat.out @@ -249,7 +249,7 @@ HOSTNAME=$(hostname) BEGINNING=$(/bin/date +"%d-%m-%Y ; %H:%M") -if [ "$SYSTEM" = "linux" ]; then +if [ "${SYSTEM}" = "linux" ]; then rep="/bin /boot /lib /opt /sbin /usr" else rep="/bsd /bin /sbin /usr" @@ -285,7 +285,7 @@ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial --exclude "/var/lib/clamav/*.tmp" \ --exclude "/home/mysqltmp" \ --exclude "/var/lib/php/sessions" \ - $rep \ + ${rep} \ /etc \ /root \ /var \ @@ -297,12 +297,12 @@ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial END=$(/bin/date +"%d-%m-%Y ; %H:%M") -echo "EvoBackup - $HOSTNAME - START $BEGINNING" \ +echo "EvoBackup - ${HOSTNAME} - START ${BEGINNING}" \ >> /var/log/evobackup.log -echo "EvoBackup - $HOSTNAME - STOP $END" \ +echo "EvoBackup - ${HOSTNAME} - STOP ${END}" \ >> /var/log/evobackup.log tail -10 /var/log/evobackup.log | \ - mail -s "[info] EvoBackup - Client $HOSTNAME" \ - $MAIL + mail -s "[info] EvoBackup - Client ${HOSTNAME}" \ + ${MAIL} From 1376771e836154bcc5c4265055fd3a430751e3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:30:07 +0200 Subject: [PATCH 04/14] shellcheck fixes --- zzz_evobackup | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index dee3cc0..0fe145a 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -2,7 +2,7 @@ # # Script Evobackup client # See https://gitea.evolix.org/evolix/evobackup -# +# # Author: Gregory Colpart # Contributors: # Romain Dessort @@ -42,6 +42,7 @@ if [ -e $PIDFILE ]; then echo "$0 tourne encore (PID $pid). Processus killé" >&2 fi echo "$$" > $PIDFILE +# shellcheck disable=SC2064 trap "rm -f $PIDFILE" EXIT # email adress for notifications @@ -55,12 +56,12 @@ SSH_CONNECT_TIMEOUT=10 test_server() { item=$1 - host=$(echo ${item} | cut -d':' -f1) - port=$(echo ${item} | cut -d':' -f2) + host=$(echo "${item}" | cut -d':' -f1) + port=$(echo "${item}" | cut -d':' -f2) # Test if the server is accepting connections - ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" ${host} -p ${port} -t "exit" - + ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" "${host}" -p "${port}" -t "exit" + # shellcheck disable=SC2181 if [ $? = 0 ]; then return 0 else @@ -78,7 +79,7 @@ pick_server() { fi salt=$(hostname | cksum | cut -d' ' -f1) - item=$(echo $(( ($(date +%d) + salt + inc) % list_length ))) + item=$(( ($(date +%d) + salt + inc) % list_length )) field=$(( item + 1 )) echo "${SERVERS}" | cut -d' ' -f${field} @@ -98,11 +99,11 @@ while :; do fi done -SSH_SERVER=$(echo $SERVER | cut -d':' -f1) -SSH_PORT=$(echo $SERVER | cut -d':' -f2) +SSH_SERVER=$(echo "${SERVER}" | cut -d':' -f1) +SSH_PORT=$(echo "${SERVER}" | cut -d':' -f2) ## We use /home/backup : feel free to use your own dir -LOCAL_BACKUP_DIR=/home/backup +LOCAL_BACKUP_DIR="/home/backup" # shellcheck disable=SC2174 mkdir -p -m 700 ${LOCAL_BACKUP_DIR} @@ -285,7 +286,7 @@ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial --exclude "/var/lib/clamav/*.tmp" \ --exclude "/home/mysqltmp" \ --exclude "/var/lib/php/sessions" \ - ${rep} \ + "${rep}" \ /etc \ /root \ /var \ From 34476ac7c7ed49ae3d31831f3e06c918386f558e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:32:09 +0200 Subject: [PATCH 05/14] whitespaces --- zzz_evobackup | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index 0fe145a..a030796 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -207,9 +207,9 @@ mkdir -p -m 700 ${LOCAL_BACKUP_DIR} ## Dump MBR / table partitions with dd and sfdisk ## Linux #for disk in $(ls /dev/[sv]d[a-z] 2>/dev/null); do -# name=$(basename $disk) -# dd if=$disk of=${LOCAL_BACKUP_DIR}/MBR-$name bs=512 count=1 2>&1 | egrep -v "(records in|records out|512 bytes)" -# fdisk -l $disk > ${LOCAL_BACKUP_DIR}/partitions-$name +# name=$(basename $disk) +# dd if=$disk of=${LOCAL_BACKUP_DIR}/MBR-$name bs=512 count=1 2>&1 | egrep -v "(records in|records out|512 bytes)" +# fdisk -l $disk > ${LOCAL_BACKUP_DIR}/partitions-$name #done #cat ${LOCAL_BACKUP_DIR}/partitions-* > ${LOCAL_BACKUP_DIR}/partitions ## OpenBSD From e852827d9a6eaedb39d2e16c79281e3d42520ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:53:07 +0200 Subject: [PATCH 06/14] reorganize sections or the script --- zzz_evobackup | 114 ++++++++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index a030796..7adf6d9 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -13,12 +13,29 @@ # # Licence: AGPLv3 # -# The following variables must be changed: -# MAIL: The email address to send notifications to. -# SERVERS: The list of hosts (hostname or IP address) and SSH port -# to send backup files to. -# -# You must then uncomment the various examples that best suit your case.# +# /!\ DON'T FORGET TO SET "MAIL" and "SERVERS" VARIABLES + +##### Configuration ############################################################ + +# email adress for notifications +MAIL=jdoe@example.com + +# list of hosts (hostname or IP) and SSH port for Rsync +SERVERS="node0.backup.example.com:2XXX node1.backup.example.com:2XXX" + +# timeout (in seconds) for the SSH test +SSH_CONNECT_TIMEOUT=10 + +## We use /home/backup : feel free to use your own dir +LOCAL_BACKUP_DIR="/home/backup" + +# You can set "linux" or "bsd" manually or let it choose automatically +SYSTEM=$(uname | tr '[:upper:]' '[:lower:]') + +##### SETUP AND FUNCTIONS ###################################################### + +# shellcheck disable=SC2174 +mkdir -p -m 700 ${LOCAL_BACKUP_DIR} PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin @@ -29,31 +46,6 @@ export LANG=C ## Force umask umask 077 -## Verify other evobackup process and kill if needed -PIDFILE=/var/run/evobackup.pid -if [ -e $PIDFILE ]; then - pid=$(cat "$PIDFILE") - # Killing the childs of evobackup. - for ppid in $(ps h --ppid "$pid" -o pid | tr -s '\n' ' '); do - kill -9 "$ppid"; - done - # Then kill the main PID. - kill -9 "$pid" - echo "$0 tourne encore (PID $pid). Processus killé" >&2 -fi -echo "$$" > $PIDFILE -# shellcheck disable=SC2064 -trap "rm -f $PIDFILE" EXIT - -# email adress for notifications -MAIL=jdoe@example.com - -# choose "linux" or "bsd" -SYSTEM=$(uname | tr '[:upper:]' '[:lower:]') - -SERVERS="node0.backup.example.com:2XXX node1.backup.example.com:2XXX" -SSH_CONNECT_TIMEOUT=10 - test_server() { item=$1 host=$(echo "${item}" | cut -d':' -f1) @@ -85,27 +77,25 @@ pick_server() { echo "${SERVERS}" | cut -d' ' -f${field} } -n=0 -SERVER="" -while :; do - server=$(pick_server "${n}") - test $? = 0 || exit 2 +## Verify other evobackup process and kill if needed +PIDFILE=/var/run/evobackup.pid +if [ -e $PIDFILE ]; then + pid=$(cat "$PIDFILE") + # Killing the childs of evobackup. + for ppid in $(ps h --ppid "$pid" -o pid | tr -s '\n' ' '); do + kill -9 "$ppid"; + done + # Then kill the main PID. + kill -9 "$pid" + echo "$0 tourne encore (PID $pid). Processus killé" >&2 +fi +echo "$$" > $PIDFILE +# shellcheck disable=SC2064 +trap "rm -f $PIDFILE" EXIT - if test_server "${server}"; then - SERVER="${server}" - break - else - n=$(( n + 1 )) - fi -done +##### LOCAL BACKUP ############################################################# -SSH_SERVER=$(echo "${SERVER}" | cut -d':' -f1) -SSH_PORT=$(echo "${SERVER}" | cut -d':' -f2) - -## We use /home/backup : feel free to use your own dir -LOCAL_BACKUP_DIR="/home/backup" -# shellcheck disable=SC2174 -mkdir -p -m 700 ${LOCAL_BACKUP_DIR} +# You can comment or uncomment sections below to customize the backup ## OpenLDAP : example with slapcat # slapcat -l ${LOCAL_BACKUP_DIR}/ldap.bak @@ -246,6 +236,25 @@ else pkg_info -m > ${LOCAL_BACKUP_DIR}/packages fi +##### REMOTE BACKUP ############################################################ + +n=0 +server="" +while :; do + server=$(pick_server "${n}") + test $? = 0 || exit 2 + + if test_server "${server}"; then + break + else + server="" + n=$(( n + 1 )) + fi +done + +SSH_SERVER=$(echo "${server}" | cut -d':' -f1) +SSH_PORT=$(echo "${server}" | cut -d':' -f2) + HOSTNAME=$(hostname) BEGINNING=$(/bin/date +"%d-%m-%Y ; %H:%M") @@ -256,6 +265,9 @@ else rep="/bsd /bin /sbin /usr" fi +# /!\ DO NOT USE COMMENTS in the rsync command /!\ +# It breaks the command and destroys data, simply remove (or add) lines. + rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial \ --exclude "lost+found" \ --exclude ".nfs.*" \ @@ -298,6 +310,8 @@ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial END=$(/bin/date +"%d-%m-%Y ; %H:%M") +##### REPORTING ################################################################ + echo "EvoBackup - ${HOSTNAME} - START ${BEGINNING}" \ >> /var/log/evobackup.log From dac06e0858dc92f220a660177420a2bfb3e7b21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:57:46 +0200 Subject: [PATCH 07/14] message in english --- zzz_evobackup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzz_evobackup b/zzz_evobackup index 7adf6d9..521f597 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -87,7 +87,7 @@ if [ -e $PIDFILE ]; then done # Then kill the main PID. kill -9 "$pid" - echo "$0 tourne encore (PID $pid). Processus killé" >&2 + echo "$0 is still running (PID ${pid}). Process has been killed" >&2 fi echo "$$" > $PIDFILE # shellcheck disable=SC2064 From 92d6b8af8790cd074b87b05413e299d835faf38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:58:01 +0200 Subject: [PATCH 08/14] more braces and quotes --- zzz_evobackup | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index 521f597..403e091 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -78,20 +78,20 @@ pick_server() { } ## Verify other evobackup process and kill if needed -PIDFILE=/var/run/evobackup.pid -if [ -e $PIDFILE ]; then - pid=$(cat "$PIDFILE") +PIDFILE="/var/run/evobackup.pid" +if [ -e "${PIDFILE}" ]; then + pid=$(cat "${PIDFILE}") # Killing the childs of evobackup. - for ppid in $(ps h --ppid "$pid" -o pid | tr -s '\n' ' '); do - kill -9 "$ppid"; + for ppid in $(ps h --ppid "${pid}" -o pid | tr -s '\n' ' '); do + kill -9 "${ppid}"; done # Then kill the main PID. - kill -9 "$pid" + kill -9 "${pid}" echo "$0 is still running (PID ${pid}). Process has been killed" >&2 fi -echo "$$" > $PIDFILE +echo "$$" > ${PIDFILE} # shellcheck disable=SC2064 -trap "rm -f $PIDFILE" EXIT +trap "rm -f ${PIDFILE}" EXIT ##### LOCAL BACKUP ############################################################# From abbb20e5d47e1388243728e09fcfa846aa92f9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 21:59:59 +0200 Subject: [PATCH 09/14] shorter lines for section titles --- zzz_evobackup | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index 403e091..04d302a 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -15,7 +15,7 @@ # # /!\ DON'T FORGET TO SET "MAIL" and "SERVERS" VARIABLES -##### Configuration ############################################################ +##### Configuration ################################################### # email adress for notifications MAIL=jdoe@example.com @@ -32,7 +32,7 @@ LOCAL_BACKUP_DIR="/home/backup" # You can set "linux" or "bsd" manually or let it choose automatically SYSTEM=$(uname | tr '[:upper:]' '[:lower:]') -##### SETUP AND FUNCTIONS ###################################################### +##### SETUP AND FUNCTIONS ############################################# # shellcheck disable=SC2174 mkdir -p -m 700 ${LOCAL_BACKUP_DIR} @@ -93,7 +93,7 @@ echo "$$" > ${PIDFILE} # shellcheck disable=SC2064 trap "rm -f ${PIDFILE}" EXIT -##### LOCAL BACKUP ############################################################# +##### LOCAL BACKUP #################################################### # You can comment or uncomment sections below to customize the backup @@ -236,7 +236,7 @@ else pkg_info -m > ${LOCAL_BACKUP_DIR}/packages fi -##### REMOTE BACKUP ############################################################ +##### REMOTE BACKUP ################################################### n=0 server="" @@ -310,7 +310,7 @@ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial END=$(/bin/date +"%d-%m-%Y ; %H:%M") -##### REPORTING ################################################################ +##### REPORTING ####################################################### echo "EvoBackup - ${HOSTNAME} - START ${BEGINNING}" \ >> /var/log/evobackup.log From ab3ed48f221a31bc2f523929cc37729fcdcc2f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Sun, 31 Mar 2019 22:09:53 +0200 Subject: [PATCH 10/14] don't quote this vaiable ; it's a list ! --- zzz_evobackup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzz_evobackup b/zzz_evobackup index 04d302a..c760680 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -298,7 +298,7 @@ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial --exclude "/var/lib/clamav/*.tmp" \ --exclude "/home/mysqltmp" \ --exclude "/var/lib/php/sessions" \ - "${rep}" \ + ${rep} \ /etc \ /root \ /var \ From d741041e4cc10932aaf04285dad2055243399422 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Mon, 1 Apr 2019 14:23:26 +0200 Subject: [PATCH 11/14] give SSH more time before failing --- zzz_evobackup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzz_evobackup b/zzz_evobackup index c760680..0e4fc3c 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -24,7 +24,7 @@ MAIL=jdoe@example.com SERVERS="node0.backup.example.com:2XXX node1.backup.example.com:2XXX" # timeout (in seconds) for the SSH test -SSH_CONNECT_TIMEOUT=10 +SSH_CONNECT_TIMEOUT=30 ## We use /home/backup : feel free to use your own dir LOCAL_BACKUP_DIR="/home/backup" From c82e77f6eec8f166ec67d4e7f6f0805f7b247375 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Mon, 1 Apr 2019 14:37:57 +0200 Subject: [PATCH 12/14] Add documentation comments to test_server and pick_server functions --- zzz_evobackup | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index 0e4fc3c..bd7aff2 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -46,8 +46,12 @@ export LANG=C ## Force umask umask 077 +# Call test_server with "HOST:PORT" string +# It will return with 0 if the server is reachable. +# It will return with 1 and a message on stderr if not. test_server() { item=$1 + # split HOST and PORT from the input string host=$(echo "${item}" | cut -d':' -f1) port=$(echo "${item}" | cut -d':' -f2) @@ -55,23 +59,32 @@ test_server() { ssh -q -o "ConnectTimeout ${SSH_CONNECT_TIMEOUT}" "${host}" -p "${port}" -t "exit" # shellcheck disable=SC2181 if [ $? = 0 ]; then + # SSH connection is OK return 0 else + # SSH connection failed echo "Failed to connect to \`${item}' within ${SSH_CONNECT_TIMEOUT} seconds" >&2 return 1 fi } +# Call pick_server with an optional positive integer to get the nth server in the list. pick_server() { - inc=${1:-0} + increment=${1:-0} list_length=$(echo "${SERVERS}" | wc -w) - if [ "${inc}" -ge "${list_length}" ]; then + if [ "${increment}" -ge "${list_length}" ]; then + # We've reached the end of the list echo "No more server available" >&2 return 1 fi + # A salt is useful to randomize the starting point in the list + # but stay identical each time it's called for a server (based on hostname). salt=$(hostname | cksum | cut -d' ' -f1) - item=$(( ($(date +%d) + salt + inc) % list_length )) + # Pick an integer between 0 and the length of the SERVERS list + # It changes each day + item=$(( ($(date +%d) + salt + increment) % list_length )) + # cut starts counting fields at 1, not 0. field=$(( item + 1 )) echo "${SERVERS}" | cut -d' ' -f${field} From c8e7977b274eb58f7b23cd57ab7407deb9f2b279 Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Mon, 1 Apr 2019 14:38:48 +0200 Subject: [PATCH 13/14] revert variable extraction --- zzz_evobackup | 59 ++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index bd7aff2..633fb69 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -26,16 +26,13 @@ SERVERS="node0.backup.example.com:2XXX node1.backup.example.com:2XXX" # timeout (in seconds) for the SSH test SSH_CONNECT_TIMEOUT=30 -## We use /home/backup : feel free to use your own dir -LOCAL_BACKUP_DIR="/home/backup" - # You can set "linux" or "bsd" manually or let it choose automatically SYSTEM=$(uname | tr '[:upper:]' '[:lower:]') ##### SETUP AND FUNCTIONS ############################################# # shellcheck disable=SC2174 -mkdir -p -m 700 ${LOCAL_BACKUP_DIR} +mkdir -p -m 700 /home/backup PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin @@ -111,13 +108,13 @@ trap "rm -f ${PIDFILE}" EXIT # You can comment or uncomment sections below to customize the backup ## OpenLDAP : example with slapcat -# slapcat -l ${LOCAL_BACKUP_DIR}/ldap.bak +# slapcat -l /home/backup/ldap.bak ### MySQL ## example with global and compressed mysqldump # mysqldump --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \ -# --opt --all-databases --force --events --hex-blob | gzip --best > ${LOCAL_BACKUP_DIR}/mysql.bak.gz +# --opt --all-databases --force --events --hex-blob | gzip --best > /home/backup/mysql.bak.gz ## example with two dumps for each table (.sql/.txt) for all databases # for i in $(echo SHOW DATABASES | mysql --defaults-extra-file=/etc/mysql/debian.cnf -P 3306 \ @@ -149,7 +146,7 @@ trap "rm -f ${PIDFILE}" EXIT # instance=$(echo "$instance"|awk '{ print $3 }') # if [ "$instance" != "3306" ] # then -# mysqldump -P $instance --opt --all-databases --hex-blob -u mysqladmin -p$mysqladminpasswd > ${LOCAL_BACKUP_DIR}/mysql.$instance.bak +# mysqldump -P $instance --opt --all-databases --hex-blob -u mysqladmin -p$mysqladminpasswd > /home/backup/mysql.$instance.bak # fi # done @@ -157,31 +154,31 @@ trap "rm -f ${PIDFILE}" EXIT ## example with pg_dumpall (warning: you need space in ~postgres) # su - postgres -c "pg_dumpall > ~/pg.dump.bak" -# mv ~postgres/pg.dump.bak ${LOCAL_BACKUP_DIR}/ +# mv ~postgres/pg.dump.bak /home/backup/ ## another method with gzip directly piped # cd /var/lib/postgresql -# sudo -u postgres pg_dumpall | gzip > ${LOCAL_BACKUP_DIR}/pg.dump.bak.gz +# sudo -u postgres pg_dumpall | gzip > /home/backup/pg.dump.bak.gz # cd - > /dev/null ## example with all tables from MYBASE excepts TABLE1 and TABLE2 -# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -t 'TABLE1' -t 'TABLE2' MYBASE +# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f /home/backup/pg-backup.tar -t 'TABLE1' -t 'TABLE2' MYBASE ## example with only TABLE1 and TABLE2 from MYBASE -# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f ${LOCAL_BACKUP_DIR}/pg-backup.tar -T 'TABLE1' -T 'TABLE2' MYBASE +# pg_dump -p 5432 -h 127.0.0.1 -U USER --clean -F t --inserts -f /home/backup/pg-backup.tar -T 'TABLE1' -T 'TABLE2' MYBASE ## MongoDB : example with mongodump ## don't forget to create use with read-only access ## > use admin ## > db.createUser( { user: "mongobackup", pwd: "PASS", roles: [ "backup", ] } ) -# test -d ${LOCAL_BACKUP_DIR}/mongodump/ && rm -rf ${LOCAL_BACKUP_DIR}/mongodump/ -# mkdir -p -m 700 ${LOCAL_BACKUP_DIR}/mongodump/ -# mongodump --quiet -u mongobackup -pPASS -o ${LOCAL_BACKUP_DIR}/mongodump/ +# test -d /home/backup/mongodump/ && rm -rf /home/backup/mongodump/ +# mkdir -p -m 700 /home/backup/mongodump/ +# mongodump --quiet -u mongobackup -pPASS -o /home/backup/mongodump/ # if [ $? -ne 0 ]; then # echo "Error with mongodump!" # fi ## Redis : example with copy .rdb file -# cp /var/lib/redis/dump.rdb ${LOCAL_BACKUP_DIR}/ +# cp /var/lib/redis/dump.rdb /home/backup/ ## ElasticSearch, take a snapshot as a backup. ## Warning: You need to have a path.repo configured. @@ -205,48 +202,48 @@ trap "rm -f ${PIDFILE}" EXIT # curl -s -XPUT "localhost:9200/_snapshot/snaprepo/snapshot_${date}?wait_for_completion=true" -o /tmp/es_snapshot_${date}.log ## RabbitMQ : export config -#rabbitmqadmin export ${LOCAL_BACKUP_DIR}/rabbitmq.config >> /var/log/evobackup.log +#rabbitmqadmin export /home/backup/rabbitmq.config >> /var/log/evobackup.log ## Dump MBR / table partitions with dd and sfdisk ## Linux #for disk in $(ls /dev/[sv]d[a-z] 2>/dev/null); do # name=$(basename $disk) -# dd if=$disk of=${LOCAL_BACKUP_DIR}/MBR-$name bs=512 count=1 2>&1 | egrep -v "(records in|records out|512 bytes)" -# fdisk -l $disk > ${LOCAL_BACKUP_DIR}/partitions-$name +# dd if=$disk of=/home/backup/MBR-$name bs=512 count=1 2>&1 | egrep -v "(records in|records out|512 bytes)" +# fdisk -l $disk > /home/backup/partitions-$name #done -#cat ${LOCAL_BACKUP_DIR}/partitions-* > ${LOCAL_BACKUP_DIR}/partitions +#cat /home/backup/partitions-* > /home/backup/partitions ## OpenBSD -# disklabel sd0 > ${LOCAL_BACKUP_DIR}/partitions +# disklabel sd0 > /home/backup/partitions # backup MegaCli config -#megacli -CfgSave -f ${LOCAL_BACKUP_DIR}/megacli_conf.dump -a0 >/dev/null +#megacli -CfgSave -f /home/backup/megacli_conf.dump -a0 >/dev/null ## Dump system and kernel versions -uname -a > ${LOCAL_BACKUP_DIR}/uname +uname -a > /home/backup/uname ## Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls) for addr in 8.8.8.8 www.evolix.fr travaux.evolix.net; do - mtr -r ${addr} > ${LOCAL_BACKUP_DIR}/mtr-${addr} - traceroute -n ${addr} > ${LOCAL_BACKUP_DIR}/traceroute-${addr} 2>&1 + mtr -r ${addr} > /home/backup/mtr-${addr} + traceroute -n ${addr} > /home/backup/traceroute-${addr} 2>&1 done ## Dump process with ps -ps auwwx >${LOCAL_BACKUP_DIR}/ps.out +ps auwwx >/home/backup/ps.out if [ "${SYSTEM}" = "linux" ]; then ## Dump network connections with netstat - netstat -taupen > ${LOCAL_BACKUP_DIR}/netstat.out + netstat -taupen > /home/backup/netstat.out ## List Debian packages - dpkg -l > ${LOCAL_BACKUP_DIR}/packages - dpkg --get-selections > ${LOCAL_BACKUP_DIR}/packages.getselections - apt-cache dumpavail > ${LOCAL_BACKUP_DIR}/packages.available + dpkg -l > /home/backup/packages + dpkg --get-selections > /home/backup/packages.getselections + apt-cache dumpavail > /home/backup/packages.available else ## Dump network connections with netstat - netstat -finet -atn > ${LOCAL_BACKUP_DIR}/netstat.out + netstat -finet -atn > /home/backup/netstat.out ## List OpenBSD packages - pkg_info -m > ${LOCAL_BACKUP_DIR}/packages + pkg_info -m > /home/backup/packages fi ##### REMOTE BACKUP ################################################### From 305655faa6b564be59cc54de7e28f6d1a00faca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lecour?= Date: Mon, 1 Apr 2019 22:14:49 +0200 Subject: [PATCH 14/14] revert some quotes and braces --- zzz_evobackup | 52 +++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/zzz_evobackup b/zzz_evobackup index 633fb69..999bc80 100755 --- a/zzz_evobackup +++ b/zzz_evobackup @@ -88,20 +88,20 @@ pick_server() { } ## Verify other evobackup process and kill if needed -PIDFILE="/var/run/evobackup.pid" -if [ -e "${PIDFILE}" ]; then - pid=$(cat "${PIDFILE}") +PIDFILE=/var/run/evobackup.pid +if [ -e $PIDFILE ]; then + pid=$(cat "$PIDFILE") # Killing the childs of evobackup. - for ppid in $(ps h --ppid "${pid}" -o pid | tr -s '\n' ' '); do - kill -9 "${ppid}"; + for ppid in $(ps h --ppid "$pid" -o pid | tr -s '\n' ' '); do + kill -9 "$ppid"; done # Then kill the main PID. - kill -9 "${pid}" - echo "$0 is still running (PID ${pid}). Process has been killed" >&2 + kill -9 "$pid" + echo "$0 is still running (PID $pid). Process has been killed" >&2 fi -echo "$$" > ${PIDFILE} +echo "$$" > $PIDFILE # shellcheck disable=SC2064 -trap "rm -f ${PIDFILE}" EXIT +trap "rm -f $PIDFILE" EXIT ##### LOCAL BACKUP #################################################### @@ -223,27 +223,27 @@ uname -a > /home/backup/uname ## Dump network routes with mtr and traceroute (warning: could be long with aggressive firewalls) for addr in 8.8.8.8 www.evolix.fr travaux.evolix.net; do - mtr -r ${addr} > /home/backup/mtr-${addr} - traceroute -n ${addr} > /home/backup/traceroute-${addr} 2>&1 + mtr -r $addr > /home/backup/mtr-${addr} + traceroute -n $addr > /home/backup/traceroute-${addr} 2>&1 done ## Dump process with ps ps auwwx >/home/backup/ps.out -if [ "${SYSTEM}" = "linux" ]; then +if [ "$SYSTEM" = "linux" ]; then ## Dump network connections with netstat - netstat -taupen > /home/backup/netstat.out + netstat -taupen >/home/backup/netstat.out ## List Debian packages - dpkg -l > /home/backup/packages - dpkg --get-selections > /home/backup/packages.getselections - apt-cache dumpavail > /home/backup/packages.available + dpkg -l >/home/backup/packages + dpkg --get-selections >/home/backup/packages.getselections + apt-cache dumpavail >/home/backup/packages.available else ## Dump network connections with netstat - netstat -finet -atn > /home/backup/netstat.out + netstat -finet -atn >/home/backup/netstat.out ## List OpenBSD packages - pkg_info -m > /home/backup/packages + pkg_info -m >/home/backup/packages fi ##### REMOTE BACKUP ################################################### @@ -269,7 +269,7 @@ HOSTNAME=$(hostname) BEGINNING=$(/bin/date +"%d-%m-%Y ; %H:%M") -if [ "${SYSTEM}" = "linux" ]; then +if [ "$SYSTEM" = "linux" ]; then rep="/bin /boot /lib /opt /sbin /usr" else rep="/bsd /bin /sbin /usr" @@ -308,26 +308,26 @@ rsync -avzh --stats --delete --delete-excluded --force --ignore-errors --partial --exclude "/var/lib/clamav/*.tmp" \ --exclude "/home/mysqltmp" \ --exclude "/var/lib/php/sessions" \ - ${rep} \ + $rep \ /etc \ /root \ /var \ /home \ /srv \ - -e "ssh -p ${SSH_PORT}" \ - "root@${SSH_SERVER}:/var/backup/" \ + -e "ssh -p $SSH_PORT" \ + "root@$SSH_SERVER:/var/backup/" \ | tail -30 >> /var/log/evobackup.log END=$(/bin/date +"%d-%m-%Y ; %H:%M") ##### REPORTING ####################################################### -echo "EvoBackup - ${HOSTNAME} - START ${BEGINNING}" \ +echo "EvoBackup - $HOSTNAME - START $BEGINNING" \ >> /var/log/evobackup.log -echo "EvoBackup - ${HOSTNAME} - STOP ${END}" \ +echo "EvoBackup - $HOSTNAME - STOP $END" \ >> /var/log/evobackup.log tail -10 /var/log/evobackup.log | \ - mail -s "[info] EvoBackup - Client ${HOSTNAME}" \ - ${MAIL} + mail -s "[info] EvoBackup - Client $HOSTNAME" \ + $MAIL