#!/bin/sh # Installiert die llama-swap-Telemetrie als NUTZER-Instanz von Telegraf. # # WOFUER: Knoten, auf denen llama-swap laeuft, aber kein sudo existiert (ROG). # Die System-Instanz (install.sh) kann hier nicht greifen: sie schreibt nach # /etc/telegraf/telegraf.d und laeuft als root-Dienst. Ausserdem liest sie das # Systemjournal mit priority>=warning — llama-swaps INFO-Zeilen (Modellstart, # Ports) liegen im NUTZER-Journal und wurden deshalb nie nach Loki geschickt. # Diese Instanz darf `journalctl --user-unit` lesen und braucht kein root. # # ZUGANGSDATEN: kommen NICHT in die Konfiguration. Das Systemd-Unit setzt # EnvironmentFile=/etc/default/telegraf; Telegraf expandiert ${PROM_URL}, # ${LOKI_URL} und ${TELEGRAF_TOKEN} beim Laden. Damit bleibt # /etc/default/telegraf (das der System-Installer geschrieben hat) die einzige # Quelle pro Knoten. # # BENUTZUNG (auf dem Zielknoten, als der Nutzer, dem llama-swap gehoert): # sh install-llamaswap-user.sh # Dateien liegen neben dem Skript # sh install-llamaswap-user.sh --raw # sonst von dort laden # sh install-llamaswap-user.sh --dry-run # nur zeigen, nichts schreiben # # IDEMPOTENT: mehrfaches Ausfuehren ist erlaubt; Unit wird neu geladen und # neu gestartet. Der Journal-Cursor bleibt erhalten (kein doppelter Versand). set -eu RAW_BASE="" DRY=0 HIER="$(cd "$(dirname "$0")" && pwd)" while [ $# -gt 0 ]; do case "$1" in --raw) RAW_BASE="$2"; shift 2 ;; --dry-run) DRY=1; shift ;; -h|--help) sed -n '2,30p' "$0"; exit 0 ;; *) printf 'Unbekannte Option: %s\n' "$1" >&2; exit 2 ;; esac done BIN_DIR="$HOME/bin" CONF_DIR="$HOME/.config/telegraf-llamaswap" UNIT_DIR="$HOME/.config/systemd/user" STATE_DIR="$HOME/.local/state/llamaswap-logs" sag() { printf ' %s\n' "$*"; } schritt() { printf '\n== %s\n' "$*"; } # ---------------------------------------------------------------- Vorbedingungen schritt "Vorbedingungen" if [ ! -r /etc/default/telegraf ]; then printf 'FEHLER: /etc/default/telegraf fehlt oder ist nicht lesbar.\n' >&2 printf ' Ohne PROM_URL/LOKI_URL/TELEGRAF_TOKEN gibt es kein Ziel.\n' >&2 printf ' Zuerst den Knoten-Installer laufen lassen (install.sh).\n' >&2 exit 1 fi for var in NODE_NAME PROM_URL LOKI_URL TELEGRAF_TOKEN; do if ! grep -q "^${var}=" /etc/default/telegraf; then printf 'FEHLER: %s fehlt in /etc/default/telegraf.\n' "$var" >&2 exit 1 fi done sag "/etc/default/telegraf vorhanden (NODE_NAME, PROM_URL, LOKI_URL, TELEGRAF_TOKEN)" TGBIN="" for kandidat in /usr/bin/telegraf /usr/local/bin/telegraf; do [ -x "$kandidat" ] && TGBIN="$kandidat" && break done [ -n "$TGBIN" ] || { printf 'FEHLER: telegraf-Binary nicht gefunden.\n' >&2; exit 1; } sag "Telegraf: $TGBIN ($("$TGBIN" --version | head -1))" # ------------------------------------------------------------------- Dateien holen hole() { # hole _rel="$1"; _dst="$2" if [ -f "$HIER/../$_rel" ]; then cp "$HIER/../$_rel" "$_dst"; sag "aus Repo: $_rel" elif [ -n "$RAW_BASE" ]; then if command -v curl >/dev/null 2>&1; then curl -fsSL -m 60 "$RAW_BASE/$_rel" -o "$_dst"; sag "geladen: $_rel" else printf 'FEHLER: curl fehlt und $_rel nicht lokal vorhanden.\n' >&2; exit 1 fi else printf 'FEHLER: %s weder lokal noch --raw gesetzt.\n' "$_rel" >&2; exit 1 fi [ -s "$_dst" ] || { printf 'FEHLER: %s ist leer.\n' "$_dst" >&2; exit 1; } } if [ "$DRY" -eq 1 ]; then schritt "Trockenlauf — es wird nichts geschrieben" sag "wuerde anlegen: $BIN_DIR/llamaswap-telemetrie.py, $BIN_DIR/llamaswap-logs.py" sag "wuerde anlegen: $CONF_DIR/telegraf.conf (0600)" sag "wuerde anlegen: $UNIT_DIR/telegraf-llamaswap.service" sag "wuerde starten: systemctl --user enable --now telegraf-llamaswap.service" exit 0 fi schritt "Programme nach $BIN_DIR" mkdir -p "$BIN_DIR" "$CONF_DIR" "$UNIT_DIR" "$STATE_DIR" hole scripts/llamaswap-telemetrie.py "$BIN_DIR/llamaswap-telemetrie.py" hole scripts/llamaswap-logs.py "$BIN_DIR/llamaswap-logs.py" chmod 755 "$BIN_DIR/llamaswap-telemetrie.py" "$BIN_DIR/llamaswap-logs.py" schritt "Konfiguration nach $CONF_DIR" hole telegraf/llamaswap-user.conf "$CONF_DIR/telegraf.conf" chmod 600 "$CONF_DIR/telegraf.conf" # 0600: hier stehen keine Geheimnisse, # aber die Datei ist auch nicht oeffentlich schritt "Unit nach $UNIT_DIR" hole telegraf/llamaswap-user.service "$UNIT_DIR/telegraf-llamaswap.service" schritt "Probelauf der beiden Programme (vor dem Dienst)" set -a; . /etc/default/telegraf; set +a metriken="$(python3 "$BIN_DIR/llamaswap-telemetrie.py" | wc -l)" logs="$(python3 "$BIN_DIR/llamaswap-logs.py" | wc -l)" sag "llamaswap-telemetrie.py: $metriken Zeilen" sag "llamaswap-logs.py: $logs Zeilen (0 ist normal, wenn gerade nichts passiert)" if [ "$metriken" -eq 0 ]; then sag "WARNUNG: keine Metriken — laeuft llama-swap auf diesem Knoten?" fi schritt "Telegraf-Konfiguration pruefen (--test, keine Ausgabe an die Ziele)" if ! "$TGBIN" --config "$CONF_DIR/telegraf.conf" --test --test-wait 5 >/dev/null 2>&1; then printf 'FEHLER: Telegraf meldet einen Konfigurationsfehler.\n' >&2 "$TGBIN" --config "$CONF_DIR/telegraf.conf" --test --test-wait 5 2>&1 | tail -5 >&2 exit 1 fi sag "Konfiguration in Ordnung" schritt "Dienst starten" systemctl --user daemon-reload systemctl --user enable --now telegraf-llamaswap.service sleep 6 zustand="$(systemctl --user is-active telegraf-llamaswap.service)" sag "telegraf-llamaswap.service: $zustand" [ "$zustand" = "active" ] || { printf 'FEHLER: Dienst laeuft nicht. Log:\n' >&2 journalctl --user -u telegraf-llamaswap.service -n 15 --no-pager >&2 exit 1 } cat <<'HINWEIS' == Fertig. Was jetzt laeuft * llama-swap /metrics -> Prometheus (Host-, GPU-Werte) * llamaswap_activity_* -> Token/Anfragen je Modell * llamacpp_* -> Token je laufendem Profil (nur mit --metrics) * Nutzer-Journal der Units -> Loki (unit="llama-swap.service") Ohne `linger` endet der Dienst mit der Sitzung des Nutzers: loginctl enable-linger $USER (braucht meist root, einmalig) Pruefen: systemctl --user status telegraf-llamaswap.service journalctl --user -u telegraf-llamaswap.service -n 20 HINWEIS