Files
ROMFASTSQL/proxmox/cluster/scripts/verifica-pveelite.ps1
Marius 5e31d975df docs(cluster): pveelite - cauza confirmata, resetul adaptorului USB LAN
Nodul nu s-a oprit niciodata. La verificarea de azi avea uptime 17h46m, cu boot
pornit la 27.08 ora 16:03:06 - a mers toata noaptea, fara retea. Jurnalul
continua cu 58.454 de linii dupa 17:26:44, ceea ce inchide definitiv discutia
alimentare vs retea.

Vinovatul, din jurnalul kernel: Realtek RTL8156B (0bda:8156, driver r8152) pe
usb 2-3. La 16:01:45 si la 17:26:41 adaptorul s-a resetat si a fost re-enumerat.
Kernelul sterge interfata si o recreeaza - dar nimeni nu o readauga in vmbr0 si
nu o ridica, pentru ca nu exista regula de hotplug. Din acel moment masina merge
perfect si e invizibila in retea.

Partea care merita retinuta e de ce la 16:01 si-a revenit si la 17:26 nu. La
16:01 LRM-ul HA era activ, deci watchdog-ul era armat: pierderea retelei a dus la
pierderea quorumului, watchdog-mux a expirat la 16:02:39 si a resetat masina la
16:02:44 - repornire care a readus reteaua din intamplare, pentru ca la boot
interfetele se ridica prin auto. La 17:26 fence-ul mutase deja vm:109 pe pvemini,
LRM-ul era idle, watchdog-ul nearmat. Nimic nu a mai repornit masina. Singurul
lucru care "repara" defectul asta era un efect secundar, nu un mecanism proiectat
- pe un nod fara servicii HA, aceeasi defectiune devine permanenta si tacuta.

Reparat cu ifreload -a de la consola, la 09:49. Restul verificarii e curat: ZFS
ONLINE fara erori, cluster 3/3, SMART fara FAILED, replicarea se reia singura.

Reparatia de fond intra in Tier 1: eno1 exista si e functional, doar ca nu are
cablu (Link detected: no). Adaptorul USB e cauza a doua incidente pe nodul asta.
Am scris si ordinea operatiilor, pentru ca inversata te lasa fara retea cu drum
pana la nod.

Prima rulare reala a scriptului a scos la iveala trei defecte ale lui, toate
reparate aici:

- tiparele de semnatura hardware prindeau linii normale de boot ("Registered
  thermal governor", "NMI watchdog: Enabled", "EDAC MC: Ver: 3.0.0") si produceau
  un verdict de defect hardware care contrazicea concluzia corecta din acelasi
  bilant. Strans tiparele si filtrat prin -p warning; verificat pe nod: 0
  potriviri.
- LRM idle era raportat ca "stare neclara". E starea normala a unui nod fara
  servicii HA - iar scriptul spune acum explicit ca idle inseamna watchdog
  nearmat, adica exact motivul pentru care caderea de la 17:26 nu s-a auto-reparat.
- Tailscale era raportat [ok] desi e delogat: systemctl is-active zice active, dar
  tailscale status zice "Logged out". De aici si cele 27 de zile de offline.

Consemnat si raspunsul la intrebarea cu magic packet, cu MAC-urile ambelor
interfete, ca sa nu se reia: WoL nu ar fi ajutat oricum, masina nu era oprita.
Dupa mutarea pe eno1 devine insa realmente utilizabil.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAEUqrv26jCM5KwAPtkHb8
2026-08-28 09:55:10 +03:00

470 lines
21 KiB
PowerShell

<#
.SYNOPSIS
Verificare completa a nodului pveelite dupa revenirea din incidentul 2026-08-27.
.DESCRIPTION
Nodul pveelite a disparut din retea la 16:01 pe 27.08.2026, a revenit dupa 89 de
secunde, apoi a disparut definitiv la 17:26, pe o masina complet idle. Cauza nu s-a
putut stabili de la distanta - nodul nu raspundea nici la ARP. Scriptul se ruleaza
IMEDIAT dupa ce nodul e accesibil din nou si raspunde la doua intrebari:
1. DE CE a cazut - din jurnalul care abia acum devine citibil.
2. E nodul in stare buna acum - ZFS, cluster, replicare, HA, SMART, Tailscale.
Pasul 1 conteaza mai mult decat tot restul, si incepe cu intrebarea care imparte
incidentul in doua: s-a OPRIT masina, sau doar a disparut din RETEA? Din afara
arata identic - fara ping, fara ARP, fara corosync - dar remediul difera complet.
Testul decisiv e daca jurnalul continua dupa ora caderii: daca da, masina a mers
mai departe si a cazut doar reteaua.
Ipoteza de retea nu e teoretica pe nodul asta: pveelite are adaptor USB de retea,
iar incidentul 2026-04-20 a pornit exact de la un USB LAN disconnect - motivul
pentru care tokenul corosync a fost marit la 10 s.
Daca insa jurnalul se opreste brusc si e TACUT inainte - fara MCE, fara eroare
termica, fara panic - atunci cauza e alimentare/hardware, ca la pvemini pe
2026-04-20, iar nodul NU e de incredere ca tinta de failover pana la testarea
sursei si a memoriei. "A pornit, deci e bine" nu e o concluzie valida aici.
Context complet: ../incidents/2026-08-27-pveelite-down.md
RULEAZA DE PE STATIA DE ADMIN. Motivul: SSH intre nodurile Proxmox trece prin
Tailscale si cere autentificare interactiva, deci comenzile inlantuite de tip
"ssh pvemini ssh pveelite" se blocheaza.
Necesita clientul OpenSSH din Windows si o cheie SSH acceptata de root pe noduri.
.PARAMETER Wait
Asteapta pana la N minute ca pveelite sa raspunda, in loc sa iasa imediat.
Util daca pornesti scriptul inainte sa apesi butonul de power.
.EXAMPLE
.\verifica-pveelite.ps1
.EXAMPLE
.\verifica-pveelite.ps1 -Wait 10
#>
[CmdletBinding()]
param(
[int]$Wait = 0
)
$ErrorActionPreference = 'Stop'
# ---------------------------------------------------------------- configurare
$NodeIp = [ordered]@{
pve1 = '10.0.20.200'
pvemini = '10.0.20.201'
pveelite = '10.0.20.202'
}
# Reperele incidentului 2026-08-27, folosite pentru a taia log-urile la fereastra
# relevanta si a nu ineca verdictul in zgomot.
$ResetSpontan = '2026-08-27 16:01:48' # reset care s-a auto-reparat in 89 s
$CadereFinala = '2026-08-27 17:26:44' # caderea definitiva
$IncidentStart = '2026-08-27 13:20' # boot-ul de dupa oprirea planificata
# Tipare de eroare hardware in jurnalul kernel. Daca NICIUNUL nu apare, verdictul
# inclina spre alimentare (masina nu apuca sa scrie nimic inainte sa dispara).
#
# Tiparele sunt deliberat STRANSE. Prima versiune cauta 'thermal', 'nmi', 'edac',
# 'BUG:' si a raportat fals pozitiv la rularea din 28.08: liniile normale de boot
# ("Registered thermal governor", "NMI watchdog: Enabled", "EDAC MC: Ver: 3.0.0",
# "DPC: error containment capabilities") au declansat un verdict de defect hardware
# care contrazicea concluzia corecta. Un fals pozitiv aici nu e zgomot inofensiv -
# trimite pe pista gresita exact cand trebuie luata o decizie.
$TipareHw = 'Machine Check|mce: |Hardware Error|Uncorrected error|' +
'temperature above threshold|critical temperature|' +
'Kernel panic|Oops: |watchdog: BUG: soft lockup|' +
'EDAC.*(CE|UE) .*error|AER: .*error|Buffer I/O error|' +
'blk_update_request.*I/O error|ATA bus error'
$ReplJobs = 9 # 9 job-uri de replicare au pveelite ca tinta
# ------------------------------------------------------------------- utilitare
function Write-Step { param([string]$Text) Write-Host ""; Write-Host "== $Text" -ForegroundColor Green }
function Write-Ok { param([string]$Text) Write-Host " [ok] $Text" -ForegroundColor Green }
function Write-Warn { param([string]$Text) Write-Host " [!] $Text" -ForegroundColor Yellow }
function Write-Bad { param([string]$Text) Write-Host " [X] $Text" -ForegroundColor Red }
function Write-Info { param([string]$Text) Write-Host " $Text" -ForegroundColor DarkGray }
function Test-Alive {
param([string]$Address, [int]$TimeoutMs = 2000)
try {
$p = New-Object System.Net.NetworkInformation.Ping
return ($p.Send($Address, $TimeoutMs).Status -eq 'Success')
} catch {
return $false
}
}
function Invoke-Node {
param([string]$Node, [string]$Command, [int]$Timeout = 15)
# stderr e capturat separat: pe Windows PowerShell 5.1, 2>&1 pe un executabil
# nativ transforma fiecare linie de stderr in ErrorRecord si strica $?.
$out = ssh -o BatchMode=yes -o ConnectTimeout=$Timeout `
-o StrictHostKeyChecking=accept-new -o LogLevel=ERROR `
"root@$($NodeIp[$Node])" $Command
return $out
}
# Colectorul de concluzii: fiecare pas adauga aici, la final se tipareste bilantul.
$Rezultate = [System.Collections.ArrayList]::new()
function Add-Rezultat {
param([string]$Nume, [ValidateSet('ok','warn','bad')][string]$Stare, [string]$Detaliu)
[void]$Rezultate.Add([pscustomobject]@{ Nume = $Nume; Stare = $Stare; Detaliu = $Detaliu })
}
# =========================================================== 0. nodul raspunde
Write-Host ""
Write-Host "VERIFICARE pveelite dupa incidentul din 2026-08-27" -ForegroundColor Cyan
Write-Host "Referinta: proxmox/cluster/incidents/2026-08-27-pveelite-down.md" -ForegroundColor DarkGray
Write-Step "0. Nodul raspunde?"
$deadline = (Get-Date).AddMinutes($Wait)
$viu = Test-Alive $NodeIp.pveelite
while (-not $viu -and (Get-Date) -lt $deadline) {
Write-Info "inca nu raspunde, reincerc... (pana la $($deadline.ToString('HH:mm')))"
Start-Sleep -Seconds 15
$viu = Test-Alive $NodeIp.pveelite
}
if (-not $viu) {
Write-Bad "pveelite ($($NodeIp.pveelite)) nu raspunde la ping."
Write-Info "Porneste nodul fizic, apoi reia. Sau ruleaza cu -Wait 10 ca sa astepte."
exit 1
}
Write-Ok "ping OK"
try {
$hostn = Invoke-Node -Node pveelite -Command 'hostname'
Write-Ok "SSH OK - $hostn"
} catch {
Write-Bad "raspunde la ping dar nu la SSH. Verifica pe consola fizica."
exit 1
}
$uptime = Invoke-Node -Node pveelite -Command 'uptime -p; uptime -s'
Write-Info ($uptime -join ' | ')
# ============================== 1. s-a oprit, sau doar a disparut din retea?
Write-Step "1. S-a oprit masina, sau doar a disparut din retea?"
Write-Info "Intrebarea asta se pune PRIMA, pentru ca imparte incidentul in doua"
Write-Info "scenarii cu remedii complet diferite:"
Write-Info " (a) masina s-a oprit sau resetat -> alimentare / RAM / termic"
Write-Info " (b) masina a mers tot timpul, dar a pierdut adaptorul USB de retea"
Write-Info " -> exact tiparul documentat pe nodul asta la 2026-04-20"
Write-Info "Din afara, cele doua arata identic: fara ping, fara ARP, fara corosync."
Write-Host ""
Write-Info "boot-uri inregistrate:"
$boots = Invoke-Node -Node pveelite -Command 'journalctl --list-boots --no-pager | tail -6'
$boots | ForEach-Object { Write-Info " $_" }
# TESTUL DECISIV: exista intrari in jurnal DUPA ora la care nodul a disparut din
# retea? Daca da, masina a continuat sa mearga si a cazut doar reteaua.
$dupaCadere = Invoke-Node -Node pveelite -Command `
"journalctl --since '$CadereFinala' --until '2026-08-28 06:00' --no-pager | wc -l"
$nrDupa = 0
[void][int]::TryParse((($dupaCadere | Select-Object -First 1) -replace '\D',''), [ref]$nrDupa)
# Al doilea test: a existat un boot in fereastra resetului de la 16:01?
$bootLa16 = Invoke-Node -Node pveelite -Command `
"journalctl --since '2026-08-27 15:55' --until '2026-08-27 16:15' --no-pager | grep -ci 'Linux version'"
$nrBoot16 = 0
[void][int]::TryParse((($bootLa16 | Select-Object -First 1) -replace '\D',''), [ref]$nrBoot16)
Write-Host ""
$scenariuRetea = $false
if ($nrDupa -gt 0) {
Write-Bad "SCENARIUL (b): jurnalul CONTINUA dupa $CadereFinala ($nrDupa linii)."
Write-Info "Masina nu s-a oprit - a mers mai departe si doar a disparut din retea."
Write-Info "Cauza e adaptorul USB de retea, nu alimentarea. Vezi sectiunea USB de mai jos."
Add-Rezultat 'Cauza caderii' 'bad' 'masina a mers mai departe => cadere de retea (USB LAN), nu alimentare'
$scenariuRetea = $true
} else {
Write-Info "Jurnalul se opreste la $CadereFinala - masina chiar a incetat sa mearga."
}
if ($nrBoot16 -gt 0) {
Write-Info "La 16:01 a existat un boot real ($nrBoot16 x 'Linux version') - deci s-a resetat."
} else {
Write-Info "La 16:01 NU exista boot in jurnal - a fost tot o disparitie din retea, nu un reset."
}
# Liniile din jurul fiecarui eveniment, cautate dupa ora - nu dupa indexul boot-ului,
# care difera intre cele doua scenarii.
foreach ($b in @(
@{ Cand = $CadereFinala; Ce = 'caderea definitiva de la 17:26' },
@{ Cand = $ResetSpontan; Ce = 'evenimentul de la 16:01' }
)) {
Write-Host ""
Write-Info "--- ultimele linii dinainte de $($b.Ce) ---"
$tail = Invoke-Node -Node pveelite -Command `
"journalctl --since '$IncidentStart' --until '$($b.Cand)' --no-pager | tail -15"
if ($tail) { $tail | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray } }
else { Write-Warn "nimic in jurnal pentru fereastra asta (rotit sau volatile)" }
}
$err = Invoke-Node -Node pveelite -Command `
"journalctl --since '$IncidentStart' --until '2026-08-28 06:00' -p err --no-pager | tail -25"
if ($err) {
Write-Warn "erori de prioritate >= err in fereastra incidentului:"
$err | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow }
} else {
Write-Info "fara erori de prioritate >= err in fereastra incidentului"
}
# --------------------------------------------- adaptorul USB de retea
Write-Host ""
Write-Info "--- adaptorul USB de retea (istoric de defectiuni pe nodul asta) ---"
$nic = Invoke-Node -Node pveelite -Command @'
echo "interfete:"; ip -br link 2>/dev/null | head -8
echo "drivere:"
for n in /sys/class/net/*; do
d=$(basename $(readlink -f $n/device/driver) 2>/dev/null)
[ -n "$d" ] && echo " $(basename $n) -> $d"
done
echo "adaptoare USB:"; lsusb 2>/dev/null | grep -iE 'ethernet|network|realtek|asix|lan' || echo " niciunul raportat de lsusb"
'@
$nic | ForEach-Object { Write-Info $_ }
$usbEv = Invoke-Node -Node pveelite -Command `
"journalctl -k --since '$IncidentStart' --no-pager | grep -iE 'usb [0-9-]+: (USB )?disconnect|usb .*reset (high|super|full)-speed|r8152|ax88179|cdc_ncm|cdc_ether|NIC Link is (Down|Up)|link is not ready|eth[0-9] speed' | tail -25"
if ($usbEv) {
Write-Bad "evenimente USB / link pe placa de retea:"
$usbEv | ForEach-Object { Write-Host " $_" -ForegroundColor Red }
Add-Rezultat 'Adaptor USB LAN' 'bad' 'deconectari/reseturi USB in jurnal - vezi liniile'
} else {
Write-Info "niciun eveniment de deconectare USB in fereastra incidentului"
if (-not $scenariuRetea) { Add-Rezultat 'Adaptor USB LAN' 'ok' 'fara deconectari in jurnal' }
}
# Cautarea tintita de semnaturi hardware, peste toate boot-urile de ieri.
Write-Host ""
Write-Info "--- semnaturi hardware in jurnal (MCE / termic / panic / EDAC) ---"
# -p warning taie zgomotul de boot inainte de a ajunge la grep: mesajele de
# inregistrare a guvernatorilor termici, EDAC si NMI sunt de nivel info.
$hw = Invoke-Node -Node pveelite -Command `
"journalctl --since '$IncidentStart' -p warning --no-pager | grep -E '$TipareHw' | tail -25"
$verdictHw = $false
if ($hw) {
Write-Bad "GASIT - nodul a lasat urme de eroare hardware:"
$hw | ForEach-Object { Write-Host " $_" -ForegroundColor Red }
Add-Rezultat 'Semnaturi hardware' 'bad' 'erori hardware in jurnal - vezi liniile de mai sus'
$verdictHw = $true
} else {
Write-Info "niciun MCE, eroare termica, panic sau EDAC in jurnal"
}
# mcelog / edac, daca sunt instalate
$mce = Invoke-Node -Node pveelite -Command `
"which mcelog >/dev/null 2>&1 && mcelog --client 2>/dev/null | tail -10; ls /sys/devices/system/edac/mc/mc0/*_count 2>/dev/null | head -3"
if ($mce) { $mce | ForEach-Object { Write-Info " $_" } }
# Cate reseturi necurate a inregistrat masina
$necurate = Invoke-Node -Node pveelite -Command `
"journalctl --list-boots --no-pager | wc -l; last -x reboot shutdown 2>/dev/null | head -8"
Write-Info "istoric reboot/shutdown:"
$necurate | Select-Object -Skip 1 | ForEach-Object { Write-Info " $_" }
if (-not $verdictHw -and -not $scenariuRetea) {
Write-Host ""
Write-Bad "VERDICT: masina a incetat sa mearga si jurnalul e TACUT inainte de asta."
Write-Info "A disparut fara sa apuce sa scrie nimic - exact tiparul pvemini din"
Write-Info "2026-04-20. Cauza e alimentare sau hardware (sursa / RAM / termic),"
Write-Info "NU software. Nodul nu e de incredere ca tinta de failover pana cand:"
Write-Info " - sursa e testata sau inlocuita"
Write-Info " - memoria e testata (memtest86+, minim o trecere completa)"
Write-Info " - se verifica praful si ventilatia (vezi temperaturile de la pasul 6)"
Add-Rezultat 'Cauza caderii' 'bad' 'jurnal tacut => alimentare/hardware, nod nesigur'
} elseif ($scenariuRetea) {
Write-Host ""
Write-Bad "VERDICT: nu a fost o cadere de alimentare - a fost reteaua."
Write-Info "Masina a mers tot timpul. Remediul e la adaptorul de retea, nu la sursa:"
Write-Info " - daca e adaptor USB, scoate-l din USB si pune-l inapoi, apoi verifica"
Write-Info " daca revine ca acelasi nume de interfata (altfel vmbr0 ramane fara port)"
Write-Info " - pe termen lung: NIC pe PCIe in loc de USB, sau al doilea link corosync"
Write-Info " - verifica si cablul si portul de switch, nu doar dongle-ul"
}
# ============================================================ 2. integritate ZFS
Write-Step "2. Integritate ZFS (relevant daca au fost opriri necurate)"
$zpool = Invoke-Node -Node pveelite -Command 'zpool status -v'
$zpool | ForEach-Object { Write-Info $_ }
if ($zpool -match 'state: ONLINE' -and $zpool -match 'No known data errors') {
if ($zpool -match 'resilver|scan: resilvered') {
Write-Warn "pool ONLINE, dar a rulat un resilver - normal dupa oprire necurata"
Add-Rezultat 'ZFS' 'warn' 'ONLINE, resilver efectuat, fara erori de date'
} else {
Write-Ok "pool ONLINE, fara erori de date"
Add-Rezultat 'ZFS' 'ok' 'ONLINE, fara erori'
}
} else {
Write-Bad "pool NU e curat - citeste iesirea de mai sus inainte de orice altceva"
Add-Rezultat 'ZFS' 'bad' 'pool degradat sau cu erori de date'
}
# ============================================================ 3. inapoi in cluster
Write-Step "3. Revenirea in cluster"
$pvecm = Invoke-Node -Node pvemini -Command 'pvecm status; echo "---"; cat /etc/pve/.members'
$pvecm | ForEach-Object { Write-Info $_ }
$m = $pvecm | Select-String 'Total votes:\s*(\d+)' | Select-Object -First 1
$totalVotes = if ($m) { $m.Matches[0].Groups[1].Value } else { '?' }
$eliteOnline = [bool]($pvecm -match '"pveelite".*"online": 1')
if ($totalVotes -eq '3' -and $eliteOnline) {
Write-Ok "cluster complet: 3 din 3 voturi, pveelite online"
Add-Rezultat 'Cluster' 'ok' '3/3 voturi, marja de quorum refacuta'
} else {
Write-Bad "cluster inca incomplet: Total votes = $totalVotes"
Add-Rezultat 'Cluster' 'bad' "Total votes = $totalVotes, pveelite inca in afara"
}
# ================================================================ 4. replicarea
Write-Step "4. Replicarea catre pveelite"
Write-Info "job-urile se reiau singure la urmatorul interval - nu e nevoie de interventie."
Write-Info "Daca vrei sa nu astepti: pvesr run --id <job> pe pvemini."
$repl = Invoke-Node -Node pvemini -Command "pvesr status" -Timeout 30
$repl | ForEach-Object { Write-Info $_ }
$esecuri = @($repl | Select-String 'pveelite' | Where-Object { $_ -notmatch '\s0\s+OK' -and $_ -match 'failed' })
if ($esecuri.Count -eq 0) {
Write-Ok "toate job-urile catre pveelite sunt OK, FailCount 0"
Add-Rezultat 'Replicare' 'ok' "toate cele $ReplJobs job-uri recuperate"
} else {
Write-Warn "$($esecuri.Count) job-uri inca in eroare - normal daca nodul tocmai a pornit"
Write-Info "reverifica peste 15-20 min sau forteaza cu: pvesr run --id <job>"
Add-Rezultat 'Replicare' 'warn' "$($esecuri.Count) job-uri inca in eroare, de reverificat"
}
# ======================================================================= 5. HA
Write-Step "5. HA - LRM-ul lui pveelite"
$ha = Invoke-Node -Node pvemini -Command 'ha-manager status'
$ha | ForEach-Object { Write-Info $_ }
if ($ha -match 'lrm pveelite \(active') {
Write-Ok "LRM pveelite activ"
Add-Rezultat 'HA' 'ok' 'LRM activ'
} elseif ($ha -match 'lrm pveelite \(idle') {
# 'idle' e starea normala pentru un nod fara servicii HA asignate - si e
# exact cazul lui pveelite dupa ce fence-ul a mutat vm:109 pe pvemini.
# ATENTIE: cu LRM idle, watchdog-ul NU e armat. La 16:01 watchdog-ul a
# repornit nodul si i-a readus reteaua; la 17:26, fara el, nodul a ramas
# pornit si fara retea pana dimineata.
Write-Ok "LRM pveelite idle - normal, nodul nu are servicii HA asignate"
Write-Info "Consecinta: watchdog-ul nu e armat, deci o cadere de retea nu se"
Write-Info "mai auto-repara prin reboot, cum s-a intamplat la 16:01."
Add-Rezultat 'HA' 'ok' 'LRM idle (fara servicii asignate) - watchdog nearmat'
} elseif ($ha -match 'lrm pveelite.*old timestamp') {
Write-Warn "LRM pveelite inca 'dead' - poate dura un minut dupa boot; reverifica"
Add-Rezultat 'HA' 'warn' "LRM inca 'old timestamp'"
} else {
Write-Warn "starea LRM neclara, citeste iesirea de mai sus"
Add-Rezultat 'HA' 'warn' 'stare LRM neclara'
}
# Atentie deliberata: vm:109 a fost recuperat pe pvemini in timpul incidentului.
if ($ha -match 'service vm:109.*pveelite') {
Write-Warn "vm:109 a revenit pe pveelite - verifica intentionat, a fost mutat pe pvemini"
}
# ===================================================================== 6. SMART
Write-Step "6. SMART si temperaturi (precedent: incidentul Kingston din aprilie)"
$smart = Invoke-Node -Node pveelite -Command @'
for d in $(lsblk -dno NAME,TYPE | awk '$2=="disk"{print $1}'); do
echo "--- /dev/$d ---"
smartctl -H -A /dev/$d 2>/dev/null | grep -iE 'overall-health|Temperature|Reallocated|Media_Wearout|Percentage Used|Power_On|Unsafe_Shutdown|CRC' | head -10
done
'@ -Timeout 30
$smart | ForEach-Object { Write-Info $_ }
if ($smart -match 'FAILED') {
Write-Bad "SMART raporteaza FAILED pe cel putin un disc"
Add-Rezultat 'SMART' 'bad' 'un disc raporteaza FAILED'
} else {
Write-Ok "SMART: fara FAILED (citeste totusi temperaturile de mai sus)"
Add-Rezultat 'SMART' 'ok' 'fara FAILED'
}
# Senzorii placii, daca exista - relevant pentru ipoteza termica
$sens = Invoke-Node -Node pveelite -Command "which sensors >/dev/null 2>&1 && sensors 2>/dev/null | grep -iE 'Core|Package|temp' | head -12"
if ($sens) {
Write-Info "senzori:"
$sens | ForEach-Object { Write-Info " $_" }
} else {
Write-Info "lm-sensors nu e instalat (apt install lm-sensors) - fara citiri termice live"
}
# ================================================================= 7. Tailscale
Write-Step "7. Tailscale - accesul out-of-band"
Write-Info "In incident, tailscaled era mort de 27 de zile: fara el, orice cadere"
Write-Info "viitoare a nodului cere din nou deplasare fizica."
$ts = Invoke-Node -Node pveelite -Command 'systemctl is-active tailscaled 2>/dev/null; tailscale status 2>&1 | head -3'
$ts | ForEach-Object { Write-Info $_ }
if ($ts -match 'Logged out|Stopped') {
# Capcana: serviciul poate fi 'active' si totusi inutilizabil. Exact asa arata
# pveelite la 28.08 - tailscaled pornit, dar delogat, ceea ce explica cele 27
# de zile de "offline". A verifica doar systemctl is-active da un fals OK.
Write-Bad "tailscaled ruleaza, dar e DELOGAT - nu exista acces out-of-band"
Write-Info "Reautentificare (cere deschiderea link-ului afisat intr-un browser):"
Write-Info " ssh root@$($NodeIp.pveelite) 'tailscale up'"
Add-Rezultat 'Tailscale' 'bad' 'delogat - fara acces out-of-band'
} elseif ($ts -match '^active') {
Write-Ok "tailscaled activ si autentificat"
Add-Rezultat 'Tailscale' 'ok' 'activ'
} else {
Write-Warn "tailscaled NU e activ - reactiveaza-l acum:"
Write-Info " ssh root@$($NodeIp.pveelite) 'systemctl enable --now tailscaled && tailscale up'"
Add-Rezultat 'Tailscale' 'warn' 'inactiv - fara acces out-of-band'
}
# ==================================================================== bilantul
Write-Host ""
Write-Host "================ BILANT ================" -ForegroundColor Cyan
foreach ($r in $Rezultate) {
switch ($r.Stare) {
'ok' { Write-Host (" [ok] {0,-16} {1}" -f $r.Nume, $r.Detaliu) -ForegroundColor Green }
'warn' { Write-Host (" [!] {0,-16} {1}" -f $r.Nume, $r.Detaliu) -ForegroundColor Yellow }
'bad' { Write-Host (" [X] {0,-16} {1}" -f $r.Nume, $r.Detaliu) -ForegroundColor Red }
}
}
Write-Host ""
$cauza = $Rezultate | Where-Object { $_.Nume -eq 'Cauza caderii' }
if ($cauza -and $cauza.Stare -eq 'bad') {
Write-Host "Concluzia care conteaza: cauza caderii NU e lamurita ca fiind software." -ForegroundColor Red
Write-Host "Trateaza pveelite ca nod nesigur si consemneaza rezultatul in" -ForegroundColor Red
Write-Host "proxmox/cluster/incidents/2026-08-27-pveelite-down.md inainte sa inchizi incidentul." -ForegroundColor Red
Write-Host ""
}
if ($Rezultate | Where-Object { $_.Stare -eq 'bad' }) { exit 1 } else { exit 0 }