Initial commit
This commit is contained in:
commit
f192ba5548
7 files changed
+316
No files matched your search
@@ -0,0 +1 @@
|
||||
*.own
|
||||
@@ -0,0 +1,111 @@
|
||||
# Proxmox Backup Status → ntfy
|
||||
|
||||
Sendet nach jedem Proxmox Backup automatisch eine kompakte Statusmeldung an einen ntfy-Server.
|
||||
|
||||
Der Hauptunterschied zum integrierten Benachrichtigungssystem von Proxmox ist die `Übersichtlichkeit` und die `korrekte Priorisierung` der Benachrichtigungen.
|
||||
Erfolgreiche Backups haben `normale` Priorität, fehlgeschlagene die `höchste` Priorität. Das erlaubt es, sich ausschließlich bei Fehlern benachrichtigen zu lassen.
|
||||
|
||||
Die Nachricht enthält unter anderem:
|
||||
|
||||
* Backup-Status (Erfolg/Fehler)
|
||||
* Start- und Endzeit
|
||||
* Gesicherte Systeme
|
||||
* Laufzeit
|
||||
* Optional komplettes Logfile bei Fehlern
|
||||
|
||||
## Beispiel Benachrichtigungen
|
||||
|
||||
| Erfolgreiches Backup | Fehlgeschlagenes Backup |
|
||||
|---|---|
|
||||
| <img src="./images/ntfy-erfolg.png" width="400"> | <img src="./images/ntfy-fehlgeschlagen.png" width="400"> |
|
||||
|
||||
---
|
||||
|
||||
# Installation
|
||||
|
||||
Scripte z. B. nach:
|
||||
|
||||
```bash
|
||||
/root/scripts/shell_proxmox_backup_status_to_ntfy.sh
|
||||
/root/scripts/shell_proxmox_backup_status_to_ntfy_hook.sh
|
||||
```
|
||||
|
||||
kopieren und ausführbar machen:
|
||||
|
||||
```bash
|
||||
chmod +x /root/scripts/shell_proxmox_backup_status_to_ntfy.sh
|
||||
chmod +x /root/scripts/shell_proxmox_backup_status_to_ntfy_hook.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Proxmox konfigurieren
|
||||
|
||||
Damit Proxmox das Script nach jedem Backup automatisch ausführt, muss die Datei:
|
||||
|
||||
```bash
|
||||
nano /etc/vzdump.conf
|
||||
```
|
||||
|
||||
angepasst werden.
|
||||
|
||||
Folgende Zeile ergänzen:
|
||||
|
||||
```ini
|
||||
script: /root/scripts/shell_proxmox_backup_status_to_ntfy_hook.sh
|
||||
```
|
||||
|
||||
Beispiel:
|
||||
|
||||
```ini
|
||||
# vzdump default settings
|
||||
|
||||
#tmpdir: DIR
|
||||
#dumpdir: DIR
|
||||
#storage: STORAGE_ID
|
||||
#mode: snapshot|suspend|stop
|
||||
#bwlimit: KBPS
|
||||
|
||||
script: /root/scripts/shell_proxmox_backup_status_to_ntfy_hook.sh
|
||||
|
||||
#exclude-path: PATHLIST
|
||||
```
|
||||
|
||||
Danach wird das Script automatisch von Proxmox bei jedem vzdump-Backup aufgerufen.
|
||||
|
||||
---
|
||||
|
||||
# Konfiguration
|
||||
|
||||
Die Konfiguration erfolgt über eine `.env` Datei.
|
||||
|
||||
Beispiel:
|
||||
|
||||
```env
|
||||
# =========================================================
|
||||
# NTFY KONFIGURATION
|
||||
# =========================================================
|
||||
|
||||
# IP oder Domain deines ntfy-Servers
|
||||
SERVER="192.168.178.25:5885"
|
||||
|
||||
# Der Name des Kanals (Topic)
|
||||
TOPIC="Proxmox"
|
||||
|
||||
# Authentifizierungs-Token
|
||||
TOKEN="tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
# Optional: Link zu einem Icon für die Benachrichtigung
|
||||
NTFY_ICON=""
|
||||
|
||||
# =========================================================
|
||||
# BACKUP-LOG EINSTELLUNGEN
|
||||
# =========================================================
|
||||
|
||||
# Steuert, ob das detaillierte Backup-Log angehängt werden soll.
|
||||
# Mögliche Werte:
|
||||
# "true" oder "ja" -> Log wird gesendet
|
||||
# "false" oder "nein" -> Log wird nicht gesendet
|
||||
# "error" -> Log wird nur bei Fehlern gesendet (default)
|
||||
SEND_LOGFILE=error
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 229 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 307 KiB |
@@ -0,0 +1,26 @@
|
||||
# =========================================================
|
||||
# NTFY KONFIGURATION
|
||||
# =========================================================
|
||||
|
||||
# IP oder Domain deines ntfy-Servers
|
||||
SERVER="192.168.178.25:5885"
|
||||
|
||||
# Der Name des Kanals (Topic)
|
||||
TOPIC="Proxmox"
|
||||
|
||||
# Authentifizierungs-Token
|
||||
TOKEN="tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
# Optional: Link zu einem Icon für die Benachrichtigung
|
||||
NTFY_ICON=""
|
||||
|
||||
# =========================================================
|
||||
# BACKUP-LOG EINSTELLUNGEN
|
||||
# =========================================================
|
||||
|
||||
# Steuert, ob das detaillierte Backup-Log angehängt werden soll.
|
||||
# Mögliche Werte:
|
||||
# "true" oder "ja" -> Log wird gesendet
|
||||
# "false" oder "nein" -> Log wird nicht gesendet
|
||||
# "error" -> Log wird nur bei Fehlern gesendet (default)
|
||||
SEND_LOGFILE=error
|
||||
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# =========================================================
|
||||
# 1. UMGEBUNG & INITIALISIERUNG
|
||||
# =========================================================
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ENV_FILE="${SCRIPT_DIR}/shell_proxmox_backup_status_to_ntfy.env"
|
||||
[[ -f "${ENV_FILE}" ]] && source "${ENV_FILE}"
|
||||
|
||||
PHASE="${1:-}"
|
||||
[[ "${PHASE}" != "job-end" ]] && exit 0
|
||||
|
||||
sleep 5
|
||||
|
||||
format_compact_time() {
|
||||
local T=$1
|
||||
[[ -z "$T" || "$T" -lt 0 ]] && T=0
|
||||
[[ "$T" -eq 0 ]] && { echo "< 1s"; return; }
|
||||
local H=$((T/3600)) M=$((T%3600/60)) S=$((T%60))
|
||||
local RES=""
|
||||
[[ $H -gt 0 ]] && RES+="${H}h "
|
||||
[[ $M -gt 0 ]] && RES+="${M}m "
|
||||
[[ $S -gt 0 || -z "$RES" ]] && RES+="${S}s"
|
||||
echo "$RES" | xargs
|
||||
}
|
||||
|
||||
# =========================================================
|
||||
# 2. TASK & LOG DATEN FINDEN
|
||||
# =========================================================
|
||||
TASK_LINE=$(tac /var/log/pve/tasks/index | grep -m 1 ":vzdump:")
|
||||
[[ -z "$TASK_LINE" ]] && exit 0
|
||||
|
||||
UPID=$(echo "$TASK_LINE" | awk '{print $1}')
|
||||
FINAL_TASK_STATUS=$(echo "$TASK_LINE" | awk '{print $NF}')
|
||||
|
||||
LOGFILE="/tmp/proxmox_backup_$(date +%Y-%m-%d_%H-%M-%S).log"
|
||||
pvesh get "/nodes/$(hostname)/tasks/${UPID}/log" --limit 0 --output-format json | jq -r '.[].t // empty' > "$LOGFILE"
|
||||
[[ ! -s "$LOGFILE" ]] && { rm -f "$LOGFILE"; exit 0; }
|
||||
|
||||
# =========================================================
|
||||
# 3. ZEITEN & JOB-INFO (DIREKT AUS LOG)
|
||||
# =========================================================
|
||||
RAW_START=$(grep -m1 "INFO: Backup started at" "$LOGFILE" | sed 's/^.*at //')
|
||||
RAW_END=$(grep -E "INFO: Backup finished at|INFO: Backup job finished" "$LOGFILE" | tail -n1 | sed 's/^.*at //')
|
||||
|
||||
SEC_START=$(date -d "$RAW_START" +%s 2>/dev/null || date +%s)
|
||||
SEC_END=$(date -d "$RAW_END" +%s 2>/dev/null || date +%s)
|
||||
|
||||
DISPLAY_START=$(date -d "@$SEC_START" "+%H:%M" 2>/dev/null)
|
||||
DISPLAY_END=$(date -d "@$SEC_END" "+%H:%M" 2>/dev/null)
|
||||
|
||||
# Extrahiere Modus und Storage direkt aus der vzdump-Aufrufzeile im Log
|
||||
L_STORAGE=$(grep -m1 "vzdump" "$LOGFILE" | sed -n "s/.*--storage \([^ ]*\).*/\1/p")
|
||||
L_MODE=$(grep -m1 "vzdump" "$LOGFILE" | sed -n "s/.*--mode \([^ ]*\).*/\1/p")
|
||||
|
||||
# Formatiere den Namen für die COMMENT Variable (z.B. Snapshot an unRAID-pbs)
|
||||
MODE_CAP=$(echo "${L_MODE:-Backup}" | sed 's/.*/\L&/; s/.*/\u&/')
|
||||
COMMENT="${MODE_CAP} auf ${L_STORAGE:-Storage}"
|
||||
|
||||
# =========================================================
|
||||
# 4. SYSTEM-LISTE AUFBEREITEN
|
||||
# =========================================================
|
||||
VM_STARTS=$(grep -n "Starting Backup of VM" "$LOGFILE")
|
||||
SYSTEM_COUNT=$(echo "$VM_STARTS" | wc -l)
|
||||
BACKUP_LIST=""
|
||||
CURRENT_STEP=0
|
||||
|
||||
while read -r start_line; do
|
||||
((CURRENT_STEP++))
|
||||
LINE_NUM=$(echo "$start_line" | cut -d: -f1)
|
||||
C_VMID=$(echo "$start_line" | grep -oP "VM \K[0-9]+")
|
||||
|
||||
VM_BLOCK=$(sed -n "${LINE_NUM},/Finished Backup of VM\|Failed at/p" "$LOGFILE")
|
||||
V_S_RAW_VM=$(echo "$VM_BLOCK" | grep -m1 "Backup started at" | sed 's/^.*at //')
|
||||
V_S_SEC_VM=$(date -d "$V_S_RAW_VM" +%s 2>/dev/null || echo 0)
|
||||
|
||||
if echo "$VM_BLOCK" | grep -qiE "ERROR:|failed"; then
|
||||
STATUS_ICON="✗"
|
||||
V_E_RAW_VM=$(echo "$VM_BLOCK" | grep -m1 "Failed at" | sed 's/^.*at //')
|
||||
V_E_SEC_VM=$(date -d "$V_E_RAW_VM" +%s 2>/dev/null || echo 0)
|
||||
[[ $V_E_SEC_VM -gt 0 ]] && V_DUR_VAL=$(format_compact_time $((V_E_SEC_VM - V_S_SEC_VM))) || V_DUR_VAL=""
|
||||
else
|
||||
STATUS_ICON="✓"
|
||||
V_DUR_RAW=$(echo "$VM_BLOCK" | grep -oP "Finished Backup of VM $C_VMID \(\K[0-9:]+")
|
||||
if [[ -n "$V_DUR_RAW" ]]; then
|
||||
IFS=: read -r h m s <<< "$V_DUR_RAW"
|
||||
V_SEC=$((10#$h * 3600 + 10#$m * 60 + 10#$s))
|
||||
V_DUR_VAL=$(format_compact_time $V_SEC)
|
||||
else
|
||||
V_DUR_VAL="< 1s"
|
||||
fi
|
||||
fi
|
||||
|
||||
V_DUR_SUFFIX=""
|
||||
[[ -n "$V_DUR_VAL" ]] && V_DUR_SUFFIX=" \`${V_DUR_VAL}\`"
|
||||
|
||||
V_NAME=""; V_TYPE=""
|
||||
if pct status "$C_VMID" >/dev/null 2>&1; then
|
||||
V_TYPE="CT"; V_NAME=$(pct config "$C_VMID" | grep "^hostname:" | awk '{print $2}')
|
||||
elif qm status "$C_VMID" >/dev/null 2>&1; then
|
||||
V_TYPE="VM"; V_NAME=$(qm config "$C_VMID" | grep "^name:" | awk '{print $2}')
|
||||
fi
|
||||
[[ -z "$V_NAME" ]] && V_NAME="VM $C_VMID"
|
||||
[[ -z "$V_TYPE" ]] && V_TYPE="?"
|
||||
|
||||
PREFIX=$([[ $CURRENT_STEP -eq $SYSTEM_COUNT ]] && echo "└─" || echo "├─")
|
||||
BACKUP_LIST+="${PREFIX} ${STATUS_ICON} **${V_NAME}** (${V_TYPE} ${C_VMID})${V_DUR_SUFFIX}"$'\n'
|
||||
done <<< "$VM_STARTS"
|
||||
|
||||
TOTAL_DIFF=$((SEC_END - SEC_START))
|
||||
TOTAL_DURATION=$(format_compact_time $TOTAL_DIFF)
|
||||
|
||||
# =========================================================
|
||||
# 5. SENDEN
|
||||
# =========================================================
|
||||
if [[ "$FINAL_TASK_STATUS" == "OK" ]]; then
|
||||
TITLE="✅ Proxmox Backup erfolgreich"
|
||||
PRIO="default"
|
||||
IS_ERROR="false"
|
||||
else
|
||||
TITLE="❌ Proxmox Backup FEHLGESCHLAGEN"
|
||||
PRIO="high"
|
||||
IS_ERROR="true"
|
||||
fi
|
||||
|
||||
MESSAGE=$(cat <<EOF
|
||||
|
||||
🖥️ \`Node \` \`$(hostname)\`
|
||||
📝 \`Typ \` \`${COMMENT}\`
|
||||
|
||||
⏱️ \`Start\` \`${DISPLAY_START} Uhr\`
|
||||
⏱️ \`Ende \` \`${DISPLAY_END} Uhr\`
|
||||
|
||||
📦 \`Backups\`
|
||||
${BACKUP_LIST%?}
|
||||
|
||||
⌛ \`Gesamtlaufzeit\` \`${TOTAL_DURATION}\`
|
||||
EOF
|
||||
)
|
||||
|
||||
SEND_VAL="${SEND_LOGFILE,,}"
|
||||
if [[ "$SEND_VAL" == "true" || "$SEND_VAL" == "ja" ]]; then
|
||||
SHOULD_SEND_LOG="true"
|
||||
elif [[ "$SEND_VAL" == "false" || "$SEND_VAL" == "nein" ]]; then
|
||||
SHOULD_SEND_LOG="false"
|
||||
else
|
||||
[[ "$IS_ERROR" == "true" ]] && SHOULD_SEND_LOG="true" || SHOULD_SEND_LOG="false"
|
||||
fi
|
||||
|
||||
if [[ "$SHOULD_SEND_LOG" == "true" ]]; then
|
||||
curl -s \
|
||||
-H "Title: Backup Log (${COMMENT})" \
|
||||
-H "Priority: min" \
|
||||
-H "Markdown: yes" \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-H "Filename: backup_$(date +%Y-%m-%d_%H-%M).log" \
|
||||
-T "${LOGFILE}" \
|
||||
"http://${SERVER}/${TOPIC}" >/dev/null 2>&1
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
curl -s \
|
||||
-H "Title: ${TITLE}" \
|
||||
-H "Priority: ${PRIO}" \
|
||||
-H "Markdown: yes" \
|
||||
-H "Authorization: Bearer ${TOKEN}" \
|
||||
-d "${MESSAGE}" \
|
||||
"http://${SERVER}/${TOPIC}" >/dev/null 2>&1
|
||||
|
||||
rm -f "$LOGFILE"
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
setsid "${SCRIPT_DIR}/shell_proxmox_backup_status_to_ntfy.sh" "$@" \
|
||||
>/dev/null 2>&1 < /dev/null &
|
||||
|
||||
exit 0
|
||||
Reference in new issue
Block a user