Skip to content
Snippets Groups Projects
Commit 74d11b19 authored by Hahn Axel (hahn)'s avatar Hahn Axel (hahn)
Browse files

Merge branch 'add_prune_script' into 'master'

prune add: timer, skip file, skin N days, limit process time, stats

See merge request !4
parents 9b439cb7 13cfbee3
No related branches found
No related tags found
1 merge request!4prune add: timer, skip file, skin N days, limit process time, stats
......@@ -5,16 +5,30 @@
#
# ----------------------------------------------------------------------
# 2024-02-01 v0.1 <axel.hahn@unibe.ch> first lines
# 2024-02-02 v0.2 <axel.hahn@unibe.ch> add: timer, skip file, skin N days, limit process time, stats
# ======================================================================
cd "$( dirname $0 )" || exit
_version=0.1
_version=0.2
logdir=_last_prune
prune_basedir=
prune_params=
prune_skipdays=7
# stop pruning more repositories when running longer N seconds
prune_timeout=7200
# flag file inside repository to mark an archived backup
sSkipfile=inactive.txt
bOptAll=0
bOptDebug=0
bOptStats=0
bOptForce=0
typeset -i iTimerStart; iTimerStart=$( date +%s )
typeset -i iCountDirs=0
typeset -i iCountMatch=0
......@@ -36,18 +50,27 @@ cfgfile=rest_pruner.cfg || exit 1
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.
Institute for Medical Education * University of Bern
GNU GPL 3.0
SYNTAX:
$_self [OPTIONS] [FILTER]
OPTIONS:
-h, --help show help and exit.
-a, --all process all repositories, default: rest only + archives
-d, --debug show more infos
-f, --force force pruning; do not wait $prune_skipdays days
-s, --status show pruning status with last prunes
PARAMETERS:
FILTER regex to filter directory list in
......@@ -56,13 +79,41 @@ PARAMETERS:
EXAMPLES:
$_self
Start pruning of all matching repositories
$_self mail
Prune servers that match "mail",
eg. my-mailhub.example.com
$_self --force mail
Prune servers that match "mail",
eg. my-mailhub.example.com
$_self --status
Show statistics with last prunes, if it is archive or
running or on error.
It shows repositories with passwords and archives.
Other repositories are not visible until you
specify -d.
EOH
}
# get age of a file in sec
# https://www.axel-hahn.de/blog/2020/03/09/bash-snippet-alter-einer-datei/
# param string filename to test
#
function _getFileAge(){
echo $(($(date +%s) - $(date +%s -r "$1")))
}
# get execution time in seconds
# global integer iTimerStart starting time in sec
function _getTimer(){
local _iTimer
_iTimer=$( date +%s )
echo $(( _iTimer - iTimerStart ))
}
# start prune of a given repository
# global string cfgfile name of the config file
# global integer rcAll sum of all prune exit status
......@@ -78,62 +129,154 @@ function _prune(){
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"
iCountMatch+=1
bDoRun=1
if [ -f "$_dir/${sSkipfile}" ]; then
echo "SKIP: $_dir - inactive backup"
bDoRun=0
elif ps -eo command | grep "restic forget.*${_dir}" | grep -v "grep" | grep . ; then
echo "SKIP: $_dir - a process is still running..."
bDoRun=0
else
rm -f "${logfile}.running"
if [ "$bOptForce" = "0" ] && [ -f "${logfile}" ]; then
local _iAge; _iAge=$( _getFileAge "${logfile}" )
local _iDays; typeset -i _iDays=$(( _iAge/60/60/24 ))
if [ $_iDays -le $prune_skipdays ]; then
echo "SKIP: $_dir - Last run $_iDays days ($_iAge sec) ago - a prune will be started after $prune_skipdays days."
bDoRun=0
fi
fi
fi
if [ "$bDoRun" -eq "1" ]; then
local _user; _user=$( stat -c "%U" "$_dir" )
echo ">>>>> $( _getTimer ) >>>>> $_dir"
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
else
test "$bOptAll" -eq "1" && echo "SKIP: $_dir - no password for this repo"
fi
}
# 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 _status(){
local _processes;
_processes="$( ps -eo command )"
echo "Prune status:"
for _dir in $( find ${prune_basedir} -maxdepth 1 -type d | grep -E "$filter")
do
local mybase; mybase=$( basename "${_dir}" )
local mypw; mypw=$( grep "^${mybase}:" "${cfgfile}" | cut -f2 -d ':')
local logfile="${logdir}/${mybase}.log"
local _flagPw="."
local _flagArchive="."
local _flagRunning="."
local _flagError="."
local _sLastPrune="?"
iCountDirs+=1
test -n "$mypw" && _flagPw="Y"
test -f "$_dir/${sSkipfile}" && _flagArchive="A"
test -f "${logfile}.error" && _flagError="E"
grep "restic forget.*${_dir}" <<< "$_processes" | grep -v "grep" | grep . >/dev/null && _flagRunning="R"
if [ -f "${logfile}" ]; then
local _iAge; _iAge=$( _getFileAge "${logfile}" )
local _iDays; typeset -i _iDays=$(( _iAge/60/60/24 ))
_sLastPrune="$_iDays days ago"
fi
if [ -n "$mypw" ] || [ "$_flagArchive" = "A" ] || [ "$bOptAll" -eq "1" ]; then
iCountMatch+=1
printf "%1s %1s %1s %1s %-12s %s\n" "$_flagPw" "$_flagArchive" "$_flagError" "$_flagRunning" "$_sLastPrune" "$_dir"
fi
done
if [ "$iCountMatch" -gt "0" ]; then
echo
echo ": : : : : :"
echo ": : : : : +-- repository dir"
echo ": : : : +-- last successful prune"
echo ": : : +-- is it currently running?"
echo ": : +-- Last prune on error?"
echo ": +-- Repository is archived?"
echo "+-- has password?"
else
echo "INFO: No (matching) Repository was found."
fi
echo
}
# ----------------------------------------------------------------------
# MAIN
# ----------------------------------------------------------------------
echo
echo "========== RESTIC REST PRUNER v${_version} =========="
echo
cat << ENDHEADER
------------------------------------------------------------------------------
--------========###| RESTIC REST PRUNER :: v${_version} |###=======--------
------------------------------------------------------------------------------
# ----- check parameters
ENDHEADER
# ----- check parameters
allparams="$*"
while [[ "$#" -gt 0 ]]; do case $1 in
-h|--help) _showHelp; exit 0;;
-a|--all) bOptAll=1; shift;;
-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;
-f|--force) bOptForce=1; shift;;
-s|--status) bOptStats=1; shift;;
*) if grep "^-" <<< "$1" >/dev/null ; then
echo; echo "ERROR: Unknown parameter: $1"; echo; _showHelp; exit 2
fi
break;
;;
esac; done
test "$bOptDebug" -eq "1" && cat << ENDDEBUGINFO
----- 8< ----- DEBUG ------------------------------------------------ 8< -----
Config:
$( ls -l inc_config.sh && echo )
$( grep "prune_.*=" inc_config.sh | grep -v "#")
$( ls -l ${cfgfile} 2>&1 && echo)
Parameters: $allparams
----- 8< ----- /DEBUG ----------------------------------------------- 8< -----
ENDDEBUGINFO
# ----- verify needed settings
if [ ! -f "$cfgfile" ]; then
......@@ -192,18 +335,32 @@ fi
test -d "${logdir}" || mkdir -p "${logdir}"
filter=${1:-.}
for mydir in $( find ${prune_basedir} -maxdepth 1 -type d | grep -E "$filter")
test "$bOptStats" -eq "1" && _status "${mydir}"
test "$bOptStats" -eq "0" && for mydir in $( find ${prune_basedir} -maxdepth 1 -type d | grep -E "$filter")
do
_iTimer=$( _getTimer )
if [ "$_iTimer" -gt "$prune_timeout" ]; then
echo "ABORT: Processing time reached $_iTimer sec - limit is $prune_timeout sec."
echo "Stopping before processing ${mydir}."
echo
break;
fi
_prune "${mydir}"
done
echo
echo "Status:"
echo "Directories: $iCountDirs"
echo "Matching : $iCountMatch"
echo "Pruned : $iCountPrune"
echo "Prune erors: $iCountPruneError"
echo
test "$bOptStats" -eq "0" && cat <<ENDSTATS
Statistics:
Elapsed time : $( _getTimer ) sec
Directories : $iCountDirs
Matching : $iCountMatch
Pruned : $iCountPrune
Prune erors : $iCountPruneError
------------------------------------------------------------------------------
ENDSTATS
echo "done - exitcode $rcAll"
exit $rcAll
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment