Files
ROMFASTSQL/docs/ups-server36-monitorizare.md
Marius b2ed5e84d0 docs(ups): capcana Task Scheduler intra in sectiunea de capcane platite
Era doar in handoff (care se sterge) si in mesajul commit-ului 03d3045. Acum e
la vedere, langa celelalte: un NEINREGISTRAT de la -Mode Status poate fi o
eroare tranzitorie de interogare, nu un task disparut.

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

21 KiB
Raw Blame History

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 — 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

# 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, de două ori (3 min de la 15:47:45, apoi 15 min de la 16:08:03) tranziția s-a văzut instantaneu în ambele sensuri, la ambele teste; emailuri de pană și de revenire la fiecare

Toate cele patru ramuri de alertare au emis email. Cele două scoateri din priză n-au măsurat autonomia — în cincisprezece minute gauge-ul a coborât doar 90 % → 80 % — dar au validat semnalul de sursă și au arătat de ce pragul pe procent nu poate fi criteriul principal (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
# 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 -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.

# 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):

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):

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:

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

Task Scheduler refuză ocazional interogarea, iar răspunsul nu înseamnă „nu există". Pe 27.08.2026 la 16:27, -Mode Status a raportat Task programat: NEINREGISTRAT deși taskul rula — State=Running, proces ups-monitor.ps1 -Mode Run viu — iar trei rulări imediat următoare au raportat corect. Cauza era în raportare, nu în task: catch-ul trata la fel „nu există" și „n-am putut întreba", și îl afișa pe cel mai alarmant. Într-o pană reală mesajul ăla ar trimite pe cineva să reinstaleze un monitor funcțional. Corectat: absența se stabilește prin $null -eq $task, iar o interogare eșuată spune NEDETERMINAT și arată eroarea.

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, din două scoateri din priză (3 minute, apoi 15 minute): autonomia tot nu e măsurată — în cincisprezece minute gauge-ul a coborât doar de la 90 % la 80 %, deci punctul de oprire nici nu s-a apropiat. Singura cifră existentă rămâne estimarea proprie a UPS-ului, ~70 de minute, nevalidată. S-au aflat însă trei lucruri care schimbă alegerea criteriului.

    (a) Gauge-ul de procent nu are o pantă pe care să se poată extrapola. În testul de 15 minute a stat blocat pe loc patru minute, apoi a accelerat de aproape zece ori:

    Interval Pantă
    16:08 → 16:12 (4 min) 0 puncte/min — imobil la 90 %
    16:12 → 16:17 0,8 puncte/min
    16:20 → 16:23 2 puncte/min

    Extrapolarea făcută la minutul 8 dădea „pragul de 35 % vine peste 220 de minute"; cea de la minutul 14 dădea 22 de minute. Aceeași baterie, aceeași sarcină, zece minute distanță.

    (b) La revenirea curentului sare haotic — reproductibil, la aceeași valoare. Ambele teste, independent:

    test 1:  96 %  ->  65 %  ->  75 %  ->  90 %      în ~100 s
    test 2:  78 %  ->  65 %  ->  70 %  ->  75 %      în ~45 s
    

    Nicio baterie nu se încarcă 25 de puncte în 80 de secunde; e recalibrare, nu încărcare. Acest zgomot nu poate opri însă serverul: tot blocul de decizie a opririi e înăuntrul ramurii if ($r.OnBattery) (ups-monitor.ps1), iar saltul se produce după revenirea curentului, când ramura nu se mai execută. Pericolul real e opus și e demonstrat de punctul (a): gauge-ul rămâne optimist cât timp bateria chiar se descarcă — opt minute și jumătate blocat la 90 % — deci un prag pe procent reacționează prea târziu, nu prea devreme.

    (c) BatteryLifeTime nu e o măsurătoare, e o numărătoare inversă. În testul de 15 minute au trecut 901 secunde, iar estimarea a scăzut cu 872 — raport 0,97, verificat și la două puncte intermediare (240/240 s și 871/872 s). UPS-ul fixează o valoare la începutul penei și scade timpul scurs din ea. Nu aduce nicio informație peste cronometrul propriu al scriptului, iar dacă estimarea inițială e greșită, numărătoarea e greșită cu exact aceeași eroare până în secunda în care se stinge.

    Semnalul de sursă (ACLineStatus) a fost, în schimb, impecabil în ambele teste — tranzițiile s-au văzut instantaneu în ambele sensuri, iar emailurile au plecat la fiecare. De aici, direcția pentru pragurile definitive:

    • timpul pe baterie rămâne criteriul principal, fiindcă se sprijină pe ACLineStatus, singurul semnal care s-a purtat impecabil;
    • shutdownAtRuntimeSeconds rămâne 0 (dezactivat) — punctul (c) arată că ar fi doar al doilea nume al aceluiași cronometru;
    • procentul rămâne plasă secundară grosieră. Nu are rost coborât mult sub 35 %: fiind optimist, nu aberant, el oricum nu declanșează primul.

    Ce ar schimba concluzia: o măsurătoare dusă până la o descărcare adâncă, unde s-ar vedea dacă gauge-ul se prăbușește brusc spre final. Pe o bază de producție asta nu se face fără fereastră de mentenanță.

  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.