#!/bin/sh
#
# KEEPALIVED-DIAGNOSE – Schritt 2 (PID-Dateien & doppelte Starts)
# Rein beobachtend – keine Veränderungen.
#

BASE="/path/to/vpn-platform"
HA_DIR="${BASE}/ha"
LOG_DIR="${BASE}/logs/keepalived"
CONTAINER="keepalived-vpn-ha"   # Platzhalter
STAMP="$(date '+%Y-%m-%d_%H-%M-%S')"
LOG_FILE="${LOG_DIR}/keepalived-pid-doppelstart_${STAMP}.log"
LATEST_FILE="${LOG_DIR}/keepalived-pid-doppelstart_latest.log"
TMP_DIR="${LOG_DIR}/tmp_pid_check_${STAMP}"

mkdir -p "${LOG_DIR}" "${TMP_DIR}" || {
    echo "FEHLER: Diagnoseverzeichnis konnte nicht erstellt werden." >&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
}

show_file() {
    FILE="$1"
    if [ -r "${FILE}" ]; then
        section "DATEI: ${FILE}"
        cat "${FILE}"
        RC=$?
        log_line "RESULT" "cat Exit-Code=${RC}"
    else
        log_line "WARN" "Datei nicht lesbar oder nicht vorhanden: ${FILE}"
    fi
}

section "START"
log_line "INFO" "Prüfung auf alte Keepalived-PID-Dateien und doppelte Startauslöser."
log_line "INFO" "Es werden keine Dienste gestartet, gestoppt oder verändert."

section "AKTUELLER PROZESS- UND CONTAINERSTATUS"
run_cmd "Keepalived-Prozesse auf dem Host" sh -c "ps -ef | grep '[k]eepalived' || true"
run_cmd "Status des Keepalived-Containers" docker ps -a --filter "name=^/${CONTAINER}$" --no-trunc
run_cmd "Container-Grundzustand" docker inspect --format \
'Name={{.Name}} Status={{.State.Status}} Running={{.State.Running}} Pid={{.State.Pid}} StartedAt={{.State.StartedAt}} FinishedAt={{.State.FinishedAt}} ExitCode={{.State.ExitCode}} RestartCount={{.RestartCount}} Error={{.State.Error}}' \
"${CONTAINER}"

section "CONTAINER-STARTKONFIGURATION"
run_cmd "Entrypoint, Kommando und Arbeitsverzeichnis" docker inspect --format \
'Path={{.Path}}
Args={{json .Args}}
Entrypoint={{json .Config.Entrypoint}}
Cmd={{json .Config.Cmd}}
WorkingDir={{.Config.WorkingDir}}
User={{.Config.User}}' \
"${CONTAINER}"

run_cmd "Restart-Policy, PID- und Netzwerkmodus" docker inspect --format \
'RestartPolicy={{json .HostConfig.RestartPolicy}}
PidMode={{.HostConfig.PidMode}}
NetworkMode={{.HostConfig.NetworkMode}}
Privileged={{.HostConfig.Privileged}}
ReadonlyRootfs={{.HostConfig.ReadonlyRootfs}}
Tmpfs={{json .HostConfig.Tmpfs}}' \
"${CONTAINER}"

run_cmd "Container-Mounts" docker inspect --format '{{range .Mounts}}{{println .Type .Source "->" .Destination "RW=" .RW}}{{end}}' "${CONTAINER}"
run_cmd "Container-Labels" docker inspect --format '{{json .Config.Labels}}' "${CONTAINER}"
run_cmd "Image-Konfiguration" docker image inspect --format \
'Image={{.RepoTags}}
Entrypoint={{json .Config.Entrypoint}}
Cmd={{json .Config.Cmd}}
Volumes={{json .Config.Volumes}}
WorkingDir={{.Config.WorkingDir}}' \
"ha-keepalived-vpn-ha"   # Platzhalter für Image

section "PID-DATEIEN IM GESTOPPTEN CONTAINER"
PID_PATHS="
/run/keepalived.pid
/var/run/keepalived.pid
/run/keepalived/keepalived.pid
/var/run/keepalived/keepalived.pid
/run/keepalived_vrrp.pid
/var/run/keepalived_vrrp.pid
/run/keepalived/keepalived_vrrp.pid
/var/run/keepalived/keepalived_vrrp.pid
"

FOUND_PID_FILE=0
for PID_PATH in ${PID_PATHS}; do
    SAFE_NAME="$(printf '%s' "${PID_PATH}" | sed 's#^/##; s#/#_#g')"
    DEST="${TMP_DIR}/${SAFE_NAME}"

    log_line "INFO" "Prüfe Containerdatei: ${PID_PATH}"
    if docker cp "${CONTAINER}:${PID_PATH}" "${DEST}" >/dev/null 2>&1; then
        FOUND_PID_FILE=1
        log_line "WARN" "PID-Datei im Container gefunden: ${PID_PATH}"
        printf '%s\n' "--- Inhalt ---"
        cat "${DEST}" 2>&1
        printf '\n%s\n' "--- Dateiinformation ---"
        ls -la "${DEST}" 2>&1

        PID_VALUE="$(tr -cd '0-9' < "${DEST}" 2>/dev/null)"
        if [ -n "${PID_VALUE}" ]; then
            log_line "INFO" "Ausgelesene PID=${PID_VALUE}"
            if [ "${PID_VALUE}" = "1" ]; then
                log_line "CRITICAL" "PID-Datei enthält 1. Bei einem Container-Neustart kann der neue PID-1-Prozess sich dadurch selbst als bereits laufenden Daemon erkennen."
            fi
            if [ -d "/proc/${PID_VALUE}" ]; then
                log_line "INFO" "Auf dem Host existiert aktuell /proc/${PID_VALUE}."
                tr '\000' ' ' < "/proc/${PID_VALUE}/cmdline" 2>/dev/null
                printf '\n'
            else
                log_line "INFO" "Auf dem Host existiert aktuell kein /proc/${PID_VALUE}."
            fi
        fi
    else
        log_line "INFO" "Nicht vorhanden: ${PID_PATH}"
    fi
done

if [ "${FOUND_PID_FILE}" -eq 0 ]; then
    log_line "INFO" "An den üblichen Stellen wurde keine Keepalived-PID-Datei gefunden."
fi

section "ÄNDERUNGEN IM CONTAINER-DATEISYSTEM"
run_cmd "Docker-Diff des gestoppten Containers" docker diff "${CONTAINER}"

section "HOSTSEITIGE PID-DATEIEN"
run_cmd "Keepalived-PID-Dateien unter /run und /var/run" \
    sh -c "find /run /var/run -maxdepth 4 -type f \( -iname '*keepalived*.pid' -o -iname 'keepalived.pid' \) -ls 2>/dev/null || true"
run_cmd "Keepalived-PID-Dateien im HA-Verzeichnis" \
    sh -c "find '${HA_DIR}' -maxdepth 5 -type f \( -iname '*keepalived*.pid' -o -iname 'keepalived.pid' \) -ls 2>/dev/null || true"

section "COMPOSE UND KEEPALIVED-DATEIEN AUF DEM HOST"
show_file "${HA_DIR}/compose-ha.yaml"
show_file "${HA_DIR}/Dockerfile"
show_file "${HA_DIR}/keepalived.conf"
show_file "${HA_DIR}/scripts/check-vpn.sh"
show_file "${HA_DIR}/scripts/set-state.sh"

if command -v docker-compose >/dev/null 2>&1; then
    run_cmd "Aufgelöste Compose-Konfiguration mit docker-compose" \
        docker-compose -f "${HA_DIR}/compose-ha.yaml" config
elif docker compose version >/dev/null 2>&1; then
    run_cmd "Aufgelöste Compose-Konfiguration mit docker compose" \
        docker compose -f "${HA_DIR}/compose-ha.yaml" config
else
    log_line "WARN" "Kein Compose-Befehl gefunden."
fi

section "MÖGLICHE DOPPELTE CONTAINER"
run_cmd "Alle Container mit Keepalived im Namen oder Bild" \
    sh -c "docker ps -a --no-trunc | grep -i 'keepalived\|ha-keepalived' || true"
run_cmd "Container aus demselben Image" \
    docker ps -a --filter "ancestor=ha-keepalived-vpn-ha" --no-trunc

section "MÖGLICHE DOPPELTE STARTAUFRUFE IM VPN-PROJEKT"
run_cmd "Verweise auf Keepalived oder compose-ha im VPN-Projekt" \
    sh -c "grep -RInE 'keepalived|compose-ha\.yaml' '${BASE}' --include='*.sh' --include='*.yaml' --include='*.yml' --include='Dockerfile' 2>/dev/null || true"

section "DSM-AUFGABENPLANER – NUR LESEN"
if command -v synoschedtask >/dev/null 2>&1; then
    run_cmd "Geplante DSM-Aufgaben mit VPN-/Keepalived-Bezug" \
        sh -c "synoschedtask --get 2>&1 | grep -i -B 5 -A 12 'keepalived\|compose-ha\|vpn-platform' || true"
else
    log_line "WARN" "synoschedtask ist nicht verfügbar."
fi

section "ZEITLICHE STARTSPUREN"
run_cmd "Letzte Keepalived-Containerlogs" docker logs --timestamps --tail 150 "${CONTAINER}"
if [ -r /var/log/messages ]; then
    run_cmd "Systemmeldungen rund um Docker, Keepalived und den Bootvorgang" \
        sh -c "grep -iE 'keepalived|compose-ha|vpn-platform|docker.*start|boot' /var/log/messages | tail -n 400"
fi

section "ABSCHLUSS"
if [ "${FOUND_PID_FILE}" -eq 1 ]; then
    log_line "WARN" "Mindestens eine PID-Datei wurde im gestoppten Container gefunden."
else
    log_line "INFO" "Keine übliche Keepalived-PID-Datei im gestoppten Container gefunden."
fi
log_line "INFO" "Es wurde nichts gelöscht und kein Dienst neu gestartet."

cp "${LOG_FILE}" "${LATEST_FILE}" 2>/dev/null || true
rm -rf "${TMP_DIR}" 2>/dev/null || true

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