File: //usr/local/bin/acronis_backup_status
#!/bin/bash
# Pad naar acrocmd executable
ACROCMD="/usr/sbin/acrocmd"
# Pad naar het JSONL-bestand
JSONL_FILE="/var/lib/linqhost/acronis_backup_status.jsonl"
# Maximaal tijdsverschil in seconden om als retry te worden gezien (4 uur = 14400 seconden)
RETRY_WINDOW=14400
# Bepaal de modus op basis van meegegeven parameters
MODE="display"
while [[ $# -gt 0 ]]; do
case "$1" in
--collect)
MODE="collect"
shift
;;
--nagios)
MODE="nagios"
shift
;;
*)
echo "Fout: Onbekende parameter '$1'" >&2
echo "Gebruik: $0 [--collect | --nagios]" >&2
exit 1
;;
esac
done
# ==============================================================================
# FUNCTIES
# ==============================================================================
# De acronis_mms server moet draaien
ensure_mms_running() {
if ! pgrep -u root -f "^/usr/lib/Acronis/BackupAndRecovery/mms" > /dev/null; then
echo "WARNING: acronis_mms service is not running"
exit 1
fi
}
# Converteren van HH:MM:SS naar afgeronde minuten
convert_to_minutes() {
local time_str="$1"
if [[ "$time_str" =~ ^([0-9]{2}):([0-9]{2}):([0-9]{2})$ ]]; then
local h="${BASH_REMATCH[1]}"
local m="${BASH_REMATCH[2]}"
local s="${BASH_REMATCH[3]}"
# Zet om naar totaal aantal seconden en rond af naar hele minuten
echo $(( (10#$h * 3600 + 10#$m * 60 + 10#$s + 30) / 60 ))
else
echo 0
fi
}
add_json_line() {
local plan="$1"
local uuid="$2"
local timestamp="$3"
local status="$4"
local retries="$5"
local duration_min="$6"
local log_dir
log_dir=$(dirname "$JSONL_FILE")
if [[ ! -d "$log_dir" ]]; then
mkdir -p "$log_dir"
fi
# Voorkom dubbele regels op basis van UUID
if [[ -f "$JSONL_FILE" ]] && grep -q "\"uuid\":\"$uuid\"" "$JSONL_FILE"; then
return 0
fi
plan=$(echo "$plan" | tr -d "'\"")
if [[ "$plan" =~ (DEFAULT_-_DAILY|DEFAULT_-_WEEKLY) ]]; then
plan="${BASH_REMATCH[1]}"
fi
local json_line="{\"plan\":\"$plan\",\"uuid\":\"$uuid\",\"timestamp\":\"$timestamp\",\"status\":\"$status\",\"retries\":$retries,\"duration_minutes\":$duration_min}"
echo "$json_line" >> "$JSONL_FILE"
echo "Nieuwe regel toegevoegd: $json_line"
}
process_activities() {
local in_chain=false
local retries=0
local last_fail_epoch=0
local chain_plan=""
local chain_uuid=""
local chain_iso_time=""
local chain_duration_min=0
while read -r line; do
line_clean=$(echo "$line" | xargs)
[ -z "$line_clean" ] && continue
plan_name=$(echo "$line_clean" | awk '{print $1}')
date_str=$(echo "$line_clean" | awk '{print $5}')
time_str=$(echo "$line_clean" | awk '{print $6}')
duration_str=$(echo "$line_clean" | awk '{print $7}')
uuid=$(echo "$line_clean" | awk '{print $9}')
status=$(echo "$line_clean" | awk '{print $10}')
duration_min=$(convert_to_minutes "$duration_str")
formatted_date=$(echo "$date_str" | sed -E 's/([0-9]{2})\.([0-9]{2})\.([0-9]{4})/\3-\2-\1/')
iso_timestamp="${formatted_date}T${time_str}"
epoch_time=$(date -d "$formatted_date $time_str" +%s 2>/dev/null)
if [[ "$status" == "Failed" ]]; then
if [[ "$in_chain" == false ]]; then
in_chain=true
retries=0
last_fail_epoch=$epoch_time
chain_plan="$plan_name"
chain_uuid="$uuid"
chain_iso_time="$iso_timestamp"
chain_duration_min=$duration_min
else
time_diff=$((epoch_time - last_fail_epoch))
if [[ $time_diff -le $RETRY_WINDOW ]]; then
((retries++))
last_fail_epoch=$epoch_time
chain_uuid="$uuid"
chain_iso_time="$iso_timestamp"
chain_duration_min=$duration_min
else
add_json_line "$chain_plan" "$chain_uuid" "$chain_iso_time" "FAILED" "$retries" "$chain_duration_min"
retries=0
last_fail_epoch=$epoch_time
chain_plan="$plan_name"
chain_uuid="$uuid"
chain_iso_time="$iso_timestamp"
chain_duration_min=$duration_min
fi
fi
elif [[ "$status" == "Succeeded" ]]; then
if [[ "$in_chain" == true ]]; then
time_diff=$((epoch_time - last_fail_epoch))
if [[ $time_diff -le $RETRY_WINDOW ]]; then
((retries++))
add_json_line "$plan_name" "$uuid" "$iso_timestamp" "OK" "$retries" "$duration_min"
in_chain=false
retries=0
else
add_json_line "$chain_plan" "$chain_uuid" "$chain_iso_time" "FAILED" "$retries" "$chain_duration_min"
add_json_line "$plan_name" "$uuid" "$iso_timestamp" "OK" "0" "$duration_min"
in_chain=false
retries=0
fi
else
add_json_line "$plan_name" "$uuid" "$iso_timestamp" "OK" "0" "$duration_min"
fi
fi
done
if [[ "$in_chain" == true ]]; then
add_json_line "$chain_plan" "$chain_uuid" "$chain_iso_time" "FAILED" "$retries" "$chain_duration_min"
fi
}
run_nagios_check() {
if [[ ! -f "$JSONL_FILE" ]]; then
echo "CRITICAL - Statusbestand $JSONL_FILE niet gevonden."
exit 2
fi
local NOW
NOW=$(date +%s)
declare -A LATEST_OK
while IFS= read -r line; do
[[ -z "$line" ]] && continue
local status plan ts epoch
status=$(echo "$line" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
if [[ "$status" == "OK" ]]; then
plan=$(echo "$line" | grep -o '"plan":"[^"]*"' | cut -d'"' -f4)
ts=$(echo "$line" | grep -o '"timestamp":"[^"]*"' | cut -d'"' -f4)
epoch=$(date -d "$(echo "$ts" | tr 'T' ' ')" +%s 2>/dev/null)
if [[ -n "$epoch" ]]; then
if [[ -z "${LATEST_OK[$plan]}" ]] || [[ $epoch -gt ${LATEST_OK[$plan]} ]]; then
LATEST_OK[$plan]=$epoch
fi
fi
fi
done < "$JSONL_FILE"
if [[ ${#LATEST_OK[@]} -eq 0 ]]; then
echo "CRITICAL - No recent backups found (OK)"
exit 2
fi
local CRITICAL_MSGS=()
local OK_MSGS=()
for plan in "${!LATEST_OK[@]}"; do
local last_epoch="${LATEST_OK[$plan]}"
local age_sec=$((NOW - last_epoch))
local max_age max_desc age_display
if [[ "$plan" =~ [Ww][Ee][Ee][Kk][Ll][Yy] ]]; then
max_age=$((9 * 86400)) # 9 dagen
max_desc="9d"
age_display="$((age_sec / 86400))d"
elif [[ "$plan" =~ [Gg][Aa][Ll][Ee][Rr][Aa] ]]; then
max_age=$((24 * 3600)) # 24 uur
max_desc="24u"
age_display="$((age_sec / 3600))u"
else
max_age=$((12 * 3600)) # 12 uur
max_desc="12u"
age_display="$((age_sec / 3600))u"
fi
if [[ $age_sec -gt $max_age ]]; then
CRITICAL_MSGS+=("Backup '$plan' older then $max_desc (${age_display})")
else
OK_MSGS+=("Backup '$plan': ${age_display} old")
fi
done
if [[ ${#CRITICAL_MSGS[@]} -gt 0 ]]; then
echo "CRITICAL - ${CRITICAL_MSGS[*]}"
exit 2
else
echo "OK - All backups OK (${OK_MSGS[*]})"
exit 0
fi
}
display_json_file() {
if [[ ! -f "$JSONL_FILE" ]]; then
echo "Geen statusbestand gevonden op $JSONL_FILE."
echo "Voer eerst '$0 --collect' uit om data te verzamelen."
exit 1
fi
cat "$JSONL_FILE"
}
# ==============================================================================
# HOOFDLOGICA
# ==============================================================================
case "$MODE" in
collect)
ensure_mms_running
RAW_CMD_OUTPUT=$("$ACROCMD" list activities --output=raw 2>&1)
EXIT_CODE=$?
if [[ $EXIT_CODE -ne 0 ]]; then
echo "Fout: '$ACROCMD' is mislukt met exit code $EXIT_CODE." >&2
echo "Output: $RAW_CMD_OUTPUT" >&2
exit $EXIT_CODE
fi
echo "$RAW_CMD_OUTPUT" | grep 'Backup plan ' | sed 's/Backup plan//g' | process_activities
;;
nagios)
ensure_mms_running
run_nagios_check
;;
display)
display_json_file
;;
esac