Files
netbird-telegraf-installer/install.sh
T

746 lines
32 KiB
Bash
Executable File

#!/usr/bin/env sh
# ============================================================================
# NetBird Observability — Telegraf Node Installer (Linux)
#
# Installiert Telegraf als systemd-Dienst und verbindet die Node fest mit dem
# zentralen Collector auf dem imac (Prometheus Remote Write + Loki) im NetBird.
#
# Unterstützt: Debian/Ubuntu/Proxmox VE (apt), RHEL/Rocky/Alma/Fedora (dnf/yum),
# Alpine (apk, OpenRC), sonstige Linux via statischem Binary.
# Architekturen: amd64 / x86_64, arm64 / aarch64, armv7.
# Windows: install.ps1 verwenden.
#
# Nutzung (als root):
# curl -fsSL https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main/install.sh | sh -s -- --name <node-name>
# Optionen:
# --name <n> Node-Name (Default: hostname -s)
# --token <t> Bearer-Token des Reverse-Proxys (Pflicht)
# --collector <ip> Direktweg im NetBird statt Reverse Proxy
# --role <r> Zusatz-Profil: proxmox | apache | docker | none (Default: auto)
# --pve-token <t> Proxmox API-Token 'user@pve!name=secret' (nur --role proxmox)
# --pve-node <n> Name des PVE-Knotens im PVE-Baum (Default: per pvesh erkannt)
# --pve-url <u> PVE-API-URL (Default: https://127.0.0.1:8006/api2/json)
# --apache-log <p> Apache-Access-Log (Default: /var/log/apache2/access.log)
# --uninstall Telegraf + Konfiguration entfernen
# --check Nur Versionsvergleich, nichts aendern (Exit 0 = aktuell)
# --version Installierte und verfuegbare Version ausgeben
# --force-update Confs/Scripts IMMER neu schreiben + Dienst neu starten
# --update-only Nur Confs/Scripts aktualisieren (kein Paket, kein Restart
# ohne Aenderung) — wird vom Auto-Updater-Timer genutzt
# --install-update-timer [daily|hourly|weekly|<N>min]
# systemd-Timer fuer den Auto-Updater einrichten
# --remove-update-timer Timer wieder entfernen
# ============================================================================
set -eu
# Ausgang ueber den NetBird-Reverse-Proxy: funktioniert auch fuer Hosts, die
# KEIN NetBird-Peer sind (Büro-LAN, Kundenlaptop, CGNAT). Token erforderlich.
PROM_URL_DEFAULT="https://imac-prometheus.x05.idx.wf/api/v1/write"
LOKI_URL_DEFAULT="https://imac-loki.x05.idx.wf"
COLLECTOR="${COLLECTOR:-}" # nur setzen fuer den Direktweg im NetBird
TELEGRAF_TOKEN="${TELEGRAF_TOKEN:-}"
NODE_NAME="${NODE_NAME:-$(hostname -s 2>/dev/null || hostname)}"
ROLE="auto"
PVE_TOKEN="${PVE_TOKEN:-}"
PVE_NODE="${PVE_NODE:-}"
PVE_URL="${PVE_URL:-}"
# Apache-Logpfad: Distributionen unterscheiden sich — Debian/Ubuntu/KeyHelp
# nutzen /var/log/apache2/, RHEL/Rocky /var/log/httpd/. Der Installer sucht beim
# ersten Lauf; --apache-log ueberschreibt.
APACHE_LOG=""
TELEGRAF_VERSION="${TELEGRAF_VERSION:-1.40.0}"
# Ueberschreibbar (Tests/Mirror): REPO_RAW=... sh install.sh
REPO_RAW="${REPO_RAW:-https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main}"
UNINSTALL=0
CHECK=0
SHOW_VERSION=0
FORCE_UPDATE=0
UPDATE_ONLY=0
TIMER_INTERVAL=""
REMOVE_TIMER=0
while [ $# -gt 0 ]; do
case "$1" in
--name) NODE_NAME="$2"; shift 2 ;;
--collector) COLLECTOR="${2:-}"; shift 2 ;;
--token) TELEGRAF_TOKEN="$2"; shift 2 ;;
--role) ROLE="$2"; shift 2 ;;
--pve-token) PVE_TOKEN="$2"; shift 2 ;;
--pve-node) PVE_NODE="$2"; shift 2 ;;
--pve-url) PVE_URL="$2"; shift 2 ;;
--apache-log) APACHE_LOG="$2"; shift 2 ;;
--uninstall) UNINSTALL=1; shift ;;
--check) CHECK=1; shift ;;
--version) SHOW_VERSION=1; shift ;;
--force-update) FORCE_UPDATE=1; shift ;;
--update-only) UPDATE_ONLY=1; shift ;;
--install-update-timer)
TIMER_INTERVAL="${2:-daily}"
case "$TIMER_INTERVAL" in
daily|hourly|weekly|[0-9]*min|[0-9]*) shift 2 ;;
*) TIMER_INTERVAL="daily"; shift ;;
esac ;;
--remove-update-timer) REMOVE_TIMER=1; shift ;;
-h|--help) sed -n '2,24p' "$0"; exit 0 ;;
*) echo "Unbekannte Option: $1" >&2; exit 2 ;;
esac
done
log() { printf '\033[1;34m[netbird-telegraf]\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m[netbird-telegraf] FEHLER:\033[0m %s\n' "$*" >&2; exit 1; }
[ "$(id -u)" -eq 0 ] || die "Bitte als root ausführen (sudo)."
# Reine Abfragen brauchen keinen Token und kein root (Timer-Verwaltung schon).
if [ "$SHOW_VERSION" -eq 1 ] || [ "$CHECK" -eq 1 ]; then
LOCAL_V="$(cat /etc/telegraf/CONFIG_VERSION 2>/dev/null || echo 'nicht installiert')"
REMOTE_V="$(curl -fsS -m 15 "$REPO_RAW/VERSION" 2>/dev/null | tr -d ' \r\n')"
[ -n "$REMOTE_V" ] || REMOTE_V="nicht erreichbar"
printf 'installiert: %s\nverfuegbar: %s\n' "$LOCAL_V" "$REMOTE_V"
[ "$CHECK" -eq 1 ] || exit 0
if [ "$LOCAL_V" = "$REMOTE_V" ] && [ -n "$LOCAL_V" ] && [ "$LOCAL_V" != "nicht installiert" ]; then
echo "Status: aktuell"; exit 0
fi
echo "Status: Update verfuegbar"; exit 10
fi
[ -n "$TELEGRAF_TOKEN" ] || die "Kein Token: --token <Bearer-Token> angeben (siehe README)."
if [ -n "${COLLECTOR:-}" ]; then
PROM_URL="http://$COLLECTOR:9090/api/v1/write"; LOKI_URL="http://$COLLECTOR:3100"
log "Direktweg im NetBird: Collector $COLLECTOR"
else
PROM_URL="$PROM_URL_DEFAULT"; LOKI_URL="$LOKI_URL_DEFAULT"
fi
# --------------------------------------------------------------------------
# Uninstall
# --------------------------------------------------------------------------
if [ "$UNINSTALL" -eq 1 ]; then
log "Entferne Telegraf …"
systemctl disable --now telegraf 2>/dev/null || rc-service telegraf stop 2>/dev/null || true
if command -v apt-get >/dev/null; then apt-get remove -y telegraf >/dev/null 2>&1 || true
elif command -v dnf >/dev/null; then dnf remove -y telegraf >/dev/null 2>&1 || true
elif command -v yum >/dev/null; then yum remove -y telegraf >/dev/null 2>&1 || true
elif command -v apk >/dev/null; then apk del telegraf >/dev/null 2>&1 || true
fi
rm -rf /etc/telegraf /usr/local/bin/telegraf /etc/systemd/system/telegraf.service
systemctl daemon-reload 2>/dev/null || true
log "Fertig."
exit 0
fi
# --------------------------------------------------------------------------
# Erkennung: OS, Arch, Rolle
# --------------------------------------------------------------------------
OS_ID="unknown"; [ -r /etc/os-release ] && . /etc/os-release && OS_ID="${ID:-unknown}"
ARCH_RAW="$(uname -m)"
case "$ARCH_RAW" in
x86_64|amd64) ARCH="amd64" ;;
aarch64|arm64) ARCH="arm64" ;;
armv7l|armhf) ARCH="armhf" ;;
*) die "Architektur $ARCH_RAW wird nicht unterstützt." ;;
esac
IS_PVE=0; command -v pveversion >/dev/null 2>&1 && IS_PVE=1
HAS_DOCKER=0; [ -S /var/run/docker.sock ] && HAS_DOCKER=1
GPU="none"
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi -L >/dev/null 2>&1; then
GPU="nvidia"
elif command -v rocm-smi >/dev/null 2>&1; then
GPU="amd"
elif [ -e /dev/dri/renderD128 ]; then
GPU="intel"
fi
HAS_APACHE=0; { command -v apache2ctl >/dev/null 2>&1 || command -v httpd >/dev/null 2>&1; } && HAS_APACHE=1
# Apache-Logpfad ermitteln: erst explizit gesetzter Wert, dann uebliche Orte,
# dann die von Apache selbst konfigurierte CustomLog-Direktive.
if [ "$HAS_APACHE" -eq 1 ] && [ -z "$APACHE_LOG" ]; then
for _p in /var/log/apache2/access.log /var/log/httpd/access_log \
/var/log/apache2/other_vhosts_access.log /var/log/httpd/access.log; do
[ -r "$_p" ] && { APACHE_LOG="$_p"; break; }
done
# Panel-Hoster (KeyHelp, Plesk, cPanel) legen PRO DOMAIN eigene Logs an.
# Dann reicht der globale Pfad nicht — Glob deckt alle VHosts ab.
if [ -z "$APACHE_LOG" ]; then
for _d in /var/log/apache2 /var/log/httpd /home/*/logs /var/log/keyhelp; do
[ -d "$_d" ] || continue
if ls "$_d"/*access*.log "$_d"/access_log >/dev/null 2>&1; then
APACHE_LOG="$_d/*access*.log"
break
fi
done
fi
if [ -z "$APACHE_LOG" ]; then
# Aus der Config lesen (KeyHelp/Plesk setzen eigene Pfade)
_cl="$(grep -rhoE '^\s*CustomLog\s+\S+' /etc/apache2/ /etc/httpd/ 2>/dev/null \
| awk '{print $2}' | grep -v '^|' | head -1)"
[ -n "$_cl" ] && [ -r "$_cl" ] && APACHE_LOG="$_cl"
fi
[ -n "$APACHE_LOG" ] || APACHE_LOG="/var/log/apache2/access.log"
fi
if [ "$ROLE" = "auto" ]; then
ROLE="none"
[ "$IS_PVE" -eq 1 ] && ROLE="proxmox"
fi
log "Node=$NODE_NAME OS=$OS_ID Arch=$ARCH Rolle=$ROLE Docker=$HAS_DOCKER Apache=$HAS_APACHE GPU=$GPU Collector=$COLLECTOR"
# --------------------------------------------------------------------------
# Erreichbarkeit des Collectors (NetBird Lazy Connection: erst anklopfen)
# --------------------------------------------------------------------------
if command -v curl >/dev/null; then
HOST_OF_URL="$(printf '%s' "$PROM_URL" | sed -E 's#^https?://([^/:]+).*#\1#')"
ping -c1 -W2 "$HOST_OF_URL" >/dev/null 2>&1 || true # NetBird Lazy Connection wecken
if curl -fsS -m 10 -H "Authorization: Bearer $TELEGRAF_TOKEN" "${PROM_URL%/api/v1/write}/-/ready" >/dev/null 2>&1; then
log "Collector erreichbar (auth ok): $PROM_URL"
else
log "WARNUNG: $PROM_URL nicht erreichbar oder Token falsch — Installation läuft weiter, Telegraf puffert und retried."
fi
fi
# --------------------------------------------------------------------------
# Update-Only: nur Konfiguration und Hilfsscripts aktualisieren.
# Kein Paket installieren, /etc/default/telegraf unangetastet lassen (Token!),
# Dienst nur neu starten, wenn sich wirklich etwas geaendert hat.
# --------------------------------------------------------------------------
SNAPSHOT_BEFORE=""
if [ "$UPDATE_ONLY" -eq 1 ]; then
SNAPSHOT_BEFORE="$(mktemp)"
cat /etc/telegraf/telegraf.d/*.conf /etc/telegraf/telegraf.conf 2>/dev/null > "$SNAPSHOT_BEFORE" || true
for s in journal-tail syslog-tail node-info proxmox-ve gpu-rocm; do
[ -f "/etc/telegraf/$s.sh" ] && cat "/etc/telegraf/$s.sh" >> "$SNAPSHOT_BEFORE" 2>/dev/null
done
fi
# --------------------------------------------------------------------------
# Installation
# --------------------------------------------------------------------------
install_apt() {
command -v gpg >/dev/null || { apt-get update -qq; apt-get install -y -qq gnupg >/dev/null; }
command -v curl >/dev/null || apt-get install -y -qq curl >/dev/null
mkdir -p /etc/apt/keyrings
curl -fsSL https://repos.influxdata.com/influxdata-archive.key | gpg --dearmor --yes -o /etc/apt/keyrings/influxdata-archive.gpg
echo "deb [signed-by=/etc/apt/keyrings/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main" > /etc/apt/sources.list.d/influxdata.list
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq telegraf >/dev/null
}
install_rpm() {
cat > /etc/yum.repos.d/influxdata.repo <<'EOF'
[influxdata]
name = InfluxData Repository - Stable
baseurl = https://repos.influxdata.com/stable/$basearch/main
enabled = 1
gpgcheck = 1
gpgkey = https://repos.influxdata.com/influxdata-archive.key
EOF
if command -v dnf >/dev/null; then dnf install -y -q telegraf; else yum install -y -q telegraf; fi
}
install_static() {
command -v curl >/dev/null || die "curl fehlt."
TB="telegraf-${TELEGRAF_VERSION}_linux_${ARCH}.tar.gz"
log "Statisches Binary $TB …"
TMP="$(mktemp -d)"
curl -fsSL "https://dl.influxdata.com/telegraf/releases/$TB" -o "$TMP/t.tgz"
tar -xzf "$TMP/t.tgz" -C "$TMP"
install -m 0755 "$TMP"/telegraf-*/usr/bin/telegraf /usr/local/bin/telegraf
rm -rf "$TMP"
id telegraf >/dev/null 2>&1 || useradd -r -s /usr/sbin/nologin -d /etc/telegraf telegraf 2>/dev/null || adduser -S -D -H -s /sbin/nologin telegraf
if command -v rc-update >/dev/null; then
cat > /etc/init.d/telegraf <<'EOF'
#!/sbin/openrc-run
description="Telegraf"
command=/usr/local/bin/telegraf
command_args="--config /etc/telegraf/telegraf.conf --config-directory /etc/telegraf/telegraf.d"
command_user=telegraf
command_background=true
pidfile=/run/telegraf.pid
start_pre() { set -a; [ -r /etc/default/telegraf ] && . /etc/default/telegraf; set +a; }
depend() { need net; }
EOF
chmod +x /etc/init.d/telegraf
return
fi
mkdir -p /etc/systemd/system
cat > /etc/systemd/system/telegraf.service <<'EOF'
[Unit]
Description=Telegraf
After=network-online.target
Wants=network-online.target
[Service]
User=telegraf
EnvironmentFile=-/etc/default/telegraf
ExecStart=/usr/local/bin/telegraf --config /etc/telegraf/telegraf.conf --config-directory /etc/telegraf/telegraf.d
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
}
if command -v telegraf >/dev/null 2>&1 || [ -x /usr/local/bin/telegraf ]; then
log "Telegraf bereits installiert ($(telegraf --version 2>/dev/null || /usr/local/bin/telegraf --version))."
[ "$UPDATE_ONLY" -eq 1 ] && log "Update-Only: Paketinstallation uebersprungen."
else
case "$OS_ID" in
debian|ubuntu|raspbian|linuxmint|pop) install_apt ;;
rhel|centos|rocky|almalinux|fedora|ol) install_rpm ;;
alpine) apk add --no-cache -q curl ca-certificates; install_static ;;
*) if command -v apt-get >/dev/null; then install_apt
elif command -v dnf >/dev/null || command -v yum >/dev/null; then install_rpm
else install_static; fi ;;
esac
fi
# --------------------------------------------------------------------------
# Konfiguration
# --------------------------------------------------------------------------
# Proxmox-Parameter VOR dem Schreiben der Konfiguration ermitteln
if [ "$ROLE" = "proxmox" ]; then
[ -n "$PVE_NODE" ] || PVE_NODE="$(pvesh get /nodes --output-format json 2>/dev/null | sed -n 's/.*"node":"\([^"]*\)".*/\1/p' | head -1)"
[ -n "$PVE_NODE" ] || PVE_NODE="$NODE_NAME"
[ -n "$PVE_URL" ] || PVE_URL="https://127.0.0.1:8006/api2/json"
log "Proxmox: node_name=$PVE_NODE base_url=$PVE_URL"
fi
mkdir -p /etc/telegraf/telegraf.d /etc/default
umask 077
cat > /etc/default/telegraf <<EOF
NODE_NAME=$NODE_NAME
# Die InfluxData-Unit nutzt \$TELEGRAF_OPTS in ExecStart. Ohne diesen Wert
# warnt systemd bei jedem Start "Referenced but unset environment variable".
# Explizit leer setzen = Warnung weg, Verhalten unveraendert.
TELEGRAF_OPTS=
# ROLE/COLLECTOR/PVE_* braucht der Auto-Updater, um das Profil zu erhalten
# (sonst verliert ein PVE-Knoten beim Update seine Rolle).
ROLE=$ROLE
COLLECTOR=${COLLECTOR:-}
PROM_URL=$PROM_URL
LOKI_URL=$LOKI_URL
TELEGRAF_TOKEN=$TELEGRAF_TOKEN
PVE_TOKEN=$PVE_TOKEN
PVE_NODE=$PVE_NODE
PVE_URL=$PVE_URL
APACHE_LOG=$APACHE_LOG
EOF
umask 022
fetch() { curl -fsSL "$REPO_RAW/$1" -o "$2" || die "Download $1 fehlgeschlagen."; }
# Ersatz fuer envsubst, falls gettext fehlt (Minimal-Container, schlanke
# Alpine-/Rocky-Installationen). Ersetzt nur die uebergebenen Variablennamen —
# gleiche Semantik wie envsubst mit expliziter Liste.
subst_vars() { # $1 = Quelldatei, $2 = Zieldatei, rest = Variablennamen
_src="$1"; _dst="$2"; shift 2
cp "$_src" "$_dst"
for _v in "$@"; do
eval "_val=\${$_v-}"
# Wert mit | als Trenner, Sonderzeichen via awk ersetzen (kein sed-Gebastel)
awk -v name="$_v" -v val="$_val" '{
gsub("\$\{" name "\}", val); print
}' "$_dst" > "$_dst.tmp" && mv "$_dst.tmp" "$_dst"
done
}
# Holt eine Conf und ersetzt ${...}-Platzhalter aus /etc/default/telegraf.
fetch_conf() {
fetch "$1" "$2.tmp"
set -a; [ -r /etc/default/telegraf ] && . /etc/default/telegraf; set +a
if command -v envsubst >/dev/null; then
envsubst '${NODE_NAME} ${PROM_URL} ${LOKI_URL} ${TELEGRAF_TOKEN} ${PVE_TOKEN} ${PVE_NODE} ${PVE_URL} ${APACHE_LOG}' < "$2.tmp" > "$2"
else
subst_vars "$2.tmp" "$2" NODE_NAME PROM_URL LOKI_URL TELEGRAF_TOKEN PVE_TOKEN PVE_NODE PVE_URL APACHE_LOG
fi
if grep -q '\${' "$2"; then
log "WARNUNG: $2 enthaelt noch unaufgeloeste Platzhalter:"
grep -o '\${[A-Z_]*}' "$2" | sort -u >&2
fi
rm -f "$2.tmp"
}
fetch_conf telegraf/base.conf /etc/telegraf/telegraf.conf
# Nur Confs entfernen, die DIESER Installer verwaltet — nicht pauschal alles.
# Sonst reisst ein Auto-Update fremde oder manuell ergaenzte Confs mit, die
# jemand bewusst nach /etc/telegraf/telegraf.d/ gelegt hat.
for _c in docker proxmox apache gpu journal nodeinfo syslog; do
rm -f "/etc/telegraf/telegraf.d/$_c.conf"
done
[ "$HAS_DOCKER" -eq 1 ] && { fetch telegraf/docker.conf /etc/telegraf/telegraf.d/docker.conf; usermod -aG docker telegraf 2>/dev/null || true; }
case "$ROLE" in
proxmox) : # pvesh-Weg braucht keinen Token (siehe unten)
fetch scripts/proxmox-ve.sh /etc/telegraf/proxmox-ve.sh
chmod 0755 /etc/telegraf/proxmox-ve.sh
# pvesh-Weg: braucht keinen Token und keine ACL (laeuft als root)
cat > /etc/telegraf/telegraf.d/proxmox.conf <<'EOF'
[[inputs.exec]]
interval = "30s"
timeout = "25s"
data_format = "prometheus"
commands = ["/etc/telegraf/proxmox-ve.sh"]
EOF
log "Proxmox: pvesh-Input aktiv (VM/CT-Metriken, kein API-Token noetig)." ;;
apache) fetch_conf telegraf/apache.conf /etc/telegraf/telegraf.d/apache.conf; usermod -aG adm telegraf 2>/dev/null || true ;;
docker|none) ;;
*) die "Unbekannte Rolle: $ROLE" ;;
esac
[ "$HAS_APACHE" -eq 1 ] && [ "$ROLE" != "apache" ] && { fetch_conf telegraf/apache.conf /etc/telegraf/telegraf.d/apache.conf; usermod -aG adm telegraf 2>/dev/null || true; }
# --- System-Logs (journald) → Loki — nur auf systemd-Systemen ---
if command -v journalctl >/dev/null 2>&1 && [ -d /run/systemd/system ]; then
fetch scripts/journal-tail.sh /etc/telegraf/journal-tail.sh
chmod 0755 /etc/telegraf/journal-tail.sh
fetch_conf telegraf/journal.conf /etc/telegraf/telegraf.d/journal.conf
# Zustandsverzeichnis fuer den Journal-Cursor
mkdir -p /var/lib/telegraf-journal
if [ "$ROLE" = "proxmox" ]; then
: # laeuft als root (Drop-in) — voller Journal-Zugriff
else
chown telegraf:telegraf /var/lib/telegraf-journal 2>/dev/null || true
usermod -aG systemd-journal telegraf 2>/dev/null || true
fi
log "Journald-Logs aktiv (Warnungen+, inkrementell ueber Cursor)."
fi
# --- Node-Info (LAN-IP, NetBird-IP/FQDN, PVE-URL) — auf jeder Node ---
fetch scripts/node-info.sh /etc/telegraf/node-info.sh
chmod 0755 /etc/telegraf/node-info.sh
cat > /etc/telegraf/telegraf.d/nodeinfo.conf <<'EOF'
[[inputs.exec]]
interval = "300s"
timeout = "25s"
data_format = "prometheus"
commands = ["/etc/telegraf/node-info.sh"]
EOF
log "Node-Info aktiv (LAN-IP, NetBird-IP/FQDN, PVE-URL)."
# --- GPU (nur wenn erkannt) ---
# Jeder Block wird NUR geschrieben, wenn das jeweilige Werkzeug wirklich da ist.
# Ein Input ohne Binary laesst Telegraf beim Start hart scheitern -> alle Metriken aus.
case "$GPU" in
nvidia)
cat > /etc/telegraf/telegraf.d/gpu.conf <<'EOF'
[[inputs.nvidia_smi]]
timeout = "10s"
[inputs.nvidia_smi.tagdrop]
compute_mode = ["*"]
EOF
log "NVIDIA-GPU erkannt: inputs.nvidia_smi aktiv."
;;
amd)
fetch scripts/gpu-rocm.sh /etc/telegraf/gpu-rocm.sh
chmod 0755 /etc/telegraf/gpu-rocm.sh
# KEIN name_override: das Script liefert die Metriknamen selbst
# (gpu_utilization_gpu, gpu_temperature_edge, ...). name_override wuerde
# alle Werte zu "gpu" kollabieren -> in Prometheus nur noch gpu_value.
# data_format = prometheus: mit "influx" haengt Telegraf "_value" an den Namen.
cat > /etc/telegraf/telegraf.d/gpu.conf <<'EOF'
[[inputs.exec]]
interval = "30s"
timeout = "20s"
data_format = "prometheus"
commands = ["/etc/telegraf/gpu-rocm.sh"]
EOF
log "AMD-GPU erkannt: rocm-smi-exec-Input aktiv."
;;
intel)
# Bewusst KEIN GPU-Input: intel_gpu_top liefert kein Prometheus/Influx-Format
# und ein nvidia_smi-Block ohne nvidia-smi wuerde Telegraf killen.
log "Intel-GPU (/dev/dri) erkannt: kein GPU-Input aktiviert (intel_gpu_top wird nicht erfasst)."
;;
*) : ;;
esac
chown -R telegraf:telegraf /etc/telegraf 2>/dev/null || true
# --------------------------------------------------------------------------
# Force-Update: Confs und Hilfsscripts erzwungen neu schreiben.
# Laeuft VOR dem Konfig-Test, damit ein Rollback unten greifen kann.
# --------------------------------------------------------------------------
write_conf_backups() { # Sicherung fuer den Rollback
BK="/var/backups/telegraf-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BK"
cp -a /etc/telegraf/telegraf.d "$BK/" 2>/dev/null || true
cp -a /etc/telegraf/telegraf.conf "$BK/" 2>/dev/null || true
printf '%s' "$BK" > /var/lib/telegraf-last-backup
}
rollback_conf() { # letzte Sicherung zurueckspielen
BK="$(cat /var/lib/telegraf-last-backup 2>/dev/null || true)"
[ -n "$BK" ] && [ -d "$BK/telegraf.d" ] || return 1
rm -rf /etc/telegraf/telegraf.d
cp -a "$BK/telegraf.d" /etc/telegraf/telegraf.d
[ -f "$BK/telegraf.conf" ] && cp -a "$BK/telegraf.conf" /etc/telegraf/telegraf.conf
log "Rollback aus $BK"
}
if [ "$FORCE_UPDATE" -eq 1 ]; then
write_conf_backups
log "Force-Update: Confs und Scripts werden neu geschrieben."
fi
# --------------------------------------------------------------------------
# Konfig testen
# --------------------------------------------------------------------------
# WICHTIG: NICHT mit --input-filter pruefen! Telegraf validiert dann nur die
# gefilterten Plugins und ueberspringt die uebrigen Konfigdateien. Ein Fehler in
# telegraf.d/apache.conf (z.B. ein ungueltiges Feld) lief damit durch, der
# Installer meldete "OK", und erst der Dienststart scheiterte:
# Job for telegraf.service failed
# Ohne Filter werden ALLE Dateien geparst — genau wie beim Dienststart. Das ist
# der einzige Test, der den Startfehler wirklich verhindert.
TG="$(command -v telegraf || echo /usr/local/bin/telegraf)"
set -a; . /etc/default/telegraf; set +a
conf_test() {
_out="$("$TG" --config /etc/telegraf/telegraf.conf \
--config-directory /etc/telegraf/telegraf.d --test --test-wait 1 2>&1)"
_rc=$?
# Nur echte Konfigurationsfehler zaehlen. Ein fehlendes Input-Binary
# (nvidia-smi) erscheint erst beim Start als E!, nicht beim Parsen — und
# Sammel-Warnungen wie die DeprecationNotice sind harmlos.
if [ "$_rc" -ne 0 ] || printf '%s' "$_out" | grep -q '^.*E!.*loading config file'; then
printf '%s\n' "$_out" | grep -E 'E!' | head -5 >&2
return 1
fi
return 0
}
if ! conf_test; then
# Bei Force-/Auto-Update zuerst zurueckrollen, dann erst aufgeben.
if [ "$FORCE_UPDATE" -eq 1 ] || [ "$UPDATE_ONLY" -eq 1 ]; then
log "Konfiguration ungültig — Rollback auf die letzte Sicherung."
rollback_conf || true
conf_test || die "Konfiguration auch nach Rollback ungültig — telegraf --test prüfen."
log "Rollback erfolgreich, alte Konfiguration aktiv."
else
die "Konfiguration ungültig — siehe Meldung oben. Einzelne Datei pruefen mit: telegraf --config /etc/telegraf/telegraf.conf --config-directory /etc/telegraf/telegraf.d --test"
fi
fi
# --------------------------------------------------------------------------
# Dienst
# --------------------------------------------------------------------------
# Proxmox-Rolle: pvesh verlangt root. Der InfluxData-Dienst laeuft als User
# "telegraf" -> das Script liefert dann still nichts. Drop-in auf root.
if [ "$ROLE" = "proxmox" ] && [ -d /etc/systemd/system ]; then
mkdir -p /etc/systemd/system/telegraf.service.d
cat > /etc/systemd/system/telegraf.service.d/10-proxmox-root.conf <<'EOF'
# pvesh (VM/CT-Metriken) erfordert root-Rechte.
[Service]
User=root
Group=root
EOF
log "Proxmox: systemd-Drop-in gesetzt — Dienst laeuft als root (pvesh braucht root)."
fi
CHANGED=1
if [ "$UPDATE_ONLY" -eq 1 ] && [ -n "$SNAPSHOT_BEFORE" ]; then
SNAPSHOT_AFTER="$(mktemp)"
cat /etc/telegraf/telegraf.d/*.conf /etc/telegraf/telegraf.conf 2>/dev/null > "$SNAPSHOT_AFTER" || true
for s in journal-tail syslog-tail node-info proxmox-ve gpu-rocm; do
[ -f "/etc/telegraf/$s.sh" ] && cat "/etc/telegraf/$s.sh" >> "$SNAPSHOT_AFTER" 2>/dev/null
done
if cmp -s "$SNAPSHOT_BEFORE" "$SNAPSHOT_AFTER"; then CHANGED=0; fi
rm -f "$SNAPSHOT_BEFORE" "$SNAPSHOT_AFTER"
if [ "$CHANGED" -eq 0 ]; then
log "Update-Only: keine Aenderung an Confs/Scripts — kein Neustart noetig."
# Versionsmarker TROTZDEM auf den Repo-Stand ziehen: sonst meldet der
# naechste Timer-Lauf erneut ein Update und laeuft endlos im Kreis.
_RV="$(curl -fsS -m 15 "$REPO_RAW/VERSION" 2>/dev/null | tr -d ' \r\n' || true)"
[ -n "$_RV" ] && printf '%s\n' "$_RV" > /etc/telegraf/CONFIG_VERSION
_RS="$(curl -fsS -m 20 "$REPO_RAW/install.sh" 2>/dev/null | { command -v sha256sum >/dev/null && sha256sum || shasum -a 256; } | cut -d' ' -f1 || true)"
[ -n "$_RS" ] && printf '%s\n' "$_RS" > /etc/telegraf/INSTALLER_SHA
printf '%s\n' "$REPO_RAW" > /etc/telegraf/REPO_RAW
exit 0
fi
log "Update-Only: Aenderungen erkannt — Dienst wird neu gestartet."
fi
if command -v systemctl >/dev/null && [ -d /run/systemd/system ]; then
systemctl daemon-reload
if [ "$UPDATE_ONLY" -eq 1 ]; then
systemctl restart telegraf
else
systemctl enable --now telegraf >/dev/null
systemctl restart telegraf
fi
sleep 3
if ! systemctl is-active --quiet telegraf; then
journalctl -u telegraf -n 20 --no-pager
# Haeufigste Ursache: ein aktivierter Input, dessen Binary fehlt
# (z.B. nvidia_smi ohne nvidia-smi). GPU-Conf verwerfen und erneut versuchen.
if [ -f /etc/telegraf/telegraf.d/gpu.conf ]; then
log "Start fehlgeschlagen — entferne GPU-Conf und versuche erneut."
rm -f /etc/telegraf/telegraf.d/gpu.conf
systemctl reset-failed telegraf 2>/dev/null || true
systemctl restart telegraf
sleep 3
fi
systemctl is-active --quiet telegraf || die "telegraf läuft nicht. journalctl -u telegraf -n 30 prüfen."
log "WARNUNG: Telegraf läuft, aber ohne GPU-Metriken (Input-Binary fehlte)."
fi
elif command -v systemctl >/dev/null; then
log "HINWEIS: systemd nicht aktiv (Container/Chroot) — Dienst wird beim nächsten Boot gestartet (enabled)."
systemctl enable telegraf >/dev/null 2>&1 || true
elif command -v rc-update >/dev/null; then
rc-update add telegraf default >/dev/null 2>&1 || true
rc-service telegraf restart >/dev/null 2>&1 || log "HINWEIS: OpenRC nicht aktiv (Container?) — Dienst beim nächsten Boot."
fi
PROM_BASE="$(printf '%s' "$PROM_URL" | sed -E 's#/api/v1/write/?$##')"
[ "$GPU" != "none" ] && log "GPU=$GPU erfasst. Hinweis: im Docker-Betrieb muss der GPU-Treiber im Container verfuegbar sein (nvidia-container-toolkit bzw. /dev/dri-Mount); im systemd-Betrieb ist das automatisch der Fall."
# --------------------------------------------------------------------------
# Versionsmarker fuer den Auto-Updater
# --------------------------------------------------------------------------
REMOTE_V="$(curl -fsS -m 15 "$REPO_RAW/VERSION" 2>/dev/null | tr -d ' \r\n' || true)"
printf '%s\n' "${REMOTE_V:-unbekannt}" > /etc/telegraf/CONFIG_VERSION
# Aktive Repo-Quelle festhalten, damit der Auto-Updater denselben Weg nutzt.
printf '%s\n' "$REPO_RAW" > /etc/telegraf/REPO_RAW
# Hash der Installer-Logik: erkennt auch Aenderungen ohne Versionssprung
# (z.B. eine Korrektur an journal-tail.sh).
if curl -fsS -m 20 "$REPO_RAW/install.sh" -o /tmp/.tg-installer.sha 2>/dev/null; then
if command -v sha256sum >/dev/null; then sha256sum /tmp/.tg-installer.sha | cut -d' ' -f1 > /etc/telegraf/INSTALLER_SHA
elif command -v shasum >/dev/null; then shasum -a 256 /tmp/.tg-installer.sha | cut -d' ' -f1 > /etc/telegraf/INSTALLER_SHA
fi
rm -f /tmp/.tg-installer.sha
fi
chmod 0644 /etc/telegraf/CONFIG_VERSION /etc/telegraf/INSTALLER_SHA 2>/dev/null || true
# --------------------------------------------------------------------------
# Auto-Updater-Timer
# --------------------------------------------------------------------------
install_update_timer() {
IV="${1:-daily}"
case "$IV" in
daily) ONCAL="*-*-* 04:30:00" ;;
hourly) ONCAL="*-*-* *:30:00" ;;
weekly) ONCAL="Mon *-*-* 04:30:00" ;;
*min) ONCAL="" ;; # OnUnitActiveSec statt OnCalendar
*) ONCAL="*-*-* 04:30:00" ;;
esac
# Der Updater holt sich das Script frisch und ruft sich selbst mit
# --update-only auf. Token kommt aus /etc/default/telegraf (nicht im Repo).
cat > /usr/local/bin/telegraf-installer-update <<'UPD'
#!/bin/sh
# Auto-Updater: nur bei echter Aenderung etwas tun.
set -u
# Repo-Quelle: aus der Umgebung, sonst aus der beim Install hinterlegten
# Datei, sonst Default. So funktioniert der Updater auch mit Mirror/Testserver.
REPO_RAW="${REPO_RAW:-$(cat /etc/telegraf/REPO_RAW 2>/dev/null || echo https://gitea.m-m.bio/mm/netbird-telegraf-installer/raw/branch/main)}"
LOG="/var/log/telegraf-installer-update.log"
say() { printf '%s %s\n' "$(date -Is)" "$*" >> "$LOG"; }
LOCAL_V="$(cat /etc/telegraf/CONFIG_VERSION 2>/dev/null || echo '')"
REMOTE_V="$(curl -fsS -m 20 "$REPO_RAW/VERSION" 2>/dev/null | tr -d ' \r\n' || true)"
[ -n "$REMOTE_V" ] || { say "Repo nicht erreichbar (NetBird down?) — kein Update."; exit 0; }
NEED=0
[ "$LOCAL_V" != "$REMOTE_V" ] && NEED=1
# Hash-Vergleich: erkennt Script-Fixes ohne Versionssprung
if [ "$NEED" -eq 0 ] && command -v sha256sum >/dev/null; then
TMP="$(mktemp)"; curl -fsS -m 25 "$REPO_RAW/install.sh" -o "$TMP" 2>/dev/null || true
if [ -s "$TMP" ]; then
R_SHA="$(sha256sum "$TMP" | cut -d' ' -f1)"
L_SHA="$(cat /etc/telegraf/INSTALLER_SHA 2>/dev/null || echo '')"
[ "$R_SHA" != "$L_SHA" ] && NEED=1
fi
rm -f "$TMP"
fi
if [ "$NEED" -eq 0 ]; then
say "aktuell ($LOCAL_V) — nichts zu tun."
exit 0
fi
say "Update $LOCAL_V -> $REMOTE_V"
TMPI="$(mktemp)"
if ! curl -fsS -m 60 "$REPO_RAW/install.sh" -o "$TMPI" 2>/dev/null; then
say "Download fehlgeschlagen."; rm -f "$TMPI"; exit 1
fi
# --update-only: nur Confs/Scripts, kein Paket, kein Tokenwechsel.
# WICHTIG: REPO_RAW und die Node-Identitaet muessen mitgegeben werden, sonst
# faellt NODE_NAME auf den Hostnamen der AUFRUFENDEN Maschine zurueck und der
# Unterlauf holt die Version von der falschen Quelle.
UPD_NAME="$(sed -n 's/^NODE_NAME=//p' /etc/default/telegraf 2>/dev/null | head -1)"
UPD_ROLE="$(sed -n 's/^ROLE=//p' /etc/default/telegraf 2>/dev/null | head -1)"
UPD_TOKEN="$(sed -n 's/^TELEGRAF_TOKEN=//p' /etc/default/telegraf 2>/dev/null | head -1)"
UPD_COLL="$(sed -n 's/^COLLECTOR=//p' /etc/default/telegraf 2>/dev/null | head -1)"
[ -n "$UPD_NAME" ] || UPD_NAME="$(hostname -s)"
set -- --update-only --name "$UPD_NAME" --token "$UPD_TOKEN"
[ -n "$UPD_ROLE" ] && set -- "$@" --role "$UPD_ROLE"
[ -n "$UPD_COLL" ] && set -- "$@" --collector "$UPD_COLL"
if REPO_RAW="$REPO_RAW" sh "$TMPI" "$@" >> "$LOG" 2>&1; then
say "Update erfolgreich."
else
say "Update FEHLGESCHLAGEN — siehe oben. Alte Konfiguration bleibt aktiv."
fi
rm -f "$TMPI"
UPD
chmod 0755 /usr/local/bin/telegraf-installer-update
if [ -d /etc/systemd/system ]; then
cat > /etc/systemd/system/telegraf-installer-update.service <<'EOF'
[Unit]
Description=Telegraf-Installer Auto-Update (nur bei Aenderung)
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/telegraf-installer-update
EOF
if [ -n "$ONCAL" ]; then
cat > /etc/systemd/system/telegraf-installer-update.timer <<EOF
[Unit]
Description=Taeglicher Telegraf-Installer Auto-Update
[Timer]
OnCalendar=$ONCAL
Persistent=true
RandomizedDelaySec=15m
[Install]
WantedBy=timers.target
EOF
else
cat > /etc/systemd/system/telegraf-installer-update.timer <<EOF
[Unit]
Description=Telegraf-Installer Auto-Update ($IV)
[Timer]
OnBootSec=$IV
OnUnitActiveSec=$IV
Persistent=true
[Install]
WantedBy=timers.target
EOF
fi
systemctl daemon-reload
systemctl enable --now telegraf-installer-update.timer >/dev/null 2>&1 \
&& log "Auto-Updater aktiv ($IV) — Log: /var/log/telegraf-installer-update.log" \
|| log "WARNUNG: Timer konnte nicht aktiviert werden (systemd nicht aktiv?)."
else
log "HINWEIS: kein systemd — Auto-Updater nur manuell (telegraf-installer-update)."
fi
}
remove_update_timer() {
command -v systemctl >/dev/null 2>&1 || { log "Auto-Updater: systemctl fehlt — Dateien werden entfernt."; rm -f /etc/systemd/system/telegraf-installer-update.timer /etc/systemd/system/telegraf-installer-update.service /usr/local/bin/telegraf-installer-update; return 0; }
systemctl disable --now telegraf-installer-update.timer >/dev/null 2>&1 || true
rm -f /etc/systemd/system/telegraf-installer-update.timer \
/etc/systemd/system/telegraf-installer-update.service \
/usr/local/bin/telegraf-installer-update
systemctl daemon-reload 2>/dev/null || true
log "Auto-Updater entfernt."
}
if [ "$REMOVE_TIMER" -eq 1 ]; then
if command -v systemctl >/dev/null 2>&1; then remove_update_timer
else log "Auto-Updater: kein systemd — nichts zu entfernen."; fi
fi
if [ -n "$TIMER_INTERVAL" ]; then install_update_timer "$TIMER_INTERVAL"; fi
log "OK — Node '$NODE_NAME' liefert an $PROM_URL (Metriken) und $LOKI_URL (Logs)."
log "Prüfen: curl -s -H 'Authorization: Bearer <TOKEN>' '$PROM_BASE/api/v1/query?query=system_uptime{node=\"$NODE_NAME\"}'"
log "Grafana: http://100.83.134.46:3000 (nur im NetBird)"