Intrebarea "nu-l putem trezi cu un magic packet?" a scos la iveala ceva ce schimba diagnosticul, nu doar raspunsul la ea. Pe WoL, pe scurt: nu se poate nici macar incerca. MAC-ul lui pveelite nu mai exista nicaieri - intrarea ARP a expirat pe pvemini (INCOMPLETE), pe pve1 (FAILED), in tabela statiei de admin si pe LXC-urile de pe LAN; nodurile au IP static, deci nu exista lease DHCP; in documentatie nu e consemnat. Raman tabela routerului sau citirea fizica de pe nod. Si chiar cu MAC-ul, placa de retea e pe USB, iar un dongle USB e nealimentat in soft-off, deci nu asculta dupa magic packet. Partea care conteaza insa e alta: pveelite ARE placa de retea pe USB, si deconectarea ei e modul de defectare deja documentat al acestui nod - incidentul 2026-04-20 a pornit exact de la un USB LAN disconnect, motiv pentru care tokenul corosync a fost marit la 10 s. Un nod care si-a pierdut adaptorul de retea arata din exterior identic cu unul oprit: fara ping, fara ARP, fara corosync, fara SSH. Toate observatiile din incident sunt compatibile cu ambele scenarii, iar eu scrisesem doar unul. Pentru 16:01 dovezile inclina in continuare spre repornire - curba de memorie din RRD se reseteaza (2,43 GB la 16:00 -> 2,10 GB la 16:30, sub valoarea de dupa boot) si NFS-ul se reataseaza. Pentru 17:26 nu exista niciun indiciu echivalent: nodul pur si simplu a incetat sa fie vizibil, ceea ce o deconectare USB explica la fel de bine ca o pierdere de alimentare. Am slabit corespunzator formularile din TL;DR si din cronologie, unde afirmasem repornirea ca fapt. Consecinta practica, pusa in document ca avertisment inainte de orice altceva: prima observatie la fata locului e daca masina merge - ventilatoare, LED-uri, imagine. Daca e pornita, nu a fost o cadere de alimentare, jurnalul e intact si reparatia e la dongle, cablu sau portul de switch. Nu apasa butonul de power inainte sa te uiti. In script, pasul 1 nu mai citeste boot-urile dupa index - indexurile difera intre cele doua scenarii si ar fi dus la concluzii gresite. Acum taie jurnalul dupa ora si pune intai testul decisiv: exista intrari dupa 17:26:44? Daca da, masina a mers mai departe si a cazut doar reteaua, iar verdictul si remediile se schimba complet. Adaugat si un bloc de diagnostic pentru adaptorul USB (interfete, drivere, lsusb, deconectari si evenimente de link in jurnalul kernel). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VAEUqrv26jCM5KwAPtkHb8
440 lines
19 KiB
PowerShell
440 lines
19 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).
|
|
$TipareHw = 'mce|machine check|hardware error|thermal|temperature above|critical temp|' +
|
|
'nmi|kernel panic|oops|BUG:|edac|pcieport.*error|ATA bus error|I/O 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) ---"
|
|
$hw = Invoke-Node -Node pveelite -Command `
|
|
"journalctl --since '$IncidentStart' --no-pager | grep -iE '$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 'Cauza caderii' 'bad' 'semnaturi 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.*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 '^active') {
|
|
Write-Ok "tailscaled activ"
|
|
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 }
|