Skip to content
Snippets Groups Projects

Version 2

Merged Hahn Axel (hahn) requested to merge version-2 into master
1 file
+ 506
0
Compare changes
  • Side-by-side
  • Inline
restore_legacy.sh 0 → 100755
+ 506
0
#!/bin/bash
# ================================================================================
#
# RESTORE - interactive restore
#
# Restore duplicity backup data to a local directory.
# Please notice: duplicity does not overwrite any dir or file. So the restore
# path is different to the path of the backed up data.
#
# SYNTAX:
# restore.sh [path-to-restore]
#
# path-to-restore - optional
# default: none ... you get an interactive selection of backup sets
#
# --------------------------------------------------------------------------------
# ah - Axel Hahn <axel.hahn@iml.unibe.ch>
# ds - Daniel Schueler <daniel.schueler@iml.unibe.ch>
#
# 2016-11-17 ah,ds v1.0
# 2017-10-11 ah,ds v1.1 added support for duplicity param --ssh-backend
# 2018-08-27 ah,ds v1.2 fix restore target with a given selection; handle '*' placeholder
# 2019-06-05 ah,ds v1.3 add custom cache dir
# ================================================================================
# --------------------------------------------------------------------------------
# CONFIG
# --------------------------------------------------------------------------------
# . `dirname $0`/inc_config.sh
. `dirname $0`/jobhelper.sh
. `dirname $0`/inc_bash.sh
STORAGE_BASEDIR=`_j_getvar ${STORAGEFILE} "storage"`
# check
if [ -z $STORAGE_BASEDIR ]; then
echo ERROR: missing config for backup target.
echo There must be an entry storage in ${STORAGEFILE}
exit 1
fi
# ----- read something from config files
RESTORE_BASEDIR=`_j_getvar ${STORAGEFILE} "restore-path"`
PASSPHRASE=`_j_getvar ${STORAGEFILE} "gnupg-passphrase"`
export PASSPHRASE
sFileSshPrivkey=`_j_getvar ${STORAGEFILE} "ssh-privatekey"`
sParams=
# task#1623 - fallback ssh backend for Debian 8
sSshBackend=`_j_getvar ${STORAGEFILE} "ssh-backend"`
if [ ! -z $sSshBackend ]; then
sParams="${sParams} --ssh-backend $sSshBackend"
fi
sFileSshPrivkey=`_j_getvar ${STORAGEFILE} "ssh-privatekey"`
if [ ! -z $sFileSshPrivkey ]; then
sParams="${sParams} --ssh-options="""-oIdentityFile=${sFileSshPrivkey}""" "
fi
# task#3046 - add custom cache dir
sCacheDir=`_j_getvar ${STORAGEFILE} "cachedir"`
if [ ! -z $sCacheDir ]; then
sParams="${sParams} --archive-dir=$sCacheDir"
fi
# ----- what to restore ...
sDir2restore=
sRestoreItem=
sDate=`date +%Y-%m-%d`
# duplicity target
sTarget=
# --------------------------------------------------------------------------------
# FUNCTIONS
# --------------------------------------------------------------------------------
# ----------------------------------------------------------------------
# enter name of directory to restore; menu item
# ----------------------------------------------------------------------
function enterBackupDir(){
h2 "select a directory to be restored"
echo "This is a list of the directories from the backup configuration."
echo "Enter the full path"
echo
echo "Enter the full path; marked entries with (*) do not exist on this machine"
echo
sDirs="`j_getDirs2Backup`"
for mydir in $sDirs
do
if [ ! -d "$mydir" ]; then
color error
echo "$mydir (*)"
color reset
else
echo "$mydir"
fi
done
color input
echo -n "[$sDir2restore] >"
color reset
read myinput
setBackupDir "${myinput}"
}
# ----------------------------------------------------------------------
# enter date to restore from; menu item
# ----------------------------------------------------------------------
function enterDate(){
h2 "edit date to restore"
echo "The acceptible time strings are intervals (like \"3D64s\"), w3-datetime"
echo "strings, like \"2002-04-26T04:22:01-07:00\" (strings like"
echo "\"2002-04-26T04:22:01\" are also acceptable - duplicity will use the"
echo "current time zone), or ordinary dates like 2/4/1997 or 2001-04-23"
echo "(various combinations are acceptable, but the month always precedes"
echo "the day)."
echo
echo "today in YYYY-MM-DD: `date +%Y-%m-%d`"
echo
color input
echo -n "[$sDate] >"
color reset
read sNewDate
if [ ! -z $sNewDate ]; then
sDate=$sNewDate
fi
}
# ----------------------------------------------------------------------
# enter relative path to restore; menu item
# ----------------------------------------------------------------------
function enterRestoreitem(){
h2 "set restore item (path)"
echo "enter a relative path behind ${sDir2restore}/"
echo "empty means: all data"
echo
color input
echo -n "[$sRestoreItem] >"
color reset
read sNewsRestoreItem
if [ ! -z $sNewsRestoreItem ]; then
sRestoreItem=$sNewsRestoreItem
setVars
fi
getRemoteFiles
}
# ----------------------------------------------------------------------
# search a file in backup; menu item
# ----------------------------------------------------------------------
function searchFile(){
h2 "search a file in backup --time $sDate"
echo "Enter something that was backuped from ${sDir2restore}"
echo "searchtext matches anywhere in filename or path - it is a grep grep in"
echo "duplicity list-current-files --time $sDate [target]"
echo "Press just Return to exit"
echo
color input
echo -n "search for >"
color reset
read sSearch
if [ ! -z $sSearch ]; then
getRemoteFiles $sSearch
fi
}
# ----------------------------------------------------------------------
# verify backup set with local files; menu item
# ----------------------------------------------------------------------
function verify(){
h2 "verify"
echo duplicity verify ${sParams} ${sTarget} -v4 $sDir2restore
color cmd
duplicity verify ${sParams} ${sTarget} -v4 $sDir2restore
fetchrc
color reset
}
# ----------------------------------------------------------------------
# show file changes in backupsets; menu item
# work in progress ... I don't know how to match a file...
# ----------------------------------------------------------------------
function showFilechanges(){
tmpcache=~/.cache/duplicity-changes-${sSafeName}.txt
h2 "show file changes"
egrep "\ \ (changed|deleted|new)\ \ " `fgrep -l "Localdir ${sDir2restore}" ~/.cache/duplicity/*/*.manifest` >$tmpcache
# ls -l $tmpcache
# head $tmpcache
echo "I hope you made a search first"
echo "Enter filename with complete path that was backuped from ${sDir2restore}"
echo "Press just Return to exit"
echo
color input
echo -n "search for >"
color reset
read sSearch
if [ ! -z "${sSearch}" ]; then
echo grep "${sSearch}"
color cmd
# duplicity collection-status --file-changed "`basename ${sSearch}`" ${sParams} ${sTarget}/`dirname "${sSearch}"`
cat $tmpcache | grep "${sSearch}" | while read line
do
sManifest=`echo $line | cut -f 1 -d ":"`
# duplicity-inc.20161111T152106Z.to.20161111T152141Z.manifest
sTime=`basename "${sManifest}" | cut -f 2 -d "."`
sOut=`echo $line | cut -f 2- -d ":"`
echo $sTime $sOut | sed "s#new#new #"
done | sort
echo
color reset
fi
}
# ----------------------------------------------------------------------
# show remote volumes with incremental and full backups
# ----------------------------------------------------------------------
function getRemoteVolumes(){
tmpoutVolumes=/tmp/outvolumelist_$$
h2 "volumes for $sDir2restore"
echo duplicity collection-status ${sParams} ${sTarget}
color cmd
duplicity collection-status ${sParams} ${sTarget} | tee -a $tmpoutVolumes
fetchrc
color reset
echo
if [ `cat $tmpoutVolumes | egrep "(Full|Incremental)" | wc -l` -eq 0 ]; then
color error
echo "ERROR: no backup sets were found for directory [$sDir2restore]"
echo
color reset
sDir2restore=
setVars
else
color ok
echo "OK, `cat $tmpoutVolumes | grep "Full" | wc -l` Full and `cat $tmpoutVolumes | grep "Incremental" | wc -l` incremental backups"
color reset
fi
rm -f $tmpoutVolumes
}
# ----------------------------------------------------------------------
# list files from backupset
# ----------------------------------------------------------------------
function getRemoteFiles(){
iLines=50
tmpout=/tmp/outfilelist_$$
sSearch=$1
if [ -z $sSearch ]; then
sSearch="^...\ ...\ ..\ ........\ ....\ $sRestoreItem"
fi
echo
echo
echo --- files ... filtered for date [$sDate] by [$sSearch]
echo duplicity list-current-files --time $sDate ${sParams} ${sTarget}
color cmd
duplicity list-current-files --time $sDate ${sParams} ${sTarget} 2>&1 | grep "$sSearch" | tee -a $tmpout | head -$iLines
fetchrc
color reset
if [ `cat $tmpout | wc -l` -eq 0 ]; then
color error
echo ERROR: your file does not match ... try another time ... or another search string
color reset
else
echo ... max $iLines lines ... maybe the output was cut
echo
if [ -z $1 ]; then
echo
doRestoreDryRun
echo
echo
fi
fi
rm -f $tmpout
}
# ----------------------------------------------------------------------
# set backup dir .. called when using cli parameter or enterBackupDir
# param string full path of a directory to retore
# ----------------------------------------------------------------------
function setBackupDir(){
if [ ! -z $1 ]; then
sDirs2Backup="`j_getDirs2Backup`"
bFound=0
for mydir in ${sDirs2Backup}
do
if [ "${mydir}" = "${1}" ]; then
bFound=1
fi
done
if [ $bFound -eq 0 ]; then
color error
echo
echo "WARNING: seems to be wrong ... "
echo "At the moment I restore only known targets."
color reset
# TODO: if we want to retore other backup sets of other servers
# we cannot be as strict
else
sDir2restore=$1
setVars
getRemoteVolumes
fi
fi
}
# ----------------------------------------------------------------------
# internal: set variables for target path and backup set to make
# duplicity calls
# ----------------------------------------------------------------------
function setVars(){
sSafeName=`j_getSafename "$sDir2restore"`
sTarget=`j_getFullTarget "$sDir2restore"`
sRestorepath="${RESTORE_BASEDIR}/${sSafeName}"
if [ ! -z $sRestoreItem ]; then
echo ${sRestoreItem} | grep '\*' >/dev/null
if [ $? -eq 0 ]; then
sRestoreItem=`dirname $sRestoreItem | sed 's#^\.##'`
color error
echo ERROR: using a placeholder is not allowed. Using the directory above.
echo [$sRestoreItem]
color reset
fi
sRestorepath="${sRestorepath}/${sRestoreItem}"
fi
}
# ----------------------------------------------------------------------
# restore dry run ... called in getRemoteFiles
# ----------------------------------------------------------------------
function doRestoreDryRun(){
echo "--- dry run"
echo duplicity restore --dry-run --file-to-restore "$sRestoreItem" --time $sDate ${sParams} ${sTarget} ${sRestorepath}
color cmd
duplicity restore --dry-run --file-to-restore "$sRestoreItem" --time $sDate ${sParams} ${sTarget} ${sRestorepath}
fetchrc
color reset
}
# ----------------------------------------------------------------------
# restore and finish the script; menu item
# ----------------------------------------------------------------------
function doRestore(){
mkdir -p $sRestorepath
h2 "RESTORE"
echo duplicity restore --file-to-restore "$sRestoreItem" --time $sDate ${sParams} ${sTarget} ${sRestorepath}
color cmd
duplicity restore --file-to-restore "$sRestoreItem" --time $sDate ${sParams} ${sTarget} ${sRestorepath}
fetchrc
color reset
echo
echo
echo Restore is finished.
echo Have look to the output above.
echo "The restore path has `find ${sRestorepath} -type f | wc -l` files (`du -hs ${sRestorepath} | awk '{ print $1 }'`)"
echo
echo find ${sRestorepath}
echo
exit 0
}
# --------------------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------------------
h1 "RESTORE - GET FILES FROM STORAGE"
# ----- Check requirements
j_requireUser "root"
j_requireBinary "duplicity"
# ----- set a directory to restore to have a useful initial point
setBackupDir $1
if [ -z $sDir2restore ]; then
enterBackupDir
fi
# ----- menu and loop
while true
do
h1 "Restore :: Menu"
# getRemoteVolumes
# getRemoteFiles
echo
echo " D - directory to restore: $sDir2restore"
echo " T - time : $sDate"
echo " W - what to restore : $sRestoreItem"
echo
echo " C - show file changes"
echo " S - search file"
echo " V - verify"
echo " B - Bash (Shell)"
echo
echo " R - start restore"
echo
echo " retore from : $sTarget"
echo " retore to : $sRestorepath"
echo -n " "
ls -d $sRestorepath >/dev/null 2>&1
if [ $? -eq 0 ]; then
color error
echo "WARNING: directory already exists! Backup will fail."
color reset
else
echo "OK, it does not exist yet"
fi
echo
echo " X - exit"
echo
color input
echo -n "Select (not case sensitive) --> "
color reset
read action
echo
case $action in
d|D)
enterBackupDir
;;
t|T)
enterDate
;;
c|C)
showFilechanges
;;
s|S)
searchFile
;;
v|V)
verify
;;
b|B)
echo type exit to return...
export PS1="[`basename $0` \u@\h \w]\$ "
bash
;;
w|W)
enterRestoreitem
;;
r|R)
doRestore
;;
x|X)
exit 0
;;
*)
echo "Try again"
esac
done
# --------------------------------------------------------------------------------
Loading