Files
ROMFASTSQL/docs/ups-server36-monitorizare.md
Marius b874cfac37 docs(ups): uneltele testului de autonomie si ce s-a aflat despre gauge
Cele trei unelte adaugate la ultimul commit (set-praguri, trace-baterie,
start-trace) nu aparaeu in documentatie. Adaugate in tabelul de fisiere si
descrise ca procedura in sectiunea de operare, in ordinea reala de folosire:
largeste praguri -> porneste trace -> scoate din priza -> opreste trace ->
restaureaza praguri.

Sectiunea 6 punctul 1 primeste rezultatul scoaterii din priza de pe 27.08:
autonomia tot nu e masurata (trei minute sunt prea putine), dar s-a vazut ca
gauge-ul de procent al acestui UPS nu e de incredere - 96% -> 65% -> 90% in
100 de secunde la revenirea curentului. Pragul de 35% se sprijina exact pe
cifra asta, iar confirmPolls=3 (45 s) e mai scurt decat fereastra de zgomot.
ACLineStatus, in schimb, a fost impecabil - de aici directia pentru pragurile
definitive: timpul pe baterie devine criteriul principal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRyaDj39hPQ89SZS6URRpS
2026-08-27 16:08:05 +03:00

381 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Monitorizare UPS pe serverul Oracle de producție (10.0.20.36)
**Server:** `ROA-CARAPETRU2` / 10.0.20.36 — Windows 11 Pro, Oracle 19c SE2, instanța `ROA`.
Acces: `ssh -p 22122 Administrator@10.0.20.36`.
**Pe scurt:** ViewPower nu a putut niciodată dialoga cu acest UPS și a fost dezactivat pe
10 august 2026, lăsând serverul fără nicio alertare timp de 17 zile. UPS-ul, în schimb,
comunică perfect cu Windows pe canalul HID nativ. Monitorizarea nouă folosește exact acel
canal. ViewPower e închis și nu mai pornește.
Se citește împreună cu [`incident-2026-08-10-server36-standby.md`](incident-2026-08-10-server36-standby.md)
— cele două se leagă în seara de 10 august.
---
## 1. Diagnosticul: ce era stricat, de fapt
### UPS-ul comunică — și a comunicat tot timpul
| Verificare | Rezultat (27.08.2026) |
|---|---|
| `USB\VID_0665&PID_5161\HID_UPS` | Status **OK**, enumerat corect |
| `HID\...&MI_01`, driver `HidBatt` | „HID UPS Battery", Status **OK** |
| `Win32_Battery` | `HID UPS`, Status `OK`, BatteryStatus `2` (pe rețea), încărcare **100%** |
| Kernel-Power ID **105** (schimbare sursă) | perechi AC↔baterie reale: 10 iun, 13 mai, 5 mai, 25 feb 2026 |
Perechile de evenimente 105 sunt dovada care închide discuția: la fiecare pană reală Windows
a *văzut* trecerea pe baterie și revenirea. Ultima pană: **10 iunie 2026**. Din 10 august
(dezactivarea ViewPower) până azi nu a mai fost niciuna, deci nu s-a pierdut niciun eveniment
— noroc, nu proiectare.
### ViewPower nu vorbește limba acestui UPS
`C:\ViewPower\log\log4j.log` acoperă **6 aug 15:40:37 → 10 aug 22:34:11** (patru treceri peste
miezul nopții, numărate în fișier). Din 5787 de linii, **5777 sunt `QPI return(NAK`**. Zero
citiri reușite: nicio tensiune, nicio stare de baterie, niciun eveniment electric.
`QPI` este comanda de identificare a protocolului Voltronic. UPS-ul răspunde `(NAK` —
„comandă nesuportată" — deci ViewPower rămâne blocat în bucla de identificare și nu ajunge
niciodată să interogheze starea.
Nu e o problemă de port: `GlobalConfig.portName=USB1F0775B7` din `config\ups.properties`
corespunde exact interfeței `HID\VID_0665&PID_5161&MI_00\8&1F0775B7&0&0000`. ViewPower e
legat de dispozitivul corect; **setul de comenzi e greșit**. UPS-ul vorbește HID Power Device
standard — de aceea îl citește Windows fără niciun driver suplimentar — nu dialectul text pe
care îl trimite ViewPower. Nu există setare care să repare asta.
### Cronologia serii de 10 august
```
22:24:12 upsTomcat pornit (o ultimă încercare de repornire)
22:24:31 ups.properties rescris
22:34:11 ultimul QPI return(NAK
22:34:44 System 7040: upsMonitor auto start → disabled
22:34:46 System 7040: upsTomcat demand start → disabled
```
Cineva a încercat să repare, nu a reușit și a dezactivat serviciile. Din acel moment: **zero
monitorizare**. Tray-ul care se deschidea și dădea `start ups monitor service error!` încerca,
de fapt, să pornească un serviciu pus pe `Disabled` (registry `Start=4`).
### Ce nu exista oricum, chiar și cu ViewPower funcțional
- **Alertare: niciuna.** Logul arată `---------emailReceivers.length()-----0`, iar
`SmsInfo.mobileNums` e gol. Nimeni nu ar fi aflat de o pană nici dacă softul mergea.
- **Oprire curată a Oracle: niciuna.** `Shutdownconfigure.excuteProgram` e gol — nu rula
niciun script înainte de shutdown.
- Regula proprie „30 min pe baterie → oprire" (`batModeShutdown=true`,
`batModeShutdownTime=30`) era inactivă odată cu serviciile.
- Vârsta acumulatorilor neurmărită (`GlobalConfig.batteryLifetime=0`).
### Plasa care exista, totuși
Planul de alimentare Windows, pe canalul HID care funcționează:
| Setare | Valoare |
|---|---|
| Critical battery level | **20 %** |
| Critical battery action | **Shut down** (și pe AC, și pe DC) |
| Low battery level / action | 40 % / *Do nothing* |
| Reserve battery level | 25 % |
Deci serverul s-ar fi oprit singur la 20 %, dar brutal: fără avertisment, fără `shutdown
immediate` pe Oracle, fără ca cineva să afle.
---
## 2. Ce s-a pus în loc
Un singur script PowerShell care citește **`GetSystemPowerStatus`** — exact API-ul pe care îl
folosește Windows pentru propria acțiune de „critical battery". Consecința practică: dacă
oprirea automată a Windows-ului ar funcționa, funcționează și scriptul; nu există un al doilea
canal care să se strice separat.
| Fișier în repo | Rol |
|---|---|
| `scripts/ups-monitor/ups-monitor.ps1` | monitorul propriu-zis (buclă + moduri de test) |
| `scripts/ups-monitor/install-ups-monitor.ps1` | instalare: copiere, `config.json`, ACL, task programat |
| `scripts/ups-monitor/test-battery.ps1` | test: simulează „pe baterie" fără scoaterea din priză |
| `scripts/ups-monitor/test-comms-loss.ps1` | test: dezactivează temporar bateria HID și verifică alerta de comunicație |
| `scripts/ups-monitor/set-praguri.ps1` | schimbă pragurile din `config.json` fără a atinge parola SMTP, și repornește taskul |
| `scripts/ups-monitor/trace-baterie.ps1` | înregistrează curba de descărcare într-un CSV (rulează ca task, sub SYSTEM) |
| `scripts/ups-monitor/start-trace.ps1` | pornește / oprește (`-Stop`) taskul de înregistrare |
| `scripts/ups-monitor/config.example.json` | șablon; **fișierul real nu se comite** (conține parola SMTP) |
Ultimele trei sunt uneltele testului de autonomie — se folosesc împreună, vezi secțiunea 3.
Pe server:
```
C:\ROMFAST\ups-monitor\ups-monitor.ps1
C:\ROMFAST\ups-monitor\config.json <- parola SMTP; ACL: doar SYSTEM + Administratori
C:\ROMFAST\ups-monitor\state.json <- starea între cicluri
C:\ROMFAST\ups-monitor\log\ups-monitor-YYYY-MM.log
C:\ROMFAST\_deploy\ <- punctul de livrare (de aici rulează instalarea)
```
Task programat **`ROMFAST UPS Monitor`**, rulează ca `NT AUTHORITY\SYSTEM` (cont deja membru
`ORA_DBA` pe acest server, deci `sqlplus / as sysdba` merge fără parolă).
### Ce face
| Eveniment | Acțiune |
|---|---|
| Trecere pe baterie | email imediat: **„PANĂ DE CURENT"** |
| Revenirea curentului | email cu durata cât s-a stat pe baterie |
| **UPS-ul nu mai e văzut de Windows** | email de alertă, repetat la 24 h cât ține defectul |
| Comunicația revine | email de confirmare |
| Prag de oprire atins | email, apoi oprire curată |
### Pragurile de oprire
```
10 minute pe baterie SAU încărcare ≤ 35 %
(Windows rămâne plasa de siguranță, la 20 %)
```
Se declanșează doar după **3 citiri consecutive** care confirmă starea pe baterie — o citire
aberantă nu poate opri serverul. Iar dacă UPS-ul **nu comunică**, scriptul nu ia nicio decizie
de oprire; alertează și atât.
### Secvența de oprire
1. email (pleacă **primul** — în pană de curent poate cădea și switch-ul în orice moment)
2. `Stop-Service OracleOraDB19Home1TNSListener` — nu mai intră conexiuni noi
3. `sqlplus / as sysdba` → `shutdown immediate`, cu timeout 180 s
4. `Stop-Service OracleServiceROA` — plasă de siguranță; serviciul e el însuși configurat
`ORA_ROA_SHUTDOWNTYPE=immediate`, `ORA_ROA_SHUTDOWN_TIMEOUT=90`, deci și oprirea lui e curată
5. `shutdown /s /f /t 30`
> La revenirea curentului serverul **nu pornește singur** decât dacă e activat
> *Restore on AC power loss* în BIOS. De verificat separat, la prima intervenție fizică.
---
## 3. Operare
```powershell
# starea curentă: UPS, Oracle, task, ultimele linii de log
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\ups-monitor\ups-monitor.ps1 -Mode Status
# verifică alertarea pe email
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\ups-monitor\ups-monitor.ps1 -Mode TestMail
# parcurge secvența de oprire în gol — nu oprește nimic
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\ups-monitor\ups-monitor.ps1 -Mode TestShutdown
```
### Ce s-a validat la punerea în funcțiune (27.08.2026)
| Test | Rezultat |
|---|---|
| Citirea stării | `pe rețea`, 100 %, `Win32_Battery: HID UPS, Status=OK` |
| `-Mode TestMail` | email primit — `mail.romfast.ro:587`, STARTTLS, `ups@romfast.ro` |
| `-Mode TestShutdown` (dry-run) | secvența parcursă integral; Oracle a rămas `Running` |
| Pierderea comunicației (`test-comms-loss.ps1`) | dispozitiv oprit 15:24:44 → alertă **15:26:44** (exact 8 cicluri × 15 s) + email; reactivare → „comunicația a revenit" + email; `Win32_Battery` înapoi la 1 instanță |
| Taskul rulează ca SYSTEM | proces `ups-monitor.ps1 -Mode Run`, `state.json` actualizat la fiecare ciclu |
| **Trecerea reală pe baterie** (scos din priză, 15:47:45 → 15:50:46) | tranziția s-a văzut instantaneu în ambele sensuri; email de pană la 15:47:55, email de revenire la 15:50:56 |
Toate cele patru ramuri de alertare au emis email. Testul cu scoaterea din priză a durat doar
trei minute — prea puțin pentru autonomie, dar suficient cât să valideze semnalul de sursă și
să descopere problema gauge-ului (secțiunea 6, punctul 1).
### Testul „pe baterie", fără scoaterea din priză
Lanțul de protecție are două jumătăți, și se testează separat:
| Jumătatea | Cum se validează |
|---|---|
| UPS → Windows (*chiar raportează trecerea pe baterie?*) | **deja dovedită de istoric**: perechile de evenimente Kernel-Power **105** la panele reale din 10 iun, 13 mai, 5 mai, 25 feb 2026 |
| Windows → script → alertă → oprirea Oracle | `test-battery.ps1`, oricând, fără hardware |
```powershell
# repetiție în gol - sigură oricând, în producție
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\_deploy\test-battery.ps1 -Percent 30 -Minute 3
# doar trecerea pe baterie, fără atingerea pragului de oprire
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\_deploy\test-battery.ps1 -Percent 80 -Minute 3
```
Scriptul scrie `SIMULARE.json` lângă `config.json`; cât există, monitorul folosește valorile
din el în locul citirii reale. Două gărzi, ca un fișier uitat să nu oprească serverul pe date
inventate:
- **`expira` e obligatoriu.** Fără el fișierul e ignorat; la depășire, monitorul îl șterge singur.
- **Oprirea e în gol**, dacă nu se cere explicit `"dryRun": false`.
Cât e activă simularea, fiecare ciclu scrie în log o linie `WARN SIMULARE ACTIVA`, iar
`-Mode Status` o afișează. `test-battery.ps1` șterge fișierul și dacă e întrerupt.
**Repetiție reală**, într-o fereastră de mentenanță — Oracle chiar se oprește și serverul
chiar se închide, dar UPS-ul rămâne în priză:
```powershell
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\_deploy\test-battery.ps1 -ConfirmReal 'DA-OPRESTE-SERVERUL'
```
Asta e singurul mod de a verifica de-adevăratelea cât durează `shutdown immediate` pe baza de
producție — informația de care depinde alegerea pragurilor.
**Rămâne netestabilă prin simulare** doar autonomia reală a UPS-ului: câte minute ține sub
sarcina actuală. Aceea cere scoaterea din priză — procedura e mai jos.
### Testul de autonomie, cu scoaterea din priză
Trei unelte, în ordinea asta. Toate rulează **pe server**, prin `ssh -p 22122`.
```powershell
# 1. lărgește pragurile, ca monitorul să nu oprească serverul în timpul testului
# (scriptul repornește singur taskul - configurația se citește doar la pornirea buclei)
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\ups-monitor\set-praguri.ps1 -Minute 60 -Procent 15
# 2. pornește înregistrarea curbei de descărcare
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\ups-monitor\start-trace.ps1 -IntervalSecunde 15
# --- abia acum se scoate din priză; minimum 15-20 de minute, ca să se vadă panta ---
# 3. după ce s-a băgat înapoi: oprește înregistrarea și restaurează pragurile de producție
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\ups-monitor\start-trace.ps1 -Stop
powershell -ExecutionPolicy Bypass -File C:\ROMFAST\ups-monitor\set-praguri.ps1 -Minute 10 -Procent 35
```
Înregistrarea rulează ca **task programat sub SYSTEM**, nu în sesiunea SSH — dacă în pană
cade switch-ul și conexiunea moare, măsurătoarea continuă. Datele rămân în
`C:\ROMFAST\ups-monitor\log\trace-baterie.csv`; scriptul **adaugă** la fișierul existent, deci
CSV-ul unui test anterior se arhivează întâi sub alt nume, altfel se amestecă rulările.
Două lucruri de verificat înainte de a scoate ștecherul: pragul de procent lărgit sub 20 %
înseamnă că **plasa de siguranță rămâne Windows-ul**, nu scriptul; și e util ca gauge-ul să
fie la 100 %, nu abia revenit dintr-un test anterior.
**Dezarmare de urgență** (monitorul rămâne pornit, dar nu mai ia nicio decizie):
```powershell
New-Item -ItemType File 'C:\ROMFAST\ups-monitor\DEZACTIVAT'
```
Ștergerea fișierului îl rearmează, fără repornire. Există și `"enabled": false` în
`config.json`, dar acela cere repornirea taskului.
**Reinstalare / schimbare praguri** (de pe stația de administrare):
```powershell
scp -P 22122 ups-monitor.ps1 install-ups-monitor.ps1 Administrator@10.0.20.36:'C:/ROMFAST/_deploy/'
ssh -p 22122 Administrator@10.0.20.36 "powershell -ExecutionPolicy Bypass -File C:\ROMFAST\_deploy\install-ups-monitor.ps1 -SmtpPassword ... -ShutdownAfterMinutesOnBattery 10 -ShutdownAtBatteryPercent 35"
```
**Emailuri:** de la `ups@romfast.ro` către `marius.mutu@romfast.ro`, prin
`mail.romfast.ro:587` (STARTTLS). Același cont SMTP pe care îl folosesc și cele trei noduri
Proxmox — credențialele sunt în `/etc/postfix/sasl_passwd` pe noduri.
---
## 4. Ce s-a întâmplat cu ViewPower
- procesele `ViewPower.exe`, `upsTray.exe`, `javaw.exe` — **oprite**;
- serviciile `upsMonitor` și `upsTomcat` — rămân **Disabled** (erau deja, din 10 august);
- **nu există autostart** — nici în `Run` (HKLM/HKCU), nici în folderele Startup; procesele
văzute pe 27 august fuseseră pornite manual;
- instalarea din `C:\ViewPower` a fost **lăsată pe disc**, ca referință pentru loguri și
configurație.
Efect secundar util: nu mai ascultă nimic pe **15178** și **8005** — un Tomcat 8.5.51 cu
OpenJDK 11.0.7 (2020–2021) nu mai stă pornit degeaba pe un server de producție.
Dezinstalarea completă (`C:\ViewPower\Uninstaller.exe`) e opțională. Înainte de ea merită
salvat `C:\ViewPower\datas` — baza Derby de ~71 MB cu istoricul softului.
---
## 5. Capcane plătite (ca să nu se redescopere)
**Task-urile programate sunt oprite de Windows exact când serverul trece pe baterie.** E
comportamentul implicit. Fără `-AllowStartIfOnBatteries -DontStopIfGoingOnBatteries` la
`New-ScheduledTaskSettingsSet`, monitorul ar fi fost ucis fix în secunda în care avea treabă.
Asta e greșeala care ar fi trecut neobservată până la prima pană reală.
**`$PSScriptRoot` este gol în valoarea implicită a unui parametru.** La legarea parametrilor
încă nu e populat, deci `[string]$ConfigPath = (Join-Path $PSScriptRoot 'config.json')` crapă
cu *„Cannot bind argument to parameter 'Path' because it is an empty string"*. Se rezolvă în
corpul scriptului.
**`[TimeSpan]::MaxValue` pentru `-RepetitionDuration` e respins**, deși e documentat ca „la
nesfârșit": *„The task XML contains a value which is incorrectly formatted or out of range.
Duration: P99999999DT23H59M59S"*. Se omite parametrul — asta chiar înseamnă la nesfârșit.
**PowerShell 5.1 nu acceptă `if`/`try` ca expresie** într-un literal de hashtable
(`@{ x = if (...) {...} }`) sau la atribuire din `try`. Scriptul e scris în consecință; se
verifică înainte de livrare cu:
```powershell
$e=$null; [System.Management.Automation.PSParser]::Tokenize((Get-Content x.ps1 -Raw), [ref]$e); $e
```
**Ghilimelele simple supraviețuiesc prin `ssh` → `powershell -File`.** `-SmtpPassword
'#Ups2020#'` a ajuns în `config.json` ca `'#Ups2020#'`, cu tot cu apostrofuri, iar serverul de
mail a răspuns *„SMTP AUTH is required for message submission on port 587"* — adică nu s-a
autentificat deloc. Pentru orice valoare cu caractere speciale: se trimite un `.ps1` cu `scp`
și se rulează acolo, nu se construiește comanda din ghilimele.
**Fișierul `.ps1` e intenționat fără diacritice.** PowerShell 5.1 citește un `.ps1` fără BOM
ca ANSI; diacriticele din literalii de șir ar ajunge corupte în emailuri. Documentația (`.md`)
nu are constrângerea asta.
---
## 6. Rămâne de făcut
1. **Testul de autonomie reală.** Pragurile de 10 min / 35 % sunt alese conservator, nu
măsurate. Sunt două necunoscute distincte, iar doar una cere scoaterea din priză:
- *cât durează oprirea curată* (`shutdown immediate` + închiderea Windows-ului) — se află
dintr-o **repetiție reală** cu `test-battery.ps1 -ConfirmReal ...`, într-o fereastră de
mentenanță, cu UPS-ul în priză;
- *cât ține UPS-ul sub sarcina actuală* — asta chiar cere scoaterea din priză, după
procedura din secțiunea 3.
Pragul corect e „autonomia măsurată minus durata opririi, cu marjă". Până când ambele sunt
măsurate, pragurile rămân o presupunere rezonabilă, nu o garanție.
**Ce s-a aflat pe 27.08.2026, dintr-o scoatere din priză de trei minute:** autonomia n-a
fost măsurată — trei minute sunt prea puține, iar singura cifră existentă rămâne estimarea
proprie a UPS-ului, ~70 de minute, nevalidată. S-a aflat însă altceva, mai important.
**Gauge-ul de procent al acestui UPS nu e de încredere.** Pe baterie a scăzut lent și
monoton (100 % → 96 % în trei minute), dar la revenirea curentului a sărit haotic:
```
15:50:26 baterie 96%
15:50:46 rețea 65% <- revine curentul
15:51:06 rețea 75%
15:51:46 rețea 90%
```
96 → 65 → 90 în 100 de secunde. Nicio baterie nu se încarcă 25 de puncte în 80 de secunde,
deci nu e încărcare — e recalibrare, sau zgomot în jurul tranziției. (La 12 minute după test
gauge-ul era tot la 90 %.)
**Consecința pentru configurația actuală:** pragul de **35 %** se sprijină exact pe numărul
ăsta nesigur, iar garda de confirmare (`confirmPolls = 3`, adică 45 s) e **mai scurtă decât
fereastra de zgomot observată (~80–100 s)**. Riscul e în ambele sensuri: o citire aberantă
sub 35 % ar putea opri inutil baza de producție, iar una optimistă ar putea întârzia
oprirea.
Semnalul de **sursă** (`ACLineStatus`) a fost, în schimb, impecabil — tranzițiile s-au văzut
instantaneu în ambele sensuri. De aici, direcția pentru pragurile definitive:
- **timpul pe baterie devine criteriul principal**, fiindcă se sprijină pe `ACLineStatus`;
- procentul rămâne doar plasă secundară, cu valoare mai mică și cu `confirmPolls` crescut
peste fereastra de zgomot (≥ 8 cicluri = 2 min);
- de evaluat `BatteryLifeTime` ca al treilea criteriu — în acest test a scăzut lin și
monoton, spre deosebire de procent. Există deja `shutdownAtRuntimeSeconds` în
`config.json`, momentan `0` = dezactivat.
2. **Vârsta acumulatorilor.** Necunoscută. Pe cluster există deja criteriul de vârstă în
testul lunar (`proxmox/cluster/ups/`); aici nu există nimic echivalent.
3. **BIOS: *Restore on AC power loss*.** De verificat la prima intervenție fizică — altfel
după o pană lungă serverul rămâne oprit până vine cineva să apese butonul.
4. **Legătura cu incidentul din 10 august:** stările de somn (S3) sunt încă disponibile pe
acest server. O oprire declanșată de UPS ajunge la `shutdown /s`, nu la sleep, deci nu e
afectată — dar problema de fond rămâne deschisă în documentul incidentului.