diff --git a/proxmox/ups/README.md b/proxmox/ups/README.md index 616a2eb..d4172c6 100644 --- a/proxmox/ups/README.md +++ b/proxmox/ups/README.md @@ -68,24 +68,33 @@ Restart servicii ### Scenario 1: Întrerupere scurtă (< 3 minute) 1. Curent se întrerupe → UPS trece pe baterie (status: OB) -2. upssched pornește timer de 180 secunde -3. Curent revine înainte de 3 minute -4. Timer anulat → **Niciun sistem nu se oprește** +2. **📧 Email: "Trecere pe baterie"** - notificare imediată +3. upssched pornește timer de 180 secunde +4. Curent revine înainte de 3 minute +5. **📧 Email: "Curent revenit - OK"** +6. Timer anulat → **Niciun sistem nu se oprește** ### Scenario 2: Întrerupere lungă (> 3 minute) 1. Curent se întrerupe → UPS pe baterie -2. Timer 180 secunde expiră -3. `/usr/local/bin/ups-shutdown-cluster.sh` pornește: - - **Step 1:** Oprește toate VM-urile de pe toate nodurile (paralel) +2. **📧 Email: "Trecere pe baterie"** +3. Timer 180 secunde expiră +4. **📧 Email: "Pe baterie 3 min - SHUTDOWN"** +5. `/usr/local/bin/ups-shutdown-cluster.sh` pornește: + - **📧 Email: "Shutdown cluster PORNIT"** + - **Step 1:** Oprește toate VM-urile și LXC de pe toate nodurile - **Step 2:** Așteaptă 90 secunde pentru oprire graceful - - **Step 3:** Shutdown pve1 și pve2 (noduri secundare) - - **Step 4:** Așteaptă 30 secunde - - **Step 5:** Shutdown pvemini (nod primary - ultimul) + - **Step 3:** Shutdown pve1 → **📧 Email: "Shutdown pve1 trimis"** + - **Step 4:** Shutdown pveelite → **📧 Email: "Shutdown pveelite trimis"** + - **Step 5:** Așteaptă 60 secunde + - **📧 Email: "Shutdown pvemini (ULTIMUL NOD)"** + - **Step 6:** Comandă UPS shutdown (oprire completă) + - **Step 7:** Shutdown pvemini (nod primary - ultimul) ### Scenario 3: Baterie scăzută imediată 1. UPS raportează LOWBATT (baterie critică) -2. Shutdown **IMEDIAT** (fără timer) -3. Același flux de shutdown orchestrat ca mai sus +2. **📧 Email: "BATERIE CRITICĂ - SHUTDOWN IMEDIAT"** +3. Shutdown **IMEDIAT** (fără timer) +4. Același flux de shutdown orchestrat ca mai sus ## Quick Start @@ -300,17 +309,29 @@ tail -50 /var/log/ups-monthly-test.log ## Configurare Personalizată -### Modificare timp de așteptare (default: 3 minute) +### Modificare timp de asteptare (default: 3 minute) -Editează `/etc/nut/upssched.conf` pe pvemini: +Fisier: `/etc/nut/upssched.conf` pe pvemini -```bash -# Schimbă din 180 (3 min) la 300 (5 min) -AT ONBATT * START-TIMER onbatt 300 +Linia relevanta: +``` +AT ONBATT * START-TIMER onbatt 180 ``` -Apoi: +Valoarea **180** = secunde (3 minute). Exemple: +- 180 = 3 minute +- 300 = 5 minute +- 600 = 10 minute + +Pentru a modifica: ```bash +# Editare manuala +nano /etc/nut/upssched.conf + +# Sau comanda directa (exemplu: 5 minute) +sed -i 's/START-TIMER onbatt [0-9]*/START-TIMER onbatt 300/' /etc/nut/upssched.conf + +# Restart serviciu pentru a aplica systemctl restart nut-monitor ``` @@ -381,12 +402,31 @@ iptables -A INPUT -p tcp --dport 3493 -s 10.0.20.0/24 -j ACCEPT - **Hardware Compatibility:** https://networkupstools.org/stable-hcl.html - **WinNUT GitHub:** https://github.com/gawindx/WinNUT-V2 +## Notificări Email + +Sistemul trimite notificări email via **PVE::Notify** pentru toate evenimentele importante: + +| Eveniment | Când | Severity | +|-----------|------|----------| +| **ONBATT** | UPS trece pe baterie | warning | +| **ONLINE** | Curentul revine | info | +| **LOWBATT** | Baterie critică | error | +| **SHUTDOWN_START** | Începe shutdown cluster | error | +| **SHUTDOWN_NODE** | Shutdown nod secundar (pentru fiecare) | error | +| **SHUTDOWN_PRIMARY** | Shutdown nod primary (ultimul) | error | +| **COMMBAD** | Comunicație pierdută cu UPS | warning | + +**Configurare:** Email-urile folosesc notificările Proxmox existente. Verifică că ai configurat un target email în **Datacenter → Notifications**. + +**Template-uri:** `/etc/pve/notification-templates/default/ups-power-event-*` + ## Funcționalități Complete ### ✅ Shutdown Orchestrat Automat - Detectare întrerupere curent (3 minute grace period) -- Oprire ordonată: VM-uri → noduri secundare → nod primary -- Notificări în timp real prin upssched +- Oprire ordonată: VM-uri/LXC → noduri secundare → nod primary +- **Oprire automată UPS** după shutdown (protecție power surge) +- Notificări email la fiecare pas ### ✅ Test Lunar Automat Baterie (NOU!) - Rulare automată pe 1 ale lunii la 00:00 @@ -410,10 +450,11 @@ iptables -A INPUT -p tcp --dport 3493 -s 10.0.20.0/24 -j ACCEPT ## Autori și Istoric - **Creat:** 2025-10-06 -- **Versiune:** 1.1 -- **Ultima modificare:** 2025-10-06 +- **Versiune:** 1.2 +- **Ultima modificare:** 2026-01-13 - **Autor:** Configurat automat via Claude Code - **Changelog:** + - v1.2 (2026-01-13): Adăugat notificări email pentru toate evenimentele UPS + oprire automată UPS - v1.1 (2025-10-06): Adăugat test lunar automat baterie cu notificări PVE::Notify - v1.0 (2025-10-06): Release inițial cu shutdown orchestrat și monitorizare NUT diff --git a/proxmox/ups/config/notification-templates/ups-power-event-body.html.hbs b/proxmox/ups/config/notification-templates/ups-power-event-body.html.hbs new file mode 100644 index 0000000..32de518 --- /dev/null +++ b/proxmox/ups/config/notification-templates/ups-power-event-body.html.hbs @@ -0,0 +1,73 @@ + + + + + + + +
+

[UPS] {{ event_title }}

+ +

Hostname: {{ hostname }}
+ Date: {{ event_date }}
+ Event: {{ event_type }}

+ +
+ {{ event_description }} +
+ +

UPS Status

+
+
+
Status
+
{{ ups_status }}
+
+
+
Battery
+
{{ battery_charge }}%
+
+
+
Input Voltage
+
{{ input_voltage }}V
+
+ {{#if battery_runtime}} +
+
Runtime
+
{{ battery_runtime }} min
+
+ {{/if}} +
+ + {{#if action_taken}} +

Action: {{ action_taken }}

+ {{/if}} + + {{#if next_steps}} +

Next Steps: {{ next_steps }}

+ {{/if}} + + +
+ + diff --git a/proxmox/ups/config/notification-templates/ups-power-event-body.txt.hbs b/proxmox/ups/config/notification-templates/ups-power-event-body.txt.hbs new file mode 100644 index 0000000..bca4ded --- /dev/null +++ b/proxmox/ups/config/notification-templates/ups-power-event-body.txt.hbs @@ -0,0 +1,31 @@ +======================================== +UPS POWER EVENT - {{ event_title }} +======================================== + +Hostname: {{ hostname }} +Date: {{ event_date }} +Event: {{ event_type }} + +{{ event_description }} + +UPS STATUS: +----------- +Status: {{ ups_status }} +Battery Charge: {{ battery_charge }}% +Input Voltage: {{ input_voltage }}V +{{#if battery_runtime}} +Battery Runtime: {{ battery_runtime }} min +{{/if}} + +{{#if action_taken}} +ACTION: {{ action_taken }} +{{/if}} + +{{#if next_steps}} +NEXT STEPS: {{ next_steps }} +{{/if}} + +======================================== +Log: /var/log/ups-events.log +Script: /usr/local/bin/upssched-cmd +======================================== diff --git a/proxmox/ups/config/notification-templates/ups-power-event-subject.txt.hbs b/proxmox/ups/config/notification-templates/ups-power-event-subject.txt.hbs new file mode 100644 index 0000000..fe1724d --- /dev/null +++ b/proxmox/ups/config/notification-templates/ups-power-event-subject.txt.hbs @@ -0,0 +1 @@ +[{{ hostname }}] UPS {{ event_type }} - {{ event_title }} diff --git a/proxmox/ups/config/upssched.conf b/proxmox/ups/config/upssched.conf index dbe2ca1..9a8b315 100644 --- a/proxmox/ups/config/upssched.conf +++ b/proxmox/ups/config/upssched.conf @@ -6,15 +6,18 @@ CMDSCRIPT /usr/local/bin/upssched-cmd PIPEFN /run/nut/upssched.pipe LOCKFN /run/nut/upssched.lock -# Când UPS trece pe baterie (ONBATT), așteaptă 180 secunde (3 minute) -# Dacă curentul revine în acest timp, anulează shutdown-ul +# Când UPS trece pe baterie (ONBATT): +# 1. Trimite notificare imediată +# 2. Așteaptă 180 secunde (3 minute) înainte de shutdown +AT ONBATT * EXECUTE onbatt_start AT ONBATT * START-TIMER onbatt 180 # Când UPS raportează baterie scăzută (LOWBATT), shutdown imediat AT LOWBATT * EXECUTE lowbatt -# Când curentul revine (ONLINE), anulează toate timer-ele +# Când curentul revine (ONLINE), anulează timer-ele și trimite notificare AT ONLINE * CANCEL-TIMER onbatt +AT ONLINE * EXECUTE online # Când comunicația cu UPS se pierde (COMMBAD), așteaptă 30 secunde AT COMMBAD * START-TIMER commbad 30 diff --git a/proxmox/ups/docs/UPS-SHUTDOWN-README.md b/proxmox/ups/docs/UPS-SHUTDOWN-README.md index 6312e32..5f52756 100644 --- a/proxmox/ups/docs/UPS-SHUTDOWN-README.md +++ b/proxmox/ups/docs/UPS-SHUTDOWN-README.md @@ -56,9 +56,9 @@ NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC #### 5. /etc/nut/upssched.conf Scheduler pentru evenimente: -- **ONBATT:** Așteaptă 180 secunde (3 minute) înainte de shutdown -- **LOWBATT:** Shutdown imediat -- **ONLINE:** Anulează toate timer-ele +- **ONBATT:** Notificare email imediată + așteaptă 180 secunde (3 minute) înainte de shutdown +- **LOWBATT:** Shutdown imediat + notificare email +- **ONLINE:** Anulează timer-ele + notificare email "curent revenit" ### Scripturi Create @@ -67,13 +67,17 @@ Scheduler pentru evenimente: Ordinea de operații: 1. Verifică status UPS (trebuie OB sau LB) -2. Oprește toate VM-urile de pe toate nodurile (paralel) -3. Așteaptă 90 secunde -4. Shutdown pve1 și pve2 (secundare) -5. Așteaptă 30 secunde -6. Shutdown pvemini (primary - ultimul) +2. **📧 Email: "Shutdown cluster PORNIT"** +3. Oprește toate VM-urile și LXC de pe toate nodurile (paralel) +4. Așteaptă 90 secunde pentru oprire graceful +5. Shutdown pve1 → **📧 Email: "Shutdown pve1 trimis"** +6. Shutdown pveelite → **📧 Email: "Shutdown pveelite trimis"** +7. Așteaptă 60 secunde +8. **📧 Email: "Shutdown pvemini (ULTIMUL NOD)"** +9. Comandă UPS shutdown (oprire completă UPS) +10. Shutdown pvemini (primary - ultimul) -Logare: `/var/log/ups-shutdown.log` +Logare: `/var/log/ups-shutdown.log` + `journalctl -t ups-shutdown` #### 2. /usr/local/bin/ups-shutdown-test.sh **Script de test (DRY RUN) - NU oprește nimic** @@ -85,12 +89,15 @@ tail -f /var/log/ups-shutdown-test.log ``` #### 3. /usr/local/bin/upssched-cmd -**Handler pentru evenimente UPS** +**Handler pentru evenimente UPS** - trimite notificări email via PVE::Notify -Apelat automat de upssched când: -- UPS pe baterie 3 minute → lansează shutdown orchestrat -- Baterie scăzută → shutdown imediat -- Pierdere comunicație → doar logging +| Eveniment | Acțiune | Email | +|-----------|---------|-------| +| `onbatt_start` | UPS trece pe baterie | "Trecere pe baterie - Timer 3 min" | +| `onbatt` | Timer 3 min expirat | "Pe baterie 3 min - SHUTDOWN" + lansare shutdown | +| `online` | Curent revenit | "Curent revenit - OK" | +| `lowbatt` | Baterie critică | "BATERIE CRITICĂ" + shutdown imediat | +| `commbad` | Comunicație pierdută | "Comunicație pierdută cu UPS" | Logare: `/var/log/ups-events.log` @@ -156,24 +163,33 @@ tail -f /var/log/ups-events.log ### Scenario 1: Întrerupere Scurtă (< 3 minute) 1. Curent se întrerupe → UPS trece pe baterie -2. Timer de 180 secunde pornește -3. Curent revine → Timer anulat -4. **Rezultat:** Niciun sistem nu se oprește +2. **📧 Email: "Trecere pe baterie"** +3. Timer de 180 secunde pornește +4. Curent revine → Timer anulat +5. **📧 Email: "Curent revenit - OK"** +6. **Rezultat:** Niciun sistem nu se oprește ### Scenario 2: Întrerupere Lungă (> 3 minute) 1. Curent se întrerupe → UPS trece pe baterie -2. Timer 180 secunde expiră -3. Scriptu de shutdown pornește: - - VM-uri se opresc pe toate nodurile - - După 90s: pve1, pve2 se opresc - - După încă 30s: pvemini se oprește -4. **Rezultat:** Shutdown orchestrat complet +2. **📧 Email: "Trecere pe baterie"** +3. Timer 180 secunde expiră +4. **📧 Email: "Pe baterie 3 min - SHUTDOWN"** +5. Script de shutdown pornește: + - **📧 Email: "Shutdown cluster PORNIT"** + - VM-uri/LXC se opresc pe toate nodurile + - După 90s: pve1 se oprește → **📧 Email** + - pveelite se oprește → **📧 Email** + - După 60s: **📧 Email: "Shutdown pvemini (ULTIMUL NOD)"** + - UPS primește comandă shutdown + - pvemini se oprește +6. **Rezultat:** Shutdown orchestrat complet + UPS oprit ### Scenario 3: Baterie Scăzută Imediată 1. UPS raportează LOWBATT -2. Shutdown **IMEDIAT** (fără timer) -3. Același flux de shutdown orchestrat -4. **Rezultat:** Shutdown rapid pentru protecție +2. **📧 Email: "BATERIE CRITICĂ - SHUTDOWN IMEDIAT"** +3. Shutdown **IMEDIAT** (fără timer) +4. Același flux de shutdown orchestrat +5. **Rezultat:** Shutdown rapid pentru protecție + UPS oprit ## Loguri și Troubleshooting @@ -234,4 +250,4 @@ tail -20 /var/log/ups-events.log ## Contact și Suport - Documentație NUT: https://networkupstools.org/ - Script creat: 2025-10-06 -- Ultima modificare: 2025-10-06 +- Ultima modificare: 2026-01-13 (adăugat notificări email + UPS shutdown) diff --git a/proxmox/ups/scripts/ups-shutdown-cluster.sh b/proxmox/ups/scripts/ups-shutdown-cluster.sh index 0564203..5672a18 100644 --- a/proxmox/ups/scripts/ups-shutdown-cluster.sh +++ b/proxmox/ups/scripts/ups-shutdown-cluster.sh @@ -1,44 +1,114 @@ #!/bin/bash # -# Script de shutdown orchestrat pentru cluster Proxmox când UPS este pe baterie critică -# Autor: Generat automat -# Data: 2025-10-06 -# Actualizat: 2025-10-06 - Adăugat suport LXC containers +# Script de shutdown orchestrat pentru cluster Proxmox cand UPS este pe baterie critica +# Trimite notificari email via PVE::Notify pentru fiecare pas +# +# Creat: 2025-10-06 +# Actualizat: 2026-01-13 - Adaugat notificari email si UPS shutdown LOGFILE=/var/log/ups-shutdown.log -NODES=(10.0.20.200 10.0.20.202) # pve1, pveelite (pvemini va fi ultimul) +NODES=("10.0.20.200" "10.0.20.202") # pve1, pveelite (pvemini va fi ultimul) +NODE_NAMES=("pve1" "pveelite") # Nume pentru notificari +UPS_NAME="nutdev1" +UPS_USER="admin" +UPS_PASS="parola99" +TEMPLATE_DIR="/etc/pve/notification-templates/default" +HOSTNAME=$(hostname) +FQDN=$(hostname -f 2>/dev/null || hostname) log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOGFILE + logger -t ups-shutdown "$1" +} + +# Obtine status UPS +get_ups_info() { + echo "Status: $(upsc $UPS_NAME ups.status 2>/dev/null || echo 'UNKNOWN')" + echo "Battery: $(upsc $UPS_NAME battery.charge 2>/dev/null || echo '?')%" + echo "Input: $(upsc $UPS_NAME input.voltage 2>/dev/null || echo '?')V" +} + +# Trimite notificare email via PVE::Notify +send_notification() { + local EVENT_TYPE="$1" + local EVENT_TITLE="$2" + local EVENT_DESC="$3" + local SEVERITY="$4" + + local UPS_STATUS=$(upsc $UPS_NAME ups.status 2>/dev/null || echo "UNKNOWN") + local BATTERY_CHARGE=$(upsc $UPS_NAME battery.charge 2>/dev/null || echo "0") + local INPUT_VOLTAGE=$(upsc $UPS_NAME input.voltage 2>/dev/null || echo "0") + local EVENT_DATE=$(date '+%Y-%m-%d %H:%M:%S') + + log_message "Sending notification: $EVENT_TITLE" + + perl -I/usr/share/perl5 << EOFPERL 2>&1 | tee -a $LOGFILE +use strict; +use warnings; +use PVE::Notify; + +my \$template_data = { + 'hostname' => '$FQDN', + 'event_date' => '$EVENT_DATE', + 'event_type' => '$EVENT_TYPE', + 'event_title' => '$EVENT_TITLE', + 'event_description' => '$EVENT_DESC', + 'event_class' => 'shutdown', + 'alert_type' => 'danger', + 'ups_status' => '$UPS_STATUS', + 'battery_charge' => '$BATTERY_CHARGE', + 'input_voltage' => '$INPUT_VOLTAGE', + 'action_taken' => 'Shutdown in curs', + 'next_steps' => '' +}; + +my \$fields = { + 'hostname' => '$HOSTNAME', + 'type' => 'ups-power-event' +}; + +eval { + PVE::Notify::notify('$SEVERITY', 'ups-power-event', \$template_data, \$fields); + print "Notification sent\\n"; +}; +if (\$@) { + print STDERR "Notification failed: \$@\\n"; +} +EOFPERL } log_message "========================================" log_message "UPS SHUTDOWN ORCHESTRATION STARTED" -log_message "UPS Status: $(upsc nutdev1 ups.status 2>/dev/null || echo 'UNKNOWN')" -log_message "Battery Charge: $(upsc nutdev1 battery.charge 2>/dev/null || echo 'UNKNOWN')%" +log_message "$(get_ups_info)" log_message "========================================" -# Verifică dacă UPS este într-adevăr pe baterie critică -UPS_STATUS=$(upsc nutdev1 ups.status 2>/dev/null) +# Verifica daca UPS este intr-adevar pe baterie critica +UPS_STATUS=$(upsc $UPS_NAME ups.status 2>/dev/null) if [[ ! $UPS_STATUS =~ (OB|LB) ]]; then log_message "WARNING: UPS status is $UPS_STATUS - not critical. Aborting shutdown." exit 0 fi +# Email: START SHUTDOWN +send_notification \ + "SHUTDOWN_START" \ + "Shutdown cluster PORNIT" \ + "UPS pe baterie critica. Se initiaza oprirea ordonata a cluster-ului Proxmox." \ + "error" + log_message "Step 1: Oprire VM-uri pe toate nodurile..." -# Oprește VM-uri pe toate nodurile (inclusiv local) +# Opreste VM-uri pe toate nodurile (inclusiv local) for node in ${NODES[@]} localhost; do if [ "$node" == "localhost" ]; then NODE_NAME="pvemini (local)" else NODE_NAME=$node fi - + log_message " - Oprire VM-uri pe $NODE_NAME..." - + if [ "$node" == "localhost" ]; then - # Local - oprește VM-urile direct for vmid in $(qm list | awk 'NR>1 {print $1}'); do vm_status=$(qm status $vmid | awk '{print $2}') if [ "$vm_status" == "running" ]; then @@ -47,7 +117,6 @@ for node in ${NODES[@]} localhost; do fi done else - # Remote - SSH către alt nod ssh -o ConnectTimeout=5 root@$node " for vmid in \$(qm list | awk 'NR>1 {print \$1}'); do vm_status=\$(qm status \$vmid | awk '{print \$2}') @@ -62,24 +131,22 @@ done log_message "Step 2: Oprire containere LXC pe toate nodurile..." -# Oprește containere LXC pe toate nodurile +# Opreste containere LXC pe toate nodurile for node in ${NODES[@]} localhost; do if [ "$node" == "localhost" ]; then NODE_NAME="pvemini (local)" else NODE_NAME=$node fi - + log_message " - Oprire LXC pe $NODE_NAME..." - + if [ "$node" == "localhost" ]; then - # Local - oprește containerele direct pct list 2>/dev/null | awk 'NR>1 && $2=="running" {print $1}' | while read ctid; do log_message " * Oprire container $ctid pe pvemini..." pct shutdown $ctid --timeout 60 & done else - # Remote - SSH către alt nod ssh -o ConnectTimeout=5 root@$node " pct list 2>/dev/null | awk 'NR>1 && \$2==\"running\" {print \$1}' | while read ctid; do echo ' * Oprire container '\$ctid' pe $node...' @@ -89,25 +156,61 @@ for node in ${NODES[@]} localhost; do fi done -log_message "Step 3: Așteptare 90 secunde pentru oprirea VM-urilor și LXC..." +log_message "Step 3: Asteptare 90 secunde pentru oprirea VM-urilor si LXC..." sleep 90 -log_message "Step 4: Oprire noduri secundare (pve1, pveelite)..." -for node in ${NODES[@]}; do - log_message " - Shutdown nod $node..." - ssh -o ConnectTimeout=5 root@$node "shutdown -h +1 'UPS on battery critical - shutting down'" 2>&1 | tee -a $LOGFILE & +log_message "Step 4: Oprire noduri secundare..." + +# Opreste nodurile secundare si trimite notificare pentru fiecare +for i in "${!NODES[@]}"; do + node="${NODES[$i]}" + node_name="${NODE_NAMES[$i]}" + + log_message " - Shutdown nod $node_name ($node)..." + + # Email: SHUTDOWN NOD SECUNDAR + send_notification \ + "SHUTDOWN_NODE" \ + "Shutdown $node_name trimis" \ + "Comanda shutdown a fost trimisa catre nodul $node_name ($node)." \ + "error" + + ssh -o ConnectTimeout=5 root@$node "shutdown -h +1 'UPS battery critical - shutting down'" 2>&1 | tee -a $LOGFILE & done -log_message "Step 5: Așteptare 30 secunde pentru shutdown noduri secundare..." -sleep 30 +log_message "Step 5: Asteptare 60 secunde pentru shutdown noduri secundare..." +sleep 60 log_message "Step 6: Oprire nod local (pvemini - primary)..." + +# Email: SHUTDOWN NOD PRIMARY (ultimul email inainte de shutdown) +send_notification \ + "SHUTDOWN_PRIMARY" \ + "Shutdown pvemini (ULTIMUL NOD)" \ + "Se opreste nodul primary pvemini. Acesta este ultimul nod din cluster. UPS-ul se va opri dupa shutdown." \ + "error" + +log_message "Step 7: Oprire UPS dupa shutdown..." + +# Comanda UPS sa se opreasca dupa un delay (permite shutdown-ul sa se finalizeze) +# Verifica daca comanda este disponibila +if upscmd -l $UPS_NAME 2>/dev/null | grep -q "shutdown.stayoff"; then + log_message " - Comanda UPS shutdown.stayoff (oprire completa)..." + upscmd -u $UPS_USER -p $UPS_PASS $UPS_NAME shutdown.stayoff 2>&1 | tee -a $LOGFILE +elif upscmd -l $UPS_NAME 2>/dev/null | grep -q "shutdown.return"; then + log_message " - Comanda UPS shutdown.return (oprire cu restart la revenire curent)..." + upscmd -u $UPS_USER -p $UPS_PASS $UPS_NAME shutdown.return 2>&1 | tee -a $LOGFILE +else + log_message " - WARNING: Nu s-a gasit comanda UPS shutdown disponibila" +fi + log_message "========================================" log_message "UPS SHUTDOWN ORCHESTRATION COMPLETED" +log_message "$(get_ups_info)" log_message "Local node will shutdown in 1 minute" log_message "========================================" -# Oprește nodul local (ultimul) -shutdown -h +1 "UPS on battery critical - primary node shutting down" +# Opreste nodul local (ultimul) +shutdown -h +1 "UPS battery critical - primary node shutting down" exit 0 diff --git a/proxmox/ups/scripts/upssched-cmd b/proxmox/ups/scripts/upssched-cmd index 99d15f0..1099746 100644 --- a/proxmox/ups/scripts/upssched-cmd +++ b/proxmox/ups/scripts/upssched-cmd @@ -1,30 +1,297 @@ #!/bin/bash # # Script apelat de upssched pentru a gestiona evenimentele UPS +# Trimite notificari email via PVE::Notify # +# Creat: 2025-10-06 +# Actualizat: 2026-01-13 - Adaugat notificari email LOGFILE=/var/log/ups-events.log +UPS_NAME="nutdev1" +TEMPLATE_DIR="/etc/pve/notification-templates/default" +HOSTNAME=$(hostname) +FQDN=$(hostname -f 2>/dev/null || hostname) log_event() { - echo "[2025-10-06 20:03:38] $1" >> $LOGFILE + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOGFILE } +# Obtine status UPS +get_ups_status() { + upsc $UPS_NAME ups.status 2>/dev/null || echo "UNKNOWN" +} + +get_battery_charge() { + upsc $UPS_NAME battery.charge 2>/dev/null || echo "0" +} + +get_input_voltage() { + upsc $UPS_NAME input.voltage 2>/dev/null || echo "0" +} + +get_battery_runtime() { + local runtime=$(upsc $UPS_NAME battery.runtime 2>/dev/null) + if [ -n "$runtime" ] && [ "$runtime" != "0" ]; then + echo $((runtime / 60)) + else + echo "" + fi +} + +# Creeaza template-uri daca nu exista +create_templates() { + mkdir -p $TEMPLATE_DIR + + cat > "$TEMPLATE_DIR/ups-power-event-subject.txt.hbs" << 'EOFTEMPLATE' +[{{ hostname }}] UPS {{ event_type }} - {{ event_title }} +EOFTEMPLATE + + cat > "$TEMPLATE_DIR/ups-power-event-body.txt.hbs" << 'EOFTEMPLATE' +======================================== +UPS POWER EVENT - {{ event_title }} +======================================== + +Hostname: {{ hostname }} +Date: {{ event_date }} +Event: {{ event_type }} + +{{ event_description }} + +UPS STATUS: +----------- +Status: {{ ups_status }} +Battery Charge: {{ battery_charge }}% +Input Voltage: {{ input_voltage }}V +{{#if battery_runtime}} +Battery Runtime: {{ battery_runtime }} min +{{/if}} + +{{#if action_taken}} +ACTION: {{ action_taken }} +{{/if}} + +{{#if next_steps}} +NEXT STEPS: {{ next_steps }} +{{/if}} + +======================================== +Log: /var/log/ups-events.log +======================================== +EOFTEMPLATE + + cat > "$TEMPLATE_DIR/ups-power-event-body.html.hbs" << 'EOFTEMPLATE' + + + + + + + +
+

[UPS] {{ event_title }}

+

Hostname: {{ hostname }}
+ Date: {{ event_date }}
+ Event: {{ event_type }}

+
+ {{ event_description }} +
+

UPS Status

+
+
+
Status
+
{{ ups_status }}
+
+
+
Battery
+
{{ battery_charge }}%
+
+
+
Input Voltage
+
{{ input_voltage }}V
+
+
+ {{#if action_taken}} +

Action: {{ action_taken }}

+ {{/if}} + {{#if next_steps}} +

Next Steps: {{ next_steps }}

+ {{/if}} + +
+ + +EOFTEMPLATE + + log_event "Templates created in $TEMPLATE_DIR/" +} + +# Trimite notificare email via PVE::Notify +send_notification() { + local EVENT_TYPE="$1" + local EVENT_TITLE="$2" + local EVENT_DESC="$3" + local EVENT_CLASS="$4" + local ALERT_TYPE="$5" + local SEVERITY="$6" + local ACTION="$7" + local NEXT_STEPS="$8" + + # Verifica si creeaza template-uri + if [ ! -f "$TEMPLATE_DIR/ups-power-event-subject.txt.hbs" ]; then + create_templates + fi + + # Obtine status UPS + local UPS_STATUS=$(get_ups_status) + local BATTERY_CHARGE=$(get_battery_charge) + local INPUT_VOLTAGE=$(get_input_voltage) + local BATTERY_RUNTIME=$(get_battery_runtime) + local EVENT_DATE=$(date '+%Y-%m-%d %H:%M:%S') + + log_event "Sending $SEVERITY notification: $EVENT_TITLE" + + perl -I/usr/share/perl5 << EOFPERL 2>&1 | tee -a $LOGFILE +use strict; +use warnings; +use PVE::Notify; + +my \$template_data = { + 'hostname' => '$FQDN', + 'event_date' => '$EVENT_DATE', + 'event_type' => '$EVENT_TYPE', + 'event_title' => '$EVENT_TITLE', + 'event_description' => '$EVENT_DESC', + 'event_class' => '$EVENT_CLASS', + 'alert_type' => '$ALERT_TYPE', + 'ups_status' => '$UPS_STATUS', + 'battery_charge' => '$BATTERY_CHARGE', + 'input_voltage' => '$INPUT_VOLTAGE', + 'battery_runtime' => '$BATTERY_RUNTIME', + 'action_taken' => '$ACTION', + 'next_steps' => '$NEXT_STEPS' +}; + +my \$fields = { + 'hostname' => '$HOSTNAME', + 'type' => 'ups-power-event' +}; + +eval { + PVE::Notify::notify('$SEVERITY', 'ups-power-event', \$template_data, \$fields); + print "Email notification sent successfully\\n"; +}; +if (\$@) { + print STDERR "Failed to send notification: \$@\\n"; +} +EOFPERL +} + +# Handler principal case $1 in + onbatt_start) + log_event "==========================================" + log_event "UPS EVENT: Trecere pe baterie - Timer 3 minute pornit" + logger -t upssched-cmd "UPS switched to battery - 3 minute timer started" + + send_notification \ + "ONBATT" \ + "Trecere pe baterie" \ + "UPS a trecut pe baterie! Daca curentul nu revine in 3 minute, se va initia shutdown-ul cluster-ului." \ + "onbatt" \ + "warning" \ + "warning" \ + "Timer 3 minute pornit" \ + "Asteptare revenire curent sau shutdown automat" + ;; + onbatt) - log_event "UPS EVENT: Pe baterie de 3 minute - Începe shutdown orchestrat" + log_event "==========================================" + log_event "UPS EVENT: Pe baterie de 3 minute - Incepe shutdown orchestrat" logger -t upssched-cmd "UPS on battery for 3 minutes - starting orchestrated shutdown" + + send_notification \ + "ONBATT_TIMEOUT" \ + "Pe baterie 3 min - SHUTDOWN" \ + "UPS a fost pe baterie timp de 3 minute. Se initiaza shutdown-ul orchestrat al cluster-ului." \ + "onbatt" \ + "danger" \ + "error" \ + "Pornire shutdown orchestrat cluster" \ + "Toate nodurile se vor opri in ordine" + /usr/local/bin/ups-shutdown-cluster.sh & ;; + + online) + log_event "==========================================" + log_event "UPS EVENT: Curent revenit - UPS online" + logger -t upssched-cmd "Power restored - UPS back online" + + send_notification \ + "ONLINE" \ + "Curent revenit - OK" \ + "Curentul electric a revenit. UPS functioneaza normal pe linia AC." \ + "online" \ + "success" \ + "info" \ + "Sistem stabil" \ + "Nicio actiune necesara" + ;; + lowbatt) - log_event "UPS EVENT: BATERIE SCĂZUTĂ - Shutdown IMEDIAT" + log_event "==========================================" + log_event "UPS EVENT: BATERIE SCAZUTA - Shutdown IMEDIAT" logger -t upssched-cmd "UPS LOW BATTERY - immediate shutdown" + + send_notification \ + "LOWBATT" \ + "BATERIE CRITICA - SHUTDOWN IMEDIAT" \ + "UPS raporteaza baterie critica! Shutdown imediat pentru protectia datelor." \ + "lowbatt" \ + "danger" \ + "error" \ + "Shutdown imediat cluster" \ + "Sistemele se opresc ACUM" + /usr/local/bin/ups-shutdown-cluster.sh & ;; + commbad) - log_event "UPS EVENT: Comunicație pierdută cu UPS de 30 secunde" + log_event "==========================================" + log_event "UPS EVENT: Comunicatie pierduta cu UPS de 30 secunde" logger -t upssched-cmd "Lost communication with UPS for 30 seconds" - # Nu facem shutdown automat pentru pierdere comunicație + + send_notification \ + "COMMBAD" \ + "Comunicatie pierduta cu UPS" \ + "Nu se poate comunica cu UPS-ul de 30 de secunde. Verificati conexiunea USB." \ + "commbad" \ + "warning" \ + "warning" \ + "Monitorizare activa" \ + "Verificati conexiunea fizica USB a UPS-ului" ;; + *) log_event "UPS EVENT: Eveniment necunoscut - $1" logger -t upssched-cmd "Unknown UPS event: $1"