From 622450574a75e7b6765733d64186640ef968b759 Mon Sep 17 00:00:00 2001 From: "Hahn Axel (hahn)" <axel.hahn@iml.unibe.ch> Date: Tue, 25 May 2021 17:21:37 +0200 Subject: [PATCH] save current restore as legacy script --- restore_legacy.sh | 506 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 506 insertions(+) create mode 100755 restore_legacy.sh diff --git a/restore_legacy.sh b/restore_legacy.sh new file mode 100755 index 0000000..4fc0993 --- /dev/null +++ b/restore_legacy.sh @@ -0,0 +1,506 @@ +#!/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 + + +# -------------------------------------------------------------------------------- -- GitLab