#!/bin/bash # ====================================================================== # # RESTIC REST PRUNER # # ---------------------------------------------------------------------- # 2024-02-01 v0.1 <axel.hahn@unibe.ch> first lines # ====================================================================== cd "$( dirname $0 )" || exit _version=0.1 logdir=_last_prune prune_basedir= prune_params= bOptDebug=0 typeset -i iCountDirs=0 typeset -i iCountMatch=0 typeset -i iCountPrune=0 typeset -i iCountPruneError=0 typeset -i rcAll=0 . "inc_config.sh" || exit 1 cfgfile=rest_pruner.cfg || exit 1 # ---------------------------------------------------------------------- # FUNCTIONS # ---------------------------------------------------------------------- # Show help text function _showHelp(){ local _self; _self=$( basename $0 ) cat <<EOH Pruner for restic rest server with append only option. This script prunes all repositories on server side. The config file [$cfgfile] contains <USER>:<RESTIC_PASSWORD> If a directory matches ${prune_basedir}/<USER> then it will be pruned. SYNTAX: $_self [OPTIONS] [FILTER] OPTIONS: -h, --help show help and exit. PARAMETERS: FILTER regex to filter directory list in ${prune_basedir}/* EXAMPLES: $_self Start pruning of all matching repositories $_self mail Prune servers that match "mail", eg. my-mailhub.example.com EOH } # start prune of a given repository # global string cfgfile name of the config file # global integer rcAll sum of all prune exit status # # param string directory to prune function _prune(){ local _dir="$1" local mybase; mybase=$( basename "${_dir}" ) local mypw; mypw=$( grep "^${mybase}:" "${cfgfile}" | cut -f2 -d ':') local logfile="${logdir}/${mybase}.log" iCountDirs+=1 if [ -n "$mypw" ]; then local _user=$( stat -c "%U" "$_dir" ) echo "----- $_dir" iCountMatch+=1 bDoRun=1 if ps -ef | grep "restic forget.*${_dir}" | grep -v "grep" | grep . ; then echo "SKIP: a process is still running..." bDoRun=0 else rm -f "${logfile}.running" echo "TODO: check age of last prune run." fi if [ "$bDoRun" -eq "1" ]; then echo "Starting prune as user $_user ..." su - $_user - /bin/bash -c " echo START $( date ) $_dir export RESTIC_PASSWORD=$mypw restic forget -r $_dir $prune_params 2>&1 " | tee "${logfile}.running" rc=${PIPESTATUS[0]} rcAll+=$rc echo END $( date ) exitcode $rc | tee -a "${logfile}.running" if [ "$rc" -eq "0" ]; then mv "${logfile}.running" "${logfile}" iCountPrune+=1 else iCountPruneError+=1 mv "${logfile}.running" "${logfile}.error" fi fi fi } # ---------------------------------------------------------------------- # MAIN # ---------------------------------------------------------------------- echo echo "========== RESTIC REST PRUNER v${_version} ==========" echo # ----- check parameters while [[ "$#" -gt 0 ]]; do case $1 in -h|--help) _showHelp; exit 0;; -d|--debug) bOptDebug=1; shift;; -p|--path) if ! grep ":{$2}:" <<< ":{$PATH}:" >/dev/null; then PATH="$2:$PATH"; fi shift; shift;; -t|--target) export DOCKER_HOST="$2"; shift; shift;; *) echo "ERROR: Unknown parameter: $1"; _showHelp; exit 2; esac; done # ----- verify needed settings if [ ! -f "$cfgfile" ]; then echo "ERROR: The configuration [$cfgfile] does not exist (yet)." exit 3 fi if [ "$USER" != "root" ]; then echo "ERROR: This script must be started as root." exit 1 fi cfgpermissions=$( stat -c '%A:%U:%G' "$cfgfile" ) if [ "$cfgpermissions" != "-r--------:root:root" ]; then echo "WARNING: The configuration file must be owned by root:root with permission 0400." ls -l "$cfgfile" echo "Try to fix it..." chown root:root "$cfgfile" chmod 0400 "$cfgfile" ls -l "$cfgfile" cfgpermissions=$( stat -c '%A:%U:%G' "$cfgfile" ) if [ "$cfgpermissions" != "-r--------:root:root" ]; then echo "Fix failed. Aborting." exit 3 fi echo "OK" fi if [ -z "${prune_basedir}" ]; then echo "ERROR: variable [prune_basedir] was not set in [inc_config.sh]" exit 3 fi if [ ! -d "${prune_basedir}" ]; then echo "ERROR: variable [prune_basedir] in [inc_config.sh] points to a directory" echo "that does not exist: ${prune_basedir}" exit 3 fi if [ -z "${prune_params}" ]; then echo "ERROR: variable [prune_params] was not set in [inc_config.sh]" exit 3 fi if ! grep "\-\-keep\-" <<< "${prune_params}" >/dev/null; then echo "ERROR: variable [prune_params] does not contain a --keep-* prameter." exit 3 fi if ! which restic >/dev/null; then echo "ERROR: The restic client was not found." exit 3 fi # ----- Go test -d "${logdir}" || mkdir -p "${logdir}" filter=${1:-.} for mydir in $( find ${prune_basedir} -maxdepth 1 -type d | grep -E "$filter") do _prune "${mydir}" done echo echo "Status:" echo "Directories: $iCountDirs" echo "Matching : $iCountMatch" echo "Pruned : $iCountPrune" echo "Prune erors: $iCountPruneError" echo echo "done - exitcode $rcAll" exit $rcAll # ----------------------------------------------------------------------