Testul DR din 2026-08-08 a raportat "Restore failed" dupa 11 secunde, fara niciun log RMAN. Cauza nu a fost restore-ul: KB5101001 fusese descarcat in timpul testului din 2026-08-01 (singurul moment in care VM 109 e pornit), a ramas staged dupa qm stop si s-a finalizat la boot-ul testului urmator. Cronologie din Event Log-ul guest-ului: 06:00:58 RestartManager 10010 - nu poate reporni powershell.exe (restore-ul) 06:01:04 SCM 7034 - OpenSSH SSH Server terminat neasteptat 06:01:06 pveelite: client_loop: send disconnect: Broken pipe -> FAILED 06:01:38 VM-ul se reboteaza singur Fereastra testului (Sambata 06:00) era in afara Active Hours (08:00-17:00), deci pentru Windows era fereastra de mentenanta valida - iar VM 109 fiind pornit doar in timpul testului, aceea era singura fereastra posibila. Agravant: sshd nu avea acsiuni de recovery (RESET_PERIOD 0), deci dupa ce a murit a ramas mort si au esuat si colectarea logului si shutdown-ul gratios. Masuri: - NoAutoUpdate=1 + AUOptions=2 pe VM 109 (aplicat direct in registry) - actiuni de recovery pentru sshd: restart la 5s/10s/30s, reset=86400 - guard "STEP 3b: Windows servicing" inainte de restore (check_servicing.ps1): asteapta idle 300s, consuma controlat un reboot in asteptare, altfel abandoneaza cu "ABORTED - Windows servicing" in loc de un "Restore failed" inselator. Fail-open daca checkul lipseste - nu are voie sa pice testul. - fereastra lunara de patching (vm109-patch-window.sh + install_updates.ps1), prima duminica 03:00, cu re-armare NoAutoUpdate=1 indiferent de rezultat Adaugat si .gitattributes: cu core.autocrlf=true scripturile .sh ajungeau in working tree cu CRLF, iar ele se deployeaza prin scp direct pe Proxmox. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BhQBTegE4PiMPPaapLHjkc
88 lines
2.7 KiB
PowerShell
88 lines
2.7 KiB
PowerShell
# install_updates.ps1 — aplică update-urile Windows pe VM 109, controlat.
|
|
#
|
|
# Rulat exclusiv din vm109-patch-window.sh (fereastra lunară de patching).
|
|
# În restul timpului VM 109 are NoAutoUpdate=1, ca Windows Update să nu mai
|
|
# poată porni singur în timpul testului DR săptămânal (incident 2026-08-08).
|
|
#
|
|
# Folosește API-ul COM Microsoft.Update.Session — funcționează într-o sesiune
|
|
# SSH non-interactivă, spre deosebire de UsoClient care raportează asincron și
|
|
# nu întoarce niciun status utilizabil.
|
|
#
|
|
# Ieșire (linii parsabile din bash):
|
|
# FOUND=<n>
|
|
# INSTALLED=<n>
|
|
# FAILED=<n>
|
|
# REBOOT_REQUIRED=<true|false>
|
|
# RESULT=<OK|NO_UPDATES|ERROR>
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
try {
|
|
$session = New-Object -ComObject Microsoft.Update.Session
|
|
$searcher = $session.CreateUpdateSearcher()
|
|
|
|
Write-Output "Searching for updates..."
|
|
$result = $searcher.Search("IsInstalled=0 AND IsHidden=0")
|
|
|
|
Write-Output ("FOUND=" + $result.Updates.Count)
|
|
|
|
if ($result.Updates.Count -eq 0) {
|
|
Write-Output "INSTALLED=0"
|
|
Write-Output "FAILED=0"
|
|
Write-Output "REBOOT_REQUIRED=false"
|
|
Write-Output "RESULT=NO_UPDATES"
|
|
exit 0
|
|
}
|
|
|
|
$toInstall = New-Object -ComObject Microsoft.Update.UpdateColl
|
|
foreach ($u in $result.Updates) {
|
|
if ($u.EulaAccepted -eq $false) { $u.AcceptEula() }
|
|
Write-Output (" + " + $u.Title)
|
|
$toInstall.Add($u) | Out-Null
|
|
}
|
|
|
|
Write-Output "Downloading..."
|
|
$downloader = $session.CreateUpdateDownloader()
|
|
$downloader.Updates = $toInstall
|
|
$downloader.Download() | Out-Null
|
|
|
|
$ready = New-Object -ComObject Microsoft.Update.UpdateColl
|
|
foreach ($u in $toInstall) {
|
|
if ($u.IsDownloaded) { $ready.Add($u) | Out-Null }
|
|
}
|
|
|
|
if ($ready.Count -eq 0) {
|
|
Write-Output "INSTALLED=0"
|
|
Write-Output "FAILED=0"
|
|
Write-Output "REBOOT_REQUIRED=false"
|
|
Write-Output "RESULT=ERROR"
|
|
exit 1
|
|
}
|
|
|
|
Write-Output "Installing..."
|
|
$installer = $session.CreateUpdateInstaller()
|
|
$installer.Updates = $ready
|
|
$installResult = $installer.Install()
|
|
|
|
# ResultCode: 2 = succeeded, 3 = succeeded with errors, restul = eșec.
|
|
$ok = 0
|
|
$ko = 0
|
|
for ($i = 0; $i -lt $ready.Count; $i++) {
|
|
$code = $installResult.GetUpdateResult($i).ResultCode
|
|
if ($code -eq 2 -or $code -eq 3) { $ok++ } else { $ko++ }
|
|
}
|
|
|
|
Write-Output ("INSTALLED=" + $ok)
|
|
Write-Output ("FAILED=" + $ko)
|
|
Write-Output ("REBOOT_REQUIRED=" + $installResult.RebootRequired.ToString().ToLower())
|
|
|
|
if ($ko -gt 0) { Write-Output "RESULT=ERROR"; exit 1 }
|
|
Write-Output "RESULT=OK"
|
|
exit 0
|
|
}
|
|
catch {
|
|
Write-Output ("ERROR: " + $_.Exception.Message)
|
|
Write-Output "RESULT=ERROR"
|
|
exit 1
|
|
}
|