Add UPS email notifications and automatic UPS shutdown
- Add email notifications via PVE::Notify for all UPS events: - ONBATT: when UPS switches to battery - ONLINE: when power is restored - LOWBATT: critical battery level - SHUTDOWN_START/NODE/PRIMARY: during cluster shutdown - COMMBAD: communication lost with UPS - Add automatic UPS shutdown command after cluster shutdown (protects against power surge when power returns) - Update upssched.conf with ONLINE handler and immediate ONBATT notification - Add notification templates for HTML and text emails - Update documentation with new features and timer configuration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; }
|
||||
.container { max-width: 600px; margin: 0 auto; background: white; padding: 25px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
|
||||
h1 { margin-top: 0; padding-bottom: 15px; border-bottom: 3px solid #3498db; }
|
||||
.status-onbatt { color: #e67e22; border-color: #e67e22; }
|
||||
.status-online { color: #27ae60; border-color: #27ae60; }
|
||||
.status-lowbatt { color: #c0392b; border-color: #c0392b; }
|
||||
.status-shutdown { color: #8e44ad; border-color: #8e44ad; }
|
||||
.alert-box { padding: 15px; border-radius: 5px; margin: 20px 0; border-left: 4px solid; }
|
||||
.alert-warning { background: #fef9e7; border-color: #f39c12; }
|
||||
.alert-danger { background: #fdedec; border-color: #e74c3c; }
|
||||
.alert-success { background: #eafaf1; border-color: #2ecc71; }
|
||||
.alert-info { background: #ebf5fb; border-color: #3498db; }
|
||||
.metrics { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 20px 0; }
|
||||
.metric { background: #ecf0f1; padding: 15px; border-radius: 5px; text-align: center; }
|
||||
.metric-label { font-size: 12px; color: #7f8c8d; text-transform: uppercase; }
|
||||
.metric-value { font-size: 24px; font-weight: bold; color: #2c3e50; margin-top: 5px; }
|
||||
.footer { margin-top: 25px; padding-top: 15px; border-top: 1px solid #ecf0f1; font-size: 12px; color: #7f8c8d; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="status-{{ event_class }}">[UPS] {{ event_title }}</h1>
|
||||
<p><strong>Hostname:</strong> {{ hostname }}<br>
|
||||
<strong>Date:</strong> {{ event_date }}<br>
|
||||
<strong>Event:</strong> {{ event_type }}</p>
|
||||
<div class="alert-box alert-{{ alert_type }}">
|
||||
<strong>{{ event_description }}</strong>
|
||||
</div>
|
||||
<h3>UPS Status</h3>
|
||||
<div class="metrics">
|
||||
<div class="metric">
|
||||
<div class="metric-label">Status</div>
|
||||
<div class="metric-value">{{ ups_status }}</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">Battery</div>
|
||||
<div class="metric-value">{{ battery_charge }}%</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-label">Input Voltage</div>
|
||||
<div class="metric-value">{{ input_voltage }}V</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if action_taken}}
|
||||
<p><strong>Action:</strong> {{ action_taken }}</p>
|
||||
{{/if}}
|
||||
{{#if next_steps}}
|
||||
<p><strong>Next Steps:</strong> {{ next_steps }}</p>
|
||||
{{/if}}
|
||||
<div class="footer">
|
||||
<p>Log: /var/log/ups-events.log<br>Proxmox UPS Monitoring</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user