mirror of
https://0xacab.org/liberate/backupninja.git
synced 2024-11-08 11:52:32 +01:00
f41ff295cc
Adding the port parameter to the borg handler with a default value of 22 is causing issues for users who had been using the standard ssh config file to set the remote port, since the -p cli argument overrides the configuration. This removes the default port number and only uses it in the connection string if defined.
236 lines
6.5 KiB
Bash
236 lines
6.5 KiB
Bash
# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
|
|
# vim: set filetype=sh sw=3 sts=3 expandtab autoindent:
|
|
#
|
|
# borg handler script for backupninja
|
|
# requires borgbackup
|
|
#
|
|
# Guillaume Subiron, Sysnove, 2016
|
|
#
|
|
# Copyright 2016 Guillaume Subiron <guillaume@sysnove.fr>
|
|
#
|
|
# This work is free. You can redistribute it and/or modify it under the
|
|
# terms of the Do What The Fuck You Want To Public License, Version 2,
|
|
# as published by Sam Hocevar. See the http://www.wtfpl.net/ file for more details.
|
|
#
|
|
#
|
|
|
|
debug "export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes"
|
|
export BORG_RELOCATED_REPO_ACCESS_IS_OK=yes
|
|
|
|
debug "export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes"
|
|
export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes
|
|
|
|
### GET CONFIG ###
|
|
|
|
getconf testconnect yes
|
|
getconf nicelevel 0
|
|
getconf ionicelevel
|
|
getconf bwlimit
|
|
|
|
setsection source
|
|
getconf init yes
|
|
getconf include
|
|
getconf exclude
|
|
getconf create_options
|
|
getconf prune yes
|
|
getconf keep 30d
|
|
getconf prune_options
|
|
getconf cache_directory
|
|
getconf ignore_missing
|
|
|
|
setsection dest
|
|
getconf user
|
|
getconf host
|
|
getconf port
|
|
getconf directory
|
|
# strip trailing /
|
|
directory=${directory%/}
|
|
getconf archive {now:%Y-%m-%dT%H:%M:%S}
|
|
getconf compression lz4
|
|
getconf encryption none
|
|
getconf passphrase
|
|
getconf sshoptions
|
|
|
|
debug "export BORG_PASSPHRASE=\"<redacted>\""
|
|
export BORG_PASSPHRASE="$passphrase"
|
|
|
|
if [ -n "$sshoptions" ]; then
|
|
debug "export BORG_RSH=\"ssh $sshoptions\""
|
|
export BORG_RSH="ssh $sshoptions"
|
|
fi
|
|
|
|
### CHECK CONFIG ###
|
|
|
|
# source includes at least one path
|
|
[ -n "$include" ] || fatal "No source includes specified"
|
|
|
|
# destination specific checks
|
|
[ -n "$directory" ] || fatal "Destination directory not set"
|
|
if [ "$host" != "localhost" ]; then
|
|
[ -n "$user" ] || fatal "Destination user not set"
|
|
[ -n "$host" ] || fatal "Destination host not set"
|
|
execstr_repository="ssh://${user}@${host}${port:+:${port}}${directory}"
|
|
else
|
|
execstr_repository="$directory"
|
|
fi
|
|
execstr_archive="$archive"
|
|
|
|
if [ -n "$cache_directory" ]; then
|
|
cache_parent_dir=$(dirname "$(readlink -f "$cache_directory")")
|
|
[ -d "$cache_parent_dir" ] || fatal "Cache directory parent dir '$cache_parent_dir' is absent or is not a directory."
|
|
debug "export BORG_CACHE_DIR=\"${cache_directory}\""
|
|
export BORG_CACHE_DIR="$cache_directory"
|
|
else
|
|
# Cache dir not set, let's clear out the environment variable to avoid
|
|
# having this directory be pointed to a random destination.
|
|
# Also apparently if we set the variable to an empty string, borg uses the
|
|
# empty string as though it was some path we specified and backup runs
|
|
# error out, so we need to unset the variable completely.
|
|
debug "unset BORG_CACHE_DIR"
|
|
unset BORG_CACHE_DIR
|
|
fi
|
|
|
|
# Check that the ionicelevel is valid
|
|
if [ -n "$ionicelevel" ] && echo "$ionicelevel" | grep -vq "^[0-7]$"; then
|
|
fatal "The value of ionicelevel is expected to be either empty or an integer from 0 to 7. Got: $ionicelevel"
|
|
fi
|
|
|
|
# Only use ionice if ionicelevel is not empty
|
|
nice="nice -n $nicelevel"
|
|
if [ -n "$ionicelevel" ]; then
|
|
nice="ionice -c2 -n $ionicelevel $nice"
|
|
fi
|
|
|
|
# check the connection at the source and destination
|
|
[ -n "$test" ] || test=0
|
|
if [ "$host" != "localhost" ] && ([ "$testconnect" = "yes" ] || [ "${test}" -eq 1 ]); then
|
|
debug "ssh $sshoptions -o PasswordAuthentication=no ${host}${port:+ -p ${port}} -l $user 'echo -n 1'"
|
|
local ret=`ssh $sshoptions -o PasswordAuthentication=no ${host}${port:+ -p ${port}} -l $user 'echo -n 1'`
|
|
if [ "$ret" = 1 ]; then
|
|
debug "Connected to $host as $user successfully"
|
|
else
|
|
teststr="borg list --show-rc -v $execstr_repository"
|
|
debug "$teststr"
|
|
output=`su -c "$teststr" 2>&1`
|
|
if echo "$output" | grep "terminating with success status" \
|
|
|| echo "$output" | grep "^\S\+ is not a valid repository." \
|
|
|| echo "$output" | grep "^Repository \S\+ does not exist."; then
|
|
debug "Connected to $host as $user successfully (forced command)"
|
|
else
|
|
error $output
|
|
fatal "Can't connect to $host as $user."
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
### INIT IF NEEDED ###
|
|
|
|
if [ "$init" == "yes" ]; then
|
|
initstr="borg init --encryption=$encryption $execstr_repository"
|
|
debug "executing borg init"
|
|
debug "$initstr"
|
|
if [ $test = 0 ]; then
|
|
output="`su -c "$initstr" 2>&1`"
|
|
if [ $? = 2 ]; then
|
|
debug $output
|
|
info "Repository was already initialized"
|
|
else
|
|
warning $output
|
|
warning "Repository has been initialized"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
### EXECUTE ###
|
|
|
|
execstr="borg create --stats --compression $compression"
|
|
|
|
set -o noglob
|
|
|
|
# includes
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
for i in $include; do
|
|
includes="${includes} '$i'"
|
|
done
|
|
IFS=$SAVEIFS
|
|
|
|
# excludes
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
for i in $exclude; do
|
|
excludes="${excludes} --exclude '$i'"
|
|
done
|
|
IFS=$SAVEIFS
|
|
|
|
set +o noglob
|
|
|
|
if [ ! -z $bwlimit ]; then
|
|
execstr="${execstr} --remote-ratelimit=${bwlimit}"
|
|
fi
|
|
|
|
if [ ! -z "$create_options" ]; then
|
|
execstr="${execstr} ${create_options}"
|
|
fi
|
|
|
|
# include client-part and server-part
|
|
execstr="${execstr} ${excludes} $execstr_repository::$execstr_archive ${includes}"
|
|
|
|
debug "executing borg create"
|
|
debug "$nice $execstr"
|
|
|
|
if [ $test = 0 ]; then
|
|
output=`$nice su -c "$execstr" 2>&1`
|
|
ret=$?
|
|
if [ $ret = 0 ]; then
|
|
debug $output
|
|
info "Successfully finished backing up source."
|
|
elif [ $ret = 1 ]; then
|
|
warnmsg=$(echo "$output" | @SED@ -n '1,/^-\+$/{x;p;d;}; x' | @SED@ '/^$/d')
|
|
if [ "$ignore_missing" = "yes" ] && ! echo "$warnmsg" | grep -qv '\[Errno 2\] No such file or directory:'; then
|
|
debug $output
|
|
info "Backing up source finished with missing file warnings."
|
|
else
|
|
warning $output
|
|
warning "Backing up source finished with warnings."
|
|
fi
|
|
else
|
|
error $output
|
|
fatal "Failed backing up source."
|
|
fi
|
|
fi
|
|
|
|
### REMOVE OLD BACKUPS ###
|
|
|
|
# borg prune
|
|
if [ "$prune" == "yes" ]; then
|
|
if [ ! "$keep" == "0" ]; then
|
|
prune_options="${prune_options} --keep-within=${keep}"
|
|
fi
|
|
prunestr="borg prune $prune_options $execstr_repository"
|
|
debug "executing borg prune"
|
|
debug "$prunestr"
|
|
if [ $test = 0 ]; then
|
|
output="`su -c "$prunestr" 2>&1`"
|
|
ret=$?
|
|
if [ $ret = 0 ]; then
|
|
debug $output
|
|
info "Removing old backups succeeded."
|
|
elif [ $ret = 1 ]; then
|
|
warning $output
|
|
warning "Removing old backups finished with warnings."
|
|
else
|
|
error $output
|
|
fatal "Failed removing old backups."
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
debug "unset BORG_PASSPHRASE"
|
|
unset BORG_PASSPHRASE
|
|
|
|
debug "unset BORG_RSH"
|
|
unset BORG_RSH
|
|
|
|
return 0
|