Reorganize proxmox documentation into subdirectories per LXC/VM

- Create cluster/ for Proxmox cluster infrastructure (SSH guide, HA monitor, UPS)
- Create lxc108-oracle/ for Oracle Database documentation and scripts
- Create vm201-windows/ for Windows 11 VM docs and SSL certificate scripts
- Add SSL certificate monitoring scripts (check-ssl-certificates.ps1, monitor-ssl-certificates.sh)
- Remove archived VM107 references (decommissioned)
- Update all cross-references between files
- Update main README.md with new structure and navigation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Marius
2026-01-27 17:02:49 +02:00
parent 1da4c2347c
commit 4d51d5b2d2
33 changed files with 954 additions and 593 deletions

View File

@@ -0,0 +1,464 @@
# Documentație UPS - Cluster Proxmox
## Despre
Această documentație descrie configurarea completă a sistemului UPS (Uninterruptible Power Supply) pentru cluster-ul Proxmox, incluzând monitorizare automată și shutdown orchestrat.
## Structură Directoare
```
proxmox/ups/
├── README.md # Acest fișier
├── config/ # Fișiere de configurare NUT
│ ├── ups.conf # Configurare driver UPS
│ ├── upsd.conf # Configurare server NUT
│ ├── upsd.users # Utilizatori și permisiuni
│ ├── upsmon.conf # Configurare monitor local
│ └── upssched.conf # Scheduler evenimente UPS
├── scripts/ # Scripturi de shutdown și testare
│ ├── ups-shutdown-cluster.sh # Script principal shutdown orchestrat
│ ├── ups-shutdown-test.sh # Script test (dry-run)
│ ├── upssched-cmd # Handler evenimente upssched
│ ├── ups-monthly-test.sh # Test lunar automat baterie
│ └── ups-maintenance-shutdown.sh # Shutdown pentru mentenanță UPS (NOU!)
└── docs/ # Documentație
├── INSTALARE-NUT.md # Ghid instalare NUT pe Proxmox
├── INSTALARE-WINNUT.md # Ghid instalare WinNUT pe Windows
├── UPS-SHUTDOWN-README.md # Documentație completă sistem
├── UPS-MONTHLY-TEST.md # Documentație test lunar baterie
└── UPS-BATTERY-REPLACEMENT.md # Procedură înlocuire baterie (NOU!)
```
🎯 Utilizare:
Pentru instalare nouă:
Citește README.md
Urmează docs/INSTALARE-NUT.md
Copiază fișiere din config/ și scripts/ pe server
Pentru backup:
Tot ce trebuie este salvat în proxmox/ups/
Versionat în Git
Pentru recovery:
Restaurează fișiere din config/ în /etc/nut/
Restaurează fișiere din scripts/ în /usr/local/bin/
Restart servicii
## Arhitectură Sistem
### Hardware
- **UPS:** INNO TECH USB to Serial (Vendor ID: 0665, Product ID: 5161)
- **Conectat la:** pvemini (10.0.20.201) via USB
- **Tip:** Voltronic/Megatec protocol (driver: nutdrv_qx)
### Cluster Proxmox
- **pvemini (10.0.20.201)** - Nod PRIMARY
- Are UPS-ul conectat fizic
- Rulează NUT server și driver
- Ultimul nod care se oprește
- **pve1 (10.0.20.200)** - Nod SECONDARY
- Se oprește primul în caz de baterie critică
- **pve2 (10.0.20.202)** - Nod SECONDARY
- Se oprește primul în caz de baterie critică
### Monitorizare
- **VM 201 (Windows 11)** - Monitorizare vizuală via WinNUT
- Afișează status UPS în timp real
- NU controlează shutdown-ul
## Flux Automat Shutdown
### Scenario 1: Întrerupere scurtă (< 3 minute)
1. Curent se întrerupe → UPS trece pe baterie (status: OB)
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. **📧 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 → **📧 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. **📧 Email: "BATERIE CRITICĂ - SHUTDOWN IMEDIAT"**
3. Shutdown **IMEDIAT** (fără timer)
4. Același flux de shutdown orchestrat ca mai sus
## Quick Start
### Pentru Administrator Nou
1. **Citește documentația:**
- Start: [`docs/UPS-SHUTDOWN-README.md`](docs/UPS-SHUTDOWN-README.md)
- Detalii NUT: [`docs/INSTALARE-NUT.md`](docs/INSTALARE-NUT.md)
- WinNUT: [`docs/INSTALARE-WINNUT.md`](docs/INSTALARE-WINNUT.md)
2. **Verifică status UPS:**
```bash
ssh root@10.0.20.201
upsc nutdev1
```
3. **Test dry-run:**
```bash
ssh root@10.0.20.201
/usr/local/bin/ups-shutdown-test.sh
cat /var/log/ups-shutdown-test.log
```
4. **Monitorizează în WinNUT:**
- Pornește WinNUT pe VM 201
- Verifică că se conectează la 10.0.20.201:3493
### Verificare Săptămânală
```bash
# Conectează-te la pvemini
ssh root@10.0.20.201
# Status UPS
upsc nutdev1 ups.status battery.charge input.voltage
# Status servicii
systemctl status nut-server nut-monitor
# Logs evenimente recente
tail -20 /var/log/ups-events.log
# Test dry-run
/usr/local/bin/ups-shutdown-test.sh
```
### Verificare Lunară
**🔋 Test Automat Baterie (1 ale lunii la 00:00):**
Scriptul `/opt/scripts/ups-monthly-test.sh` rulează automat lunar și:
- Testează capacitatea reală a bateriei
- Monitorizează scăderea charge și voltage
- Evaluează sănătatea bateriei (EXCELLENT/GOOD/FAIR/POOR)
- Trimite raport HTML prin email via PVE::Notify
**Verificare rezultat test:**
```bash
ssh root@10.0.20.201
# Vezi ultimul test
tail -50 /var/log/ups-monthly-test.log
# Rulare manuală (pentru testare)
/opt/scripts/ups-monthly-test.sh
```
**Documentație completă:** [`docs/UPS-MONTHLY-TEST.md`](docs/UPS-MONTHLY-TEST.md)
---
**Test fizic manual (opțional):**
- Deconectează UPS de la priză timp de 30 secunde
- Verifică că WinNUT detectează schimbarea (On Battery)
- Verifică logs: `tail -f /var/log/ups-events.log`
- Reconectează **înainte de 3 minute** pentru a evita shutdown
**Verificare SSH între noduri:**
```bash
ssh root@10.0.20.201
ssh root@10.0.20.200 "hostname"
ssh root@10.0.20.202 "hostname"
```
## Instalare de la Zero
### 1. Instalare NUT pe pvemini
```bash
# Instalare pachete
apt update
apt install -y nut nut-client nut-server
# Copiere fișiere de configurare
cd /path/to/ROMFASTSQL/proxmox/ups
scp config/* root@10.0.20.201:/etc/nut/
# Copiere scripturi shutdown
scp scripts/ups-shutdown-cluster.sh scripts/ups-shutdown-test.sh scripts/upssched-cmd root@10.0.20.201:/usr/local/bin/
ssh root@10.0.20.201 "chmod +x /usr/local/bin/ups-*.sh /usr/local/bin/upssched-cmd"
# Copiere script test lunar
scp scripts/ups-monthly-test.sh root@10.0.20.201:/opt/scripts/
ssh root@10.0.20.201 "chmod +x /opt/scripts/ups-monthly-test.sh"
# Configurare cron pentru test lunar
ssh root@10.0.20.201 "(crontab -l 2>/dev/null | grep -v ups-monthly-test; echo '# UPS Monthly Battery Test'; echo '0 0 1 * * /opt/scripts/ups-monthly-test.sh') | crontab -"
# Configurare permisiuni
ssh root@10.0.20.201 "chown nut:nut /etc/nut/ups*.conf /etc/nut/upsd.*"
ssh root@10.0.20.201 "chmod 640 /etc/nut/upsd.users"
# Pornire servicii
ssh root@10.0.20.201 "systemctl enable nut-server nut-monitor"
ssh root@10.0.20.201 "systemctl start nut-server nut-monitor"
# Verificare
ssh root@10.0.20.201 "upsc nutdev1"
```
### 2. Instalare WinNUT pe VM 201
Vezi ghid detaliat: [`docs/INSTALARE-WINNUT.md`](docs/INSTALARE-WINNUT.md)
```
Server: 10.0.20.201
Port: 3493
UPS: nutdev1
User: admin
Pass: parola99
Polling: 15
```
## Troubleshooting Rapid
### UPS nu răspunde
```bash
ssh root@10.0.20.201
# Verifică UPS conectat
lsusb | grep 0665
# Restart driver
upsdrvctl stop && upsdrvctl start
# Verifică status
upsc nutdev1
```
### WinNUT nu se conectează
1. **Verifică Polling Interval ≠ 0** (pune 15)
2. **Test port:**
```powershell
Test-NetConnection -ComputerName 10.0.20.201 -Port 3493
```
3. **Verifică server:**
```bash
ssh root@10.0.20.201 "ss -tulpn | grep 3493"
```
### Scriptul de shutdown nu funcționează
```bash
# Test SSH între noduri
ssh root@10.0.20.201 "ssh root@10.0.20.200 hostname"
# Dacă eșuează, reconfigurează SSH keys
ssh root@10.0.20.201
ssh-keygen -f /root/.ssh/known_hosts -R 10.0.20.200
ssh-keyscan -H 10.0.20.200 >> /root/.ssh/known_hosts
```
## Logs Important
| Fișier | Scop |
|--------|------|
| `/var/log/ups-shutdown.log` | Shutdown orchestrat real |
| `/var/log/ups-shutdown-test.log` | Test dry-run |
| `/var/log/ups-events.log` | Evenimente UPS (upssched) |
| `/var/log/ups-monthly-test.log` | **Test lunar baterie (NOU!)** |
| `journalctl -u nut-server` | Server NUT |
| `journalctl -u nut-monitor` | Monitor NUT |
## Comenzi Utile
```bash
# Status UPS complet
upsc nutdev1
# Doar câmpuri importante
upsc nutdev1 ups.status battery.charge input.voltage output.voltage
# Comenzi disponibile
upscmd -l nutdev1
# Conexiuni active NUT
ss -tnp | grep 3493
# Monitoring live
watch -n 2 'upsc nutdev1 ups.status battery.charge input.voltage'
# Test shutdown (DRY RUN - nu oprește nimic)
/usr/local/bin/ups-shutdown-test.sh
# Test lunar baterie (cu raport email)
/opt/scripts/ups-monthly-test.sh
# Verifică ultimul test lunar
tail -50 /var/log/ups-monthly-test.log
```
## Configurare Personalizată
### Modificare timp de asteptare (default: 3 minute)
Fisier: `/etc/nut/upssched.conf` pe pvemini
Linia relevanta:
```
AT ONBATT * START-TIMER onbatt 180
```
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
```
### Adăugare noduri noi în cluster
Editează `/usr/local/bin/ups-shutdown-cluster.sh`:
```bash
# Adaugă IP-ul noului nod
NODES=("10.0.20.200" "10.0.20.202" "10.0.20.XXX")
```
## Backup și Restore
### Backup configurație
```bash
# De pe stația locală
cd /path/to/ROMFASTSQL/proxmox/ups
# Backup configurație
ssh root@10.0.20.201 "tar czf /tmp/nut-backup.tar.gz /etc/nut/*.conf /usr/local/bin/ups*.sh /usr/local/bin/upssched-cmd"
scp root@10.0.20.201:/tmp/nut-backup.tar.gz ./nut-backup-$(date +%Y%m%d).tar.gz
```
### Restore configurație
```bash
# Extrage backup
tar xzf nut-backup-YYYYMMDD.tar.gz
# Copiază pe server
scp -r etc/nut/* root@10.0.20.201:/etc/nut/
scp usr/local/bin/* root@10.0.20.201:/usr/local/bin/
# Restart servicii
ssh root@10.0.20.201 "systemctl restart nut-server nut-monitor"
```
## Securitate
### Parole
**IMPORTANT:** Schimbă parolele default!
```bash
ssh root@10.0.20.201
nano /etc/nut/upsd.users
# Schimbă "parola99" cu ceva sigur
# Apoi restart:
systemctl restart nut-server
```
### Firewall
NUT portul 3493 trebuie accesibil din rețea locală. Dacă ai firewall:
```bash
# Permite port 3493 din subnet local
iptables -A INPUT -p tcp --dport 3493 -s 10.0.20.0/24 -j ACCEPT
```
## Suport și Documentație
- **NUT Official:** https://networkupstools.org/
- **NUT Documentation:** https://networkupstools.org/docs/user-manual.chunked/
- **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/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
- Test real capacitate baterie (comutare pe baterie ~10 secunde)
- Evaluare sănătate: EXCELLENT/GOOD/FAIR/POOR
- Rapoarte HTML + email prin PVE::Notify
- Recomandări automate pentru înlocuire baterie
- Log detaliat istoric teste
### ✅ Monitorizare Continuă
- WinNUT pe VM 201 (Windows 11) pentru vizualizare real-time
- NUT server pe pvemini expune date la toate nodurile
- Logging complet evenimente și teste
### ✅ Mentenanță Baterie (NOU!)
- Script automat shutdown orchestrat pentru înlocuire baterie
- Procedură pas-cu-pas completă cu checklist-uri
- Recovery procedures pentru probleme comune
- Documentație: [`docs/UPS-BATTERY-REPLACEMENT.md`](docs/UPS-BATTERY-REPLACEMENT.md)
## Autori și Istoric
- **Creat:** 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
## Licență
Documentația și scripturile sunt furnizate "as-is" fără garanție.
NUT și WinNUT sunt software open-source cu licențele lor respective.

View File

@@ -0,0 +1,73 @@
<!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>
{{#if battery_runtime}}
<div class="metric">
<div class="metric-label">Runtime</div>
<div class="metric-value">{{ battery_runtime }} min</div>
</div>
{{/if}}
</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 System</p>
</div>
</div>
</body>
</html>

View File

@@ -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
========================================

View File

@@ -0,0 +1 @@
[{{ hostname }}] UPS {{ event_type }} - {{ event_title }}

View File

@@ -0,0 +1,7 @@
[nutdev1]
driver = nutdrv_qx
port = auto
vendorid = 0665
productid = 5161
subdriver = cypress
desc = "UPS Cypress via USB"

View File

@@ -0,0 +1,170 @@
# Network UPS Tools: example upsd configuration file
#
# This file contains access control data, you should keep it secure.
#
# It should only be readable by the user that upsd becomes. See the FAQ.
#
# Each entry below provides usage and default value.
#
# For more information, refer to upsd.conf manual page.
# =======================================================================
# MAXAGE <seconds>
# MAXAGE 15
#
# This defaults to 15 seconds. After a UPS driver has stopped updating
# the data for this many seconds, upsd marks it stale and stops making
# that information available to clients. After all, the only thing worse
# than no data is bad data.
#
# You should only use this if your driver has difficulties keeping
# the data fresh within the normal 15 second interval. Watch the syslog
# for notifications from upsd about staleness.
# =======================================================================
# TRACKINGDELAY <seconds>
# TRACKINGDELAY 3600
#
# This defaults to 1 hour. When instant commands and variables setting status
# tracking is enabled, status execution information are kept during this
# amount of time, and then cleaned up.
# =======================================================================
# ALLOW_NO_DEVICE <Boolean>
# ALLOW_NO_DEVICE true
#
# Normally upsd requires that at least one device section is defined in ups.conf
# when the daemon starts, to serve its data. For automatically managed services
# it may be preferred to have upsd always running, and reload the configuration
# when power devices become defined.
#
# Boolean values 'true', 'yes', 'on' and '1' mean that the server would not
# refuse to start with zero device sections found in ups.conf.
#
# Boolean values 'false', 'no', 'off' and '0' mean that the server should refuse
# to start if zero device sections were found in ups.conf. This is the default.
# =======================================================================
# STATEPATH <path>
# STATEPATH /var/run/nut
#
# Tell upsd to look for the driver state sockets in 'path' rather
# than the default that was compiled into the program.
# =======================================================================
# LISTEN <IP address or name> [<port>]
# LISTEN 127.0.0.1 3493
# LISTEN ::1 3493
# LISTEN myhostname 83493
# LISTEN myhostname.mydomain
#
# This defaults to the localhost listening addresses and port 3493.
# In case of IP v4 or v6 disabled kernel, only the available one will be used.
#
# You may specify each interface IP address or name that you want upsd to
# listen on for connections, optionally with a port number.
#
# You may need this if you have multiple interfaces on your machine and
# you don't want upsd to listen to all interfaces (for instance on a
# firewall, you may not want to listen to the external interface).
#
# This will only be read at startup of upsd. If you make changes here,
# you'll need to restart upsd, reload will have no effect.
# =======================================================================
# MAXCONN <connections>
# MAXCONN 1024
#
# This defaults to maximum number allowed on your system. Each UPS, each
# LISTEN address and each client count as one connection. If the server
# runs out of connections, it will no longer accept new incoming client
# connections. Only set this if you know exactly what you're doing.
# =======================================================================
# CERTFILE <certificate file>
# CERTFILE /usr/local/ups/etc/upsd.pem
#
# When compiled with SSL support with OpenSSL backend,
# you can enter the certificate file here.
# The certificates must be in PEM format and must be sorted starting with
# the subject's certificate (server certificate), followed by intermediate
# CA certificates (if applicable_ and the highest level (root) CA. It should
# end with the server key. See 'docs/security.txt' or the Security chapter of
# NUT user manual for more information on the SSL support in NUT.
#
# See 'docs/security.txt' or the Security chapter of NUT user manual
# for more information on the SSL support in NUT.
# =======================================================================
# CERTPATH <certificate file or directory>
# CERTPATH /usr/local/ups/etc/cert/upsd
#
# When compiled with SSL support with NSS backend,
# you can enter the certificate path here.
# Certificates are stored in a dedicated database (split into 3 files).
# Specify the path of the database directory.
#
# See 'docs/security.txt' or the Security chapter of NUT user manual
# for more information on the SSL support in NUT.
# =======================================================================
# CERTIDENT <certificate name> <database password>
# CERTIDENT "my nut server" "MyPasSw0rD"
#
# When compiled with SSL support with NSS backend,
# you can specify the certificate name to retrieve from database to
# authenticate itself and the password
# required to access certificate related private key.
#
# See 'docs/security.txt' or the Security chapter of NUT user manual
# for more information on the SSL support in NUT.
# =======================================================================
# CERTREQUEST <certificate request level>
# CERTREQUEST REQUIRE
#
# When compiled with SSL support with NSS backend and client certificate
# validation (disabled by default, see 'docs/security.txt'),
# you can specify if upsd requests or requires client's' certificates.
# Possible values are :
# - 0 to not request to clients to provide any certificate
# - 1 to require to all clients a certificate
# - 2 to require to all clients a valid certificate
#
# See 'docs/security.txt' or the Security chapter of NUT user manual
# for more information on the SSL support in NUT.
# =======================================================================
# DISABLE_WEAK_SSL <Boolean>
# DISABLE_WEAK_SSL true
#
# Tell upsd to disable older/weak SSL/TLS protocols and ciphers.
#
# With relatively recent versions of OpenSSL or NSS it will be restricted
# to TLSv1.2 or better.
#
# Unless you have really ancient clients, you probably want to enable this.
# Currently disabled by default to ensure compatibility with existing setups.
# =======================================================================
# DEBUG_MIN <Integer>
# DEBUG_MIN 2
#
# Optionally specify a minimum debug level for `upsd` data daemon, e.g. for
# troubleshooting a deployment, without impacting foreground or background
# running mode directly, and without need to edit init-scripts or service
# unit definitions. Note that command-line option `-D` can only increase
# this verbosity level.
#
# NOTE: if the running daemon receives a `reload` command, presence of the
# `DEBUG_MIN NUMBER` value in the configuration file can be used to tune
# debugging verbosity in the running service daemon (it is recommended to
# comment it away or set the minimum to explicit zero when done, to avoid
# huge journals and I/O system abuse). Keep in mind that for this run-time
# tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files
# is applied instantly and overrides any previously set value, from file
# or CLI options, regardless of older logging level being higher or lower
# than the newly found number; a missing (or commented away) value however
# does not change the previously active logging verbosity.
LISTEN 127.0.0.1 3493
LISTEN 10.0.20.201 3493

View File

@@ -0,0 +1,80 @@
# Network UPS Tools: Example upsd.users
#
# This file sets the permissions for upsd - the UPS network daemon.
# Users are defined here, are given passwords, and their privileges are
# controlled here too. Since this file will contain passwords, keep it
# secure, with only enough permissions for upsd to read it.
# --------------------------------------------------------------------------
# Each user gets a section. To start a section, put the username in
# brackets on a line by itself. To set something for that user, specify
# it under that section heading. The username is case-sensitive, so
# admin and AdMiN are two different users.
#
# Possible settings:
#
# password: The user's password. This is case-sensitive.
#
# --------------------------------------------------------------------------
#
# actions: Let the user do certain things with upsd.
#
# Valid actions are:
#
# SET - change the value of certain variables in the UPS
# FSD - set the "forced shutdown" flag in the UPS
#
# --------------------------------------------------------------------------
#
# instcmds: Let the user initiate specific instant commands. Use "ALL"
# to grant all commands automatically. There are many possible
# commands, so use 'upscmd -l' to see what your hardware supports. Here
# are a few examples:
#
# test.panel.start - Start a front panel test
# test.battery.start - Start battery test
# test.battery.stop - Stop battery test
# calibrate.start - Start calibration
# calibrate.stop - Stop calibration
#
# --------------------------------------------------------------------------
#
# Example:
#
# [admin]
# password = mypass
# actions = SET
# instcmds = ALL
#
#
# --- Configuring for a user who can execute tests only
#
# [testuser]
# password = pass
# instcmds = test.battery.start
# instcmds = test.battery.stop
#
# --- Configuring for upsmon
#
# To add a user for your upsmon, use this example:
#
# [upsmon]
# password = pass
# upsmon primary
# or
# upsmon secondary
#
# The matching MONITOR line in your upsmon.conf would look like this:
#
# MONITOR myups@localhost 1 upsmon pass primary (or secondary)
#
# See comments in the upsmon.conf(.sample) file for details about this
# keyword and the difference of NUT secondary and primary systems.
[admin]
password = parola99
actions = SET
instcmds = ALL
upsmon master

View File

@@ -0,0 +1,466 @@
# Network UPS Tools: example upsmon configuration
#
# This file contains passwords, so keep it secure.
# --------------------------------------------------------------------------
# RUN_AS_USER <userid>
#
# By default, upsmon splits into two processes. One stays as root and
# waits to run the SHUTDOWNCMD. The other one switches to another userid
# and does everything else.
#
# The default unprivileged user is set at compile-time with the option
# 'configure --with-user=...'
#
# You can override it with '-u <user>' when starting upsmon, or just
# define it here for convenience.
#
# Note: if you plan to use the reload feature, this file (upsmon.conf)
# must be readable by this user! Since it contains passwords, DO NOT
# make it world-readable. Also, do not make it writable by the upsmon
# user, since it creates an opportunity for an attack by changing the
# SHUTDOWNCMD to something malicious.
#
# For best results, you should create a new normal user like "nutmon",
# and make it a member of a "nut" group or similar. Then specify it
# here and grant read access to the upsmon.conf for that group.
#
# This user should not have write access to upsmon.conf.
#
# RUN_AS_USER nut
# --------------------------------------------------------------------------
# MONITOR <system> <powervalue> <username> <password> ("primary"|"secondary")
#
# List systems you want to monitor. Not all of these may supply power
# to the system running upsmon, but if you want to watch it, it has to
# be in this section.
#
# You must have at least one of these declared.
#
# <system> is a UPS identifier in the form <upsname>@<hostname>[:<port>]
# like ups@localhost, su700@mybox, etc.
#
# Examples:
#
# - "su700@mybox" means a UPS called "su700" on a system called "mybox"
#
# - "fenton@bigbox:5678" is a UPS called "fenton" on a system called
# "bigbox" which runs upsd on port "5678".
#
# The UPS names like "su700" and "fenton" are set in your ups.conf
# in [brackets] which identify a section for a particular driver.
#
# If the ups.conf on host "doghouse" has a section called "snoopy", the
# identifier for it would be "snoopy@doghouse".
#
# <powervalue> is an integer - the number of power supplies that this UPS
# feeds on this system. Most personal computers only have one power supply,
# so this value is normally set to 1, while most modern servers have at least
# two. You need a pretty big or special box to have any other value here.
#
# You can also set this to 0 for a system that doesn't take any power
# from the MONITORed supply, which you still want to monitor (e.g. for an
# administrative workstation fed from a different circuit than the datacenter
# servers it monitors). Use <powervalue> if 0 when you want to hear about
# changes for a given UPS without shutting down when it goes critical.
#
# <username> and <password> must match an entry in that system's
# upsd.users. If your username is "upsmon" and your password is
# "blah", the upsd.users would look like this:
#
# [upsmon]
# password = blah
# upsmon primary # (or secondary)
#
# "primary" means this system will shutdown last, allowing the secondary
# systems time to shutdown first.
#
# "secondary" means this system shuts down immediately when power goes
# critical and less than MINSUPPLIES power sources have reliable input feeds.
#
# The general assumption is that the "primary" system is the one with direct
# connection to an UPS (such as serial or USB cable), so the primary system
# runs the NUT driver and 'upsd' server locally and can manage the device,
# and it would often tell the UPS to completely power itself off as a step
# in power-race avoidance (see POWERDOWNFLAG for details).
#
# Also, since the primary system stays up the longest, it suffers higher risks
# of ungraceful shutdown if the estimation of remaining runtime (or of the
# time it takes to shut down this system) was guessed wrong. By consequence,
# the "secondary" systems typically monitor the power environment state
# through the 'upsd' processes running on the remote (often "primary") systems
# and do not directly interact with an UPS (no local NUT drivers are running
# on the secondary systems). As such, secondaries typically shut down as
# soon as there is a sufficiently long power outage, or a low-battery alert
# from the UPS, or a loss of connection to the primary while the power was
# last known to be missing.
#
# This assumption and configuration can also make sense for networked UPSes,
# where a rack full of servers might overload the communications capacity
# of the networked management card on the UPS - in this case you might either
# reduce the 'snmp-ups' or 'netxml-ups' driver polling rate, or dedicate a
# "primary" server and set up the rest as "secondary" systems.
#
# In case of such large setups as mentioned above, beware also that shutdown
# times of the rack done all at once can substantially differ from smaller
# scale experiments with single-server shutdowns, since systems can compete
# for shared storage and other limited resources as they go down (and also
# not everyone may safely shut down simultaneously - e.g. a NAS or DB server
# would better go down after all its clients). You would be well served by
# higher-end UPSes with manageable thresholds to declare a critical state.
#
# Examples:
#
# MONITOR myups@bigserver 1 upswired blah primary
# MONITOR su700@server.example.com 1 upsmon secretpass secondary
# MONITOR nutdev1@localhost 1 upsmon pass primary # (or secondary)
# --------------------------------------------------------------------------
# MINSUPPLIES <num>
#
# Give the number of power supplies that must be receiving power to keep
# this system running. Most systems have one power supply, so you would
# put "1" in this field.
#
# Large/expensive server type systems usually have more, and can run with
# a few missing. Some of these can run with 2 out of 4, for example,
# so you'd set that to 2. The idea is to keep the box running as long
# as possible, right?
#
# Obviously you have to put the redundant supplies on different UPS circuits
# for this to make sense! See big-servers.txt in the docs subdirectory
# for more information and ideas on how to use this feature.
MINSUPPLIES 1
# --------------------------------------------------------------------------
# SHUTDOWNCMD "<command>"
#
# upsmon runs this command when the system needs to be brought down.
#
# This should work just about everywhere ... if it doesn't, well, change it,
# perhaps to a more complicated custom script.
#
# Note that while you experiment with the initial setup and want to test how
# your configuration reacts to power state changes and ultimately when power
# is reported to go critical, but do not want your system to actually turn
# off, consider setting the SHUTDOWNCMD temporarily to do something benign -
# such as posting a message with 'logger' or 'wall' or 'mailx'. Do be careful
# to plug the UPS back into the wall in a timely fashion.
SHUTDOWNCMD "/sbin/shutdown -h +0"
# --------------------------------------------------------------------------
# NOTIFYCMD <command>
#
# upsmon calls this to send messages when things happen
#
# This command is called with the full text of the message (from NOTIFYMSG)
# as one argument.
#
# The environment string NOTIFYTYPE will contain the type string of
# whatever caused this event to happen.
#
# The environment string UPSNAME will contain the name of the system/device
# that generated the change.
#
# Note that this is only called for NOTIFY events that have EXEC set with
# NOTIFYFLAG. See NOTIFYFLAG below for more details.
#
# Making this some sort of shell script might not be a bad idea.
# Alternately you can use the upssched program as your NOTIFYCMD for some
# more complex setups (e.g. to ease handling of notification storms).
# For more information and ideas, see docs/scheduling.txt
#
# Example:
# NOTIFYCMD /bin/notifyme
# --------------------------------------------------------------------------
# POLLFREQ <n>
#
# Polling frequency for normal activities, measured in seconds.
#
# Adjust this to keep upsmon from flooding your network, but don't make
# it too high or it may miss certain short-lived power events.
POLLFREQ 5
# --------------------------------------------------------------------------
# POLLFREQALERT <n>
#
# Polling frequency in seconds while UPS on battery.
#
# You can make this number lower than POLLFREQ, which will make updates
# faster when any UPS is running on battery. This is a good way to tune
# network load if you have a lot of these things running.
#
# The default is 5 seconds for both this and POLLFREQ.
POLLFREQALERT 5
# --------------------------------------------------------------------------
# HOSTSYNC - How long upsmon will wait before giving up on another upsmon
#
# The primary upsmon process uses this number when waiting for secondary
# systems to disconnect once it has set the forced shutdown (FSD) flag.
# If they don't disconnect after this many seconds, it goes on without them.
#
# Similarly, upsmon secondary processes wait up to this interval for the
# primary upsmon to set FSD when an UPS they are monitoring goes critical -
# that is, on battery and low battery. If the primary doesn't do its job,
# the secondaries will shut down anyway to avoid damage to the file systems.
#
# This "wait for FSD" is done to avoid races where the status changes
# to critical and back between polls by the primary.
HOSTSYNC 15
# --------------------------------------------------------------------------
# DEADTIME - Interval to wait before declaring a stale ups "dead"
#
# upsmon requires a UPS to provide status information every few seconds
# (see POLLFREQ and POLLFREQALERT) to keep things updated. If the status
# fetch fails, the UPS is marked stale. If it stays stale for more than
# DEADTIME seconds, the UPS is marked dead.
#
# A dead UPS that was last known to be on battery is assumed to have gone
# to a low battery condition. This may force a shutdown if it is providing
# a critical amount of power to your system.
#
# Note: DEADTIME should be a multiple of POLLFREQ and POLLFREQALERT.
# Otherwise you'll have "dead" UPSes simply because upsmon isn't polling
# them quickly enough. Rule of thumb: take the larger of the two
# POLLFREQ values, and multiply by 3.
DEADTIME 15
# --------------------------------------------------------------------------
# POWERDOWNFLAG - Flag file for forcing UPS shutdown on the primary system
#
# upsmon will create a file with this name in primary mode when it's time
# to shut down the load. You should check for this file's existence in
# your shutdown scripts and run 'upsdrvctl shutdown' if it exists, to tell
# the UPS(es) to power off.
#
# See the config-notes.txt file in the docs subdirectory for more information.
# Refer to the section:
# [[UPS_shutdown]] "Configuring automatic shutdowns for low battery events"
# or refer to the online version.
POWERDOWNFLAG /etc/killpower
# --------------------------------------------------------------------------
# NOTIFYMSG - change messages sent by upsmon when certain events occur
#
# You can change the default messages to something else if you like.
#
# NOTIFYMSG <notify type> "message"
#
# NOTIFYMSG ONLINE "UPS %s on line power"
# NOTIFYMSG ONBATT "UPS %s on battery"
# NOTIFYMSG LOWBATT "UPS %s battery is low"
# NOTIFYMSG FSD "UPS %s: forced shutdown in progress"
# NOTIFYMSG COMMOK "Communications with UPS %s established"
# NOTIFYMSG COMMBAD "Communications with UPS %s lost"
# NOTIFYMSG SHUTDOWN "Auto logout and shutdown proceeding"
# NOTIFYMSG REPLBATT "UPS %s battery needs to be replaced"
# NOTIFYMSG NOCOMM "UPS %s is unavailable"
# NOTIFYMSG NOPARENT "upsmon parent process died - shutdown impossible"
#
# Note that %s is replaced with the identifier of the UPS in question.
#
# Possible values for <notify type>:
#
# ONLINE : UPS is back online
# ONBATT : UPS is on battery
# LOWBATT : UPS has a low battery (if also on battery, it's "critical")
# FSD : UPS is being shutdown by the primary (FSD = "Forced Shutdown")
# COMMOK : Communications established with the UPS
# COMMBAD : Communications lost to the UPS
# SHUTDOWN : The system is being shutdown
# REPLBATT : The UPS battery is bad and needs to be replaced
# NOCOMM : A UPS is unavailable (can't be contacted for monitoring)
# NOPARENT : The process that shuts down the system has died (shutdown impossible)
# --------------------------------------------------------------------------
# NOTIFYFLAG - change behavior of upsmon when NOTIFY events occur
#
# By default, upsmon sends walls (global messages to all logged in users)
# and writes to the syslog when things happen. You can change this.
#
# NOTIFYFLAG <notify type> <flag>[+<flag>][+<flag>] ...
#
# NOTIFYFLAG ONLINE SYSLOG+WALL
# NOTIFYFLAG ONBATT SYSLOG+WALL
# NOTIFYFLAG LOWBATT SYSLOG+WALL
# NOTIFYFLAG FSD SYSLOG+WALL
# NOTIFYFLAG COMMOK SYSLOG+WALL
# NOTIFYFLAG COMMBAD SYSLOG+WALL
# NOTIFYFLAG SHUTDOWN SYSLOG+WALL
# NOTIFYFLAG REPLBATT SYSLOG+WALL
# NOTIFYFLAG NOCOMM SYSLOG+WALL
# NOTIFYFLAG NOPARENT SYSLOG+WALL
#
# Possible values for the flags:
#
# SYSLOG - Write the message in the syslog
# WALL - Write the message to all users on the system
# EXEC - Execute NOTIFYCMD (see above) with the message
# IGNORE - Don't do anything
#
# If you use IGNORE, don't use any other flags on the same line.
# --------------------------------------------------------------------------
# RBWARNTIME - replace battery warning time in seconds
#
# upsmon will normally warn you about a battery that needs to be replaced
# every 43200 seconds, which is 12 hours. It does this by triggering a
# NOTIFY_REPLBATT which is then handled by the usual notify structure
# you've defined above.
#
# If this number is not to your liking, override it here.
RBWARNTIME 43200
# --------------------------------------------------------------------------
# NOCOMMWARNTIME - no communications warning time in seconds
#
# upsmon will let you know through the usual notify system if it can't
# talk to any of the UPS entries that are defined in this file. It will
# trigger a NOTIFY_NOCOMM by default every 300 seconds unless you
# change the interval with this directive.
NOCOMMWARNTIME 300
# --------------------------------------------------------------------------
# FINALDELAY - last sleep interval before shutting down the system
#
# On a primary, upsmon will wait this long after sending the NOTIFY_SHUTDOWN
# before executing your SHUTDOWNCMD. If you need to do something in between
# those events, increase this number. Remember, at this point your UPS is
# almost depleted, so don't make this too high. If needed, on high-end UPS
# devices you can usually configure when the low-battery state is announced
# based on estimated remaining run-time or on charge level of the batteries.
#
# Alternatively, you can set this very low so you don't wait around when
# it's time to shut down. Some UPSes don't give much warning for low
# battery and will require a value of 0 here for a safe shutdown.
#
# Note: If FINALDELAY on the secondary is greater than HOSTSYNC on the
# primary, the primary will give up waiting for that secondary system
# to disconnect.
FINALDELAY 5
# --------------------------------------------------------------------------
# CERTPATH - path to certificates (database directory or directory with CA's)
#
# When compiled with SSL support, you can enter the certificate path here.
#
# With NSS:
# Certificates are stored in a dedicated database (split into 3 files).
# Specify the path of the database directory.
#
# CERTPATH /etc/nut/cert/upsmon
#
# With OpenSSL:
# Directory containing CA certificates in PEM format, used to verify
# the server certificate presented by the upsd server. The files each
# contain one CA certificate. The files are looked up by the CA subject
# name hash value, which must hence be available.
#
# CERTPATH /usr/ssl/certs
#
# See 'docs/security.txt' or the Security chapter of NUT user manual
# for more information on the SSL support in NUT.
# --------------------------------------------------------------------------
# CERTIDENT - self certificate name and database password
# CERTIDENT <certificate name> <database password>
#
# When compiled with SSL support with NSS, you can specify the certificate
# name to retrieve from database to authenticate itself and the password
# required to access certificate related private key.
#
# CERTIDENT "my nut monitor" "MyPasSw0rD"
#
# See 'docs/security.txt' or the Security chapter of NUT user manual
# for more information on the SSL support in NUT.
# --------------------------------------------------------------------------
# CERTHOST - security properties for an host
# CERTHOST <hostname> <certificate name> <certverify> <forcessl>
#
# When compiled with SSL support with NSS, you can specify security directive
# for each server you can contact.
# Each entry maps server name with the expected certificate name and flags
# indicating if the server certificate is verified and if the connection
# must be secure.
#
# CERTHOST localhost "My nut server" 1 1
#
# See 'docs/security.txt' or the Security chapter of NUT user manual
# for more information on the SSL support in NUT.
# --------------------------------------------------------------------------
# CERTVERIFY - make upsmon verify all connections with certificates
# CERTVERIFY 1
#
# When compiled with SSL support, make upsmon verify all connections with
# certificates.
# Without this, there is no guarantee that the upsd is the right host.
# Enabling this greatly reduces the risk of man in the middle attacks.
# This effectively forces the use of SSL, so don't use this unless
# all of your upsd hosts are ready for SSL and have their certificates
# in order.
# When compiled with NSS support of SSL, can be overridden for host
# specified with a CERTHOST directive.
# --------------------------------------------------------------------------
# FORCESSL - force upsmon to use SSL
# FORCESSL 1
#
# When compiled with SSL, specify that a secured connection must be used
# to communicate with upsd.
# If you don't use 'CERTVERIFY 1', then this will at least make sure
# that nobody can sniff your sessions without a large effort. Setting
# this will make upsmon drop connections if the remote upsd doesn't
# support SSL, so don't use it unless all of them have it running.
# When compiled with NSS support of SSL, can be overridden for host
# specified with a CERTHOST directive.
# --------------------------------------------------------------------------
# DEBUG_MIN - specify minimal debugging level for upsmon daemon
# e.g. DEBUG_MIN 6
#
# Optionally specify a minimum debug level for `upsmon` daemon, e.g. for
# troubleshooting a deployment, without impacting foreground or background
# running mode directly, and without need to edit init-scripts or service
# unit definitions. Note that command-line option `-D` can only increase
# this verbosity level.
#
# NOTE: if the running daemon receives a `reload` command, presence of the
# `DEBUG_MIN NUMBER` value in the configuration file can be used to tune
# debugging verbosity in the running service daemon (it is recommended to
# comment it away or set the minimum to explicit zero when done, to avoid
# huge journals and I/O system abuse). Keep in mind that for this run-time
# tuning, the `DEBUG_MIN` value *present* in *reloaded* configuration files
# is applied instantly and overrides any previously set value, from file
# or CLI options, regardless of older logging level being higher or lower
# than the newly found number; a missing (or commented away) value however
# does not change the previously active logging verbosity.
# Monitorizare UPS - înlocuiește cu numele tău de UPS și credențialele
MONITOR nutdev1@localhost 1 admin parola99 master
# Folosește upssched pentru notificări
NOTIFYCMD /usr/sbin/upssched
# Activează notificările cu EXEC pentru a triggera upssched
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYFLAG COMMOK SYSLOG+WALL+EXEC
NOTIFYFLAG COMMBAD SYSLOG+WALL+EXEC

View File

@@ -0,0 +1,33 @@
# Configurare upssched pentru shutdown orchestrat cluster Proxmox
#
# Acest fișier definește acțiuni temporale pentru evenimente UPS
# Actualizat: 2026-01-14 - Adaugat notificari periodice status baterie
CMDSCRIPT /usr/local/bin/upssched-cmd
PIPEFN /run/nut/upssched.pipe
LOCKFN /run/nut/upssched.lock
# Când UPS trece pe baterie (ONBATT):
# 1. Trimite notificare imediată + pornește monitorizare periodică
# 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):
# 1. Anulează timer-ul de shutdown
# 2. Trimite notificare + pornește monitorizare încărcare
# 3. Notificări la 5, 10, 30 minute pentru a vedea încărcarea
AT ONLINE * CANCEL-TIMER onbatt
AT ONLINE * EXECUTE online
AT ONLINE * START-TIMER charge_5min 300
AT ONLINE * START-TIMER charge_10min 600
AT ONLINE * START-TIMER charge_30min 1800
# Când comunicația cu UPS se pierde (COMMBAD), așteaptă 30 secunde
AT COMMBAD * START-TIMER commbad 30
# Când comunicația este restabilită (COMMOK), anulează timer-ul
AT COMMOK * CANCEL-TIMER commbad

View File

@@ -0,0 +1,460 @@
# Instalare și Configurare NUT (Network UPS Tools) pe Proxmox
## Despre
Acest ghid descrie instalarea și configurarea NUT (Network UPS Tools) pe un cluster Proxmox pentru monitorizare UPS și shutdown orchestrat automat.
## Arhitectură
- **Nod PRIMARY (pvemini - 10.0.20.201):** Are UPS-ul conectat fizic via USB, rulează NUT server și driver
- **Noduri SECONDARY (pve1, pve2):** Pot monitoriza UPS-ul prin rețea (opțional)
- **VM 201 (Windows 11):** Monitorizare vizuală prin WinNUT client
## Prerequisite
- Proxmox VE instalat
- UPS conectat via USB la nodul primary
- Acces root la noduri
## 1. Instalare NUT pe Nodul PRIMARY
### 1.1. Instalare pachete
```bash
apt update
apt install -y nut nut-client nut-server
```
### 1.2. Detectare UPS
```bash
# Listează dispozitive USB
lsusb
# Exemple output:
# Bus 001 Device 002: ID 0665:5161 Cypress Semiconductor USB to Serial
# Verifică dacă kernel-ul a detectat UPS-ul
dmesg | grep -i ups
dmesg | grep -i hid
```
### 1.3. Testare driver NUT
```bash
# Caută driver potrivit pentru UPS-ul tău
nut-scanner -U
# sau
nut-scanner --usb_scan
```
## 2. Configurare NUT
### 2.1. Configurare Driver UPS (`/etc/nut/ups.conf`)
Creează configurația pentru UPS:
```bash
cat > /etc/nut/ups.conf << 'EOF'
[nutdev1]
driver = nutdrv_qx
port = auto
vendorid = 0665
productid = 5161
subdriver = cypress
desc = "UPS Cypress via USB"
EOF
```
**Note:**
- Înlocuiește `vendorid` și `productid` cu valorile de la `lsusb`
- Driver-ul `nutdrv_qx` funcționează pentru majoritatea UPS-urilor Voltronic/Megatec/Q1
- Alte drivere comune: `usbhid-ups`, `blazer_usb`, `nutdrv_qx`
### 2.2. Configurare Server NUT (`/etc/nut/upsd.conf`)
```bash
cat >> /etc/nut/upsd.conf << 'EOF'
# Ascultă pe localhost pentru monitorul local
LISTEN 127.0.0.1 3493
# Ascultă pe IP-ul nodului pentru clienți din rețea
LISTEN 10.0.20.201 3493
EOF
```
**Note:**
- Înlocuiește `10.0.20.201` cu IP-ul nodului tău PRIMARY
- Portul default NUT este 3493
### 2.3. Configurare Utilizatori (`/etc/nut/upsd.users`)
```bash
cat > /etc/nut/upsd.users << 'EOF'
[admin]
password = parola99
actions = SET
instcmds = ALL
upsmon master
EOF
```
**IMPORTANT:** Schimbă parola `parola99` cu ceva sigur!
### 2.4. Configurare Monitor Local (`/etc/nut/upsmon.conf`)
Editează `/etc/nut/upsmon.conf` și adaugă:
```bash
# Monitorizare UPS local
MONITOR nutdev1@localhost 1 admin parola99 master
# Folosește upssched pentru notificări
NOTIFYCMD /usr/sbin/upssched
# Activează notificările cu EXEC pentru evenimente
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYFLAG COMMOK SYSLOG+WALL+EXEC
NOTIFYFLAG COMMBAD SYSLOG+WALL+EXEC
```
**Note:**
- `master` = acest nod controlează UPS-ul (va fi ultimul care se închide)
- `1` = powervalue (câte surse de alimentare alimentează acest UPS)
### 2.5. Configurare NUT Mode (`/etc/nut/nut.conf`)
```bash
cat > /etc/nut/nut.conf << 'EOF'
MODE=netserver
EOF
```
Moduri disponibile:
- `none` - NUT dezactivat
- `standalone` - Doar local, fără rețea
- `netserver` - Server + local (recomandat pentru PRIMARY)
- `netclient` - Doar client (pentru noduri SECONDARY)
## 3. Pornire Servicii
### 3.1. Pornire driver UPS
```bash
upsdrvctl start
```
Ar trebui să vezi:
```
Network UPS Tools - UPS driver controller 2.8.0
Network UPS Tools - Megatec/Q1 protocol USB driver 0.32 (2.8.0)
Using subdriver: Cypress 0.10
```
### 3.2. Pornire server NUT
```bash
systemctl enable nut-server
systemctl start nut-server
systemctl status nut-server
```
### 3.3. Pornire monitor NUT
```bash
systemctl enable nut-monitor
systemctl start nut-monitor
systemctl status nut-monitor
```
## 4. Verificare Funcționare
### 4.1. Test status UPS
```bash
# Listează UPS-uri disponibile
upsc -l
# Afișează toate informațiile despre UPS
upsc nutdev1
# Doar status
upsc nutdev1 ups.status
# Baterie
upsc nutdev1 battery.charge
upsc nutdev1 battery.voltage
# Tensiuni
upsc nutdev1 input.voltage
upsc nutdev1 output.voltage
```
### 4.2. Verificare conexiuni
```bash
# Verifică dacă upsd ascultă pe portul 3493
ss -tulpn | grep 3493
# Ar trebui să vezi:
# tcp LISTEN 0 16 127.0.0.1:3493 0.0.0.0:*
# tcp LISTEN 0 16 10.0.20.201:3493 0.0.0.0:*
```
### 4.3. Test de pe alt sistem
```bash
# De pe un alt nod sau sistem:
upsc nutdev1@10.0.20.201
```
## 5. Configurare Scheduler Evenimente (upssched)
### 5.1. Creare `/etc/nut/upssched.conf`
```bash
cat > /etc/nut/upssched.conf << 'EOF'
CMDSCRIPT /usr/local/bin/upssched-cmd
PIPEFN /run/nut/upssched.pipe
LOCKFN /run/nut/upssched.lock
# UPS pe baterie - așteaptă 180 secunde (3 minute)
AT ONBATT * START-TIMER onbatt 180
# Baterie scăzută - acțiune imediată
AT LOWBATT * EXECUTE lowbatt
# Curent revenit - anulează timer
AT ONLINE * CANCEL-TIMER onbatt
# Comunicație pierdută - așteaptă 30 secunde
AT COMMBAD * START-TIMER commbad 30
# Comunicație restabilită
AT COMMOK * CANCEL-TIMER commbad
EOF
```
### 5.2. Creare handler script
Copiaza scriptul `upssched-cmd` din directorul `scripts/` in `/usr/local/bin/`:
```bash
cp scripts/upssched-cmd /usr/local/bin/
chmod +x /usr/local/bin/upssched-cmd
```
### 5.3. Configurare sudo pentru user nut
Scripturile ruleaza ca user `nut` si au nevoie de sudo pentru a accesa PVE::Notify:
```bash
# Instaleaza sudo daca nu exista
apt-get install -y sudo
# Configureaza permisiuni sudo pentru user nut
cat > /etc/sudoers.d/nut << 'EOF'
nut ALL=(root) NOPASSWD: /usr/bin/perl
EOF
chmod 440 /etc/sudoers.d/nut
```
### 5.4. Configurare permisiuni fisiere log
Fisierele de log trebuie sa fie writable de user-ul `nut`:
```bash
touch /var/log/ups-events.log /var/log/ups-shutdown.log
chown nut:nut /var/log/ups-events.log /var/log/ups-shutdown.log
chmod 664 /var/log/ups-events.log /var/log/ups-shutdown.log
```
### 5.5. Creare director runtime
```bash
mkdir -p /run/nut
chown nut:nut /run/nut
chmod 770 /run/nut
```
## 6. Instalare Scripturi Shutdown Orchestrat
### 6.1. Copiere scripturi
```bash
# Script principal de shutdown
cp scripts/ups-shutdown-cluster.sh /usr/local/bin/
chmod +x /usr/local/bin/ups-shutdown-cluster.sh
# Script de test (dry-run)
cp scripts/ups-shutdown-test.sh /usr/local/bin/
chmod +x /usr/local/bin/ups-shutdown-test.sh
```
### 6.2. Editare noduri în script
Editează `/usr/local/bin/ups-shutdown-cluster.sh` și verifică:
```bash
NODES=("10.0.20.200" "10.0.20.202") # IP-urile nodurilor SECONDARY
```
### 6.3. Configurare SSH între noduri
Pentru ca scriptul să funcționeze, trebuie ca nodul PRIMARY să poată face SSH pe nodurile SECONDARY fără parolă:
```bash
# Generează SSH key dacă nu există
ssh-keygen -t ed25519 -N "" -f /root/.ssh/id_ed25519
# Copiază cheia pe nodurile SECONDARY
ssh-copy-id root@10.0.20.200
ssh-copy-id root@10.0.20.202
# Test conexiune
ssh root@10.0.20.200 "hostname"
ssh root@10.0.20.202 "hostname"
```
## 7. Testare
### 7.1. Test dry-run
```bash
/usr/local/bin/ups-shutdown-test.sh
cat /var/log/ups-shutdown-test.log
```
### 7.2. Test simulare UPS pe baterie (ATENȚIE!)
**⚠️ PERICOL:** Acest test va iniția shutdown real dacă îl lași să ruleze 3 minute!
```bash
# Monitorizează logs
tail -f /var/log/ups-events.log &
# Deconectează fizic UPS-ul de la priză
# Așteaptă 10-30 secunde
# Verifică că logs-urile arată "ONBATT"
# RECONECTEAZĂ UPS-ul înainte de 3 minute!
# Verifică că timer-ul a fost anulat
journalctl -u nut-monitor -f
```
## 8. Troubleshooting
### 8.1. Driver-ul nu pornește
```bash
# Verifică permisiuni USB
ls -la /dev/bus/usb/*/*
# Driver manual cu debug
/lib/nut/nutdrv_qx -a nutdev1 -DDDDD
# Verifică logs
journalctl -u nut-driver@nutdev1 -f
```
### 8.2. Server nu pornește
```bash
# Verifică configurația
upsd -c reload
# Debug mode
upsd -D
# Logs
journalctl -u nut-server -f
```
### 8.3. Monitor nu se conectează
```bash
# Verifică parola în upsd.users
cat /etc/nut/upsd.users
# Verifică MONITOR line în upsmon.conf
grep "^MONITOR" /etc/nut/upsmon.conf
# Test manual
upsmon -D
```
### 8.4. UPS nu răspunde
```bash
# Reload driver
upsdrvctl stop
upsdrvctl start
# Verifică comunicația USB
lsusb -v -d 0665:5161
```
## 9. Logs și Monitorizare
### Logs importante:
```bash
/var/log/ups-shutdown.log # Shutdown orchestrat real
/var/log/ups-shutdown-test.log # Test dry-run
/var/log/ups-events.log # Evenimente UPS (upssched)
journalctl -u nut-server # Server NUT
journalctl -u nut-monitor # Monitor NUT
journalctl -u nut-driver@nutdev1 # Driver UPS
```
### Comenzi utile:
```bash
# Status complet UPS
upsc nutdev1
# Comenzi disponibile
upscmd -l nutdev1
# Variabile disponibile
upsc nutdev1 | grep -E "battery|input|output|ups.status"
# Monitorizare în timp real
watch -n 2 'upsc nutdev1 ups.status battery.charge input.voltage'
```
## 10. Întreținere
### Zilnic/Săptămânal:
```bash
# Verifică status UPS
upsc nutdev1 ups.status battery.charge
# Verifică servicii
systemctl status nut-server nut-monitor
```
### Lunar:
```bash
# Test dry-run
/usr/local/bin/ups-shutdown-test.sh
# Test fizic (deconectare scurtă < 1 min)
```
### Anual:
```bash
# Test complet de baterie pe UPS
# Backup înainte de test!
```
## Referințe
- Documentație oficială NUT: https://networkupstools.org/
- Lista drivere compatibile: https://networkupstools.org/stable-hcl.html
- NUT Users Manual: https://networkupstools.org/docs/user-manual.chunked/index.html
- Troubleshooting Guide: https://networkupstools.org/docs/user-manual.chunked/ar01s07.html

View File

@@ -0,0 +1,376 @@
# Instalare și Configurare WinNUT pe Windows 11 (VM 201)
## Despre
WinNUT este un client NUT (Network UPS Tools) pentru Windows care permite monitorizarea vizuală a unui UPS conectat la un server NUT remote (în cazul nostru, pvemini).
**IMPORTANT:** WinNUT este folosit DOAR pentru monitorizare vizuală. Shutdown-ul automat este gestionat de scripturile de pe Proxmox.
## Prerequisite
- Windows 11 (VM 201 pe pvemini)
- Server NUT funcțional pe pvemini (10.0.20.201)
- Conectivitate rețea către serverul NUT (port 3493)
## 1. Descărcare WinNUT
### Opțiunea 1: GitHub Releases (Recomandat)
1. Deschide browser în VM 201
2. Accesează: https://github.com/gawindx/WinNUT-V2/releases
3. Descarcă ultima versiune (ex: `WinNUT-v2.x.x-Setup.exe`)
### Opțiunea 2: Build from source (Opțional)
```powershell
# Clonează repository
git clone https://github.com/gawindx/WinNUT-V2.git
cd WinNUT-V2
# Urmează instrucțiunile de build din README
```
## 2. Instalare WinNUT
### 2.1. Rulare instalator
1. Rulează `WinNUT-v2.x.x-Setup.exe` ca Administrator
2. Acceptă UAC prompt
3. Alege directorul de instalare (implicit: `C:\Program Files\WinNUT`)
4. Finalizează instalarea
### 2.2. Verificare instalare
WinNUT ar trebui să pornească automat după instalare. Icon-ul va apărea în system tray.
## 3. Configurare WinNUT
### 3.1. Deschidere fereastră Options
- Click dreapta pe icon-ul WinNUT din system tray
- Selectează **"Options"** sau dublu-click pe icon
### 3.2. Tab Connection
Configurează următoarele:
| Câmp | Valoare | Descriere |
|------|---------|-----------|
| **NUT host** | `10.0.20.201` | IP-ul serverului NUT (pvemini) |
| **NUT Port** | `3493` | Portul default NUT |
| **UPS Name** | `nutdev1` | Numele UPS-ului (din ups.conf) |
| **Polling Interval** | `15` | Interval de polling în secunde (NU pune 0!) |
| **Login** | `admin` | Username (din upsd.users) |
| **Password** | `parola99` | Parola (din upsd.users) |
| **Re-establish connection** | ☑ Checked | Reconectare automată |
**IMPORTANT:**
- **Polling Interval** trebuie să fie > 0 (recomandat: 15)
- Dacă Polling Interval = 0, WinNUT nu se va conecta!
### 3.3. Tab Calibration
Lasă valorile default sau ajustează după preferințe pentru afișarea gauge-urilor.
### 3.4. Tab Miscellaneous
Configurări opționale:
-**Start with Windows** - Pornire automată
-**Minimize to tray** - Minimizare în system tray
-**Sound alerts** - Alerte sonore (opțional)
### 3.5. Tab Shutdown Options
**⚠️ IMPORTANT:** NU configura shutdown options în WinNUT!
Shutdown-ul este gestionat automat de scripturile de pe Proxmox. WinNUT este doar pentru monitorizare.
Lasă toate opțiunile de shutdown dezactivate:
- ☐ Shutdown on battery
- ☐ Shutdown on low battery
- ☐ Force shutdown
### 3.6. Salvare configurație
1. Click **OK** pentru a salva
2. WinNUT se va reconecta automat la serverul NUT
3. În câteva secunde, ar trebui să vezi datele UPS-ului
## 4. Verificare Funcționare
### 4.1. Fereastră principală
După conectare cu succes, ar trebui să vezi:
**Gauge-uri (indicatoare circulare):**
- **Input Voltage** (Tensiune intrare): ~230V
- **Output Voltage** (Tensiune ieșire): ~230V
- **Frequency** (Frecvență): ~50Hz
- **Battery Charge** (Încărcare baterie): 0-100%
- **Battery Voltage** (Tensiune baterie): ~24V (depinde de UPS)
- **UPS Load** (Sarcină UPS): 0-100%
**Status checkboxes:**
-**UPS On Line** - UPS pe curent electric (normal)
-**UPS On Battery** - UPS pe baterie (întrerupere curent)
-**UPS Overload** - UPS supraîncărcat
-**UPS Battery Low** - Baterie scăzută
**Informații suplimentare:**
- **Manufacturer:** (producător UPS)
- **Name:** nutdev1
- **Serial:** (număr serie)
- **Firmware:** (versiune firmware)
### 4.2. System tray icon
- **Verde:** UPS On Line (normal)
- **Galben:** UPS On Battery (atenție)
- **Roșu:** UPS Battery Low (critic)
### 4.3. Mesaj reconectare
În partea de jos a ferestrei vezi:
```
[id 4: 10/6/2025 7:56:48 PM] Try Reconnect 1 / 30
```
Dacă vezi acest mesaj constant:
1. Verifică configurația Connection (mai ales Polling Interval)
2. Verifică conectivitatea rețea (ping 10.0.20.201)
3. Verifică că serverul NUT rulează pe pvemini
## 5. Testare
### 5.1. Test conectivitate din PowerShell
```powershell
# Test ping
Test-NetConnection -ComputerName 10.0.20.201 -Port 3493
# Ar trebui să vezi:
# TcpTestSucceeded : True
```
### 5.2. Test simulare UPS pe baterie
1. Deconectează fizic UPS-ul de la priză (pe pvemini)
2. Observă în WinNUT:
- Checkbox **"UPS On Battery"** devine ☑
- Icon în system tray devine galben
- Input voltage scade
- Battery charge începe să scadă
3. Reconectează UPS-ul
4. Observă că status revine la **"UPS On Line"**
**NU lăsa UPS-ul pe baterie mai mult de 3 minute** - se va declanșa shutdown automat!
## 6. Troubleshooting
### 6.1. WinNUT nu se conectează
**Verificări:**
1. **Polling Interval = 0?**
- Schimbă la 15 secunde
- Click OK și așteaptă 10-20 secunde
2. **Firewall blochează portul 3493?**
```powershell
# Test port
Test-NetConnection -ComputerName 10.0.20.201 -Port 3493
```
3. **Server NUT nu rulează?**
- SSH pe pvemini:
```bash
systemctl status nut-server
ss -tulpn | grep 3493
```
4. **Date de autentificare greșite?**
- Verifică username/password din Options
- Compară cu `/etc/nut/upsd.users` de pe pvemini
5. **Nume UPS greșit?**
- Verifică că UPS Name = `nutdev1`
- Listează UPS-uri disponibile:
```bash
ssh root@10.0.20.201 "upsc -l"
```
### 6.2. WinNUT se conectează dar nu afișează date
1. **Restart WinNUT:**
- Click dreapta → Exit
- Pornește WinNUT din nou
2. **Verifică permisiuni:**
- Username `admin` trebuie să existe în `/etc/nut/upsd.users`
3. **Verifică logs pe server:**
```bash
ssh root@10.0.20.201 "journalctl -u nut-server -n 50"
```
### 6.3. Icon-ul lipsește din system tray
1. Deschide **Settings → Personalization → Taskbar**
2. Click pe **"Taskbar corner overflow"**
3. Activează **WinNUT**
### 6.4. Eroare "Connection refused"
**Pe pvemini, verifică:**
```bash
# Server ascultă pe IP-ul corect?
ss -tulpn | grep 3493
# Firewall permite trafic?
iptables -L INPUT -n | grep 3493
# Restart server
systemctl restart nut-server
```
## 7. Configurare Avansată
### 7.1. Monitorizare multiple UPS-uri
WinNUT poate monitoriza un singur UPS. Pentru multiple UPS-uri:
- Rulează multiple instanțe WinNUT (necesită build custom)
- Folosește alte tool-uri (NUT-Monitor, upsc via SSH)
### 7.2. Export date UPS
WinNUT nu are funcție de export built-in. Pentru logging:
**Opțiunea 1: PowerShell script**
```powershell
# Script simplu de logging UPS via SSH
while ($true) {
$status = ssh root@10.0.20.201 "upsc nutdev1 ups.status battery.charge input.voltage"
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp - $status" | Out-File -Append C:\UPS-Logs\ups-log.txt
Start-Sleep -Seconds 60
}
```
**Opțiunea 2: Monitoring tools**
- Prometheus + NUT Exporter
- Grafana + InfluxDB
- Zabbix
### 7.3. Notificări personalizate
Pentru notificări Windows când UPS trece pe baterie:
**PowerShell monitoring script:**
```powershell
# Rulează continuu, verifică status UPS
$lastStatus = "OL"
while ($true) {
try {
$currentStatus = ssh root@10.0.20.201 "upsc nutdev1 ups.status"
if ($currentStatus -match "OB" -and $lastStatus -eq "OL") {
# Notificare Windows
[System.Windows.Forms.MessageBox]::Show(
"UPS a trecut pe baterie!",
"ALERT UPS",
[System.Windows.Forms.MessageBoxButtons]::OK,
[System.Windows.Forms.MessageBoxIcon]::Warning
)
}
$lastStatus = $currentStatus
} catch {
Write-Host "Error: $_"
}
Start-Sleep -Seconds 10
}
```
## 8. Alternative la WinNUT
Dacă WinNUT nu funcționează satisfăcător:
### 8.1. NUT-Monitor (Java)
- Cross-platform (Windows, Linux, macOS)
- Interfață mai modernă
- Download: https://github.com/networkupstools/nut/wiki/NUT-Monitor
### 8.2. upsc via SSH
Folosește direct comanda `upsc` prin SSH:
```powershell
# PowerShell - Status UPS
ssh root@10.0.20.201 "upsc nutdev1"
# Doar câmpuri specifice
ssh root@10.0.20.201 "upsc nutdev1 ups.status battery.charge input.voltage"
# Monitoring continuu
while ($true) {
Clear-Host
ssh root@10.0.20.201 "upsc nutdev1 ups.status battery.charge input.voltage"
Start-Sleep -Seconds 5
}
```
### 8.3. Web UI pe server
Instalează web UI pe pvemini:
```bash
# Instalare NUT CGI scripts
apt install -y nut-cgi apache2
# Configurare
# Accesează: http://10.0.20.201/cgi-bin/nut/upsstats.cgi
```
## 9. Pornire Automată WinNUT
### 9.1. Via Task Scheduler
1. Deschide **Task Scheduler**
2. Create Task:
- **General:**
- Name: WinNUT Auto Start
- Run whether user is logged on or not
- **Triggers:**
- At startup
- **Actions:**
- Start a program: `C:\Program Files\WinNUT\WinNUT.exe`
- **Conditions:**
- Start only if network available
### 9.2. Via Startup Folder
1. `Win + R` → `shell:startup`
2. Crează shortcut către `WinNUT.exe`
## 10. Documentație și Suport
- **WinNUT GitHub:** https://github.com/gawindx/WinNUT-V2
- **NUT Documentation:** https://networkupstools.org/
- **Issues:** Raportează probleme pe GitHub Issues
## Rezumat Configurare Rapidă
```
NUT host: 10.0.20.201
NUT Port: 3493
UPS Name: nutdev1
Polling Interval: 15
Login: admin
Password: parola99
Re-establish conn: ✓ Checked
```
**Click OK → Așteaptă 10-20 secunde → Vezi date UPS!**

View File

@@ -0,0 +1,515 @@
# Procedură Înlocuire Baterie UPS
## Despre
Ghid complet pentru înlocuirea bateriei UPS când cluster-ul Proxmox este complet alimentat de UPS. Include scripturi automate, checklist-uri și proceduri de recovery.
**⚠️ IMPORTANT:** Toate cele 3 noduri (pve1, pvemini, pveelite) sunt pe același UPS, deci **trebuie oprit complet cluster-ul**.
## Când Trebuie Înlocuită Bateria?
### Indicatori din Testele Lunare:
| Indicator | Acțiune |
|-----------|---------|
| **Health: POOR** (charge drop > 55%) | ⚠️ URGENT - Înlocuiește IMEDIAT |
| **Health: FAIR** (charge drop 35-55%) | 📅 Planifică în 1-3 luni |
| **Health: GOOD** (charge drop 15-35%) | ✅ Monitorizează lunar |
| **Health: EXCELLENT** (charge drop < 15%) | Baterie OK |
### Alte Semne:
- Vârsta bateriei > 3-4 ani
- UPS emite beep-uri frecvente
- Timp de autonomie scăzut vizibil (< 5 minute cu sarcină normală)
- Baterie umflată sau deteriorată fizic
- 3+ teste lunare consecutive cu health FAIR/POOR
## Pregătire
### 1. Comandă Baterie Nouă
**Verifică specificațiile UPS-ului:**
```bash
ssh root@10.0.20.201 "upsc nutdev1 2>/dev/null | grep -E 'battery.voltage.nominal|battery.type'"
```
Pentru UPS-ul tău (INNO TECH):
- Tensiune nominală: **24V** (2x 12V în serie)
- Tip: Probabil **12V 7Ah** sau **12V 9Ah** (2 bucăți)
**Verifică FIZIC bateria actuală** înainte de comandă:
- Model exact scris pe baterie
- Capacitate (Ah)
- Dimensiuni fizice
### 2. Planificare Fereastră de Mentenanță
**Timpul estimat: 30-60 minute**
Breakdown:
- Shutdown cluster: ~10 minute
- Înlocuire fizică baterie: 10-15 minute
- Pornire și verificare cluster: 10-15 minute
- **Buffer pentru probleme:** 15-20 minute
**Moment recomandat:**
- Duminică 02:00-04:00 (minimal impact)
- SAU orice fereastră de mentenanță aprobată
### 3. Anunță În Avans
**Template email/notificare:**
```
Subject: [IMPORTANT] Mentenanță Programată UPS - Duminică 02:00-04:00
Bună ziua,
Duminică, [DATA], între orele 02:00-04:00 va avea loc o intervenție
programată pentru înlocuirea bateriei UPS.
IMPACT:
- Toate serverele/serviciile vor fi indisponibile timp de ~45 minute
- Cluster Proxmox va fi oprit complet
- VM-uri și servicii vor fi oprite orchestrat și repornite automat
Ce se va întâmpla:
1. 02:00 - Shutdown orchestrat cluster (VM-uri + noduri)
2. 02:15 - Înlocuire fizică baterie UPS
3. 02:30 - Pornire noduri + verificare cluster
3. 02:45 - Pornire VM-uri și verificare servicii
În caz de probleme, timpul poate fi extins cu 30-60 minute.
Vă rugăm să salvați orice lucru în curs și să vă deconectați
de la servicii cu 10 minute înainte (01:50).
Mulțumim pentru înțelegere!
```
## Procedură Pas-cu-Pas
### ETAPA 1: Pre-Shutdown (15 minute înainte)
**1.1. Conectare la pvemini:**
```bash
ssh root@10.0.20.201
```
**1.2. Verificare finală status cluster:**
```bash
# Status cluster
pvecm status
# VM-uri running
qm list | grep running
# Status UPS
upsc nutdev1 ups.status battery.charge
# Backup-uri recente?
ls -lh /var/lib/vz/dump/ | tail -5
```
**1.3. Notificare utilizatori (dacă aplicabil):**
```bash
# Trimite mesaj pe toate nodurile (wall)
for node in pve1 pvemini pveelite; do
ssh root@$node "wall 'ATENȚIE: Cluster se va opri în 15 minute pentru mentenanță UPS!'"
done
```
### ETAPA 2: Shutdown Orchestrat
**2.1. Rulare script automat:**
```bash
cd /opt/scripts
./ups-maintenance-shutdown.sh
```
Scriptul va:
- Cere confirmare (scrie **DA**)
- Opri toate VM-urile (timeout 180s)
- Opri containerele LXC
- Opri nodurile secundare (pve1, pveelite)
- Opri pvemini (ultimul)
**2.2. Monitorizare (opțional):**
Deschide un al doilea terminal SSH și monitorizează:
```bash
# Monitor log
tail -f /var/log/ups-maintenance.log
# Monitor VM-uri
watch -n 5 'qm list'
```
**2.3. Așteptare:**
- Script va afișa countdown
- Totul se va opri automat în ~10 minute
- **pvemini se va opri ultimul (2 minute după nodurile secundare)**
### ETAPA 3: Verificare Oprire Completă
**3.1. Verifică LED-uri:**
- **pve1:** LED-uri stinse
- **pveelite:** LED-uri stinse
- **pvemini:** LED-uri stinse
**3.2. Verifică ventilatoare:**
- Ascultă - toate ventilatoarele ar trebui fie oprite
**3.3. Dacă un nod nu s-a oprit:**
- Conectează monitor/keyboard la nod
- SAU apasă lung butonul de power (10 secunde) pentru force shutdown
- **ULTIMĂ OPȚIUNE:** Deconectează alimentarea
### ETAPA 4: Înlocuire Fizică Baterie
** ATENȚIE LA SIGURANȚĂ:**
- Folosește mănuși izolante
- NU scurtcircuita terminalele bateriei
- Notează polaritatea (+/-)
**4.1. Deconectare UPS:**
```
1. Deconectează UPS de la priză (scoate din priză)
2. Apasă butonul de power al UPS-ului 5 secunde (descarcă condensatori)
```
**4.2. Deschide UPS:**
```
1. Identifică panoul de acces baterie (de obicei față sau spate)
2. Deșurubează/deschide panoul
3. Fotografiază conexiunile (pentru referință)
```
**4.3. Deconectare baterie veche:**
```
1. Notează polaritatea (+ la roșu, - la negru)
2. Deconectează mai întâi cablul NEGATIV (-)
3. Apoi deconectează cablul POZITIV (+)
4. Scoate bateria veche cu grijă
```
**4.4. Instalare baterie nouă:**
```
1. Plasează bateria nouă în suport
2. Conectează cablul POZITIV (+) PRIMUL
3. Apoi conectează cablul NEGATIV (-)
4. Verifică că conexiunile sunt ferme
5. Asigură-te că bateria nu se mișcă
```
**4.5. Închide UPS:**
```
1. Închide panoul de acces
2. Fixează șuruburile
```
**4.6. Reconectare:**
```
1. Conectează UPS la priză
2. Pornește UPS (buton de power)
3. Verifică LED-uri: ar trebui să vadă "charging" sau "online"
4. Ascultă beep-uri - normal este 1 beep la pornire
```
**4.7. Așteptare încărcare inițială:**
- Lasă UPS-ul conectat 2-3 minute încarce bateria nouă
- Verifică nu sunt erori pe display
### ETAPA 5: Pornire Cluster
**5.1. Pornire noduri - Ordine inversă:**
**Primul: Noduri secundare (pve1, pveelite)**
```
1. Apasă butonul de power pe pve1
2. Apasă butonul de power pe pveelite
3. Așteaptă 2 minute pentru boot
```
**Al doilea: Nod primary (pvemini)**
```
1. Apasă butonul de power pe pvemini
2. Așteaptă 3 minute pentru boot complet
```
**5.2. Conectare la pvemini când e disponibil:**
```bash
# Așteaptă până poți face SSH
ssh root@10.0.20.201
```
### ETAPA 6: Verificări Post-Pornire
**6.1. Verificare cluster:**
```bash
# Status cluster - ar trebui să vezi toate cele 3 noduri
pvecm status
# Verifică quorum
corosync-quorumtool -s
# Toate nodurile online?
pvecm nodes
```
**Așteptat:**
```
Quorate: Yes
Expected votes: 3
Total votes: 3
Nodeid: 1 (pve1) - online
Nodeid: 2 (pvemini) - online
Nodeid: 3 (pveelite) - online
```
**6.2. Verificare UPS:**
```bash
# Status UPS
upsc nutdev1
# Valori importante:
upsc nutdev1 ups.status # Ar trebui: OL (Online)
upsc nutdev1 battery.charge # Poate fi 50-80% (baterie nouă în încărcare)
upsc nutdev1 battery.voltage # ~24-27V
```
**6.3. Verificare servicii NUT:**
```bash
systemctl status nut-server
systemctl status nut-monitor
# Logs pentru erori
journalctl -u nut-server -n 50
```
### ETAPA 7: Pornire VM-uri
**7.1. Verifică ce VM-uri au autostart:**
```bash
# VM-uri cu onboot=1
grep -r "onboot: 1" /etc/pve/qemu-server/
# Sau
qm list | head -1 && grep "^onboot" /etc/pve/qemu-server/*.conf | grep "onboot: 1"
```
**7.2. Pornire VM-uri critice manual:**
```bash
# Listează toate VM-urile
qm list
# Pornește VM-uri importante
qm start 201 # roacentral (Windows 11)
# Adaugă alte VM-uri critice
# Sau pornește toate VM-urile care erau running:
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
qm start $vmid
done
```
**7.3. Verificare VM-uri:**
```bash
# Status VM-uri
qm list
# Pentru fiecare VM important, verifică:
qm status 201
```
### ETAPA 8: Test Final Baterie Nouă
**8.1. Rulare test baterie NUT:**
```bash
# Test automat
/opt/scripts/ups-monthly-test.sh
# Monitorizează log
tail -f /var/log/ups-monthly-test.log
```
**8.2. Verificare rezultat test:**
```bash
# Ar trebui să vezi EXCELLENT sau GOOD pentru baterie nouă
tail -30 /var/log/ups-monthly-test.log | grep -A 5 "Sănătate baterie"
```
**Așteptat pentru baterie nouă:**
- Charge drop: < 10% (EXCELLENT)
- Voltage drop: 1-2V
- Recuperare rapidă: < 60 secunde
**8.3. Test fizic (opțional dar recomandat):**
```bash
# Deconectează UPS de la priză 10 secunde
# Monitorizează în WinNUT pe VM 201
# UPS ar trebui să susțină sarcina fără probleme
# Reconectează la priză
```
### ETAPA 9: Notificare Finalizare
**9.1. Email/notificare utilizatori:**
```
Subject: Mentenanță UPS Finalizată Cu Succes
Mentenanța programată a fost finalizată cu succes.
STATUS:
✅ Baterie UPS înlocuită
✅ Toate nodurile cluster online
✅ Quorum OK
✅ VM-uri repornite
✅ Test baterie: [EXCELLENT/GOOD]
Serviciile sunt disponibile.
Durata totală: [XX] minute
Mulțumim pentru răbdare!
```
**9.2. Documentare în log:**
```bash
echo "[$(date)] UPS Battery replaced. Old battery removed, new battery installed. Test result: [RESULT]. Cluster fully operational." >> /var/log/ups-maintenance.log
```
## Troubleshooting
### Problema 1: Un nod nu pornește după shutdown
**Verificări:**
```bash
# Încearcă SSH
ssh root@[IP-NOD]
# Dacă nu răspunde:
# 1. Verifică LED-uri de pe nod - sunt aprinse?
# 2. Conectează monitor la nod - ce erori apar?
# 3. Verifică cablul de rețea
# 4. Hard reset: butoane power lung (10s) apoi pornește din nou
```
**Recovery:**
```bash
# Dacă nodul lipsește din cluster:
pvecm nodes
# Forțează quorum cu 2 noduri (ULTIMĂ OPȚIUNE):
pvecm expected 2
```
### Problema 2: UPS nu funcționează după înlocuire baterie
**Verificări:**
- LED-uri UPS - ce culoare?
- Beep-uri - ce pattern?
- Polaritate baterie corectă? (+ la +, - la -)
- Conexiuni ferme?
**Soluții:**
```bash
# Verifică ce raportează NUT
upsc nutdev1
# Dacă nu răspunde:
systemctl restart nut-driver@nutdev1
systemctl restart nut-server
```
### Problema 3: Baterie nouă se descarcă prea repede în test
**Normal pentru bateriile noi:**
- Primele 2-3 cicluri de încărcare pot fi instabile
- Bateria trebuie "condiționată" (câteva cicluri complete)
**Verificare:**
```bash
# Rulează test din nou după 24 ore
/opt/scripts/ups-monthly-test.sh
# Dacă și al 2-lea test e POOR:
# -> Baterie defectă, returnează la furnizor
```
### Problema 4: Cluster nu formează quorum
**Verificări:**
```bash
# Status pe fiecare nod
ssh root@10.0.20.200 "pvecm status"
ssh root@10.0.20.201 "pvecm status"
ssh root@10.0.20.202 "pvecm status"
# Corosync funcționează?
ssh root@10.0.20.201 "systemctl status corosync"
```
**Recovery:**
```bash
# Restart corosync pe toate nodurile
for node in 10.0.20.200 10.0.20.201 10.0.20.202; do
ssh root@$node "systemctl restart corosync pve-cluster"
done
# Așteaptă 30 secunde
sleep 30
# Verifică din nou
pvecm status
```
## Checklist Post-Înlocuire
### Verificare Imediată (primele 24 ore):
- [ ] Toate nodurile online în cluster
- [ ] Quorum OK (pvecm status)
- [ ] UPS status: OL (Online)
- [ ] Baterie nouă se încarcă (battery.charge crește)
- [ ] Test automat baterie: EXCELLENT sau GOOD
- [ ] VM-uri critice pornite și funcționale
- [ ] Servicii în producție OK
- [ ] Notificare utilizatori trimisă
- [ ] Documentat în log (/var/log/ups-maintenance.log)
### Monitorizare Prima Săptămână:
- [ ] Zi 1: Verificare battery.charge ajunge la 100%
- [ ] Zi 3: Test fizic scurt (deconectare 10s)
- [ ] Zi 7: Test baterie complet (rulare script lunar manual)
### Acțiuni După 1 Lună:
- [ ] Verificare test lunar automat (1 ale lunii)
- [ ] Rezultat ar trebui fie în continuare EXCELLENT/GOOD
- [ ] Dacă nu: verifică baterie/conexiuni
## Checklist Înainte de Următoarea Mentenanță
Pentru mentenanța viitoare (peste 3-4 ani), verifică că:
- [ ] Acest document este actualizat
- [ ] IP-urile nodurilor sunt corecte în script
- [ ] Backup-uri recente există
- [ ] Procedura a fost testată/revizuită
- [ ] Ai bateria de rezervă comandată din timp
## Referințe
- Script shutdown: `/opt/scripts/ups-maintenance-shutdown.sh`
- Log mentenanță: `/var/log/ups-maintenance.log`
- Test lunar: `/opt/scripts/ups-monthly-test.sh`
- Documentație UPS: [`UPS-SHUTDOWN-README.md`](UPS-SHUTDOWN-README.md)
---
**Autor:** Claude Code
**Data:** 2025-10-06
**Versiune:** 1.0

View File

@@ -0,0 +1,470 @@
# Test Lunar Automat Baterie UPS
## Despre
Script automat pentru testarea lunară a bateriei UPS care rulează pe data de 1 a fiecărei luni la ora 00:00. Testul verifică capacitatea reală a bateriei prin comutare pe baterie și monitorizare descărcare/recuperare.
## Funcționalitate
### Ce face scriptul:
1. **Verificare status UPS** înainte de test
- Battery charge, voltage
- Input/output voltage
- Load %
- Verifică că UPS este Online
2. **Rulare test baterie automat**
- Comandă: `upscmd nutdev1 test.battery.start.quick`
- UPS comută pe baterie pentru ~10 secunde
- Descarcă efectiv bateria pentru testare reală
3. **Monitorizare în timp real** (30 secunde)
- Status UPS
- Battery charge %
- Battery voltage
- Detectare anomalii
4. **Analiză rezultate**
- Calculează scăderea încărcării (%)
- Calculează scăderea tensiunii (V)
- Evaluează sănătatea bateriei
5. **Monitorizare recuperare** (5 minute)
- Urmărește reîncărcarea bateriei
- Calculează rata de recuperare
- Oprește când bateria > 95%
6. **Generare rapoarte**
- Raport HTML detaliat cu grafice
- Raport text pentru email
- Log detaliat în `/var/log/ups-monthly-test.log`
7. **Notificare email**
- Trimite raport prin sistemul de notificări Proxmox
- Include sănătatea bateriei în subject
- Rapoarte salvate în `/tmp/ups-test-YYYYMM/`
## Evaluare Sănătate Baterie
Scriptul evaluează sănătatea bateriei bazat pe scăderea încărcării în timpul testului:
| Scădere Încărcare | Sănătate | Status | Acțiune Necesară |
|-------------------|----------|--------|------------------|
| < 10% | **EXCELLENT** | Verde | Nicio acțiune necesară |
| 10-30% | **GOOD** | Verde | Continuă monitorizarea |
| 30-50% | **FAIR** | Galben | Planifică înlocuire în 3-6 luni |
| > 50% | **POOR** | 🔴 Roșu | **URGENT: Înlocuiește bateria!** |
### Exemple de rezultate reale:
**Test 1 (2025-10-06 20:45):**
- Scădere încărcare: 0% (charge reporting delay)
- Scădere tensiune: 1.64V (27.88V → 26.24V)
- Evaluare: **EXCELLENT**
- Recuperare: 30 secunde la 100%
**Notă:** UPS-ul raportează uneori încărcarea cu întârziere. Scăderea tensiunii este un indicator mai precis al capacității bateriei.
## Instalare
### 1. Copiere script pe server
```bash
scp scripts/ups-monthly-test.sh root@10.0.20.201:/opt/scripts/
ssh root@10.0.20.201 "chmod +x /opt/scripts/ups-monthly-test.sh"
```
### 2. Configurare cron
Script-ul se adaugă automat în cron la instalare, dar poți verifica:
```bash
ssh root@10.0.20.201 "crontab -l | grep ups-monthly-test"
```
Ar trebui să vezi:
```
# UPS Monthly Battery Test - Rulează pe 1 ale lunii la 00:00
0 0 1 * * /opt/scripts/ups-monthly-test.sh
```
### 3. Test manual (recomandat înainte de prima rulare lunară)
```bash
ssh root@10.0.20.201 "/opt/scripts/ups-monthly-test.sh"
```
**ATENȚIE:** Testul va comuta UPS-ul pe baterie pentru ~10 secunde!
## Configurare
### Parametri editabili în script:
```bash
UPS_NAME="nutdev1" # Numele UPS-ului din NUT
UPS_USER="admin" # Username pentru comenzi NUT
UPS_PASS="parola99" # Parola pentru comenzi NUT
MAIL_TO="root@pam" # Destinatar email rapoarte
```
### Personalizare cron:
Pentru a schimba data/ora de rulare, editează cron:
```bash
ssh root@10.0.20.201
crontab -e
```
Exemple:
```bash
# Rulează pe 1 ale lunii la 02:00 (noapte)
0 2 1 * * /opt/scripts/ups-monthly-test.sh
# Rulează în fiecare Duminică la 00:00 (săptămânal)
0 0 * * 0 /opt/scripts/ups-monthly-test.sh
# Rulează pe 15 ale lunii la 00:00 (mijloc de lună)
0 0 15 * * /opt/scripts/ups-monthly-test.sh
```
## Rapoarte Generate
### 1. Raport HTML
**Locație:** `/tmp/ups-test-YYYYMM/ups-test-report.html`
Conține:
- Header cu data, UPS, nod
- Status sănătate baterie (color-coded)
- Metrici în grid layout:
- Încărcare înainte/după
- Tensiune înainte/după
- Scădere încărcare
- Recuperare în 5 min
- Tabel detalii tehnice
- Recomandări bazate pe sănătate
- Footer cu timestamp și paths
### 2. Raport Text
**Locație:** `/tmp/ups-test-YYYYMM/ups-test-report.txt`
Versiune text simplă pentru email.
### 3. Log Detaliat
**Locație:** `/var/log/ups-monthly-test.log`
Log complet cu toate măsurătorile:
- Timestamp pentru fiecare pas
- Status UPS în timp real
- Toate valorile măsurate
- Erori sau warnings
**Păstrare:** Log-ul este append-only, conține istoric complet al tuturor testelor.
## Logs și Monitorizare
### Vizualizare log în timp real:
```bash
ssh root@10.0.20.201 "tail -f /var/log/ups-monthly-test.log"
```
### Verificare ultimul test:
```bash
ssh root@10.0.20.201 "tail -50 /var/log/ups-monthly-test.log"
```
### Căutare teste anterioare:
```bash
# Caută toate testele din 2025
ssh root@10.0.20.201 "grep 'UPS MONTHLY BATTERY TEST - START' /var/log/ups-monthly-test.log | grep 2025"
# Vezi rezultatul ultimului test
ssh root@10.0.20.201 "grep 'Sănătate baterie:' /var/log/ups-monthly-test.log | tail -1"
```
### Verificare cron execution:
```bash
# Verifică că cron a rulat scriptul
ssh root@10.0.20.201 "grep ups-monthly-test /var/log/syslog"
```
## Email Notifications
### Configurare sistem de mail
Scriptul încearcă să trimită email prin:
1. **mail command** (recomandat)
2. **logger** (fallback - doar în syslog)
#### Instalare mail command (dacă nu există):
```bash
ssh root@10.0.20.201 "apt update && apt install -y mailutils"
```
#### Configurare SMTP pentru Proxmox:
Editează `/etc/postfix/main.cf`:
```bash
relayhost = smtp.gmail.com:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt
```
Creează `/etc/postfix/sasl_passwd`:
```
smtp.gmail.com:587 your-email@gmail.com:your-app-password
```
Apoi:
```bash
postmap /etc/postfix/sasl_passwd
chmod 600 /etc/postfix/sasl_passwd*
systemctl restart postfix
```
#### Test email:
```bash
echo "Test email from UPS monitoring" | mail -s "Test" root@pam
```
### Verificare email trimis:
```bash
# Verifică mail queue
ssh root@10.0.20.201 "mailq"
# Verifică mail logs
ssh root@10.0.20.201 "grep 'UPS' /var/log/mail.log"
```
## Troubleshooting
### Testul nu pornește
**Verificare:**
```bash
# UPS online?
upsc nutdev1 ups.status
# Comenzi disponibile?
upscmd -l nutdev1 | grep battery
# Autentificare corectă?
upscmd -u admin -p parola99 nutdev1 test.battery.start.quick
```
### Bateria nu se descarcă în test
**Cauze posibile:**
- UPS-ul nu suportă test real (unele modele low-end)
- Test prea scurt pentru a fi detectat
- Baterie foarte sănătoasă (scădere < 1%)
**Verificare:**
```bash
# Monitorizează tensiune în loc de charge
watch -n 1 'upsc nutdev1 battery.voltage'
# Apoi rulează test manual și observă scăderea
upscmd -u admin -p parola99 nutdev1 test.battery.start.quick
```
### Email nu ajunge
**Verificări:**
```bash
# Mail command instalat?
which mail
# Postfix rulează?
systemctl status postfix
# Verifică logs
tail -50 /var/log/mail.log
# Test manual
echo "Test" | mail -s "Test Subject" root@pam
```
### Script blochează sau timeout
**Cauze:**
- Testul baterie durează prea mult
- UPS nu răspunde
- Probleme rețea
**Soluție:**
Editează scriptul și reduce timeout-urile:
```bash
# Reduce monitorizare de la 15 la 5 iterații
for i in {1..5}; do
```
## Întreținere
### Lunar (După Rulare Automată)
```bash
# Verifică că testul a rulat
ssh root@10.0.20.201 "tail -100 /var/log/ups-monthly-test.log | grep 'COMPLETE'"
# Vezi rezultatul
ssh root@10.0.20.201 "grep 'Sănătate baterie' /var/log/ups-monthly-test.log | tail -1"
# Verifică raportul HTML
ssh root@10.0.20.201 "ls -lh /tmp/ups-test-*/ups-test-report.html"
```
### Anual
```bash
# Cleanup rapoarte vechi (> 12 luni)
ssh root@10.0.20.201 "find /tmp/ups-test-* -type d -mtime +365 -exec rm -rf {} +"
# Rotare log dacă devine prea mare (> 100MB)
ssh root@10.0.20.201 "
if [ \$(stat -f%z /var/log/ups-monthly-test.log) -gt 104857600 ]; then
mv /var/log/ups-monthly-test.log /var/log/ups-monthly-test.log.old
gzip /var/log/ups-monthly-test.log.old
fi
"
```
### La Înlocuire Baterie
După înlocuirea bateriei UPS:
```bash
# Rulează test manual pentru baseline
ssh root@10.0.20.201 "/opt/scripts/ups-monthly-test.sh"
# Verifică că rezultatul este EXCELLENT
ssh root@10.0.20.201 "tail -20 /var/log/ups-monthly-test.log"
# Notează data înlocuirii în log
ssh root@10.0.20.201 "echo '[$(date)] Baterie UPS înlocuită - baseline test executat' >> /var/log/ups-monthly-test.log"
```
## Interpretare Rezultate
### Exemplu rezultat bun:
```
Sănătate baterie: EXCELLENT
Scădere încărcare: 5%
Scădere tensiune: 1.64V
Recuperare: 5% în 30 secunde
```
**Interpretare:** Baterie în stare excelentă, poate susține sarcina, se reîncarcă rapid.
### Exemplu rezultat acceptabil:
```
Sănătate baterie: FAIR
Scădere încărcare: 35%
Scădere tensiune: 4.2V
Recuperare: 15% în 120 secunde
```
**Interpretare:** Baterie uzată, planifică înlocuire în 3-6 luni.
### Exemplu rezultat critic:
```
Sănătate baterie: POOR
Scădere încărcare: 65%
Scădere tensiune: 8.5V
Recuperare: 25% în 300 secunde
```
**Interpretare:** **URGENT!** Baterie critică, înlocuiește imediat! Risc mare de shutdown neplanificat.
## Recomandări Baterie
### Când să înlocuiești bateria:
| Indicator | Bun | Acceptabil | Critic |
|-----------|-----|------------|--------|
| **Vârstă baterie** | < 2 ani | 2-4 ani | > 4 ani |
| **Scădere încărcare** | < 10% | 10-50% | > 50% |
| **Scădere tensiune** | < 2V | 2-5V | > 5V |
| **Timp recuperare** | < 1 min | 1-5 min | > 5 min |
| **Teste failed** | 0 | 1-2 | > 3 |
### Factori care afectează durata de viață:
- **Temperatură:** Ideal 20-25°C (fiecare +10°C reduce durata cu 50%)
- **Cicluri descărcare:** < 20 cicluri/an = bun
- **Profunzime descărcare:** Descărcări până la 50% = OK, sub 20% = deteriorare
- **Calitate baterie:** Baterii branded (APC, Eaton) vs. generice
## Automatizare Avansată
### Alertare automată când bateria devine POOR:
Adaugă în script (după evaluarea sănătății):
```bash
if [ "$BATTERY_HEALTH" == "POOR" ]; then
# Trimite alert urgent
echo "URGENT: Bateria UPS necesită înlocuire!" | \
mail -s "🔴 ALERT UPS: Baterie CRITICĂ!" admin@company.com
# Notificare SMS (dacă ai configurat)
curl -X POST "https://api.service.com/sms" \
-d "to=+40xxxxxxxxx&message=ALERT: Baterie UPS critica!"
fi
```
### Integrare cu Prometheus/Grafana:
Exportă metrici pentru monitorizare long-term:
```bash
# La final de script, exportă metrici
cat >> /var/lib/node_exporter/textfile_collector/ups_battery.prom << EOF
# HELP ups_battery_health Battery health score (0-100)
# TYPE ups_battery_health gauge
ups_battery_health{ups="nutdev1"} $(( 100 - CHARGE_DROP ))
# HELP ups_battery_charge_drop Battery charge drop during test
# TYPE ups_battery_charge_drop gauge
ups_battery_charge_drop{ups="nutdev1"} $CHARGE_DROP
# HELP ups_battery_test_timestamp Last battery test timestamp
# TYPE ups_battery_test_timestamp gauge
ups_battery_test_timestamp{ups="nutdev1"} $(date +%s)
EOF
```
## Referințe
- **NUT Commands:** https://networkupstools.org/docs/user-manual.chunked/ar01s07.html
- **Battery Testing Best Practices:** https://www.apc.com/us/en/faqs/FAQ000267818/
- **Proxmox Notifications:** https://pve.proxmox.com/wiki/Notifications
## Istoric Versiuni
- **v1.0** (2025-10-06)
- Release inițial
- Test automat baterie cu `test.battery.start.quick`
- Rapoarte HTML și text
- Email notifications
- Cron lunar (1 ale lunii)
- Evaluare sănătate baterie (4 nivele)
- Monitorizare recuperare 5 minute
---
**Autor:** Claude Code
**Ultima actualizare:** 2025-10-06

View File

@@ -0,0 +1,253 @@
# Documentație Sistem UPS Shutdown Orchestrat
## Configurare Completă
### Hardware
- **UPS:** INNO TECH USB to Serial (ID: 0665:5161)
- **Conectat la:** pvemini (10.0.20.201) - via USB
- **Cluster Proxmox:**
- pvemini (10.0.20.201) - PRIMARY (are UPS-ul conectat)
- pve1 (10.0.20.200) - SECONDARY
- pve2 (10.0.20.202) - SECONDARY
### Software
- **NUT (Network UPS Tools)** versiunea 2.8.0
- **WinNUT** pe VM 201 (Windows 11) pentru monitorizare vizuală
### Fișiere de Configurare
#### 1. /etc/nut/ups.conf
Configurează driver-ul pentru UPS:
```
[nutdev1]
driver = nutdrv_qx
port = auto
vendorid = 0665
productid = 5161
subdriver = cypress
desc = "UPS Cypress via USB"
```
#### 2. /etc/nut/upsd.conf
Server NUT - ascultă pe localhost și rețea:
```
LISTEN 127.0.0.1 3493
LISTEN 10.0.20.201 3493
```
#### 3. /etc/nut/upsd.users
Utilizatori autorizați:
```
[admin]
password = parola99
actions = SET
instcmds = ALL
upsmon master
```
#### 4. /etc/nut/upsmon.conf
Monitor local:
```
MONITOR nutdev1@localhost 1 admin parola99 master
NOTIFYCMD /usr/sbin/upssched
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC
```
#### 5. /etc/nut/upssched.conf
Scheduler pentru evenimente:
- **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
#### 1. /usr/local/bin/ups-shutdown-cluster.sh
**Script principal de shutdown orchestrat**
Ordinea de operații:
1. Verifică status UPS (trebuie OB sau LB)
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` + `journalctl -t ups-shutdown`
#### 2. /usr/local/bin/ups-shutdown-test.sh
**Script de test (DRY RUN) - NU oprește nimic**
Folosește-l pentru a testa:
```bash
/usr/local/bin/ups-shutdown-test.sh
tail -f /var/log/ups-shutdown-test.log
```
#### 3. /usr/local/bin/upssched-cmd
**Handler pentru evenimente UPS** - trimite notificări email via PVE::Notify
| 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`
## Testare și Verificare
### Verificare Status UPS
```bash
# Status general
upsc nutdev1
# Doar status
upsc nutdev1 ups.status
# Baterie
upsc nutdev1 battery.charge
# Tensiuni
upsc nutdev1 input.voltage output.voltage
```
### Verificare Servicii
```bash
systemctl status nut-server
systemctl status nut-monitor
journalctl -u nut-server -f
journalctl -u nut-monitor -f
```
### Test Manual Shutdown (DRY RUN)
```bash
/usr/local/bin/ups-shutdown-test.sh
```
### Test Simulare UPS pe Baterie
**⚠️ ATENȚIE: Acest test va iniția shutdown real dacă îl lași 3 minute!**
```bash
# Deconectează fizic UPS-ul de la priză pentru 30 secunde
# Monitorizează logs:
tail -f /var/log/ups-events.log
# Reconectează înainte de 3 minute pentru a anula shutdown-ul
```
## Monitorizare din WinNUT (VM 201)
### Conexiune
- **Server:** 10.0.20.201
- **Port:** 3493
- **UPS Name:** nutdev1
- **Username:** admin
- **Password:** parola99
- **Polling Interval:** 15 secunde
### Ce Vezi în WinNUT
- Input/Output Voltage
- Frequency
- Battery Charge (%)
- Battery Voltage
- UPS Load (%)
- UPS Status (Online/On Battery/Low Battery)
## Scenarii de Funcționare
### Scenario 1: Întrerupere Scurtă (< 3 minute)
1. Curent se întrerupe → UPS trece pe baterie
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. **📧 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. **📧 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
### Fișiere de Log
```bash
/var/log/ups-shutdown.log # Shutdown orchestrat real
/var/log/ups-shutdown-test.log # Test dry-run
/var/log/ups-events.log # Evenimente UPS (upssched)
journalctl -u nut-server # Server NUT
journalctl -u nut-monitor # Monitor NUT
```
### Comenzi Utile
```bash
# Liste conexiuni active la NUT
ss -tnp | grep :3493
# Test conectivitate de pe alt nod
ssh root@10.0.20.200 'upsc nutdev1@10.0.20.201'
# Restart servicii
systemctl restart nut-server nut-monitor
```
## Întreținere
### Verificare Săptămânală
```bash
# Status UPS
upsc nutdev1 ups.status battery.charge
# Test dry-run
/usr/local/bin/ups-shutdown-test.sh
# Verificare logs
tail -20 /var/log/ups-events.log
```
### Verificare Lunară
- Test fizic: deconectează UPS 30 secunde
- Verifică că WinNUT detectează schimbarea
- Verifică că logs arată evenimentul
- Reconectează înainte de 3 minute
## ⚠️ IMPORTANT
1. **Nu modifica** timpul de 3 minute fără consultare - trebuie să fie suficient pentru:
- VM-uri să se oprească graceful
- Noduri secundare să se închidă
- pvemini să rămână ultimul funcțional
2. **Testează periodic** scriptul dry-run pentru a verifica că SSH funcționează între noduri
3. **Monitorizează** statusul bateriei UPS - înlocuiește bateria când charge devine sub 80%
4. **WinNUT** este doar pentru monitorizare - shutdown-ul este automat de pe Proxmox
## Contact și Suport
- Documentație NUT: https://networkupstools.org/
- Script creat: 2025-10-06
- Ultima modificare: 2026-01-13 (adăugat notificări email + UPS shutdown)

View File

@@ -0,0 +1,156 @@
#!/bin/bash
#
# Script de shutdown orchestrat pentru mentenanță UPS
# Folosit când trebuie să oprești complet clusterul pentru înlocuire baterie
#
# Autor: Claude Code
# Data: 2025-10-06
LOGFILE="/var/log/ups-maintenance.log"
NODES=("10.0.20.200" "10.0.20.202") # pve1, pveelite (adaptează dacă IP-urile sunt altele)
# Culori pentru output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOGFILE
}
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}UPS MAINTENANCE - CLUSTER SHUTDOWN${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
echo -e "${YELLOW}⚠️ ATENȚIE: Acest script va opri TOATE nodurile cluster!${NC}"
echo -e "${YELLOW}⚠️ Folosit pentru mentenanță UPS (înlocuire baterie)${NC}"
echo ""
echo -e "${RED}Cluster nodes care vor fi oprite:${NC}"
echo " - pve1 (10.0.20.200)"
echo " - pveelite (10.0.20.202)"
echo " - pvemini (10.0.20.201) - ULTIMUL"
echo ""
read -p "Continui cu shutdown? (scrie 'DA' pentru confirmare): " confirm
if [ "$confirm" != "DA" ]; then
echo -e "${RED}Anulat de utilizator.${NC}"
exit 0
fi
log "========================================"
log "MAINTENANCE SHUTDOWN - START"
log "Initiated by: $(whoami)"
log "========================================"
# 1. Verificare status cluster înainte
log "Step 1: Verificare status cluster..."
pvecm status | tee -a $LOGFILE
echo ""
# 2. Oprire VM-uri pe toate nodurile
log "Step 2: Oprire VM-uri pe TOATE nodurile..."
echo -e "${BLUE}Oprire VM-uri pe pvemini (local)...${NC}"
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
vm_name=$(qm config $vmid | grep '^name:' | cut -d' ' -f2 || echo "VM-$vmid")
vm_status=$(qm status $vmid | awk '{print $2}')
if [ "$vm_status" == "running" ]; then
log " Oprire VM $vmid ($vm_name) pe pvemini..."
qm shutdown $vmid --timeout 180 &
else
log " VM $vmid ($vm_name) deja oprit"
fi
done
# Oprire VM-uri pe nodurile secundare
for node_ip in ${NODES[@]}; do
echo -e "${BLUE}Oprire VM-uri pe nod $node_ip...${NC}"
ssh -o ConnectTimeout=5 root@$node_ip "
for vmid in \$(qm list | awk 'NR>1 {print \$1}'); do
vm_name=\$(qm config \$vmid | grep '^name:' | cut -d' ' -f2 || echo 'VM-'\$vmid)
vm_status=\$(qm status \$vmid | awk '{print \$2}')
if [ \"\$vm_status\" == \"running\" ]; then
echo ' Oprire VM '\$vmid' ('\$vm_name') pe $node_ip...'
qm shutdown \$vmid --timeout 180 &
fi
done
" 2>&1 | tee -a $LOGFILE
done
log "Așteptare 3 minute pentru shutdown VM-uri..."
echo -e "${YELLOW}Aștept 180 secunde pentru oprirea graceful a VM-urilor...${NC}"
for i in {180..1}; do
echo -ne "\r${YELLOW}Rămas: $i secunde...${NC} "
sleep 1
done
echo ""
# 3. Verificare VM-uri oprite
log "Step 3: Verificare VM-uri oprite..."
running_vms=$(qm list | awk 'NR>1 && $3=="running" {print $1}')
if [ ! -z "$running_vms" ]; then
log "WARNING: VM-uri încă pornite pe pvemini: $running_vms"
echo -e "${YELLOW}WARNING: Unele VM-uri încă rulează. Oprire forțată în 30 secunde...${NC}"
sleep 30
for vmid in $running_vms; do
log " Force stop VM $vmid"
qm stop $vmid
done
fi
# 4. Oprire containere (dacă există)
log "Step 4: Oprire containere LXC (dacă există)..."
pct list 2>/dev/null | awk 'NR>1 && $2=="running" {print $1}' | while read ctid; do
log " Oprire container $ctid"
pct shutdown $ctid --timeout 60 &
done
sleep 70
# 5. Oprire noduri secundare
log "Step 5: Oprire noduri secundare (pve1, pveelite)..."
for node_ip in ${NODES[@]}; do
log " Shutdown nod $node_ip în 2 minute..."
echo -e "${RED}Shutdown nod $node_ip...${NC}"
ssh -o ConnectTimeout=5 root@$node_ip "shutdown -h +2 'UPS Maintenance - Battery Replacement'" 2>&1 | tee -a $LOGFILE &
done
log "Așteptare 150 secunde pentru shutdown noduri secundare..."
echo -e "${YELLOW}Aștept 150 secunde pentru oprirea nodurilor secundare...${NC}"
for i in {150..1}; do
echo -ne "\r${YELLOW}Rămas: $i secunde până la shutdown pvemini...${NC} "
sleep 1
done
echo ""
# 6. Oprire nod local (pvemini) - ULTIMUL
log "Step 6: Oprire pvemini (nod PRIMARY - ULTIMUL)..."
log "========================================"
log "MAINTENANCE SHUTDOWN - COMPLETE"
log "Nodurile secundare ar trebui să fie oprite."
log "pvemini se va opri în 2 minute."
log "========================================"
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}SHUTDOWN ORCHESTRAT FINALIZAT${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
echo -e "${YELLOW}URMĂTORII PAȘI:${NC}"
echo "1. Așteaptă 2 minute pentru oprirea completă a pvemini"
echo "2. Verifică că toate LED-urile nodurilor sunt stinse"
echo "3. Deconectează UPS de la priză"
echo "4. Înlocuiește bateria UPS"
echo "5. Reconectează UPS la priză"
echo "6. Pornește nodurile (apasă buton power sau WOL)"
echo "7. Verifică cluster cu: pvecm status"
echo ""
echo -e "${RED}pvemini se va opri în 2 minute!${NC}"
echo ""
shutdown -h +2 "UPS Maintenance - Battery Replacement - Primary Node"
exit 0

View File

@@ -0,0 +1,435 @@
#!/bin/bash
#
# Script de test lunar automat baterie UPS
# Rulează pe 1 ale fiecărei luni la 00:00
# Trimite raport prin notificările Proxmox (PVE::Notify)
#
# IMPORTANT: Timing-ul de citire este CRITIC!
# - Battery.charge scade DOAR între 10-40 secunde după pornirea testului
# - UPS actualizează valorile cu delay de 5-10 secunde
#
# Creat: 2025-10-06
# Autor: Claude Code
LOGFILE="/var/log/ups-monthly-test.log"
UPS_NAME="nutdev1"
UPS_USER="admin"
UPS_PASS="parola99"
TEMPLATE_DIR="/etc/pve/notification-templates/default"
START_TIME=$(date +%s)
HOSTNAME=$(hostname)
FQDN=$(hostname -f)
# Funcție logging
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOGFILE
}
# Funcție pentru crearea template-urilor de notificare
create_templates() {
mkdir -p $TEMPLATE_DIR
# Template: Subject
cat > "$TEMPLATE_DIR/ups-battery-test-subject.txt.hbs" << 'EOFTEMPLATE'
[{{ hostname }}] UPS Battery Test - {{ health_status }}
EOFTEMPLATE
# Template: Body Text
cat > "$TEMPLATE_DIR/ups-battery-test-body.txt.hbs" << 'EOFTEMPLATE'
========================================
UPS MONTHLY BATTERY TEST REPORT
========================================
Hostname: {{ hostname }}
Date: {{ test_date }}
UPS: {{ ups_name }}
BATTERY HEALTH: {{ health_status }}
{{ health_emoji }} {{ health_description }}
TEST RESULTS:
-------------
Battery Charge Drop: {{ charge_drop }}%
Battery Voltage Drop: {{ voltage_drop }}V
Minimum Charge Reached: {{ min_charge }}%
Minimum Voltage: {{ min_voltage }}V
Recovery Time: {{ recovery_time }}s
BEFORE TEST:
- Battery Charge: {{ before_charge }}%
- Battery Voltage: {{ before_voltage }}V
- UPS Load: {{ before_load }}%
AFTER TEST ({{ test_duration }}s):
- Battery Charge: {{ after_charge }}%
- Battery Voltage: {{ after_voltage }}V
- UPS Load: {{ after_load }}%
RECOMMENDATIONS:
{{ recommendations }}
========================================
Script: /opt/scripts/ups-monthly-test.sh
Log: /var/log/ups-monthly-test.log
========================================
EOFTEMPLATE
# Template: Body HTML
cat > "$TEMPLATE_DIR/ups-battery-test-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: 800px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
h1 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 15px; margin-top: 0; }
.status-badge { display: inline-block; padding: 10px 20px; border-radius: 5px; font-weight: bold; font-size: 18px; margin: 15px 0; }
.status-excellent { background-color: #d4edda; color: #155724; border: 2px solid #28a745; }
.status-good { background-color: #d1ecf1; color: #0c5460; border: 2px solid #17a2b8; }
.status-fair { background-color: #fff3cd; color: #856404; border: 2px solid #ffc107; }
.status-poor { background-color: #f8d7da; color: #721c24; border: 2px solid #dc3545; }
.metrics { display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin: 25px 0; }
.metric { background: #ecf0f1; padding: 20px; border-radius: 5px; border-left: 4px solid #3498db; }
.metric-label { font-size: 13px; color: #7f8c8d; text-transform: uppercase; letter-spacing: 0.5px; }
.metric-value { font-size: 28px; font-weight: bold; color: #2c3e50; margin-top: 8px; }
.section { margin: 25px 0; padding: 20px; background: #f8f9fa; border-radius: 5px; }
.section h2 { color: #34495e; margin-top: 0; font-size: 20px; }
.recommendations { background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 20px 0; }
.recommendations ul { margin: 10px 0; padding-left: 20px; }
.footer { margin-top: 30px; padding-top: 20px; border-top: 2px solid #ecf0f1; font-size: 12px; color: #7f8c8d; text-align: center; }
table { width: 100%; border-collapse: collapse; margin: 15px 0; }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
th { background-color: #3498db; color: white; font-weight: 600; }
tr:hover { background-color: #f5f5f5; }
</style>
</head>
<body>
<div class="container">
<h1>[BATTERY] UPS Battery Test Report</h1>
<p><strong>Hostname:</strong> {{ hostname }}<br>
<strong>Date:</strong> {{ test_date }}<br>
<strong>UPS:</strong> {{ ups_name }}</p>
<div class="status-badge status-{{ health_class }}">
{{ health_emoji }} Battery Health: {{ health_status }}
</div>
<p style="font-size: 16px; margin-top: 15px;">{{ health_description }}</p>
<h2 style="margin-top: 30px;">Test Metrics</h2>
<div class="metrics">
<div class="metric">
<div class="metric-label">Charge Drop</div>
<div class="metric-value">{{ charge_drop }}%</div>
</div>
<div class="metric">
<div class="metric-label">Voltage Drop</div>
<div class="metric-value">{{ voltage_drop }}V</div>
</div>
<div class="metric">
<div class="metric-label">Min Charge</div>
<div class="metric-value">{{ min_charge }}%</div>
</div>
<div class="metric">
<div class="metric-label">Recovery Time</div>
<div class="metric-value">{{ recovery_time }}s</div>
</div>
</div>
<div class="section">
<h2>Detailed Measurements</h2>
<table>
<tr>
<th>Parameter</th>
<th>Before Test</th>
<th>After Test</th>
</tr>
<tr>
<td>Battery Charge</td>
<td>{{ before_charge }}%</td>
<td>{{ after_charge }}%</td>
</tr>
<tr>
<td>Battery Voltage</td>
<td>{{ before_voltage }}V</td>
<td>{{ after_voltage }}V</td>
</tr>
<tr>
<td>UPS Load</td>
<td>{{ before_load }}%</td>
<td>{{ after_load }}%</td>
</tr>
</table>
</div>
<div class="recommendations">
<h2 style="margin-top: 0;">📋 Recommendations</h2>
{{{ recommendations }}}
</div>
<div class="footer">
<p><strong>Script:</strong> /opt/scripts/ups-monthly-test.sh<br>
<strong>Log File:</strong> /var/log/ups-monthly-test.log</p>
<p style="margin-top: 10px;">Proxmox VE - UPS Monitoring System</p>
</div>
</div>
</body>
</html>
EOFTEMPLATE
log "Templates created in $TEMPLATE_DIR/"
}
# Verifică și creează template-urile dacă nu există
if [ ! -f "$TEMPLATE_DIR/ups-battery-test-subject.txt.hbs" ]; then
log "Creating notification templates..."
create_templates
fi
log "========================================"
log "UPS MONTHLY BATTERY TEST - START"
log "========================================"
# 1. Verificare status UPS înainte de test
log "Step 1: Verificare status UPS înainte de test..."
BEFORE_STATUS=$(upsc $UPS_NAME ups.status 2>/dev/null)
BEFORE_CHARGE=$(upsc $UPS_NAME battery.charge 2>/dev/null)
BEFORE_VOLTAGE=$(upsc $UPS_NAME battery.voltage 2>/dev/null)
BEFORE_LOAD=$(upsc $UPS_NAME ups.load 2>/dev/null)
log " Status: $BEFORE_STATUS"
log " Battery Charge: $BEFORE_CHARGE%"
log " Battery Voltage: $BEFORE_VOLTAGE V"
log " Load: $BEFORE_LOAD%"
# Verifică dacă UPS este online
if [[ $BEFORE_STATUS != *"OL"* ]]; then
log "ERROR: UPS nu este online! Status: $BEFORE_STATUS"
log "Test ANULAT"
exit 1
fi
# Verifică încărcare baterie
if [ "$BEFORE_CHARGE" -lt 95 ]; then
log "WARNING: Baterie nu este complet încărcată ($BEFORE_CHARGE%)"
fi
# 2. Pornire test baterie
log ""
log "Step 2: Pornire test baterie..."
TEST_START_TIME=$(date +%s)
upscmd -u $UPS_USER -p $UPS_PASS $UPS_NAME test.battery.start.quick 2>&1 | tee -a $LOGFILE
if [ ${PIPESTATUS[0]} -eq 0 ]; then
log "Test baterie pornit cu succes!"
else
log "ERROR: Nu am putut porni testul de baterie!"
exit 1
fi
# 3. TIMING CRITIC: Așteptare 10-15 secunde pentru ca charge să scadă
log ""
log "Step 3: Monitorizare test baterie (timing critic pentru charge drop)..."
MIN_CHARGE=$BEFORE_CHARGE
MIN_VOLTAGE=$BEFORE_VOLTAGE
CHARGE_AT_15S=$BEFORE_CHARGE
VOLTAGE_AT_15S=$BEFORE_VOLTAGE
# Primele 5 secunde - inițializare test
sleep 5
# 10-40 secunde - fereastra critică când charge scade
for i in {1..7}; do
CURRENT_CHARGE=$(upsc $UPS_NAME battery.charge 2>/dev/null)
CURRENT_VOLTAGE=$(upsc $UPS_NAME battery.voltage 2>/dev/null)
# Capturează minimul
if [ ! -z "$CURRENT_CHARGE" ] && [ "$CURRENT_CHARGE" -lt "$MIN_CHARGE" ]; then
MIN_CHARGE=$CURRENT_CHARGE
fi
if [ ! -z "$CURRENT_VOLTAGE" ]; then
MIN_VOLTAGE=$(echo "$CURRENT_VOLTAGE $MIN_VOLTAGE" | awk '{if ($1 < $2) print $1; else print $2}')
fi
# Citire la 15 secunde (punct optim)
if [ $i -eq 2 ]; then
CHARGE_AT_15S=$CURRENT_CHARGE
VOLTAGE_AT_15S=$CURRENT_VOLTAGE
log " [15s CRITICAL] Charge: $CURRENT_CHARGE% | Voltage: $CURRENT_VOLTAGE V"
else
log " [$((5 + i*5))s] Charge: $CURRENT_CHARGE% | Voltage: $CURRENT_VOLTAGE V"
fi
sleep 5
done
TEST_END_TIME=$(date +%s)
TEST_DURATION=$((TEST_END_TIME - TEST_START_TIME))
log " Minimum Charge: $MIN_CHARGE%"
log " Minimum Voltage: $MIN_VOLTAGE V"
# 4. Așteptare recuperare și citire finală
log ""
log "Step 4: Așteptare recuperare baterie (15 secunde)..."
sleep 15
AFTER_STATUS=$(upsc $UPS_NAME ups.status 2>/dev/null)
AFTER_CHARGE=$(upsc $UPS_NAME battery.charge 2>/dev/null)
AFTER_VOLTAGE=$(upsc $UPS_NAME battery.voltage 2>/dev/null)
AFTER_LOAD=$(upsc $UPS_NAME ups.load 2>/dev/null)
log " Status: $AFTER_STATUS"
log " Battery Charge: $AFTER_CHARGE%"
log " Battery Voltage: $AFTER_VOLTAGE V"
log " Load: $AFTER_LOAD%"
# 5. Calcul metrici
CHARGE_DROP=$((BEFORE_CHARGE - MIN_CHARGE))
VOLTAGE_DROP=$(echo "$BEFORE_VOLTAGE - $MIN_VOLTAGE" | bc 2>/dev/null || echo "0")
# Rotunjire voltage drop la 2 zecimale
VOLTAGE_DROP=$(printf "%.2f" $VOLTAGE_DROP 2>/dev/null || echo $VOLTAGE_DROP)
log ""
log "Step 5: Analiza rezultate test..."
log " Durată test: $TEST_DURATION secunde"
log " Scădere încărcare: $CHARGE_DROP% (de la $BEFORE_CHARGE% la $MIN_CHARGE%)"
log " Scădere tensiune: $VOLTAGE_DROP V (de la $BEFORE_VOLTAGE V la $MIN_VOLTAGE V)"
# 6. Evaluare sănătate baterie
BATTERY_HEALTH="UNKNOWN"
HEALTH_CLASS="fair"
HEALTH_EMOJI="[INFO]"
HEALTH_DESCRIPTION=""
RECOMMENDATIONS=""
if [ "$CHARGE_DROP" -lt 15 ]; then
BATTERY_HEALTH="EXCELLENT"
HEALTH_CLASS="excellent"
HEALTH_EMOJI="[OK]"
HEALTH_DESCRIPTION="Battery is in excellent condition with minimal discharge during test."
RECOMMENDATIONS="<ul><li>✅ Battery is healthy and functioning normally</li><li>Continue monthly testing</li><li>No action required</li></ul>"
log " Sănătate baterie: EXCELENTĂ (scădere < 15%)"
elif [ "$CHARGE_DROP" -lt 35 ]; then
BATTERY_HEALTH="GOOD"
HEALTH_CLASS="good"
HEALTH_EMOJI="[OK]"
HEALTH_DESCRIPTION="Battery shows normal wear but performs adequately."
RECOMMENDATIONS="<ul><li>Battery is functioning well</li><li>Monitor monthly for degradation trends</li><li>No immediate action needed</li></ul>"
log " Sănătate baterie: BUNĂ (scădere 15-35%)"
elif [ "$CHARGE_DROP" -lt 55 ]; then
BATTERY_HEALTH="FAIR"
HEALTH_CLASS="fair"
HEALTH_EMOJI="[WARNING]"
HEALTH_DESCRIPTION="Battery shows significant wear and should be monitored closely."
RECOMMENDATIONS="<ul><li>⚠️ Battery is aging</li><li>Plan replacement in 3-6 months</li><li>Increase monitoring frequency</li><li>Order replacement battery soon</li></ul>"
log " Sănătate baterie: ACCEPTABILĂ (scădere 35-55%)"
else
BATTERY_HEALTH="POOR"
HEALTH_CLASS="poor"
HEALTH_EMOJI="[CRITICAL]"
HEALTH_DESCRIPTION="Battery is critically weak and requires immediate replacement!"
RECOMMENDATIONS="<ul><li>🔴 <strong>URGENT:</strong> Battery needs immediate replacement!</li><li>Order new battery NOW</li><li>UPS may not provide adequate protection</li><li>Risk of unexpected shutdown</li></ul>"
log " Sănătate baterie: SLABĂ (scădere > 55%) - NECESITĂ ÎNLOCUIRE!"
fi
# 7. Monitorizare recuperare (30 secunde)
log ""
log "Step 6: Monitorizare recuperare baterie..."
RECOVERY_START=$(date +%s)
sleep 30
RECOVERY_CHARGE=$(upsc $UPS_NAME battery.charge 2>/dev/null)
RECOVERY_TIME=$(($(date +%s) - RECOVERY_START))
log " Charge după $RECOVERY_TIME secunde: $RECOVERY_CHARGE%"
# 8. Calculează timpul total
END_TIME=$(date +%s)
RUNTIME=$((END_TIME - START_TIME))
# 9. Determină severity pentru notificare
if [ "$BATTERY_HEALTH" = "EXCELLENT" ] || [ "$BATTERY_HEALTH" = "GOOD" ]; then
SEVERITY="info"
elif [ "$BATTERY_HEALTH" = "FAIR" ]; then
SEVERITY="warning"
else
SEVERITY="error"
fi
# 10. Trimite notificarea prin PVE::Notify
log ""
log "Step 7: Trimitere notificare prin PVE::Notify..."
# Escape pentru Perl heredoc
RECOMMENDATIONS_ESCAPED=$(echo "$RECOMMENDATIONS" | sed "s/'/\\'/g")
perl -I/usr/share/perl5 << EOFPERL
use strict;
use warnings;
use PVE::Notify;
my \$template_data = {
'hostname' => '$FQDN',
'test_date' => '$(date '+%Y-%m-%d %H:%M:%S')',
'ups_name' => '$UPS_NAME',
'health_status' => '$BATTERY_HEALTH',
'health_class' => '$HEALTH_CLASS',
'health_emoji' => '$HEALTH_EMOJI',
'health_description' => '$HEALTH_DESCRIPTION',
'charge_drop' => '$CHARGE_DROP',
'voltage_drop' => '$VOLTAGE_DROP',
'min_charge' => '$MIN_CHARGE',
'min_voltage' => '$MIN_VOLTAGE',
'before_charge' => '$BEFORE_CHARGE',
'before_voltage' => '$BEFORE_VOLTAGE',
'before_load' => '$BEFORE_LOAD',
'after_charge' => '$AFTER_CHARGE',
'after_voltage' => '$AFTER_VOLTAGE',
'after_load' => '$AFTER_LOAD',
'test_duration' => '$TEST_DURATION',
'recovery_time' => '$RECOVERY_TIME',
'recommendations' => '$RECOMMENDATIONS_ESCAPED'
};
my \$fields = {
'hostname' => '$HOSTNAME',
'type' => 'ups-battery-test',
'health' => '$BATTERY_HEALTH'
};
eval {
PVE::Notify::notify('$SEVERITY', 'ups-battery-test', \$template_data, \$fields);
print "Notification sent successfully\\n";
};
if (\$@) {
print STDERR "Failed to send notification: \$@\\n";
exit 1;
}
EOFPERL
PERL_EXIT_CODE=$?
if [ $PERL_EXIT_CODE -eq 0 ]; then
log "Notificare trimisă cu succes prin PVE::Notify"
else
log "ERROR: Notificarea a eșuat (exit code: $PERL_EXIT_CODE)"
fi
# 11. Finalizare
log ""
log "========================================"
log "UPS MONTHLY BATTERY TEST - COMPLETE"
log "Sănătate baterie: $BATTERY_HEALTH"
log "Scădere încărcare: $CHARGE_DROP%"
log "Scădere tensiune: $VOLTAGE_DROP V"
log "Timp total: $RUNTIME secunde"
log "========================================"
exit 0

View File

@@ -0,0 +1,230 @@
#!/bin/bash
#
# 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-14 - Fix permisiuni log file, adaugat sudo pentru PVE::Notify
LOGFILE=/var/log/ups-shutdown.log
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)
# Asigura ca fisierul de log exista si are permisiunile corecte
# Scriptul poate rula 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_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOGFILE 2>/dev/null
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"
/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' => '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 "$(get_ups_info)"
log_message "========================================"
# 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..."
# 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
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
vm_status=$(qm status $vmid | awk '{print $2}')
if [ "$vm_status" == "running" ]; then
log_message " * Oprire VM $vmid pe pvemini..."
qm shutdown $vmid --timeout 60 &
fi
done
else
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}')
if [ \"\$vm_status\" == \"running\" ]; then
echo ' * Oprire VM '\$vmid' pe $node...'
qm shutdown \$vmid --timeout 60 &
fi
done
" 2>&1 | tee -a $LOGFILE
fi
done
log_message "Step 2: Oprire 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
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
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...'
pct shutdown \$ctid --timeout 60 &
done
" 2>&1 | tee -a $LOGFILE
fi
done
log_message "Step 3: Asteptare 90 secunde pentru oprirea VM-urilor si LXC..."
sleep 90
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: 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 "========================================"
# Opreste nodul local (ultimul)
shutdown -h +1 "UPS battery critical - primary node shutting down"
exit 0

View File

@@ -0,0 +1,63 @@
#!/bin/bash
#
# Script de TEST pentru shutdown orchestrat - NU oprește nimic
#
LOGFILE=/var/log/ups-shutdown-test.log
NODES=(10.0.20.200 10.0.20.202)
log_message() {
echo "[2025-10-06 20:03:03] $1" | tee -a $LOGFILE
}
log_message "========================================"
log_message "UPS SHUTDOWN TEST STARTED (DRY RUN)"
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 "Input Voltage: $(upsc nutdev1 input.voltage 2>/dev/null || echo 'UNKNOWN')V"
log_message "Output Voltage: $(upsc nutdev1 output.voltage 2>/dev/null || echo 'UNKNOWN')V"
log_message "========================================"
log_message "TEST: Ar opri VM-urile de pe toate nodurile..."
for node in ${NODES[@]} localhost; do
if [ "$node" == "localhost" ]; then
NODE_NAME="pvemini (local)"
else
NODE_NAME=$node
fi
log_message " - VM-uri pe $NODE_NAME:"
if [ "$node" == "localhost" ]; then
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
vm_name=$(qm config $vmid | grep '^name:' | cut -d' ' -f2)
vm_status=$(qm status $vmid | awk '{print $2}')
log_message " * VM $vmid ($vm_name): $vm_status"
done
else
ssh -o ConnectTimeout=5 root@$node "
for vmid in \$(qm list | awk 'NR>1 {print \$1}'); do
vm_name=\$(qm config \$vmid | grep '^name:' | cut -d' ' -f2)
vm_status=\$(qm status \$vmid | awk '{print \$2}')
echo ' * VM '\$vmid' ('\$vm_name'): '\$vm_status
done
" 2>&1 | tee -a $LOGFILE
fi
done
log_message ""
log_message "TEST: Ordinea de shutdown ar fi:"
log_message " 1. Toate VM-urile de pe toate nodurile (paralel)"
log_message " 2. Așteptare 90 secunde"
log_message " 3. Shutdown pve1 (10.0.20.200)"
log_message " 4. Shutdown pve2 (10.0.20.202)"
log_message " 5. Așteptare 30 secunde"
log_message " 6. Shutdown pvemini (10.0.20.201) - PRIMARY/LAST"
log_message ""
log_message "========================================"
log_message "UPS SHUTDOWN TEST COMPLETED (DRY RUN)"
log_message "NICIUN sistem nu a fost oprit - doar test"
log_message "========================================"
exit 0

View File

@@ -0,0 +1,436 @@
#!/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'
<!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; }
.status-charging { color: #3498db; border-color: #3498db; }
.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"
/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