#!/bin/bash # # Script apelat de upssched pentru a gestiona evenimentele UPS # Trimite notificari email via PVE::Notify # # Creat: 2025-10-06 # Actualizat: 2026-01-14 - Adaugat notificari periodice status baterie 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) BATTERY_MONITOR_PID="/run/nut/battery-monitor.pid" # Asigura ca fisierul de log exista si are permisiunile corecte # Scriptul ruleaza ca user 'nut', deci fisierul trebuie sa fie writable ensure_logfile() { if [ ! -f "$LOGFILE" ]; then touch "$LOGFILE" 2>/dev/null || sudo touch "$LOGFILE" fi if [ ! -w "$LOGFILE" ]; then sudo chown nut:nut "$LOGFILE" 2>/dev/null sudo chmod 664 "$LOGFILE" 2>/dev/null fi } ensure_logfile log_event() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOGFILE 2>/dev/null || \ logger -t upssched-cmd "LOG_FALLBACK: $1" } # 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 } get_battery_voltage() { upsc $UPS_NAME battery.voltage 2>/dev/null || echo "0" } get_ups_load() { upsc $UPS_NAME ups.load 2>/dev/null || echo "0" } # 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" /usr/bin/sudo /usr/bin/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 } # Porneste monitorizarea periodica a bateriei (la fiecare minut) start_battery_monitor() { # Opreste monitorul existent daca exista stop_battery_monitor log_event "Starting battery discharge monitor (every 60 seconds)" # Porneste procesul de monitorizare in background ( MINUTE=1 while true; do sleep 60 # Verifica daca UPS-ul e inca pe baterie STATUS=$(upsc $UPS_NAME ups.status 2>/dev/null) if [[ ! "$STATUS" =~ "OB" ]]; then log_event "Battery monitor: UPS no longer on battery, stopping monitor" break fi CHARGE=$(get_battery_charge) VOLTAGE=$(get_battery_voltage) RUNTIME=$(get_battery_runtime) LOAD=$(get_ups_load) log_event "Battery monitor: Minute $MINUTE - Charge: ${CHARGE}%, Voltage: ${VOLTAGE}V, Load: ${LOAD}%" send_notification \ "BATTERY_STATUS" \ "Status baterie - ${CHARGE}% (min $MINUTE)" \ "UPS pe baterie de $MINUTE minute. Baterie: ${CHARGE}%, Voltaj: ${VOLTAGE}V, Load: ${LOAD}%${RUNTIME:+, Runtime: ${RUNTIME} min}" \ "onbatt" \ "warning" \ "warning" \ "Monitorizare descarcare" \ "Se trimite status la fiecare minut" MINUTE=$((MINUTE + 1)) done rm -f $BATTERY_MONITOR_PID ) & echo $! > $BATTERY_MONITOR_PID log_event "Battery monitor started with PID $(cat $BATTERY_MONITOR_PID)" } # Opreste monitorizarea periodica a bateriei stop_battery_monitor() { if [ -f "$BATTERY_MONITOR_PID" ]; then PID=$(cat $BATTERY_MONITOR_PID) if [ -n "$PID" ] && kill -0 $PID 2>/dev/null; then log_event "Stopping battery monitor (PID $PID)" kill $PID 2>/dev/null # Asteapta putin si forteaza daca nu s-a oprit sleep 1 kill -9 $PID 2>/dev/null fi rm -f $BATTERY_MONITOR_PID fi } # Trimite status incarcare baterie send_charge_status() { local MINUTES="$1" local CHARGE=$(get_battery_charge) local VOLTAGE=$(get_battery_voltage) local INPUT=$(get_input_voltage) local LOAD=$(get_ups_load) log_event "Charge status at $MINUTES min: ${CHARGE}%, Voltage: ${VOLTAGE}V, Input: ${INPUT}V" send_notification \ "CHARGING_STATUS" \ "Incarcare baterie - ${CHARGE}% (+${MINUTES} min)" \ "Status incarcare la $MINUTES minute dupa revenirea curentului. Baterie: ${CHARGE}%, Voltaj baterie: ${VOLTAGE}V, Tensiune intrare: ${INPUT}V, Load: ${LOAD}%" \ "charging" \ "info" \ "info" \ "Monitorizare incarcare" \ "Bateria se incarca" } # 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" # Porneste monitorizarea periodica a bateriei start_battery_monitor ;; onbatt) 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" # Opreste monitorizarea - urmeaza shutdown stop_battery_monitor 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" # Opreste monitorizarea descarcarii stop_battery_monitor send_notification \ "ONLINE" \ "Curent revenit - OK" \ "Curentul electric a revenit. UPS functioneaza normal pe linia AC. Se vor trimite statusuri de incarcare la 5, 10 si 30 de minute." \ "online" \ "success" \ "info" \ "Sistem stabil" \ "Monitorizare incarcare activa" ;; charge_5min) log_event "==========================================" log_event "UPS EVENT: Status incarcare la 5 minute" send_charge_status "5" ;; charge_10min) log_event "==========================================" log_event "UPS EVENT: Status incarcare la 10 minute" send_charge_status "10" ;; charge_30min) log_event "==========================================" log_event "UPS EVENT: Status incarcare la 30 minute" send_charge_status "30" ;; lowbatt) log_event "==========================================" log_event "UPS EVENT: BATERIE SCAZUTA - Shutdown IMEDIAT" logger -t upssched-cmd "UPS LOW BATTERY - immediate shutdown" # Opreste monitorizarea stop_battery_monitor 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 "==========================================" log_event "UPS EVENT: Comunicatie pierduta cu UPS de 30 secunde" logger -t upssched-cmd "Lost communication with UPS for 30 seconds" 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" ;; esac