HEX
Server: nginx/1.30.4
System: Linux d-twindigital-web-1.host-ed.eu 4.18.0-553.141.2.el8_10.x86_64 #1 SMP Wed Jul 8 10:28:18 EDT 2026 x86_64
User: u_twindigital_html (1009)
PHP: 8.3.30
Disabled: NONE
Upload Files
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