parent
b8843a5d22
commit
5c007da2b0
535
bare.sh
535
bare.sh
|
@ -1,11 +1,12 @@
|
|||
#!/bin/bash
|
||||
VALIDCOMMANDS="go ls init repos stats diff forget"
|
||||
VALIDCOMMANDS="go ls init repos stats diff forget get"
|
||||
|
||||
RCFILE=${HOME}/.backup/config
|
||||
DEF_AUTHFILE=${HOME}/.backup/auth
|
||||
REPOFILE=${HOME}/.backup/repos
|
||||
STATFILE=${HOME}/.backup/stats
|
||||
LOGFILE=/var/log/backup.log
|
||||
FULLLOGFILE_BASE=/tmp/full_backup_log
|
||||
|
||||
RESTIC=/usr/local/bin/restic
|
||||
RCLONE=/usr/local/bin/rclone
|
||||
|
@ -16,19 +17,51 @@ USMB=/usr/local/bin/usmb
|
|||
RCLONEOPTS="--progress --buffer-size 10M --cache-chunk-no-memory"
|
||||
|
||||
SPEED=""
|
||||
RESTOREDIRBASE="/mnt/restore"
|
||||
CRONMODE=0
|
||||
CONNECTIONS=""
|
||||
LOG=/dev/stdout
|
||||
DATE=/bin/date
|
||||
DOALL=0
|
||||
REPOSTOBACKUP=""
|
||||
REPO_LIST=""
|
||||
TESTMODE=0
|
||||
VERBOSE=0
|
||||
|
||||
function cecho() {
|
||||
local col
|
||||
col="$1"
|
||||
shift 1
|
||||
echo -e "${col}$*${PLAIN}"
|
||||
}
|
||||
function error() {
|
||||
cecho "$RED" "Error: $*"
|
||||
}
|
||||
function action() {
|
||||
cecho "$CYAN" "$*"
|
||||
}
|
||||
|
||||
function log() {
|
||||
local now
|
||||
local now col lowrer
|
||||
now=`${DATE} +%Y/%m/%d-%H:%M:%S`
|
||||
echo "${now} <${mode}> $*" >>${LOG}
|
||||
lower=$(echo "$*" | tr '[:upper:]' '[:lower:]')
|
||||
if [[ $lower == *error* ]]; then
|
||||
col="$RED"
|
||||
elif [[ $lower == *fail* ]]; then
|
||||
col="$RED"
|
||||
elif [[ $lower == *success* ]]; then
|
||||
col="$GREEN"
|
||||
elif [[ $lower == *starting* ]]; then
|
||||
col="$BOLD"
|
||||
elif [[ $lower == *created* ]]; then
|
||||
col="$BOLD"
|
||||
elif [[ $lower == *creating* ]]; then
|
||||
col="$BOLD"
|
||||
elif [[ $lower == *finished* ]]; then
|
||||
col="$BOLD"
|
||||
else
|
||||
col="$CYAN"
|
||||
fi
|
||||
echo -e "$CYAN${now} <${mode}> $col$*$PLAIN" >>${LOG}
|
||||
}
|
||||
|
||||
function updatestats() {
|
||||
|
@ -52,9 +85,10 @@ function usage-repo() {
|
|||
echo " Default password file is: $DEF_AUTHFILE"
|
||||
echo ""
|
||||
echo "Backup method tags:"
|
||||
echo " restic Backup using restic (default repo is Backblaze B2 bucket \$B2_BUCKET_PREFIX-<reponame>)"
|
||||
echo " rclone Backup using rclone (default repo is Backblaze B2 bucket \$B2_BUCKET_PREFIX-<reponame>)"
|
||||
echo " rsync Backup using rsync (defualt repo is \$DEF_RSYNC_USER@\$DEF_RSYNC_SERVER:\$DEF_RSYNC_DIR/<reponame>)"
|
||||
echo " restic Backup using restic (default repo is Backblaze B2 bucket \$B2_BUCKET_PREFIX-<reponame>)"
|
||||
echo " rclone Backup using rclone (default repo is Backblaze B2 bucket \$B2_BUCKET_PREFIX-<reponame>)"
|
||||
echo " rsync Backup using rsync (default repo is \$DEF_RSYNC_USER@\$DEF_RSYNC_SERVER:\$DEF_RSYNC_DIR/<reponame>)"
|
||||
echo " postgres Dump all postgres databases. Instead of local file path, specify database name to backup. If empty, all dbs are backed up."
|
||||
echo ""
|
||||
echo "Pre-backup commands to access local files:"
|
||||
echo " nfs Mount \$DEF_NFS_SERVER:\$DEF_NFS_SERVER_BASE/<sharename> to <repopath>"
|
||||
|
@ -78,6 +112,8 @@ function usage-rc() {
|
|||
echo " export RESTIC_KEEPDAYS=31 # Days to keep restic backups for"
|
||||
echo " export RESTICOPTS=\"--one-file-system\" # Extra args to pass to restic"
|
||||
echo ""
|
||||
echo " export PGUSER=postgres # Postgresql username"
|
||||
echo ""
|
||||
echo " export DEF_RSYNC_SERVER=xxx # Server used for repos with 'rsync' tag"
|
||||
echo " export DEF_RSYNC_USER=backups # Username for rsync server"
|
||||
echo " export DEF_RSYNC_DIR=/home/backups/backups # Remote directory on rsync server"
|
||||
|
@ -94,6 +130,7 @@ function usage() {
|
|||
echo "usage: $0 command reponame"
|
||||
echo ""
|
||||
echo " -a Run on all repos defined as 'auto'"
|
||||
echo " -d dir Restore mode: specify where to put restored files (default: $RESTOREDIRBASE)"
|
||||
echo " -h Show this usage text"
|
||||
echo " -s num Limit speed to 'num' Mbps (default: unlimited)"
|
||||
echo " -x num Use 'num' simultaneous connections (default: 20)"
|
||||
|
@ -320,15 +357,27 @@ function do_mount() {
|
|||
fi
|
||||
fi
|
||||
|
||||
if ! [[ -e ${DATAPATH} ]]; then
|
||||
log "Error: ${DATAPATH} doesn't exist"
|
||||
return 1
|
||||
fi
|
||||
checktag "$f" postgres # datapath is used for sql filename in pgsql backups
|
||||
if [[ $? -eq 0 ]]; then
|
||||
# Make sure the db exists
|
||||
if ! [[ -z ${DATAPATH} ]]; then
|
||||
psql -lqt | cut -d \| -f 1 | grep -qw ${DATAPATH}
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log "Error: PostgreSQL database '${DATAPATH}' doesn't exist"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if ! [[ -e ${DATAPATH} ]]; then
|
||||
log "Error: ${DATAPATH} doesn't exist"
|
||||
return 1
|
||||
fi
|
||||
|
||||
count=`ls ${DATAPATH} | wc -l`
|
||||
if [ $count -le 2 ]; then
|
||||
log "Error: ${DATAPATH} exists but appears to be empty"
|
||||
return 1
|
||||
count=`ls ${DATAPATH} | wc -l`
|
||||
if [ $count -le 2 ]; then
|
||||
log "Error: ${DATAPATH} exists but appears to be empty"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
@ -346,14 +395,60 @@ function do_umount() {
|
|||
fi
|
||||
}
|
||||
|
||||
function updatedir() {
|
||||
local temp r tempwd
|
||||
tempwd=$(echo "$wd" | sed -e 's-/\{1,\}-/-g')
|
||||
temp=$( ${RESTIC} $AUTHOPTS $CONNECTIONSOPTS -q ls -l $RESTORESNAPID $tempwd 2>/dev/null )
|
||||
r=$?
|
||||
if [[ $r -ne 0 || -z $temp ]]; then
|
||||
return 1
|
||||
fi
|
||||
wd="$tempwd"
|
||||
contents=$( echo "$temp" | awk -v wd=$wd '{ sub(wd,""); sub(wd "/", ""); print $0; }')
|
||||
subdirs=$( echo "${contents}" | grep "^d" | awk '{ print $NF}' | sed -e 's,^/,,')
|
||||
subfiles=$( echo "${contents}" | awk '{ print $NF}' | sed -e 's,^/,,')
|
||||
return 0
|
||||
}
|
||||
|
||||
function showrestoreinfo() {
|
||||
cecho "$YELLOW$BOLD" "Repo to restore from:"
|
||||
cecho "$YELLOW" " $f (snapshot $RESTORESNAPID)"
|
||||
echo
|
||||
cecho "$YELLOW$BOLD" "Files to restore:"
|
||||
if [[ -z $RESTORELIST ]]; then
|
||||
cecho "$YELLOW" " (none)"
|
||||
else
|
||||
cecho "$YELLOW" "$RESTORELIST" | sed -e 's/^ //' | tr ' ' '\n' | sed -e 's/^/ /g'
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
function restorecmd_help() {
|
||||
echo
|
||||
echo "x Abort"
|
||||
echo "q Abort"
|
||||
echo "lcd dir Change local restore dir"
|
||||
echo "ls Show files in current repo dir"
|
||||
echo "cd Change current repo dir"
|
||||
echo "dirs Start subdirectories of current repo dir"
|
||||
echo "go Start restore of marked file"
|
||||
echo "w List files marked for restore"
|
||||
echo "a file Mark file to be restored"
|
||||
echo "d file Un-mark file from restore list"
|
||||
echo
|
||||
}
|
||||
|
||||
# Handle args
|
||||
ARGS="acdhs:tvx:"
|
||||
ARGS="acd:hs:tvx:"
|
||||
|
||||
while getopts "$ARGS" i; do
|
||||
case "$i" in
|
||||
a)
|
||||
DOALL=1
|
||||
;;
|
||||
d)
|
||||
RESTOREDIRBASE="$OPTARG";
|
||||
;;
|
||||
h)
|
||||
usage;
|
||||
exit 1
|
||||
|
@ -382,21 +477,33 @@ while getopts "$ARGS" i; do
|
|||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
if [[ $CRONMODE -eq 0 ]]; then
|
||||
BOLD="\033[1m"
|
||||
PLAIN="\033[0m"
|
||||
UNDERLINE="\033[4m"
|
||||
RED="\033[31m"
|
||||
GREEN="\033[32m"
|
||||
YELLOW="\033[33m"
|
||||
BLUE="\033[34m"
|
||||
CYAN="\033[36m"
|
||||
LINK="$BLUE$UNDERLINE"
|
||||
fi
|
||||
|
||||
if ! [ -e ${RCFILE} ]; then
|
||||
echo "Error - can't find ${RCFILE}"
|
||||
error "can't find ${RCFILE}"
|
||||
echo ""
|
||||
usage-rc
|
||||
exit 1
|
||||
fi
|
||||
if ! [ -e ${REPOFILE} ]; then
|
||||
echo "Error - can't find ${REPOFILE}"
|
||||
error "can't find ${REPOFILE}"
|
||||
echo ""
|
||||
usage-repo
|
||||
exit 1
|
||||
fi
|
||||
which bc >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error - can't find bc in path"
|
||||
error "can't find bc in path"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
@ -404,7 +511,7 @@ fi
|
|||
. ${RCFILE}
|
||||
|
||||
if [[ -z $RESTIC_KEEPDAYS ]]; then
|
||||
echo "Error - \$RESTIC_KEEPDAYS not set."
|
||||
error "\$RESTIC_KEEPDAYS not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -415,6 +522,25 @@ else
|
|||
KSPEED=""
|
||||
fi
|
||||
|
||||
CMD="$1"
|
||||
shift 1
|
||||
|
||||
# command synonyms
|
||||
if [[ $CMD == "repolist" ]]; then
|
||||
CMD="repos"
|
||||
elif [[ $CMD == "restore" ]]; then
|
||||
CMD="get"
|
||||
elif [[ $CMD == "snapshots" ]]; then
|
||||
CMD="ls"
|
||||
fi
|
||||
|
||||
|
||||
if (echo "$VALIDCOMMANDS" | grep -wq $CMD) ; then
|
||||
true
|
||||
else
|
||||
error "invalid command $CMD. Should one of: $VALIDCOMMANDS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get list of defined repos
|
||||
idx=0
|
||||
|
@ -426,11 +552,11 @@ for f in `cat $REPOFILE | grep ";" | grep -v "^#"`; do
|
|||
thisrpath=`getrepopath $f`
|
||||
if [[ ${thisrpath,,} == *b2* ]]; then
|
||||
if [[ -z $B2_APP_ID ]]; then
|
||||
echo "Error - \$B2_APP_ID not set."
|
||||
error "\$B2_APP_ID not set."
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z $B2_APP_KEY ]]; then
|
||||
echo "Error - \$B2_APP_KEY not set."
|
||||
error "\$B2_APP_KEY not set."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
@ -439,31 +565,50 @@ for f in `cat $REPOFILE | grep ";" | grep -v "^#"`; do
|
|||
if [[ $DOALL -eq 1 ]]; then
|
||||
checktag "$f" auto
|
||||
if [[ $? -eq 0 ]]; then
|
||||
REPOSTOBACKUP="$REPOSTOBACKUP `echo $f | sed -e 's/\;.*//'`"
|
||||
REPO_LIST="$REPO_LIST `echo $f | sed -e 's/\;.*//'`"
|
||||
fi
|
||||
fi
|
||||
idx=$((idx + 1))
|
||||
done
|
||||
|
||||
if ! [[ $VALIDCOMMANDS == *"$CMD"* ]]; then
|
||||
echo "Error - invalid command $CMD. Should one of: $VALIDCOMMANDS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CMD="$1"
|
||||
shift 1
|
||||
|
||||
if [[ -z $REPOSTOBACKUP ]]; then
|
||||
REPOSTOBACKUP="$*"
|
||||
if [[ $CMD == "get" ]]; then
|
||||
# one repo + snapshotid/date
|
||||
err=0
|
||||
if [[ -z $REPO_LIST ]]; then
|
||||
if [[ $# -ge 1 ]]; then
|
||||
REPO_LIST=$1 ;shift 1
|
||||
else
|
||||
error "no reponame provided."
|
||||
exit 1
|
||||
fi
|
||||
if [[ $# -ge 1 ]]; then
|
||||
RESTORESNAPID=$1 ; shift 1
|
||||
fi
|
||||
RESTORELIST="$*"
|
||||
else
|
||||
echo "restore usage: $0 get repo_name (snapshotid|latest)"
|
||||
echo " or"
|
||||
echo " $0 get repo_name (snapshotid|latest) file1 file2 etc"
|
||||
echo
|
||||
echo "Files will be restored to $RESTOREDIRBASE/repo_name/"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# one or more repos
|
||||
if [[ -z $REPO_LIST ]]; then
|
||||
REPO_LIST="$*"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $CMD == "repos" ]]; then
|
||||
format="%-10s%-20s%-20s%s\n"
|
||||
echo "Repos defined in ${RCFILE}:"
|
||||
format="%-20s%-20s%-30s%s\n"
|
||||
cecho "${CYAN}" "Repos defined in $BOLD${RCFILE}$PLAIN$CYAN:"
|
||||
echo ""
|
||||
printf "$format" "Repo" "Path" "Tags" "Repo path"
|
||||
head=$(printf "$format" "Repo" "Path/DB" "Repo path" "Tags")
|
||||
cecho "$BOLD$YELLOW" "$head"
|
||||
for x in ${REPODEFS[@]}; do
|
||||
|
||||
IFS=';' read -ra tok <<< "$x"
|
||||
thisrepo=${tok[0]}
|
||||
thispath=${tok[1]}
|
||||
|
@ -475,19 +620,24 @@ if [[ $CMD == "repos" ]]; then
|
|||
thisrpath=`getrepopath $thisrepo`
|
||||
[[ -z $thisrpath ]] && thisrpath="(default)"
|
||||
|
||||
printf "$format" "$thisrepo" "$thispath" "$tags" "$thisrpath"
|
||||
if [[ $tags == *postgres* && -z $thispath ]]; then
|
||||
thispath="(all dbs)"
|
||||
fi
|
||||
|
||||
line=$(printf "$format" "$thisrepo" "$thispath" "$thisrpath" "$tags")
|
||||
cecho "$YELLOW" "$line"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -z $REPOSTOBACKUP ]]; then
|
||||
if [[ -z $REPO_LIST ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate repos
|
||||
GOODREPOS=""
|
||||
for f in $REPOSTOBACKUP; do
|
||||
for f in $REPO_LIST; do
|
||||
REPO=${f}
|
||||
DATAPATH=$(getdatapath $f)
|
||||
REPOPATH=$(getrepopath $f)
|
||||
|
@ -559,12 +709,17 @@ for f in $REPOSTOBACKUP; do
|
|||
fi
|
||||
|
||||
if [[ -z $DATAPATH ]]; then
|
||||
log "can't find matching repo for $f - make sure it is listed in ${REPOFILE}"
|
||||
continue
|
||||
checktag "$f" postgres
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log "error - can't find matching repo for $f - make sure it is listed in ${REPOFILE}"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $CMD == "go" ]]; then
|
||||
NEEDMOUNT=1
|
||||
elif [[ $CMD == "get" ]]; then
|
||||
NEEDMOUNT=1
|
||||
elif [[ $CMD == "diff" ]]; then
|
||||
NEEDMOUNT=1
|
||||
else
|
||||
|
@ -585,15 +740,15 @@ for f in $REPOSTOBACKUP; do
|
|||
fi
|
||||
done
|
||||
|
||||
REPOSTOBACKUP="$GOODREPOS"
|
||||
if [[ -z $REPOSTOBACKUP ]]; then
|
||||
REPO_LIST="$GOODREPOS"
|
||||
if [[ -z $REPO_LIST ]]; then
|
||||
log "Error: errors found with all repos. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $TESTMODE -eq 1 ]]; then
|
||||
echo "Would have run '$CMD' on these repos:"
|
||||
for f in $REPOSTOBACKUP; do
|
||||
action "Would have run '$CMD' on these repos:"
|
||||
for f in $REPO_LIST; do
|
||||
DATAPATH=$(getdatapath $f)
|
||||
echo " $f -> $DATAPATH"
|
||||
if [[ $NEEDMOUNT -eq 1 ]]; then
|
||||
|
@ -606,9 +761,10 @@ fi
|
|||
errcount=0 # used for 'check' mode
|
||||
warncount=0 # used for 'check' mode
|
||||
errtext=""
|
||||
for f in $REPOSTOBACKUP; do
|
||||
for f in $REPO_LIST; do
|
||||
REPO=${f}
|
||||
DATAPATH=$(getdatapath $REPO)
|
||||
FULLLOGFILE="${FULLLOGFILE_BASE}_${REPO}.txt"
|
||||
checktag "$f" usmb
|
||||
if [[ $? -eq 0 ]]; then
|
||||
if [[ -z $USMB_PREFIX ]]; then
|
||||
|
@ -661,6 +817,8 @@ for f in $REPOSTOBACKUP; do
|
|||
|
||||
if [[ $CMD == "go" ]]; then
|
||||
NEEDMOUNT=1
|
||||
elif [[ $CMD == "get" ]]; then
|
||||
NEEDMOUNT=1
|
||||
elif [[ $CMD == "diff" ]]; then
|
||||
NEEDMOUNT=1
|
||||
else
|
||||
|
@ -695,10 +853,32 @@ for f in $REPOSTOBACKUP; do
|
|||
else
|
||||
CONNECTIONSOPTS="-o b2.connections=${CONNECTIONS}"
|
||||
fi
|
||||
|
||||
checktag "$f" postgres
|
||||
if [[ $? -eq 0 ]]; then
|
||||
CONNECTIONSOPTS="$OTHEROPTS --tag postgres"
|
||||
fi
|
||||
|
||||
if [[ $VERBOSE -eq 1 ]]; then
|
||||
OTHEROPTS="$OTHEROPTS -v"
|
||||
fi
|
||||
|
||||
DBOPTS=""
|
||||
DBDUMPCMD=""
|
||||
checktag "$f" postgres
|
||||
if [[ $? -eq 0 ]]; then
|
||||
DBOPTS="$DBOPTS --clean"
|
||||
OTHEROPTS="$OTHEROPTS --stdin"
|
||||
if [[ -z ${DATAPATH} ]]; then
|
||||
DBDUMPCMD="pg_dumpall"
|
||||
DBFILENAME="alldbs.sql"
|
||||
else
|
||||
DBDUMPCMD="pg_dump"
|
||||
DBFILENAME="${DATAPATH}.sql"
|
||||
DBOPTS="$DBOPTS ${DATAPATH}" # Last dbdump option is database name
|
||||
fi
|
||||
fi
|
||||
|
||||
export RESTIC_EXCLUDEFILE=`getrepoexcludefile "$f"`
|
||||
if [[ ! -z $RESTIC_EXCLUDEFILE ]]; then
|
||||
OTHEROPTS="$OTHEROPTS --exclude-file=${RESTIC_EXCLUDEFILE}"
|
||||
|
@ -718,7 +898,7 @@ for f in $REPOSTOBACKUP; do
|
|||
for xx in $list; do
|
||||
eval val='$'$xx
|
||||
if [[ -z $val ]]; then
|
||||
echo "Error - \$$xx not set. Please update ${RCFILE}."
|
||||
error "\$$xx not set. Please update ${RCFILE}."
|
||||
echo ""
|
||||
usage-rc
|
||||
exit 1
|
||||
|
@ -770,34 +950,257 @@ for f in $REPOSTOBACKUP; do
|
|||
oneday=$( echo "24 * 60 * 60" | bc)
|
||||
if [[ $code -eq 0 ]]; then
|
||||
if [[ $age -le $oneday ]]; then
|
||||
echo "OK: Last backup for '$REPO' succeeded on $humanstamp."
|
||||
cecho "$GREEN" "OK: Last backup for '$REPO' succeeded on $humanstamp."
|
||||
rv=0
|
||||
else
|
||||
echo "CRITICAL: Last backup for '$REPO' succeeded on $humanstamp (age $age not in last 24 hours)."
|
||||
cecho "$RED" "CRITICAL: Last backup for '$REPO' succeeded on $humanstamp (age $age not in last 24 hours)."
|
||||
errcount=$(( $errcount + 1))
|
||||
rv=2
|
||||
fi
|
||||
else
|
||||
echo "CRITICAL: Last backup for '$REPO' failed on $humanstamp."
|
||||
cecho "$RED" "CRITICAL: Last backup for '$REPO' failed on $humanstamp."
|
||||
rv=2
|
||||
errcount=$(( $errcount + 1))
|
||||
fi
|
||||
else
|
||||
echo "WARNING: No history found for repo '$REPO'"
|
||||
cecho "$YELLOW" "WARNING: No history found for repo '$REPO'"
|
||||
rv=1
|
||||
warncount=$(( $warncount + 1))
|
||||
fi
|
||||
elif [[ $mode == "restic" ]]; then
|
||||
if [[ $CMD == "go" ]]; then
|
||||
if [[ $CRONMODE -eq 1 ]]; then
|
||||
${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH 2>&1 | egrep "^(Added|processed|snapshot)" >> ${LOG}
|
||||
rv=${PIPESTATUS[0]}
|
||||
if [[ $VERBOSE -eq 1 ]]; then
|
||||
echo "debug: running: [${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH" >>${LOG}
|
||||
echo "debug: full log is in ${FULLLOGFILE}" >>${LOG}
|
||||
checktag "$f" postgres
|
||||
if [[ $? -eq 0 ]] ; then
|
||||
$DBDUMPCMD $DBOPTS | ${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS --stdin-filename $DBFILENAME 2>&1 >> ${FULLLOGFILE}
|
||||
rv=$?
|
||||
else
|
||||
${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH 2>&1 >> ${FULLLOGFILE}
|
||||
rv=$?
|
||||
fi
|
||||
egrep "^(Added|processed|snapshot)" ${FULLLOGFILE} >>${LOG}
|
||||
else
|
||||
checktag "$f" postgres
|
||||
if [[ $? -eq 0 ]] ; then
|
||||
${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH 2>&1 | egrep "^(Added|processed|snapshot)" >> ${LOG}
|
||||
rv=${PIPESTATUS[0]}
|
||||
else
|
||||
$DBDUMPCMD $DBOPTS | ${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS --stdin-filename $DBFILENAME 2>&1 | egrep "^(Added|processed|snapshot)" >> ${LOG}
|
||||
rv=${PIPESTATUS[0]}
|
||||
fi
|
||||
fi
|
||||
else
|
||||
[[ $VERBOSE -eq 1 ]] && log "debug: running: [${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH"
|
||||
${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH 2>&1 >> ${LOG}
|
||||
checktag "$f" postgres
|
||||
if [[ $? -eq 0 ]] ; then
|
||||
[[ $VERBOSE -eq 1 ]] && log "debug: running: [$DBDUMPCMD $DBOPTS | ${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS --stdin-filename $DBFILENAME"
|
||||
$DBDUMPCMD $DBOPTS | ${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS --stdin-filename $DBFILENAME 2>&1 >> ${LOG}
|
||||
rv=$?
|
||||
else
|
||||
[[ $VERBOSE -eq 1 ]] && log "debug: running: [${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH"
|
||||
${RESTIC} backup $AUTHOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH 2>&1 >> ${LOG}
|
||||
rv=$?
|
||||
fi
|
||||
fi
|
||||
elif [[ $CMD == "get" ]]; then
|
||||
RESTOREDIR="$RESTOREDIRBASE/$f/"
|
||||
snaps=$(${RESTIC} snapshots $AUTHOPTS $CONNECTIONSOPTS 2>&1 | grep -v ID | awk '(NF >= 4) { print }')
|
||||
checktag "$f" postgres
|
||||
if [[ $? -ne 0 ]]; then
|
||||
snaps=$(echo "$snaps" | grep -v postgres)
|
||||
fi
|
||||
snapids=$(echo "$snaps" | awk '{ print $1 }')
|
||||
defsid=$(echo "$snapids" | tail -1)
|
||||
|
||||
if [[ -z $RESTORESNAPID ]]; then
|
||||
cecho "$BOLD$CYAN" "Found these snapshots:"
|
||||
echo "$snaps"
|
||||
RESTORESNAPID="xxxxxx"
|
||||
while [[ ! $snaps == *$RESTORESNAPID* ]]; do
|
||||
read -p "snapshot [$defsid]: " RESTORESNAPID
|
||||
if [[ $RESTORESNAPID == "latest" || -z $RESTORESNAPID ]]; then
|
||||
RESTORESNAPID=$defsid
|
||||
fi
|
||||
done
|
||||
elif [[ $RESTORESNAPID == "latest" ]]; then
|
||||
RESTORESNAPID=$defsid
|
||||
elif [[ ! $snaps == *$RESTORESNAPID* ]]; then
|
||||
error "snapshot '$RESTORESNAPID' not found."
|
||||
echo
|
||||
cecho "$RED" "Valid snapshots for repo $f:"
|
||||
cecho "$RED" "$snaps"
|
||||
exit 1
|
||||
|
||||
fi
|
||||
if [[ -z $RESTORELIST ]]; then
|
||||
action "Opening repo for snapshot $BOLD$RESTORESNAPID$PLAIN$CYAN..."
|
||||
wd=/
|
||||
updatedir
|
||||
c="ls"
|
||||
doit=0
|
||||
while [[ ! $c == "x" && ! c == "q" ]]; do
|
||||
if [[ $c == "ls" ]]; then
|
||||
echo "$contents"
|
||||
elif [[ $c == "go" ]]; then
|
||||
if [[ -z $RESTORELIST ]]; then
|
||||
cecho "$RED" "Nothing to restore!"
|
||||
else
|
||||
doit=1
|
||||
fi
|
||||
break
|
||||
elif [[ $c == "x" || $c == "q" ]]; then
|
||||
doit=0
|
||||
break
|
||||
elif [[ $c == "?" || $c == "h" ]]; then
|
||||
restorecmd_help
|
||||
elif [[ -z $c ]]; then
|
||||
true
|
||||
elif [[ $c == "dirs" ]]; then
|
||||
echo "subdirs:"
|
||||
echo "$subdirs" | sed -e 's/^/ /'
|
||||
elif [[ $c == w* ]]; then
|
||||
showrestoreinfo
|
||||
elif [[ $c == a* || $c == mark* ]]; then
|
||||
file=$(echo "$c" | awk '{ print $2 }')
|
||||
# remove leading /
|
||||
file=$(echo $file | sed -e 's,^/,,')
|
||||
if [[ -z $file ]]; then
|
||||
error "no file provided"
|
||||
else
|
||||
echo "$RESTORELIST" | tr ' ' '\n' | egrep -q "^$wd$file$"
|
||||
thisrv=$?
|
||||
if [[ $thisrv -eq 0 ]]; then
|
||||
error "'$file' already in restore list"
|
||||
else
|
||||
if [[ $file == */* ]]; then
|
||||
# add without checking
|
||||
if [[ -z $RESTORELIST ]]; then
|
||||
RESTORELIST="$wd$file"
|
||||
else
|
||||
RESTORELIST="$RESTORELIST $wd$file"
|
||||
fi
|
||||
action "Added to restore list: $BOLD$file$PLAIN$CYAN (no verify)"
|
||||
else
|
||||
echo "$subfiles" | grep -qw "$file"
|
||||
rv=$?
|
||||
if [[ $rv -eq 0 ]]; then
|
||||
RESTORELIST="$RESTORELIST $wd$file"
|
||||
action "Added to restore list: $BOLD$file"
|
||||
else
|
||||
error "'$file' doesn't exist"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
elif [[ $c == d* || $c == unmark* ]]; then
|
||||
file=$(echo "$c" | awk '{ print $2 }')
|
||||
file="$wd$file"
|
||||
echo "$RESTORELIST" | tr ' ' '\n' | egrep -q "^$file$"
|
||||
if [[ $? -eq 0 ]]; then
|
||||
#RESTORELIST=$(echo "$RESTORELIST" | sed -e 's/^ //' | tr ' ' '\n' | grep -wv $file | tr '\n' ' ' | egrep -v "^$" | sed -e 's/^/ /')
|
||||
RESTORELIST=$(echo "$RESTORELIST" | sed -e "s, $file,,")
|
||||
action "Removed from restore list: $BOLD$file"
|
||||
else
|
||||
error "Restore list doesn't contain '$file'"
|
||||
fi
|
||||
elif [[ $c == cd* ]]; then
|
||||
newdir=$(echo "$c" | awk '{ print $2 }')
|
||||
olddir=$wd
|
||||
needupdate=1
|
||||
if [[ $newdir == "/" ]]; then
|
||||
wd=$newdir
|
||||
rv=0
|
||||
elif [[ $newdir == /* ]]; then
|
||||
wd=$newdir/
|
||||
updatedir
|
||||
rv=$?
|
||||
needupdate=0
|
||||
elif [[ $newdir == */* ]]; then
|
||||
wd=$wd$newdir/
|
||||
updatedir
|
||||
rv=$?
|
||||
needupdate=0
|
||||
elif [[ $newdir == ".." ]]; then
|
||||
wd=$(dirname $wd)
|
||||
rv=0
|
||||
else
|
||||
echo "$subdirs" | grep -qw "$newdir"
|
||||
rv=$?
|
||||
if [[ $rv -eq 0 ]]; then
|
||||
wd=$wd$newdir/
|
||||
fi
|
||||
fi
|
||||
if [[ $rv -eq 0 ]]; then
|
||||
[[ $needupdate -eq 1 ]] && updatedir
|
||||
else
|
||||
error "no such directory '$newdir'"
|
||||
wd=$olddir
|
||||
fi
|
||||
elif [[ $c == lcd* ]]; then
|
||||
newlocaldir=$(echo "$c" | awk '{ print $2 }')
|
||||
if [[ -d $newlocaldir ]]; then
|
||||
RESTOREDIR="$newlocaldir"
|
||||
elif [[ -e $newlocaldir ]]; then
|
||||
error "'$newlocaldir' is not a directory"
|
||||
else
|
||||
error "'$newlocaldir' does not exist"
|
||||
fi
|
||||
else
|
||||
error "bad command '$c' (? for help)"
|
||||
fi
|
||||
echo
|
||||
action "Restore path: $RESTOREDIR"
|
||||
echo -en "$CYAN$wd> $PLAIN"
|
||||
read c
|
||||
done
|
||||
else
|
||||
# restorelist not empty
|
||||
doit=1
|
||||
fi
|
||||
if [[ $doit -eq 1 ]]; then
|
||||
showrestoreinfo
|
||||
action "Performing restore..."
|
||||
echo
|
||||
RESTOREOPTS=""
|
||||
for r in $RESTORELIST; do
|
||||
RESTOREOPTS="$RESTOREOPTS -i $r"
|
||||
done
|
||||
[[ $VERBOSE -eq 1 ]] && log "debug: running: ${RESTIC} restore $AUTHOPTS $CONNECTIONSOPTS -t "$RESTOREDIR" $RESTOREOPTS $RESTORESNAPID"
|
||||
${RESTIC} restore $AUTHOPTS $CONNECTIONSOPTS -t "$RESTOREDIR" $RESTOREOPTS $RESTORESNAPID 2>&1 >> ${LOG}
|
||||
rv=$?
|
||||
|
||||
if [[ $rv -eq 0 ]]; then
|
||||
# check that we got them all
|
||||
tried=0
|
||||
success=0
|
||||
failed=0
|
||||
for r in $RESTORELIST; do
|
||||
tried=$((tried + 1))
|
||||
if [[ -e $RESTOREDIR/$r ]]; then
|
||||
success=$((success + 1))
|
||||
else
|
||||
failed=$((failed + 1))
|
||||
fi
|
||||
done
|
||||
echo
|
||||
echo -en "${CYAN}${BOLD}Restored $success / $tried items$PLAIN"
|
||||
[[ $failed -gt 0 ]] && cecho "$RED" " ($failed failed)" || echo
|
||||
echo
|
||||
if [[ $success -eq $tried ]]; then
|
||||
rv=0
|
||||
else
|
||||
rv=1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
action "${BOLD}Aborting..."
|
||||
rv=1
|
||||
fi
|
||||
elif [[ $CMD == "ls" ]]; then
|
||||
|
||||
[[ $VERBOSE -eq 1 ]] && log "debug: running: ${RESTIC} snapshots $AUTHOPTS $CONNECTIONSOPTS $OTHEROPTS "
|
||||
${RESTIC} snapshots $AUTHOPTS $CONNECTIONSOPTS 2>&1 >> ${LOG}
|
||||
rv=$?
|
||||
elif [[ $CMD == "stats" ]]; then
|
||||
|
@ -815,9 +1218,6 @@ for f in $REPOSTOBACKUP; do
|
|||
else
|
||||
cmdtorun="${RESTIC} init $AUTHOPTS $CONNECTIONSOPTS"
|
||||
if [[ $VERBOSE -eq 1 ]]; then
|
||||
|
||||
|
||||
|
||||
log "export RESTIC_REPOSITORY=\"$REPO_PATH\""
|
||||
log "export RESTIC_PASSWORD_FILE=`getrepopassfile \"$f\"`"
|
||||
log "will run: [${cmdtorun}]"
|
||||
|
@ -837,16 +1237,18 @@ for f in $REPOSTOBACKUP; do
|
|||
fi
|
||||
elif [[ $mode == "rsync" ]]; then
|
||||
REMOTE=""
|
||||
if [[ $CMD == "go" ]]; then
|
||||
#echo run ${RSYNC} ${RSYNC_OPTIONS} $DATAPATH/ ${RSYNC_REPOSITORY} 2>&1 >> ${LOG}
|
||||
#exit 1
|
||||
checktag "$f" postgres
|
||||
if [[ $? -eq 0 ]] ; then
|
||||
log "Error: postgres backups not supported for rsync mode."
|
||||
rv=1
|
||||
elif [[ $CMD == "go" ]]; then
|
||||
${RSYNC} ${RSYNC_OPTIONS} $DATAPATH/ ${RSYNC_REPOSITORY} 2>&1 >> ${LOG}
|
||||
rv=$?
|
||||
elif [[ $CMD == "ls" ]]; then
|
||||
ssh ${DEF_RSYNC_USER}@${DEF_RSYNC_SERVER} ls ${RSYNC_FULLDIR} 2>&1 >> ${LOG}
|
||||
rv=$?
|
||||
elif [[ $CMD == "stats" ]]; then
|
||||
echo "Size of remote data for ${REPO}:"
|
||||
action "Size of remote data for ${REPO}:"
|
||||
ssh ${DEF_RSYNC_USER}@${DEF_RSYNC_SERVER} du -hs ${RSYNC_FULLDIR} 2>&1 >> ${LOG}
|
||||
rv=$?
|
||||
elif [[ $CMD == "diff" ]]; then
|
||||
|
@ -866,7 +1268,7 @@ for f in $REPOSTOBACKUP; do
|
|||
fi
|
||||
fi
|
||||
elif [[ $CMD == "forget" ]]; then
|
||||
log "Error: forget not supported for rsync mode."
|
||||
log "Error: forget not supported for $mode mode."
|
||||
rv=1
|
||||
else
|
||||
log "Error: invalid command $CMD"
|
||||
|
@ -875,7 +1277,11 @@ for f in $REPOSTOBACKUP; do
|
|||
else
|
||||
# rclone
|
||||
REMOTE=""
|
||||
if [[ $CMD == "go" ]]; then
|
||||
checktag "$f" postgres
|
||||
if [[ $? -eq 0 ]] ; then
|
||||
log "Error: postgres backups not supported for $mode mode."
|
||||
rv=1
|
||||
elif [[ $CMD == "go" ]]; then
|
||||
${RCLONE} sync $RCLONEOPTS $CONNECTIONSOPTS $SPEEDOPTS $OTHEROPTS $DATAPATH $RCLONE_REPOSITORY 2>&1 >> ${LOG}
|
||||
rv=$?
|
||||
elif [[ $CMD == "ls" ]]; then
|
||||
|
@ -965,3 +1371,4 @@ if [[ $CMD == "check" ]]; then
|
|||
fi
|
||||
exit $rv
|
||||
fi
|
||||
|
||||
|
|
Loading…
Reference in New Issue