diff --git a/README.md b/README.md index 70d5508..ab70158 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,100 @@ -# prtg-smart-health-check +# PRTG SMART Monitoring Script (`prtg-smart-health-check.v1.sh`) +Dieses Bash-Skript überwacht die S.M.A.R.T.-Werte einer physischen Festplatte oder SSD (SATA, SAS oder NVMe) und liefert die Daten im PRTG-kompatiblen XML-Format. Es wird über einen **SSH Script (erweitert)** Sensor eingebunden und kann automatisch erkennen, ob es sich um ein klassisches oder NVMe-Gerät handelt. + +## 🔧 Voraussetzungen + +- Ein Linux-System (z. B. Debian/Ubuntu/Proxmox) +- Das Paket `smartmontools` muss installiert sein: + ```bash + sudo apt install smartmontools + ``` +- Das Skript muss mit `bash` ausgeführt werden +- PRTG benötigt SSH-Zugriff mit einem Benutzer, der das Skript ausführen darf + +## 📁 Installation + +1. Erstelle den Zielpfad für das Skript (empfohlenes Verzeichnis): + ```bash + sudo mkdir -p /var/prtg/scriptsxml/ + ``` + +2. Kopiere das Skript in dieses Verzeichnis und mache es ausführbar: + ```bash + sudo cp prtg-smart-health-check.v1.sh /var/prtg/scriptsxml/ + sudo chmod +x /var/prtg/scriptsxml/prtg-smart-health-check.v1.sh + ``` + +3. Erlaube dem PRTG-SSH-Benutzer die Nutzung von `smartctl` ohne Passwort: + ```bash + echo "prtguser ALL=(ALL) NOPASSWD: /usr/sbin/smartctl" | sudo tee /etc/sudoers.d/prtg-smart + ``` + > **Hinweis**: Ersetze `prtguser` durch den tatsächlichen Benutzer, den PRTG per SSH verwendet. + +## 🧪 Testlauf + +Vorab kann das Skript manuell getestet werden: +```bash +sudo /var/prtg/scriptsxml/prtg-smart-health-check.v1.sh /dev/nvme0n1 +``` + +## ⚙️ PRTG-Einbindung + +1. Öffne dein PRTG Webinterface +2. Wähle das gewünschte Gerät (der Linux-Host) +3. Klicke auf **„Sensor hinzufügen“ → „SSH Script (Erweitert)“** +4. Wähle im Dropdown das Skript `prtg-smart-health-check.v1.sh` +5. Als **Parameter** gibst du das physikalische Device an, z. B.: + ``` + /dev/sda + ``` + oder + ``` + /dev/nvme0n1 + ``` + +6. Lasse das Feld **„Mutex Name“** leer +7. Speichern – fertig ✅ + +![SMART Sensor in PRTG](assets/screenshot_1.png) + +> ❗ **Wichtig**: +> Der Benutzer, mit dem PRTG sich per SSH verbindet, muss das angegebene Device lesen dürfen (z. B. `/dev/nvme0n1`). Üblicherweise ist das nur per `sudo` mit `smartctl` möglich – genau deshalb ist die `sudoers`-Datei erforderlich. + +## 📊 Was wird überwacht? + +**SATA/SAS:** +- Temperatur +- Betriebsstunden +- Reallocated Sectors +- Pending Sectors +- Uncorrectable Sectors +- CRC-Fehler und mehr + +**NVMe:** +- Temperatur +- Wear-Level (% Verbrauch) +- Datenmenge geschrieben/gelesen (TB) +- Unsafe Shutdowns +- Fehlerlogs +- Power-Cycles +- Verlauf des Verschleißes direkt im Sensortext + +![SMART Sensor in PRTG](assets/screenshot_2.png) + +## 📁 Caching für Wear-Level-Verlauf + +Das Skript speichert den letzten Wear-Level-Wert unter: +``` +/var/prtg/scriptsxml/.smart_wear_dev_nvme0n1.cache +``` +Daraus ergibt sich im Sensortext z. B.: +``` +Wear: 9 % – +1 % seit 2025-03-27 +``` + +--- + +🧠 Ideal für Admins, die Verschleiß frühzeitig erkennen und NVMe-Smartdaten sauber im Monitoring sehen wollen. + +Autor: Patrick Asmus – [www.techniverse.net](https://www.techniverse.net) diff --git a/assets/screenshot_1.png b/assets/screenshot_1.png new file mode 100644 index 0000000..517b853 Binary files /dev/null and b/assets/screenshot_1.png differ diff --git a/assets/screenshot_2.png b/assets/screenshot_2.png new file mode 100644 index 0000000..b468499 Binary files /dev/null and b/assets/screenshot_2.png differ diff --git a/prtg-smart-health-check.v1.sh b/prtg-smart-health-check.v1.sh new file mode 100644 index 0000000..2547676 --- /dev/null +++ b/prtg-smart-health-check.v1.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# Beschreibung: Überwacht die S.M.A.R.T Werte eines physikalischen Devices und gibt diese als XML in PRTG aus +# Parameter: /dev/sda +# Autor: Patrick Asmus +# Web: https://www.techniverse.net +# Version: 1.0 +# Datum: 28.03.2025 +# Modifikation: Initial +##################################################### + +DEVICE="$1" + +if [ -z "$DEVICE" ]; then + echo "1Kein Gerät angegeben" + exit 1 +fi + +if ! command -v smartctl &>/dev/null; then + echo "1smartctl nicht installiert" + exit 1 +fi + +if [ ! -b "$DEVICE" ]; then + echo "1Gerät $DEVICE nicht gefunden" + exit 1 +fi + +SMART_OUTPUT=$(sudo smartctl -x "$DEVICE") + +# Herstellerinformationen extrahieren +MODEL=$(echo "$SMART_OUTPUT" | awk -F: '/Model Number|Device Model/ {print $2}' | xargs) +SERIAL=$(echo "$SMART_OUTPUT" | awk -F: '/Serial Number/ {print $2}' | xargs) +VENDOR=$(echo "$SMART_OUTPUT" | awk -F: '/Vendor/ {print $2}' | xargs) +[ -z "$VENDOR" ] && VENDOR=$(echo "$MODEL" | awk '{print $1}') +MODEL=${MODEL:-Unbekanntes Modell} +SERIAL=${SERIAL:-Keine Seriennummer} +VENDOR=${VENDOR:-Unbekannter Hersteller} + +# Gerätetyp erkennen +if echo "$SMART_OUTPUT" | grep -q "NVMe Version"; then + TYPE="nvme" +else + TYPE="sata" +fi + +XML="" + +if [ "$TYPE" = "sata" ]; then + get_value() { + echo "$SMART_OUTPUT" | awk -v id="$1" '$1 == id {print $10}' + } + + TEMP=$(get_value 194) + HOURS=$(get_value 9) + REALLOC=$(get_value 5) + REALLOC_EVENT=$(get_value 196) + PENDING=$(get_value 197) + UNCORRECTABLE=$(get_value 198) + CRC_ERROR=$(get_value 199) + REPORTED_UNCORRECT=$(get_value 187) + + for var in TEMP HOURS REALLOC REALLOC_EVENT PENDING UNCORRECTABLE CRC_ERROR REPORTED_UNCORRECT; do + eval "[ -z \$$var ] && $var=0" + done + + XML+=" + Temperature (°C)$TEMPTemperature14555 + Power-On Hours$HOURSHours + Reallocated Sectors$REALLOCCount110 + Reallocated Events$REALLOC_EVENTCount + Pending Sectors$PENDINGCount11 + Offline Uncorrectable$UNCORRECTABLECount11 + Reported Uncorrect$REPORTED_UNCORRECTCount + CRC Error Count$CRC_ERRORCount + $VENDOR | $MODEL | SN: $SERIAL | $DEVICE" + +elif [ "$TYPE" = "nvme" ]; then + get_nvme_value() { + echo "$SMART_OUTPUT" | grep -E "^$1:" | head -n1 | awk -F: '{gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2}' + } + + TEMP=$(get_nvme_value "Temperature" | awk '{print $1}') + HOURS=$(get_nvme_value "Power On Hours" | sed 's/\.//g') + PERCENT_USED=$(get_nvme_value "Percentage Used" | sed 's/%//') + MEDIA_ERRORS=$(get_nvme_value "Media and Data Integrity Errors") + ERROR_LOGS=$(get_nvme_value "Error Information Log Entries") + UNSAFE_SHUTDOWNS=$(get_nvme_value "Unsafe Shutdowns") + WARN_TEMP_TIME=$(get_nvme_value "Warning Comp. Temperature Time") + CRIT_TEMP_TIME=$(get_nvme_value "Critical Comp. Temperature Time") + POWER_CYCLES=$(get_nvme_value "Power Cycles") + WRITTEN_TB=$(get_nvme_value "Data Units Written" | grep -o '\[[0-9.]* TB\]' | tr -d '[]TB ') + READ_TB=$(get_nvme_value "Data Units Read" | grep -o '\[[0-9.]* TB\]' | tr -d '[]TB ') + + # === Wear Level Verlauf verfolgen === + CACHE_FILE="/var/prtg/scriptsxml/.smart_wear_${DEVICE//\//_}.cache" + NOW_DATE=$(date '+%Y-%m-%d') + if [ -f "$CACHE_FILE" ]; then + LAST_LEVEL=$(awk -F: '{print $1}' "$CACHE_FILE") + LAST_DATE=$(awk -F: '{print $2}' "$CACHE_FILE") + DIFF=$((PERCENT_USED - LAST_LEVEL)) + + if [ "$DIFF" -ne 0 ]; then + TREND=" – +$DIFF % seit $LAST_DATE" + echo "$PERCENT_USED:$NOW_DATE" > "$CACHE_FILE" + else + TREND=" – unverändert seit $LAST_DATE" + fi + else + echo "$PERCENT_USED:$NOW_DATE" > "$CACHE_FILE" + TREND=" – erster Messpunkt" + fi + + for var in TEMP HOURS PERCENT_USED MEDIA_ERRORS ERROR_LOGS UNSAFE_SHUTDOWNS WARN_TEMP_TIME CRIT_TEMP_TIME POWER_CYCLES WRITTEN_TB READ_TB; do + eval "[ -z \$$var ] && $var=0" + done + + XML+=" + Temperature (°C)$TEMPTemperature16580 + Power-On Hours$HOURSHours + Wear Level (Percentage Used)$PERCENT_USEDPercent17090 + Power Cycles$POWER_CYCLESCount + Media/Data Errors$MEDIA_ERRORSCount11 + SMART Error Logs$ERROR_LOGSCount + Unsafe Shutdowns$UNSAFE_SHUTDOWNSCount + Warning Temp Time$WARN_TEMP_TIMETimeSeconds + Critical Temp Time$CRIT_TEMP_TIMETimeSeconds110 + Data Written (TB)$WRITTEN_TBCustom + Data Read (TB)$READ_TBCustom + $VENDOR | $MODEL | SN: $SERIAL | $DEVICE | Wear: $PERCENT_USED %$TREND" +else + XML+="1Unbekannter Gerätetyp" +fi + +XML+="" +echo "$XML"