OPs-Agent bleibt in der Praesenz: check_fds.sh meldet working/idle

check_fds.sh rief last_seen_at des OPs-Agenten nie an - der Agent fiel zehn
Minuten nach seiner Registrierung dauerhaft vom Schreibtisch, obwohl der
Ping-Check normal weiterlief. Das Skript meldet jetzt zu Beginn "working" und
am Ende (auch bei einem fruehen Abbruch, per trap) "idle" per
POST /api/v1/agents/{id}/activity, analog zum Cron-Skript des
Entwickler-Agenten. Fehler dabei werden nur protokolliert, nicht fatal.

Dafuer braucht monitor-api.conf zusaetzlich MONITOR_AGENT_ID:
register-ops-agent.sh schreibt sie bei einer Neuregistrierung mit und
traegt sie bei einer bestehenden, aber noch unmigrierten Datei ohne
Neuregistrierung nach.

Schliesst #75.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
fds2610-bot 2026-09-02 12:49:34 +02:00
parent d10c999542
commit 51c6a7b648
4 changed files with 86 additions and 10 deletions

View file

@ -149,12 +149,16 @@ läuft als die API — dann fällt der Umweg über die Datei `status.txt` weg:
``` ```
Das Skript liest `MONITOR_ADMIN_API_KEY` und `MONITOR_API_BASE` aus der `.env`, legt einen Das Skript liest `MONITOR_ADMIN_API_KEY` und `MONITOR_API_BASE` aus der `.env`, legt einen
Agenten der Rolle `ops` an (sitzt als „OPs" sichtbar an einem Schreibtisch, Issue #66) und Agenten der Rolle `ops` an (sitzt als „OPs" sichtbar an einem Schreibtisch, Issue #66) und
schreibt den nur einmalig ausgegebenen API-Key mit `chmod 600` nach `monitor-api.conf`. schreibt den nur einmalig ausgegebenen API-Key mitsamt der Agenten-ID (`MONITOR_AGENT_ID`)
Eine bestehende `monitor-api.conf` überschreibt es nicht (`--force` erzwingt es). mit `chmod 600` nach `monitor-api.conf`.
Eine bestehende `monitor-api.conf` überschreibt es nicht (`--force` erzwingt es); fehlt dort
nur `MONITOR_AGENT_ID` (ältere Installationen, Issue #75), trägt das Skript die ID ohne
Neuregistrierung nach.
Von Hand geht es weiterhin so: Agenten wie in Weg 2 registrieren (Rolle `ops`), Von Hand geht es weiterhin so: Agenten wie in Weg 2 registrieren (Rolle `ops`),
`monitor-api-sample.conf` nach `monitor-api.conf` neben `check_fds.sh` kopieren, dort `monitor-api-sample.conf` nach `monitor-api.conf` neben `check_fds.sh` kopieren, dort
`MONITOR_API_BASE` (ohne `/api/v1`) und `MONITOR_API_KEY` eintragen, `chmod 600` setzen. `MONITOR_API_BASE` (ohne `/api/v1`), `MONITOR_API_KEY` und `MONITOR_AGENT_ID` eintragen,
`chmod 600` setzen.
`check_fds.sh` meldet dann nach jedem Ping zusätzlich per REST (`online` → `ok`, `check_fds.sh` meldet dann nach jedem Ping zusätzlich per REST (`online` → `ok`,
`offline` → `error`) und schreibt `status.txt` unverändert weiter für den alten Wandmonitor. `offline` → `error`) und schreibt `status.txt` unverändert weiter für den alten Wandmonitor.
@ -162,6 +166,12 @@ Die System-ID entsteht dabei aus dem Hostnamen (`Nextcloud(intern)` → `nextclo
der Originalname bleibt als Anzeigename erhalten. Ist die API nicht erreichbar, läuft die der Originalname bleibt als Anzeigename erhalten. Ist die API nicht erreichbar, läuft die
Ping-Überwachung normal weiter und protokolliert nur eine Warnung. Ping-Überwachung normal weiter und protokolliert nur eine Warnung.
Zusätzlich meldet `check_fds.sh` bei jedem Lauf `working` zu Beginn und `idle` am Ende
(`POST /api/v1/agents/{id}/activity`, benötigt `MONITOR_AGENT_ID`) — ohne diese Meldung fiel
der OPs-Agent zehn Minuten nach der Registrierung dauerhaft aus der Präsenz, obwohl der
Ping-Check längst lief (Issue #75). Fehlt `MONITOR_AGENT_ID`, bleibt nur diese Meldung aus,
der Rest von `check_fds.sh` läuft unverändert weiter.
## ⚙️ Hosts über die Oberfläche pflegen ## ⚙️ Hosts über die Oberfläche pflegen
Ist Weg 3 eingerichtet, muss für einen neuen oder entfernten Server niemand mehr die Ist Weg 3 eingerichtet, muss für einen neuen oder entfernten Server niemand mehr die

View file

@ -20,6 +20,7 @@ API_CONF="$SCRIPT_DIR/monitor-api.conf"
# eine lokale Datei und erreicht die API dann nicht. # eine lokale Datei und erreicht die API dann nicht.
MONITOR_API_BASE="" MONITOR_API_BASE=""
MONITOR_API_KEY="" MONITOR_API_KEY=""
MONITOR_AGENT_ID=""
if [ -f "$API_CONF" ]; then if [ -f "$API_CONF" ]; then
# shellcheck source=/dev/null # shellcheck source=/dev/null
. "$API_CONF" . "$API_CONF"
@ -140,6 +141,34 @@ report_to_api() {
fi fi
} }
# Meldet den eigenen Zustand per POST /api/v1/agents/{id}/activity (Issue #75): ohne diese
# Meldung faellt der OPs-Agent zehn Minuten nach seiner Registrierung aus der Praesenz
# (AgentRepository::PRESENCE_TIMEOUT_SECONDS), obwohl der Ping-Check laengst laeuft - bisher
# schrieb kein Aufruf in check_fds.sh je last_seen_at. MONITOR_AGENT_ID fehlt in aelteren
# monitor-api.conf; ist es leer, meldet die Funktion wie report_to_api still nichts, statt
# den Lauf abzubrechen.
report_activity() {
local state="$1"
if [ -z "$MONITOR_API_BASE" ] || [ -z "$MONITOR_API_KEY" ] || [ -z "$MONITOR_AGENT_ID" ]; then
return 0
fi
local code
if ! code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 \
-X POST "${MONITOR_API_BASE%/}/api/v1/agents/$MONITOR_AGENT_ID/activity" \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${MONITOR_API_KEY}" \
-d "{\"state\":\"$(json_escape "$state")\"}"); then
echo " Warnung: API unter $MONITOR_API_BASE nicht erreichbar, Zustand '$state' nicht gemeldet."
return 0
fi
if [ "$code" != "200" ]; then
echo " Warnung: API antwortet mit HTTP $code auf die Zustandsmeldung '$state'."
fi
}
# Funktion zum Prüfen einer IP und Schreiben des Status # Funktion zum Prüfen einer IP und Schreiben des Status
check_ip() { check_ip() {
local hostname="$1" local hostname="$1"
@ -187,6 +216,14 @@ check_ip() {
# Hauptskript # Hauptskript
echo "Pruefung: $(date)" echo "Pruefung: $(date)"
# Rahmt den ganzen Lauf, damit der Agent auch bei einem fruehen "exit 1" (fehlende
# hosts.conf/mail_fds.py weiter unten) nicht dauerhaft als "working" haengen bleibt -
# analog zum Cron-Skript des Entwickler-Agenten, das ebenfalls working/idle um seinen Lauf
# herum meldet (Issue #75).
trap 'report_activity idle' EXIT
report_activity working
sync_hosts_from_api sync_hosts_from_api
if [ ! -f "$HOST_FILE" ]; then if [ ! -f "$HOST_FILE" ]; then
echo "Fehler: Datei $HOST_FILE nicht gefunden." echo "Fehler: Datei $HOST_FILE nicht gefunden."

View file

@ -19,3 +19,9 @@ MONITOR_API_BASE="http://monitor.example.lan:8091"
# API-Key des registrierten Agenten # API-Key des registrierten Agenten
MONITOR_API_KEY="" MONITOR_API_KEY=""
# ID des registrierten Agenten (aus der Registrierungsantwort). Noetig, damit check_fds.sh
# per POST /api/v1/agents/{id}/activity working/idle melden und so in der Praesenz bleiben
# kann (Issue #75) - ohne diesen Wert unterbleibt nur diese Meldung, alles andere
# funktioniert weiter wie zuvor.
MONITOR_AGENT_ID=""

View file

@ -61,23 +61,45 @@ if [ "$ADMIN_API_KEY" = "change-me" ]; then
echo "Fehler: MONITOR_ADMIN_API_KEY ist noch der Beispielwert 'change-me'." >&2 echo "Fehler: MONITOR_ADMIN_API_KEY ist noch der Beispielwert 'change-me'." >&2
exit 1 exit 1
fi fi
if [ -e "$API_CONF" ] && [ "$FORCE" -ne 1 ]; then
echo "Fehler: $API_CONF existiert bereits - der bisherige OPs-Agent ist offenbar schon" >&2
echo " registriert. Zum Neuanlegen die Datei wegsichern oder --force angeben." >&2
exit 1
fi
json_escape() { json_escape() {
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
} }
# Ein zweiter Agent gleichen Namens wuerde einen weiteren der acht Schreibtische belegen. # Ein zweiter Agent gleichen Namens wuerde einen weiteren der acht Schreibtische belegen.
# GET /api/v1/agents ist unauthentifiziert (API.md "Agenten") und dient hier auch als # GET /api/v1/agents ist unauthentifiziert (API.md "Agenten") und dient hier auch als
# Erreichbarkeitspruefung. # Erreichbarkeitspruefung. Wird vor der Existenzpruefung von $API_CONF geholt, weil eine
# bestehende, aber noch unmigrierte Datei (Issue #75, siehe unten) die ID aus genau dieser
# Antwort nachtraegt, statt den Agenten neu zu registrieren.
agents_json=$(curl -sS --max-time 10 "$API_ROOT/api/v1/agents" 2>/dev/null) || { agents_json=$(curl -sS --max-time 10 "$API_ROOT/api/v1/agents" 2>/dev/null) || {
echo "Fehler: API unter $API_ROOT nicht erreichbar. Laeuft 'docker compose up'?" >&2 echo "Fehler: API unter $API_ROOT nicht erreichbar. Laeuft 'docker compose up'?" >&2
exit 1 exit 1
} }
if [ -e "$API_CONF" ] && [ "$FORCE" -ne 1 ]; then
if ! grep -q '^MONITOR_AGENT_ID=' "$API_CONF"; then
# Migration (Issue #75): aeltere monitor-api.conf kennen MONITOR_AGENT_ID noch nicht,
# ohne das check_fds.sh den Aktivitaets-Endpoint nicht adressieren kann. Die ID laesst
# sich hier ohne Neuregistrierung nachtragen - GET /api/v1/agents kennt sie bereits
# (Reihenfolge der Felder wie von AgentRepository::hidingKey() geliefert: "id" direkt
# vor "display_name").
# "|| true" haengt am Ende der Pipeline: findet keiner der beiden grep-Aufrufe eine
# Uebereinstimmung, wuerde ihr Exit-Code mit "set -o pipefail" sonst das ganze Skript
# kommentarlos beenden, statt in die Fehlermeldung darunter zu fallen.
existing_id=$(printf '%s' "$agents_json" \
| grep -oE "\"id\":[0-9]+,\"display_name\":\"$(json_escape "$DISPLAY_NAME")\"" \
| head -n1 | grep -oE '[0-9]+' || true)
if [ -n "$existing_id" ]; then
printf 'MONITOR_AGENT_ID="%s"\n' "$existing_id" >> "$API_CONF"
echo "MONITOR_AGENT_ID fehlte in $API_CONF und wurde nachgetragen (ID $existing_id)."
exit 0
fi
fi
echo "Fehler: $API_CONF existiert bereits - der bisherige OPs-Agent ist offenbar schon" >&2
echo " registriert. Zum Neuanlegen die Datei wegsichern oder --force angeben." >&2
exit 1
fi
if printf '%s' "$agents_json" | grep -q "\"display_name\":\"$(json_escape "$DISPLAY_NAME")\""; then if printf '%s' "$agents_json" | grep -q "\"display_name\":\"$(json_escape "$DISPLAY_NAME")\""; then
echo "Fehler: Ein Agent namens \"$DISPLAY_NAME\" ist bereits registriert." >&2 echo "Fehler: Ein Agent namens \"$DISPLAY_NAME\" ist bereits registriert." >&2
echo " Anderen Anzeigenamen uebergeben oder den alten Agenten loeschen." >&2 echo " Anderen Anzeigenamen uebergeben oder den alten Agenten loeschen." >&2
@ -117,6 +139,7 @@ cat > "$API_CONF" <<CONF
MONITOR_API_BASE="$API_ROOT" MONITOR_API_BASE="$API_ROOT"
MONITOR_API_KEY="$api_key" MONITOR_API_KEY="$api_key"
MONITOR_AGENT_ID="$agent_id"
CONF CONF
chmod 600 "$API_CONF" chmod 600 "$API_CONF"