# 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.