#!/bin/sh
#
# KEEPALIVED-DIAGNOSE – Schritt 1 (Bestandsaufnahme)
# Rein beobachtend – keine Veränderungen.
#

BASE="/path/to/vpn-platform"
HA_DIR="${BASE}/ha"
LOG_DIR="${BASE}/logs/keepalived"
STAMP="$(date '+%Y-%m-%d_%H-%M-%S')"
LOG_FILE="${LOG_DIR}/keepalived-diagnose_${STAMP}.log"
LATEST_FILE="${LOG_DIR}/keepalived-diagnose_latest.log"

mkdir -p "${LOG_DIR}" || {
    echo "FEHLER: Log-Verzeichnis konnte nicht erstellt werden: ${LOG_DIR}" >&2
    exit 10
}

exec 3>&1
exec >>"${LOG_FILE}" 2>&1

log_line() {
    LEVEL="$1"
    shift
    printf '%s [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "${LEVEL}" "$*"
}

section() {
    printf '\n============================================================\n'
    log_line "SECTION" "$*"
    printf '============================================================\n'
}

run_cmd() {
    DESCRIPTION="$1"
    shift
    log_line "INFO" "${DESCRIPTION}"
    "$@"
    RC=$?
    log_line "RESULT" "Exit-Code=${RC}"
    return 0
}

command_exists() {
    command -v "$1" >/dev/null 2>&1
}

section "START DER KEEPALIVED-DIAGNOSE"
log_line "INFO" "Logdatei: ${LOG_FILE}"
log_line "INFO" "Diese Aufnahme verändert keine Dienste oder Netzwerkeinstellungen."

section "SYSTEM UND ZEIT"
run_cmd "Hostname" hostname
run_cmd "Datum und Uhrzeit" date
run_cmd "Laufzeit des NAS" uptime
run_cmd "Ausführender Benutzer" id
run_cmd "Kernel-Version" uname -a

section "VERZEICHNISSE UND DATEIEN"
run_cmd "Inhalt des HA-Verzeichnisses" ls -la "${HA_DIR}"
if [ -d "${HA_DIR}" ]; then
    run_cmd "Shell-Skripte im HA-Verzeichnis" find "${HA_DIR}" -maxdepth 3 -type f -name '*.sh' -print
    run_cmd "Keepalived-Konfigurationsdateien im HA-Verzeichnis" find "${HA_DIR}" -maxdepth 4 -type f \( -name 'keepalived.conf' -o -name '*keepalived*' \) -print
fi

section "KEEPALIVED-PROZESS AUF DEM HOST"
if command_exists pgrep; then
    run_cmd "Laufende Keepalived-Prozesse" pgrep -af keepalived
else
    run_cmd "Laufende Keepalived-Prozesse" sh -c "ps | grep '[k]eepalived'"
fi

section "DOCKER-STATUS"
if command_exists docker; then
    run_cmd "Docker-Version" docker version
    run_cmd "Alle Container mit Status" docker ps -a --no-trunc

    KEEPALIVED_CONTAINERS="$(docker ps -a --format '{{.Names}}' 2>/dev/null | grep -i 'keepalived' || true)"

    if [ -n "${KEEPALIVED_CONTAINERS}" ]; then
        for CONTAINER in ${KEEPALIVED_CONTAINERS}; do
            section "KEEPALIVED-CONTAINER: ${CONTAINER}"

            run_cmd "Container-Zustand, Startzeit, Neustarts und Health" \
                docker inspect --format \
                'Name={{.Name}} Status={{.State.Status}} Running={{.State.Running}} StartedAt={{.State.StartedAt}} FinishedAt={{.State.FinishedAt}} ExitCode={{.State.ExitCode}} Error={{.State.Error}} RestartCount={{.RestartCount}} Health={{if .State.Health}}{{.State.Health.Status}}{{else}}nicht-konfiguriert{{end}}' \
                "${CONTAINER}"

            run_cmd "Letzte 300 Container-Logzeilen mit Zeitstempel" \
                docker logs --timestamps --tail 300 "${CONTAINER}"

            run_cmd "Keepalived-Version im Container" \
                docker exec "${CONTAINER}" sh -c 'keepalived --version 2>&1 || /usr/sbin/keepalived --version 2>&1'

            run_cmd "Keepalived-Prozesse im Container" \
                docker exec "${CONTAINER}" sh -c "ps | grep '[k]eepalived'"

            run_cmd "Suche nach keepalived.conf im Container" \
                docker exec "${CONTAINER}" sh -c "find /etc /config /run /state -maxdepth 4 -name 'keepalived.conf' 2>/dev/null"

            CONFIG_PATHS="$(docker exec "${CONTAINER}" sh -c "find /etc /config /run /state -maxdepth 4 -name 'keepalived.conf' 2>/dev/null" 2>/dev/null)"
            if [ -n "${CONFIG_PATHS}" ]; then
                for CONFIG_PATH in ${CONFIG_PATHS}; do
                    run_cmd "Inhalt der Konfiguration ${CONFIG_PATH}" \
                        docker exec "${CONTAINER}" sh -c "cat '${CONFIG_PATH}'"

                    run_cmd "Syntaxprüfung der Konfiguration ${CONFIG_PATH}" \
                        docker exec "${CONTAINER}" sh -c "keepalived -t -f '${CONFIG_PATH}' 2>&1 || /usr/sbin/keepalived -t -f '${CONFIG_PATH}' 2>&1"
                done
            else
                log_line "WARN" "Im Container wurde keine keepalived.conf gefunden."
            fi

            run_cmd "Netzwerkschnittstellen im Container" \
                docker exec "${CONTAINER}" sh -c 'ip addr 2>&1 || ifconfig -a 2>&1'

            run_cmd "Routing im Container" \
                docker exec "${CONTAINER}" sh -c 'ip route show 2>&1 || route -n 2>&1'

            run_cmd "Vorhandene Zustandsdateien im Container" \
                docker exec "${CONTAINER}" sh -c "find /state /run /tmp -maxdepth 3 -type f 2>/dev/null | sort"
        done
    else
        log_line "WARN" "Kein Container mit 'keepalived' im Namen gefunden."
    fi
else
    log_line "ERROR" "Der Docker-Befehl wurde nicht gefunden."
fi

section "NETZWERKZUSTAND (anonymisiert)"
# Beispiel: eth0 und eth1 sind Platzhalter, die VIP ist nur ein Beispiel
run_cmd "Adresse und Status von eth0" ip addr show eth0 || true
run_cmd "Adresse und Status von eth1" ip addr show eth1 || true
run_cmd "Prüfung auf die HA-VIP (Beispiel: 192.168.xxx.xxx)" sh -c "ip addr show | grep -n '192\.168\.xxx\.xxx' || true"
run_cmd "Aktuelle Routingtabelle" ip route show || true
run_cmd "Aktuelle Policy-Regeln" ip rule show || true

section "VPN-HEALTHCHECK"
if [ -f "${HA_DIR}/check-vpn.sh" ]; then
    log_line "INFO" "Healthcheck wird einmalig zur Diagnose ausgeführt: ${HA_DIR}/check-vpn.sh"
    if [ -x "${HA_DIR}/check-vpn.sh" ]; then
        "${HA_DIR}/check-vpn.sh"
    else
        sh "${HA_DIR}/check-vpn.sh"
    fi
    RC=$?
    log_line "RESULT" "check-vpn.sh Exit-Code=${RC}"
else
    log_line "WARN" "Healthcheck nicht gefunden: ${HA_DIR}/check-vpn.sh"
fi

section "HA-ZUSTANDSDATEIEN AUF DEM HOST"
if [ -d "${HA_DIR}" ]; then
    run_cmd "Dateien mit Statusbezug" \
        sh -c "find '${HA_DIR}' -maxdepth 4 -type f \( -name 'current' -o -name '*state*' -o -name '*status*' \) -print"
    STATE_FILES="$(find "${HA_DIR}" -maxdepth 4 -type f \( -name 'current' -o -name '*state*' -o -name '*status*' \) 2>/dev/null)"
    if [ -n "${STATE_FILES}" ]; then
        for STATE_FILE in ${STATE_FILES}; do
            run_cmd "Inhalt der Zustandsdatei ${STATE_FILE}" cat "${STATE_FILE}"
        done
    fi
fi

section "RELEVANTE SYSTEMPROTOKOLLE"
if [ -r /var/log/messages ]; then
    run_cmd "Keepalived-Meldungen aus /var/log/messages" \
        sh -c "grep -i 'keepalived\|vrrp\|192\.168\.xxx\.xxx' /var/log/messages | tail -n 300"
else
    log_line "WARN" "/var/log/messages ist nicht lesbar oder nicht vorhanden."
fi

if [ -r /var/log/syslog ]; then
    run_cmd "Keepalived-Meldungen aus /var/log/syslog" \
        sh -c "grep -i 'keepalived\|vrrp\|192\.168\.xxx\.xxx' /var/log/syslog | tail -n 300"
fi

section "PORT UND HEALTH-ENDPUNKT"
if command_exists netstat; then
    run_cmd "Prüfung auf Port 9999" sh -c "netstat -lntup 2>/dev/null | grep ':9999' || true"
elif command_exists ss; then
    run_cmd "Prüfung auf Port 9999" sh -c "ss -lntup 2>/dev/null | grep ':9999' || true"
else
    log_line "WARN" "Weder netstat noch ss ist verfügbar."
fi

if command_exists curl; then
    run_cmd "HTTP-Prüfung des lokalen Health-Endpunkts" \
        curl -sS --max-time 10 -D - http://127.0.0.1:9999/
else
    log_line "WARN" "curl wurde nicht gefunden; Health-Endpunkt nicht per HTTP geprüft."
fi

section "ABSCHLUSS"
log_line "INFO" "Diagnoseaufnahme beendet."
log_line "INFO" "Der Dienst wurde nicht neu gestartet."
log_line "INFO" "Die Netzwerk- und Firewall-Konfiguration wurde nicht verändert."

cp "${LOG_FILE}" "${LATEST_FILE}" 2>/dev/null || true

printf '\nLog erstellt:\n%s\n' "${LOG_FILE}" >&3
printf 'Aktuelle Kopie:\n%s\n' "${LATEST_FILE}" >&3
exit 0