aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--files/handlers/rsync169
1 files changed, 80 insertions, 89 deletions
diff --git a/files/handlers/rsync b/files/handlers/rsync
index e098a84..01a2987 100644
--- a/files/handlers/rsync
+++ b/files/handlers/rsync
@@ -39,7 +39,6 @@
# keepdaily = for long storage format, specify the number of daily backup increments
# keepweekly = for long storage format, specify the number of weekly backup increments
# keepmonthly = for long storage format, specify the number of monthly backup increments
-# lockfile = lockfile to be kept during backup execution
# nicelevel = rsync command nice level
# enable_mv_timestamp_bug = set to "yes" if your system isnt handling timestamps correctly
# tmp = temp folder
@@ -60,7 +59,7 @@
# exclude_vserver = vserver-name (valid only if vservers = yes on backupninja.conf)
# numericids = when set to 1, use numeric ids instead of user/group mappings on rsync
# compress = if set to 1, compress data on rsync (remote source only)
-# bandwidthlimit = set a badnwidth limit in KB/s (remote source only)
+# bandwidthlimit = set a bandwidth limit in KB/s (remote source only)
# remote_rsync = remote rsync program (remote source only)
# id_file = ssh key file (remote source only)
# batch = set to "yes" to rsync use a batch file as source
@@ -79,7 +78,7 @@
# port = remote port number (remote destination only)
# user = remote user name (remote destination only)
# id_file = ssh key file (remote destination only)
-# bandwidthlimit = set a badnwidth limit in KB/s (remote destination only)
+# bandwidthlimit = set a bandwidth limit in KB/s (remote destination only)
# remote_rsync = remote rsync program (remote dest only)
# batch = set to "yes" to rsync write a batch file from the changes
# batchbase = folder where the batch file should be written
@@ -125,11 +124,10 @@ function eval_config {
getconf mountpoint
getconf backupdir
getconf format short
- getconf days
+ getconf days 7
getconf keepdaily 5
getconf keepweekly 3
getconf keepmonthly 1
- getconf lockfile
getconf nicelevel 0
getconf enable_mv_timestamp_bug no
getconf tmp /tmp
@@ -176,7 +174,7 @@ function eval_config {
getconf include
getconf exclude
getconf exclude_vserver
- getconf numericids
+ getconf numericids 0
getconf compress 0
# dest section
@@ -217,7 +215,7 @@ function eval_config {
fi
fi
- getconf numericids
+ getconf numericids 0
getconf compress 0
# services section
@@ -230,19 +228,16 @@ function eval_config {
if [ "$dest" != "local" ] && [ "$from" == "remote" ]; then
fatal "When source is remote, destination should be local."
- exit 1
fi
if [ "$from" != "local" ] && [ "$from" != "remote" ]; then
fatal "Invalid source $from"
- exit 1
fi
backupdir="$mountpoint/$backupdir"
if [ "$dest" == "local" ] && [ ! -d "$backupdir" ]; then
- error "Backupdir $backupdir does not exist"
- exit 1
+ fatal "Backupdir $backupdir does not exist"
fi
if [ ! -z "$log" ]; then
@@ -280,9 +275,7 @@ function eval_config {
mv=move_files
fi
- for path in $exclude; do
- excludes="$excludes --exclude=$path"
- done
+ excludes=`echo "$exclude" | sed -e "s/^/--exclude='/g" -e "s/ /' --exclude='/g" -e "s/$/'/"`
# Make sure we'll run bash at the destination
ssh_cmd="$ssh_cmd /bin/bash"
@@ -376,7 +369,7 @@ function rotate_short_remote {
echo "Debug: removing orphaned metadata \$file"
rm -rf $metadata/\$file
fi
- done
+ done
##### END REMOTE SCRIPT #######
EOF
) | (while read a; do passthru $a; done)
@@ -397,8 +390,8 @@ function rotate_long {
local metadata
if [ ! -d "$backuproot" ]; then
- echo "Debug: skipping rotate of $backuproot as it doesn't exist."
- exit
+ warning "Skipping rotate of $backuproot as it doesn't exist."
+ return
fi
for rottype in daily weekly monthly; do
@@ -411,7 +404,7 @@ function rotate_long {
echo "Debug: $dir.1 does not exist, skipping."
continue 1
elif [ ! -f $metadata.1/created ] && [ ! -f $metadata.1/rotated ]; then
- echo "Warning: metadata does not exist for $dir.1. This backup may be only partially completed. Skipping rotation."
+ warning "Warning: metadata does not exist for $dir.1. This backup may be only partially completed. Skipping rotation."
continue 1
fi
@@ -427,11 +420,16 @@ function rotate_long {
else
created=0
fi
+ # Validate created date
+ if [ -z "$created" ] || echo $created | grep -v -q -e '^[0-9]*$'; then
+ warning "Invalid metadata $created. Skipping rotation."
+ break
+ fi
cutoff_time=$(( now - (seconds*(i-1)) ))
if [ ! $created -gt $cutoff_time ]; then
next=$(( i + 1 ))
if [ ! -d $dir.$next ]; then
- echo "Debug: $rottype.$i --> $rottype.$next"
+ debug "$rottype.$i --> $rottype.$next"
$nice mv $dir.$i $dir.$next
mkdir -p $metadata.$next
date +%c%n%s > $metadata.$next/rotated
@@ -439,10 +437,10 @@ function rotate_long {
$nice mv $metadata.$i/created $metadata.$next
fi
else
- echo "Debug: skipping rotation of $dir.$i because $dir.$next already exists."
+ debug "skipping rotation of $dir.$i because $dir.$next already exists."
fi
else
- echo "Debug: skipping rotation of $dir.$i because it was created" $(( (now-created)/86400)) "days ago ("$(( (now-cutoff_time)/86400))" needed)."
+ debug "skipping rotation of $dir.$i because it was created" $(( (now-created)/86400)) "days ago ("$(( (now-cutoff_time)/86400))" needed)."
fi
fi
done
@@ -450,9 +448,11 @@ function rotate_long {
max=$((keepdaily+1))
if [ $keepweekly -gt 0 -a -d $backuproot/daily.$max -a ! -d $backuproot/weekly.1 ]; then
- echo "Debug: daily.$max --> weekly.1"
+ debug "daily.$max --> weekly.1"
$nice mv $backuproot/daily.$max $backuproot/weekly.1
mkdir -p $backuproot/metadata/weekly.1
+ # Update increment folder date and setup metadata
+ $touch $backuproot/weekly.1
date +%c%n%s > $backuproot/metadata/weekly.1/rotated
#if [ -f $backuproot/metadata/daily.$max/created ]; then
# $nice mv $backuproot/metadata/daily.$max/created $backuproot/metadata/weekly.1/
@@ -461,9 +461,11 @@ function rotate_long {
max=$((keepweekly+1))
if [ $keepmonthly -gt 0 -a -d $backuproot/weekly.$max -a ! -d $backuproot/monthly.1 ]; then
- echo "Debug: weekly.$max --> monthly.1"
+ debug "weekly.$max --> monthly.1"
$nice mv $backuproot/weekly.$max $backuproot/monthly.1
mkdir -p $backuproot/metadata/monthly.1
+ # Update increment folder date and setup metadata
+ $touch $backuproot/monthly.1
date +%c%n%s > $backuproot/metadata/monthly.1/rotated
#if [ -f $backuproot/metadata/weekly.$max/created ]; then
# $nice mv $backuproot/metadata/weekly.$max/created $backuproot/metadata/weekly.1/
@@ -479,10 +481,10 @@ function rotate_long {
for (( i=$oldest; i >= $max; i-- )); do
if [ -d $dir.$i ]; then
if [ -d $backuproot/rotate.tmp ]; then
- echo "Debug: removing rotate.tmp"
+ debug "removing rotate.tmp"
$nice rm -rf $backuproot/rotate.tmp
fi
- echo "Debug: moving $rottype.$i to rotate.tmp"
+ debug "moving $rottype.$i to rotate.tmp"
$nice mv $dir.$i $backuproot/rotate.tmp
fi
done
@@ -515,7 +517,7 @@ function rotate_long_remote {
now=\`date +%s\`
if [ ! -d "$backuproot" ]; then
- echo "Debug: skipping rotate of $backuproot as it doesn't exist."
+ echo "Fatal: skipping rotate of $backuproot as it doesn't exist."
exit
fi
@@ -545,6 +547,11 @@ function rotate_long_remote {
else
created=0
fi
+ # Validate created date
+ if [ -z "\$created" ] || echo \$created | grep -v -q -e '^[0-9]*$'; then
+ echo "Warning: Invalid metadata \$created. Skipping rotation."
+ break
+ fi
cutoff_time=\$(( now - (seconds*(i-1)) ))
if [ ! \$created -gt \$cutoff_time ]; then
next=\$(( i + 1 ))
@@ -571,6 +578,8 @@ function rotate_long_remote {
echo "Debug: daily.\$max --> weekly.1"
$nice mv $backuproot/daily.\$max $backuproot/weekly.1
mkdir -p $backuproot/metadata/weekly.1
+ # Update increment folder date and setup metadata
+ $touch $backuproot/weekly.1
date +%c%n%s > $backuproot/metadata/weekly.1/rotated
#if [ -f $backuproot/metadata/daily.\$max/created ]; then
# $nice mv $backuproot/metadata/daily.\$max/created $backuproot/metadata/weekly.1/
@@ -582,6 +591,8 @@ function rotate_long_remote {
echo "Debug: weekly.\$max --> monthly.1"
$nice mv $backuproot/weekly.\$max $backuproot/monthly.1
mkdir -p $backuproot/metadata/monthly.1
+ # Update increment folder date and setup metadata
+ $touch $backuproot/monthly.1
date +%c%n%s > $backuproot/metadata/monthly.1/rotated
#if [ -f $backuproot/metadata/weekly.\$max/created ]; then
# $nice mv $backuproot/metadata/weekly.\$max/created $backuproot/metadata/weekly.1/
@@ -642,22 +653,19 @@ function setup_long_dirs {
if [ -d $tmpdir ]; then
mv $tmpdir $dir.1
if [ $? == 1 ]; then
- echo "Fatal: could mv $destdir/rotate.tmp $dir.1 on host $host"
- exit 1
+ fatal "Could not move $tmpdir to $dir.1 on host $host"
fi
else
mkdir --parents $dir.1
if [ $? == 1 ]; then
- echo "Fatal: could not create directory $dir.1 on host $host"
- exit 1
+ fatal "Could not create directory $dir.1 on host $host"
fi
fi
if [ -d $dir.2 ]; then
echo "Debug: update links $backuptype.2 --> $backuptype.1"
cp -alf $dir.2/. $dir.1
#if [ $? == 1 ]; then
- # echo "Fatal: could not create hard links to $dir.1 on host $host"
- # exit 1
+ # fatal "Could not create hard links to $dir.1 on host $host"
#fi
fi
fi
@@ -758,7 +766,6 @@ function prepare_storage {
btype=monthly
else
fatal "keeping no backups";
- exit 1
fi
suffix="$btype.1"
@@ -777,7 +784,6 @@ function prepare_storage {
suffix=""
else
fatal "Invalid backup format $format"
- exit 1
fi
}
@@ -821,7 +827,6 @@ function set_batch_mode {
batch_option="--read-batch=$batch_file"
else
fatal "Batch file not found: $batch_file"
- exit 1
fi
elif [ "$batch" == "write" ]; then
mkdir -p `dirname $batch_file`
@@ -838,7 +843,11 @@ function update_metadata {
if [ "$dest" == "local" ]; then
metadata="`dirname $dest_path`/metadata/`basename $dest_path`"
mkdir -p $metadata
- date +%c%n%s > $metadata/created
+ # Use the backup start time and not the time the backup was
+ # finished, otherwise daily rotations might not take place.
+ # If we used backup end time, in the next handler run
+ # we might not have $now - $created >= 24:00
+ echo "$starttime" > $metadata/created
$touch $backupdir/$SECTION/$suffix
else
folder="`echo $dest_path | cut -d : -f 2`"
@@ -848,7 +857,11 @@ function update_metadata {
$ssh_cmd <<EOF
##### BEGIN REMOTE SCRIPT #####
mkdir -p $metadata
- date +%c%n%s > $metadata/created
+ # Use the backup start time and not the time the backup was
+ # finished, otherwise daily rotations might not take place.
+ # If we used backup end time, in the next handler run
+ # we might not have $now - $created >= 24:00
+ echo "$starttime" > $metadata/created
##### END REMOTE SCRIPT #######
EOF
) | (while read a; do passthru $a; done)
@@ -866,7 +879,6 @@ function test_connect {
if [ -z "$host" ] || [ -z "$user" ]; then
fatal "Remote host or user not set"
- exit 1
fi
debug "$ssh_cmd 'echo -n 1'"
@@ -874,52 +886,12 @@ function test_connect {
if [ "$result" != "1" ]; then
fatal "Can't connect to $host as $user."
- exit 1
else
debug "Connected to $host successfully"
fi
}
-function set_lockfile {
-
- if [ ! -z "$lockfile" ]; then
- mkdir -p `dirname $lockfile`
- if ( set -o noclobber; echo "$$" > "$lockfile" ) &> /dev/null; then
- trap 'unset_lockfile' INT TERM EXIT
- else
- fatal "Could not create lockfile $lockfile, exiting"
- fi
- fi
-
-}
-
-function unset_lockfile {
-
- if [ ! -z "$lockfile" ]; then
- $rm -f $lockfile || warning "Could not remove lockfile $lockfile"
- fi
-
-}
-
-function check_lockfile {
-
- local pid process
-
- if [ ! -z "$lockfile" ] && [ -f "$lockfile" ]; then
- pid="`cat $lockfile`"
- process="`ps --no-headers -o comm $pid`"
- if [ "$?" == "0" ] && [ "`ps --no-headers -o comm $$`" == "$process" ]; then
- info "Another backup is running for $lockfile, skipping run"
- exit
- else
- info "Found old lockfile $lockfile, removing it"
- unset_lockfile
- fi
- fi
-
-}
-
function set_filelist {
filelist_flag=""
@@ -940,7 +912,7 @@ function set_filelist {
function set_rsync_options {
- if [ ! -z "$numericids" ]; then
+ if [ "$numericids" != "0" ]; then
rsync_options="$rsync_options --numeric-ids"
fi
@@ -968,7 +940,6 @@ function set_rsync_options {
if [ "$protocol" == "ssh" ]; then
if [ ! -e "$id_file" ]; then
fatal "SSH Identity file $id_file not found"
- exit 1
else
debug RSYNC_RSH=\"$ssh_cmd_base\"
echo RSYNC_RSH=\"$ssh_cmd_base\" >> $log
@@ -1023,8 +994,7 @@ function mount_rw {
if [ -d "$mountpoint" ]; then
mount -o remount,rw $mountpoint
if (($?)); then
- error "Could not mount $mountpoint"
- exit 1
+ fatal "Could not mount $mountpoint"
fi
fi
fi
@@ -1108,17 +1078,39 @@ function end_mux {
}
+function set_pipefail {
+
+ # Save initial pipefail status for later restoration
+ if echo "$SHELLOPTS" | grep -q ":pipefail"; then
+ pipefail="-o"
+ else
+ pipefail="+o"
+ fi
+
+ # Ensure that a non-zero rsync exit status is caught by our handler
+ set -o pipefail
+
+}
+
+function restore_pipefail {
+
+ if [ ! -z "$pipefail" ]; then
+ set $pipefail pipefail
+ fi
+
+}
+
# the backup procedure
eval_config
-check_lockfile
-set_lockfile
set_rsync_options
start_mux
stop_services
mount_rw
+set_pipefail
-echo "Starting backup at `date`" >> $log
+starttime="`date +%c%n%s`"
+echo "Starting backup at `echo "$starttime" | head -n 1`" >> $log
for SECTION in $include; do
@@ -1129,22 +1121,21 @@ for SECTION in $include; do
set_dest
info "Syncing $SECTION on $dest_path..."
- debug $nice $rsync "${rsync_options[@]}" $filelist_flag $excludes $batch_option $orig $dest_path
- $nice $rsync "${rsync_options[@]}" $filelist_flag $excludes $batch_option $orig $dest_path | tee -a $log
+ debug $nice $rsync "${rsync_options[@]}" $filelist_flag "$excludes" $batch_option $orig $dest_path
+ $nice $rsync "${rsync_options[@]}" $filelist_flag "$excludes" $batch_option $orig $dest_path | tee -a $log
if [ "$?" != "0" ]; then
fatal "Rsync error when trying to transfer $SECTION"
- exit 1
fi
update_metadata
done
+restore_pipefail
mount_ro
run_fsck
start_services
-unset_lockfile
end_mux
echo "Finnishing backup at `date`" >> $log