552eb628b7
Sprint 4 — qualità codice: - scripts/_Common.psm1: New-CISessionOption, Resolve-VmrunPath, Invoke-Vmrun - PSScriptAnalyzerSettings.psd1: project-wide PSSA rules (security + formatting) - Remove-BuildVM.ps1: SupportsShouldProcess (-WhatIf support) - Invoke-RemoteBuild.ps1, Get-BuildArtifacts.ps1: use New-CISessionOption from module - New-BuildVM.ps1: use Resolve-VmrunPath + Invoke-Vmrun from module Sprint 5 — affidabilità: - Backup-CITemplate.ps1: stop runner, timestamped VMDK backup, prune old, restart - Watch-RunnerHealth.ps1: auto-restart act_runner, cooldown 3/h, EventLog + webhook - Register-CIScheduledTasks.ps1: add CI-RunnerHealth task (every 15 min) Sprint 6 — perf baseline: - Set-TemplateSharedFolders.ps1: idempotent VMX editor for NuGet/pip shared folders - Invoke-RemoteBuild.ps1: -UseSharedCache injects NUGET_PACKAGES + PIP_CACHE_DIR in guest - Measure-CIBenchmark.ps1: times clone/start/IP/WinRM/destroy, appends to benchmark.jsonl Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
124 lines
4.7 KiB
PowerShell
124 lines
4.7 KiB
PowerShell
#Requires -Version 5.1
|
||
<#
|
||
.SYNOPSIS
|
||
Stops and permanently deletes an ephemeral build VM.
|
||
|
||
.DESCRIPTION
|
||
Performs a graceful shutdown (soft stop) with a timeout fallback to
|
||
a hard stop, then uses vmrun deleteVM to remove all VM files.
|
||
Finally, removes the clone directory from disk.
|
||
|
||
This script is designed to be called from a try/finally block so
|
||
it always runs, even on build failure.
|
||
|
||
.PARAMETER VMPath
|
||
Full path to the clone VM's .vmx file.
|
||
|
||
.PARAMETER VmrunPath
|
||
Full path to vmrun.exe.
|
||
Default: C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe
|
||
|
||
.PARAMETER GracefulTimeoutSeconds
|
||
Seconds to wait for graceful shutdown before forcing power-off.
|
||
Default: 15
|
||
|
||
.EXAMPLE
|
||
.\Remove-BuildVM.ps1 -VMPath "F:\CI\BuildVMs\Clone_run-42_20260508_143022\Clone_run-42_20260508_143022.vmx"
|
||
#>
|
||
[CmdletBinding(SupportsShouldProcess)]
|
||
param(
|
||
[Parameter(Mandatory)]
|
||
[string] $VMPath,
|
||
|
||
[string] $VmrunPath = 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe',
|
||
|
||
[ValidateRange(5, 60)]
|
||
[int] $GracefulTimeoutSeconds = 15
|
||
)
|
||
|
||
Set-StrictMode -Version Latest
|
||
$ErrorActionPreference = 'Continue' # Don't stop on errors — always try next step
|
||
|
||
$cloneDir = Split-Path $VMPath -Parent
|
||
|
||
Write-Host "[Remove-BuildVM] Destroying VM: $VMPath"
|
||
|
||
# ── Step 1: Check if VM exists at all ────────────────────────────────────────
|
||
if (-not (Test-Path $VMPath -PathType Leaf)) {
|
||
Write-Warning "[Remove-BuildVM] VMX file not found — nothing to remove: $VMPath"
|
||
# Still attempt to remove the directory in case of partial clone
|
||
if ((Test-Path $cloneDir) -and $PSCmdlet.ShouldProcess($cloneDir, 'Remove partial clone directory')) {
|
||
Remove-Item $cloneDir -Recurse -Force -ErrorAction SilentlyContinue
|
||
}
|
||
return
|
||
}
|
||
|
||
if (-not $PSCmdlet.ShouldProcess($VMPath, 'Stop and delete build VM')) { return }
|
||
|
||
# ── Step 2: Graceful stop ─────────────────────────────────────────────────────
|
||
Write-Host "[Remove-BuildVM] Sending soft stop..."
|
||
& $VmrunPath -T ws stop $VMPath soft 2>&1 | Out-Null
|
||
|
||
$deadline = (Get-Date).AddSeconds($GracefulTimeoutSeconds)
|
||
while ((Get-Date) -lt $deadline) {
|
||
Start-Sleep -Seconds 2
|
||
$stateOutput = & $VmrunPath -T ws getState $VMPath 2>&1
|
||
if ($stateOutput -notmatch 'running') {
|
||
Write-Host "[Remove-BuildVM] VM stopped gracefully."
|
||
break
|
||
}
|
||
}
|
||
|
||
# ── Step 3: Force stop if still running ──────────────────────────────────────
|
||
$stateOutput = & $VmrunPath -T ws getState $VMPath 2>&1
|
||
if ($stateOutput -match 'running') {
|
||
Write-Host "[Remove-BuildVM] Graceful stop timed out — forcing hard stop..."
|
||
& $VmrunPath -T ws stop $VMPath hard 2>&1 | Out-Null
|
||
}
|
||
|
||
# Poll vmrun list until VMX is gone — vmware-vmx.exe may hold file locks briefly
|
||
# after stop. Waiting for the entry to disappear ensures deleteVM won't race the
|
||
# process exit.
|
||
$vmxNorm = $VMPath.Trim().ToLower()
|
||
$releaseDeadline = (Get-Date).AddSeconds(20)
|
||
while ((Get-Date) -lt $releaseDeadline) {
|
||
$listedVMs = & $VmrunPath -T ws list 2>&1 |
|
||
Where-Object { $_ -notmatch '^Total running' } |
|
||
ForEach-Object { "$_".Trim().ToLower() }
|
||
if ($listedVMs -notcontains $vmxNorm) { break }
|
||
Start-Sleep -Seconds 2
|
||
}
|
||
|
||
# ── Step 4: Delete VM via vmrun — retry up to 3× with backoff ────────────────
|
||
Write-Host "[Remove-BuildVM] Deleting VM..."
|
||
$deleteOutput = ''
|
||
$deleteExit = -1
|
||
foreach ($delay in @(0, 3, 6)) {
|
||
if ($delay -gt 0) {
|
||
Write-Host "[Remove-BuildVM] Retrying deleteVM in ${delay}s..."
|
||
Start-Sleep -Seconds $delay
|
||
}
|
||
$deleteOutput = & $VmrunPath -T ws deleteVM $VMPath 2>&1
|
||
$deleteExit = $LASTEXITCODE
|
||
if ($deleteExit -eq 0) { break }
|
||
}
|
||
|
||
if ($deleteExit -ne 0) {
|
||
Write-Warning "[Remove-BuildVM] vmrun deleteVM failed after retries (exit $deleteExit): $deleteOutput"
|
||
Write-Warning "[Remove-BuildVM] Will attempt manual directory removal."
|
||
}
|
||
|
||
# ── Step 5: Remove clone directory (catches any leftover files) ───────────────
|
||
if (Test-Path $cloneDir) {
|
||
Write-Host "[Remove-BuildVM] Removing clone directory: $cloneDir"
|
||
Remove-Item $cloneDir -Recurse -Force -ErrorAction SilentlyContinue
|
||
if (Test-Path $cloneDir) {
|
||
Write-Warning "[Remove-BuildVM] Clone directory could not be fully removed: $cloneDir"
|
||
Write-Warning " Manual cleanup required."
|
||
} else {
|
||
Write-Host "[Remove-BuildVM] Clone directory removed."
|
||
}
|
||
}
|
||
|
||
Write-Host "[Remove-BuildVM] VM destruction complete."
|