From e9e8a790ba928efbd0d278774ffdca1ba63d530f Mon Sep 17 00:00:00 2001 From: Jeremy Lecour Date: Wed, 1 Apr 2020 18:39:56 +0200 Subject: [PATCH] refactor check, inc, rm subcommands function extractions variables extractions comments --- lib/bkctld-check | 32 ++++++++--------- lib/bkctld-inc | 91 ++++++++++++++++++++++++++++++++++------------ lib/bkctld-rm | 93 +++++++++++++++++++++++++++++------------------- lib/config | 77 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+), 78 deletions(-) diff --git a/lib/bkctld-check b/lib/bkctld-check index 26fd8ee..e6be6f3 100755 --- a/lib/bkctld-check +++ b/lib/bkctld-check @@ -38,27 +38,21 @@ fi read_variable() { var_name=$1 file=$2 + pattern="^\s*${var_name}=-?[0-9]+" grep --extended-regexp --only-matching "${pattern}" "${file}" | cut -d= -f2 } check_jail() { - jail=$1 + jail_name=$1 + jail_path=$(jail_path "${jail_name}") cur_time=$(date "+%s") - last_conn=$(stat --format=%Y "${JAILDIR}/${jail}/var/log/lastlog") + last_conn=$(stat --format=%Y "${jail_path}/var/log/lastlog") date_diff=$(( (cur_time - last_conn) / (60*60) )) - if [ -f "${CONFDIR}/${jail}.d/check_policy" ]; then - # canonical configuration file - check_policy_file="${CONFDIR}/${jail}.d/check_policy" - elif [ -f "${JAILDIR}/${jail}/etc/bkctld-check" ]; then - # backward compatible configuration file - check_policy_file="${CONFDIR}/${jail}/etc/bkctld-check" - else - check_policy_file="" - fi + check_policy_file=$(jail_check_policy_file "${jail_name}") if [ -f "${check_policy_file}" ]; then local_critical=$(read_variable "CRITICAL" "${check_policy_file}") @@ -73,24 +67,26 @@ check_jail() { if [ "${local_critical}" -gt "0" ] && [ "${date_diff}" -gt "${local_critical}" ]; then nb_crit=$((nb_crit + 1)) - output="${output}CRITICAL - ${jail} - ${date_diff} hours (critical: ${local_critical})\n" + output="${output}CRITICAL - ${jail_name} - ${date_diff} hours (critical: ${local_critical})\n" [ "${return}" -le 2 ] && return=2 elif [ "${local_warning}" -gt "0" ] && [ "${date_diff}" -gt "${local_warning}" ]; then nb_warn=$((nb_warn + 1)) - output="${output}WARNING - ${jail} - ${date_diff} hours (warning: ${local_warning})\n" + output="${output}WARNING - ${jail_name} - ${date_diff} hours (warning: ${local_warning})\n" [ "${return}" -le 1 ] && return=1 else nb_ok=$((nb_ok + 1)) - output="${output}OK - ${jail} - ${date_diff} hours (critical: ${local_critical}, warning: ${local_warning})\n" + output="${output}OK - ${jail_name} - ${date_diff} hours (critical: ${local_critical}, warning: ${local_warning})\n" fi } -for jail in $("${LIBDIR}/bkctld-list"); do - if [ -f "${JAILDIR}/${jail}/var/log/lastlog" ]; then - check_jail "${jail}" +for jail_name in $(jails_list); do + jail_path=$(jail_path "${jail_name}") + + if [ -f "${jail_path}/var/log/lastlog" ]; then + check_jail "${jail_name}" else nb_unkn=$((nb_unkn + 1)) - output="${output}UNKNOWN - ${jail} doesn't have lastlog !\n" + output="${output}UNKNOWN - ${jail_name} doesn't have lastlog !\n" [ "${return}" -le 3 ] && return=3 fi done diff --git a/lib/bkctld-inc b/lib/bkctld-inc index 8d51f4c..733953e 100755 --- a/lib/bkctld-inc +++ b/lib/bkctld-inc @@ -7,32 +7,77 @@ # shellcheck source=./config LIBDIR="$(dirname $0)" && . "${LIBDIR}/config" -date=$(date +"%Y-%m-%d-%H") -for jail in $("${LIBDIR}/bkctld-list"); do - inc="${INCDIR}/${jail}/${date}" - mkdir -p "${INCDIR}/${jail}" - if [ ! -d "${inc}" ]; then - start=$(date +"%H:%M:%S") - jail_inode=$(stat --format=%i "${JAILDIR}/${jail}") - if [ "$jail_inode" -eq 256 ]; then - /bin/btrfs subvolume snapshot -r "${JAILDIR}/${jail}" "${inc}" | debug - end=$(date +"%H:%M:%S") - notice "${jail} : made ${date} inc [${start}/${end}]" - else - lock="/run/lock/bkctld/inc-${jail}.lock" - if [ -f "${lock}" ]; then - warning "${jail} : trying to run already running inc" +create_inc_btrfs() { + jail_name=$1 + inc_name=$2 + + jail_path=$(jail_path "${jail_name}") + inc_path=$(inc_path "${jail_name}" "${inc_name}") + + start=$(current_time) + + if dry_run; then + echo "[dry-run] btrfs subvolume snapshot of ${jail_path} to ${inc_path}" + else + mkdir --parents "$(dirname "${inc_path}")" + # create a btrfs readonly snapshot from the jail + /bin/btrfs subvolume snapshot -r "${jail_path}" "${inc_path}" | debug + fi + + end=$(current_time) + notice "${jail_name} : ${inc_name} inc created [${start}/${end}]" +} +create_inc_ext() { + jail_name=$1 + inc_name=$2 + + jail_path=$(jail_path "${jail_name}") + inc_path=$(inc_path "${jail_name}" "${inc_name}") + + lock="${LOCKDIR}/inc-${jail_name}.lock" + if [ -f "${lock}" ]; then + warning "${jail_name} : skipping ${inc_name}, it is already being created." + else + ( + start=$(current_time) + mkdir --parents "${LOCKDIR}" && touch "${lock}" + # shellcheck disable=SC2064 + trap "rm -f ${lock}" 0 + + if dry_run; then + echo "[dry-run] copy of ${jail_path} to ${inc_path}" else - ( - mkdir -p /run/lock/bkctld && touch "${lock}" - trap "rm -f ${lock}" 0 - cp -alx "${JAILDIR}/${jail}/" "${inc}" - end=$(date +"%H:%M:%S") - notice "${jail} : made ${date} inc [${start}/${end}]" - ) + mkdir --parents "$(dirname "${inc_path}")" + # create a copy of the jail with hard links + cp --archive --link --one-file-system "${jail_path}/" "${inc_path}" fi + + end=$(current_time) + notice "${jail_name} : ${inc_name} inc created [${start}/${end}]" + ) + fi +} + +inc_name=$(date +"%Y-%m-%d-%H") + +for jail_name in $(jails_list); do + jail_path=$(jail_path "${jail_name}") + inc_path=$(inc_path "${jail_name}" "${inc_name}") + incs_policy_file=$(jail_incs_policy_file ${jail_name}) + + # If not incs policy is found, we don't create incs + if [ -n "${incs_policy_file}" ]; then + # If not incs directory is found, we don't create incs + if [ ! -d "${inc_path}" ]; then + if is_btrfs "${jail_path}"; then + create_inc_btrfs "${jail_name}" "${inc_name}" + else + create_inc_ext "${jail_name}" "${inc_name}" + fi + else + warning "${jail_name} : skipping ${inc_name}, it already exists." fi else - warning "${jail} : trying to made already existant inc" + warning "${jail_name} : skipping ${inc_name}, incs policy not found." fi done diff --git a/lib/bkctld-rm b/lib/bkctld-rm index e6d7832..26d5f82 100755 --- a/lib/bkctld-rm +++ b/lib/bkctld-rm @@ -17,58 +17,77 @@ relative_date() { echo ${past_date} } -remove_inc() { - jail=$1 - inc=$2 +delete_inc_btrfs() { + jail_name=$1 + inc_name=$2 - start=$(date +"%H:%M:%S") - inc_inode=$(stat --format=%i "${INCDIR}/${jail}/${inc}") - if [ "${inc_inode}" -eq 256 ]; then - /bin/btrfs subvolume delete "${INCDIR}/${jail}/${inc}" | debug - end=$(date +"%H:%M:%S") - notice "${jail} : deleted ${inc} inc [${start}/${end}]" + inc_path=$(inc_path "${jail_name}" "${inc_name}") + + start=$(current_time) + + if dry_run; then + echo "[dry-run] delete btrfs subvolume ${inc_path}" else - lock="/run/lock/bkctld/rm-${jail}.lock" - if [ -f "${lock}" ]; then - warning "${jail} : trying to run already running rm" - else - ( - empty="/tmp/bkctld-${$}-$(date +%N)" - mkdir -p /run/lock/bkctld && touch "${lock}" && mkdir -p "${empty}" - trap "rm -f ${lock} && rmdir ${empty}" 0 - rsync -a --delete "${empty}/" "${INCDIR}/${jail}/${inc}/" - rmdir "${INCDIR}/${jail}/${inc}/" - end=$(date +"%H:%M:%S") - notice "${jail} : deleted ${inc} inc [${start}/${end}]" - ) - fi + /bin/btrfs subvolume delete "${inc_path}" | debug + fi + + end=$(current_time) + notice "${jail_name} : ${inc_name} inc deleted [${start}/${end}]" +} +delete_inc_ext() { + jail_name=$1 + inc_name=$2 + + inc_path=$(inc_path "${jail_name}" "${inc_name}") + + lock_file="${LOCKDIR}/rm-${jail_name}.lock" + if [ -f "${lock_file}" ]; then + warning "${jail_name} : skipping ${inc_name}, it is already being deleted." + else + ( + mkdir --parents "${LOCKDIR}" && touch "${lock_file}" || error "Failed to acquire lock file '${lock_file}'" + empty=$(mktemp -d --suffix ".${$}" bkctld.XXXXX) + # shellcheck disable=SC2064 + trap "rm -f ${lock_file}; rmdir ${empty}" 0 + + if dry_run; then + echo "[dry-run] delete ${inc_path} with rsync from ${empty}" + else + rsync --archive --delete "${empty}/" "${inc_path}/" + fi + rmdir "${inc_path}/" + + end=$(current_time) + notice "${jail_name} : ${inc_name} inc deleted [${start}/${end}]" + ) fi } -for jail in $("${LIBDIR}/bkctld-list"); do - incs=$(ls "${INCDIR}/${jail}") - - if [ -f "${CONFDIR}/${jail}.d/incs_policy" ]; then - incs_policy_file="${CONFDIR}/${jail}.d/incs_policy" - elif [ -f "${CONFDIR}/${jail}" ]; then - incs_policy_file="${CONFDIR}/${jail}" - else - incs_policy_file="" - fi +for jail_name in $(jails_list); do + incs_policy_file=$(jail_incs_policy_file ${jail_name}) + # If not incs policy if found, we don't remove incs if [ -n "${incs_policy_file}" ]; then incs_policy_keep_file="$(mktemp)" + # shellcheck disable=SC2064 + trap "rm ${incs_policy_keep_file}" 0 # loop for each line in jail configuration - for incs_policy_line in $(cat ${incs_policy_file}); do + for incs_policy_line in $(cat ${incs_policy_file} | grep "^\+"); do # inc date in ISO format incs_policy_date=$(relative_date ${incs_policy_line}) echo ${incs_policy_date} >> "${incs_policy_keep_file}" done + # shellcheck disable=SC2046 + incs_to_delete=$(echo $(incs_list "${jail_name}") | grep -v -f "${incs_policy_keep_file}") - for inc in $(echo "${incs}" | grep -v -f "${incs_policy_keep_file}"); do - remove_inc "${jail}" "${inc}" + for inc_name in ${incs_to_delete}; do + inc_path=$(inc_path "${jail_name}" "${inc_name}") + if is_btrfs "${inc_path}"; then + delete_inc_btrfs "${jail_name}" "${inc_name}" + else + delete_inc_ext "${jail_name}" "${inc_name}" + fi done - rm "${incs_policy_keep_file}" fi done diff --git a/lib/config b/lib/config index dac4f09..00d9ff8 100755 --- a/lib/config +++ b/lib/config @@ -10,6 +10,7 @@ BACKUP_DISK="${BACKUP_DISK:-}" JAILDIR="${JAILDIR:-/backup/jails}" INCDIR="${INCDIR:-/backup/incs}" TPLDIR="${TPLDIR:-/usr/share/bkctld}" +LOCKDIR="${LOCKDIR:-/run/lock/bkctld}" INDEX_DIR="${INDEX_DIR:-/backup/index}" IDX_FILE="${IDX_FILE:-${INDEX_DIR}/bkctld-jails.idx}" LOCALTPLDIR="${LOCALTPLDIR:-/usr/local/share/bkctld}" @@ -62,3 +63,79 @@ error() { fi exit 1 } + +dry_run() { + test "$DRY_RUN" = "1" +} + +current_time() { + date +"%H:%M:%S" +} + +# Returns true if the given path is on a btrfs filesystem +is_btrfs() { + path=$1 + + inode=$(stat --format=%i "${path}") + + test $inode -eq 256 +} + +# Returns the list of all jails +jails_list() { + # shellcheck disable=SC2091 + "${LIBDIR}/bkctld-list" +} +# Returns the list of all incs for a jail +incs_list() { + jail_name=$1 + # shellcheck disable=SC2091 + ls "$(incs_path "${jail_name}")/" +} +# Returns the complete path of a jail +jail_path() { + jail_name=$1 + + echo "${JAILDIR}/${jail_name}" +} +# Returns the path of incs for a jail +incs_path() { + jail_name=$1 + + echo "${INCDIR}/${jail_name}" +} +# Returns the path of a specific inc for a jail +inc_path() { + jail_name=$1 + inc_name=$2 + + echo "${INCDIR}/${jail_name}/${inc_name}" +} +jail_incs_policy_file() { + jail_name=$1 + + new_file="${CONFDIR}/${jail_name}.d/incs_policy" + old_file="${CONFDIR}/${jail_name}" + + if [ -f "${new_file}" ]; then + echo "${new_file}" + elif [ -f "${old_file}" ]; then + echo "${old_file}" + else + echo "" + fi +} +jail_check_policy_file() { + jail_name=$1 + + new_file="${CONFDIR}/${jail_name}.d/check_policy" + # old_file="${JAILDIR}/${jail_name}/etc/bkctld-check" + + if [ -f "${new_file}" ]; then + echo "${new_file}" + # elif [ -f "${old_file}" ]; then + # echo "${old_file}" + else + echo "" + fi +}