Skip to content
Snippets Groups Projects
restic.sh 9.39 KiB
#!/bin/bash
# ================================================================================
#
# TRANSFER :: PLUGIN - TEMPLATE
#
# this script will be included in ../../transfer.sh
#
# --------------------------------------------------------------------------------
# ah - Axel Hahn <axel.hahn@iml.unibe.ch>
# 2021-05-19  ah    v0.0   INIT ... WIP
# ================================================================================

# --------------------------------------------------------------------------------
# ENV VARS
# export variables that are needed by the backup tool
# --------------------------------------------------------------------------------

# export PASSPHRASE

# --------------------------------------------------------------------------------
# INIT
# --------------------------------------------------------------------------------


    function t_checkRequirements(){
        j_requireUser "root"
        j_requireBinary "restic"
    }

    function t_setVars(){
        export RESTIC_PASSWORD=$PASSPHRASE

        # if we set RESTIC_REPOSITORY then "-r TARGET" is not 
        # needed in restic commands
        export RESTIC_REPOSITORY=$( j_getFullTarget )

        # WORKAROUND for bug while writing on a SMB target
        export GODEBUG="asyncpreemptoff=1"

        RESTORE_ITEM=latest
        RESTORE_FILTER=
        RESTORE_CMD=
    }

# --------------------------------------------------------------------------------
# GENERATE PARAMS :: ALL DIRS
# --------------------------------------------------------------------------------

    # return a string with default params
    # param  string  param1 of transfer.sh; one of full|inc|auto
    # param  string  param2 of transfer.sh; for auto: date i.e. 3M for 3 monthes
    function t_getParamDefault(){
        # verbose to see more details
        echo -n --verbose=$( _j_getvar ${STORAGEFILE} "restic_verbose")

    }
    # return a string with backup default params
    function t_getParamBackup(){
        # tagging
        echo -n --tag $( _j_getvar ${STORAGEFILE} "restic_tag")
    }

    # return a cli parameter for a single exlude directory
    # param  string  cache directory for local index files
    function t_getParamCacheDir(){
        if [ ! -z "$1" ]; then
            local sCacheDir="$1"
            if [ ! -d $sCacheDir ]; then
                mkdir -p $sCacheDir
                chmod 750 $sCacheDir
            fi
            echo --cache-dir $sCacheDir
        fi
    }

    # return a cli parameter for a single exlude directory
    # param  string  exlude pattern
    function t_getParamExlude(){
        test -z "$1" || echo --exclude "'"$*"'"
    }
    # return a cli parameter for a single exlude directory
    # param  string  exlude pattern
    function t_getParamInlude(){
        test -z "$1" || echo --include "'"$*"'"
    }

    # return a cli parameter to use an ssh keyfile
    # param  string  filename if ssh private key file
    function t_getParamSshKey(){
        if [ ! -z "$1" ]; then
            # scp://backup@storage.example.com//netshare/backup/one
            #       ^^^^^^^^^^^^^^^^^^^^^^^^^^
            #       sshtarget fetches user@host ... if protocol matches
            echo $STORAGE_BASEDIR | grep -E "^(scp|sftp|rsync):" >/dev/null
            if [ $? -eq 0 ]; then
                local sshtarget=$( echo $STORAGE_BASEDIR | cut -f 3 -d '/' )
                echo -o sftp.command="'"ssh -i ${1} ${sshtarget} -s sftp"'"
                # echo -n "-o sftp.command=''"
            fi
        fi
    }

# --------------------------------------------------------------------------------
# ACTIONS :: TRANSFER
# --------------------------------------------------------------------------------
    # pre backup actions
    # uses global vars from ../../transfer.sh
    function t_cmdPre(){

        local _mycmd="restic init ${sParams}"
        echo $_mycmd
        color cmd 
        eval $_mycmd
        local _myrc=$?
        color reset

        # detect return code ... do not abort on any error.
        t_rcCheckInit $_myrc

    }


    # post backup actions
    # uses global vars from ../../transfer.sh
    function t_cmdPost(){

        echo "--- CLEANUP local data:"
        echo restic cache --cleanup
        color cmd
        restic cache --cleanup
        local _myrc=$?
        color reset
        case $_myrc in
            0) color ok;      echo "OK" ;;
            *) color error;   echo "Cleanup error - returncode was $_myrc" ;;
        esac
        color reset
        echo

        echo "--- UNLOCK ... just in case :-)" 
        echo restic unlock ${sParams}
        eval restic unlock ${sParams}
        echo

        echo "--- PRUNE"
        local _tag=$( _j_getvar ${STORAGEFILE} "restic_tag")

        local _keep_h=$( _j_getvar ${STORAGEFILE} "restic_keep-hourly")
        local _keep_d=$( _j_getvar ${STORAGEFILE} "restic_keep-daily")
        local _keep_w=$( _j_getvar ${STORAGEFILE} "restic_keep-weekly")
        local _keep_m=$( _j_getvar ${STORAGEFILE} "restic_keep-monthly")
        local _keep_y=$( _j_getvar ${STORAGEFILE} "restic_keep-yearly")
        
        local _mycmd="restic forget \
          ${sParams} \
          --tag $_tag \
          --group-by "paths,tags" \
          --keep-hourly $_keep_h \
          --keep-daily $_keep_d \
          --keep-weekly $_keep_w \
          --keep-monthly $_keep_m \
          --keep-yearly $_keep_y"
        echo $_mycmd
        color cmd 
        eval $_mycmd
        local _myrc=$?
        color reset

        t_rcCheckCleanup $_myrc
        echo
    }

# --------------------------------------------------------------------------------
# ACTIONS :: SINGLE DIR
# --------------------------------------------------------------------------------

    # get target url/ directory
    # param  string  directory to backup
    function t_sd_getTarget(){
        # directory based target
        # j_getFullTarget "$1"
        # for host based backup target - remove param:
        j_getFullTarget ""
    }

    function t_sd_getCmdBackup(){
        echo eval restic backup ${sBackupParams} ${mydir}
    }

    # pre backup actions
    # uses global vars from ../../transfer.sh
    function t_sd_cmdPre(){
        echo "Nothing here."
    }


    # post backup actions
    # uses global vars from ../../transfer.sh
    function t_sd_cmdPost(){
        echo "Nothing here."
    }

# --------------------------------------------------------------------------------
# RESTORE
# --------------------------------------------------------------------------------

    # show stored volumes on backup repository
    # used in restore; directory param is checked before
    # param  string  name of backup dir, i.e. /etc
    function t_cmdShowVolumes(){
        eval restic snapshots ${sParams} --path $sDir2restore
    }

    # select a snapshot to restore from
    function t_restoreSelect(){
        local _selid=
        echo "--- Existing snapshots:"
        color cmd
        t_cmdShowVolumes
        color reset
        showPrompt "ID of the snapshot to restore from [$RESTORE_ITEM] >"
        read _selid
        test -z "$_selid" && _selid=$RESTORE_ITEM
        RESTORE_ITEM=$_selid
        echo using \"$RESTORE_ITEM\"
        echo
    }
    # set a filter to reduce count of files to restore
    function t_restoreFilter(){
        local _inc=
        echo "--- Filter:"
        echo "By default all files will be restored."
        echo "You can limit it by setting include rules."
        echo "You can enter ..."
        echo "  - a single directory name anywhere in the folderstructure"
        echo "  - a filename without path"
        echo "  - a filemask"
        showPrompt "Include []>"
        read _inc
        RESTORE_FILTER="$_sIncParams $( t_getParamInlude "$_inc" )"
        echo using parameter \"$RESTORE_FILTER\"
        echo
    }
    # show stored volumes on backup repository
    # used in restore; directory param is checked before
    # param  string  name of backup dir, i.e. /etc
    function t_cmdRestore(){
        echo "eval restic restore ${sParams} --path $sDir2restore --target ${sRestorepath} $RESTORE_FILTER $RESTORE_ITEM"
    }

# --------------------------------------------------------------------------------
# VERIFY RETURNCODES
# --------------------------------------------------------------------------------

    # init repository
    function t_rcCheckInit(){
        case $1 in
            0) color ok;      echo "OK - the repository was created." ;;
            1) color warning; echo "You can ignore the error if the repository was initialized already." ;;
            *) color error;   echo "Verify output above - returncode of restic init was $1" ;;
        esac
        color reset
    }
    # backup files
    function t_rcCheckBackup(){
        case $1 in
            0) color ok;      echo "OK" ;;
            1) color error;   echo "Unable to connect with restic repository." ;;
            *) color error;   echo "Backup error - returncode was $1" ;;
        esac
        color reset
    }

    # repository cleanup
    function t_rcCheckCleanup(){
        case $1 in
            0) color ok;      echo "OK" ;;
            *) color error;   echo "Cleanup error - returncode was $1" ;;
        esac
        color reset
    }

    # restore files
    function t_rcCheckRestore(){
        case $1 in
            0) color ok;      echo "OK" ;;
            *) color error;   echo "Restore error - returncode was $1" ;;
        esac
        color reset
    }

# --------------------------------------------------------------------------------