feat(benchmark): add static IP support to Measure-CIBenchmark

- Add -StaticIP/-Netmask/-Gateway params; injects guestinfo into cloned
  VMX before start, mirroring job.py _inject_guestinfo_ip behaviour
- Add -GuestInfoOnly switch to Get-GuestIPAddress: skips vmrun
  getGuestIPAddress fallback to prevent race where transient DHCP address
  is returned before ci-static-ip.ps1 finishes reconfiguring the NIC
- Benchmark passes -GuestInfoOnly automatically when -StaticIP is set
- staticIP field added to benchmark.jsonl for DHCP vs static comparison

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 22:21:27 +02:00
parent 87d440b672
commit e538c0c037
2 changed files with 53 additions and 12 deletions
+34 -2
View File
@@ -89,7 +89,14 @@ param(
'/var/lib/ci/logs/' '/var/lib/ci/logs/'
} else { } else {
'F:\CI\Logs' 'F:\CI\Logs'
}) }),
# Optional static IP injection (mirrors ip_pool in job.py).
# If supplied, guestinfo.ip-assignment/netmask/gateway are written into the
# cloned VMX before start so ci-static-ip.ps1 applies the IP at boot.
[string] $StaticIP = '',
[string] $Netmask = '255.255.255.0',
[string] $Gateway = ''
) )
Set-StrictMode -Version Latest Set-StrictMode -Version Latest
@@ -138,9 +145,27 @@ if (-not (Test-Path $OutputDir)) {
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
} }
function Set-GuestInfoIP {
param([string]$VmxPath, [string]$IP, [string]$Mask, [string]$Gw)
$keys = @('guestinfo.ip-assignment', 'guestinfo.netmask', 'guestinfo.gateway')
$lines = (Get-Content -LiteralPath $VmxPath -Encoding UTF8) |
Where-Object { ($_ -split '=')[0].Trim().ToLower() -notin $keys }
$lines += "guestinfo.ip-assignment = `"$IP`""
if ($Mask) { $lines += "guestinfo.netmask = `"$Mask`"" }
if ($Gw) { $lines += "guestinfo.gateway = `"$Gw`"" }
Set-Content -LiteralPath $VmxPath -Value $lines -Encoding UTF8
}
$benchmarkLog = Join-Path $OutputDir 'benchmark.jsonl' $benchmarkLog = Join-Path $OutputDir 'benchmark.jsonl'
$results = [System.Collections.Generic.List[pscustomobject]]::new() $results = [System.Collections.Generic.List[pscustomobject]]::new()
$useStaticIP = $StaticIP -match '^\d{1,3}(\.\d{1,3}){3}$'
if ($useStaticIP) {
Write-Host "[bench] Static IP mode: $StaticIP / $Netmask gw=$Gateway"
} else {
Write-Host "[bench] DHCP mode (no -StaticIP supplied)"
}
Write-Host "" Write-Host ""
Write-Host "=== CI Benchmark template: $(Split-Path $TemplatePath -Leaf) snapshot: $SnapshotName iterations: $Iterations ===" Write-Host "=== CI Benchmark template: $(Split-Path $TemplatePath -Leaf) snapshot: $SnapshotName iterations: $Iterations ==="
Write-Host "" Write-Host ""
@@ -186,6 +211,12 @@ for ($i = 1; $i -le $Iterations; $i++) {
Write-Warning "[bench] Could not measure clone size: $_" Write-Warning "[bench] Could not measure clone size: $_"
} }
# ── Static IP injection (before start) ───────────────────────────────
if ($useStaticIP) {
Set-GuestInfoIP -VmxPath $cloneVmx -IP $StaticIP -Mask $Netmask -Gw $Gateway
Write-Host "[bench] guestinfo injected: $StaticIP"
}
# ── Phase: start ────────────────────────────────────────────────────── # ── Phase: start ──────────────────────────────────────────────────────
Write-Host "[bench] Starting VM..." Write-Host "[bench] Starting VM..."
$sw.Restart() $sw.Restart()
@@ -198,7 +229,7 @@ for ($i = 1; $i -le $Iterations; $i++) {
Write-Host "[bench] Waiting for guest IP..." Write-Host "[bench] Waiting for guest IP..."
$sw.Restart() $sw.Restart()
$vmIP = Get-GuestIPAddress -VmrunPath $VmrunPath -VmxPath $cloneVmx ` $vmIP = Get-GuestIPAddress -VmrunPath $VmrunPath -VmxPath $cloneVmx `
-TimeoutSeconds $TimeoutSeconds -TimeoutSeconds $TimeoutSeconds -GuestInfoOnly:$useStaticIP
if (-not $vmIP) { throw "Timed out waiting for guest IP after $TimeoutSeconds s" } if (-not $vmIP) { throw "Timed out waiting for guest IP after $TimeoutSeconds s" }
$t.ip = [math]::Round($sw.Elapsed.TotalSeconds, 2) $t.ip = [math]::Round($sw.Elapsed.TotalSeconds, 2)
$t.vmIP = $vmIP $t.vmIP = $vmIP
@@ -250,6 +281,7 @@ for ($i = 1; $i -le $Iterations; $i++) {
template = Split-Path $TemplatePath -Leaf template = Split-Path $TemplatePath -Leaf
snapshot = $SnapshotName snapshot = $SnapshotName
guestOS = $resolvedGuestOS guestOS = $resolvedGuestOS
staticIP = if ($useStaticIP) { $StaticIP } else { $null }
cloneSec = $t.clone cloneSec = $t.clone
startSec = $t.start startSec = $t.start
ipSec = $t.ip ipSec = $t.ip
+19 -10
View File
@@ -254,10 +254,16 @@ function Get-GuestIPAddress {
param( param(
[Parameter(Mandatory)] [string] $VmrunPath, [Parameter(Mandatory)] [string] $VmrunPath,
[Parameter(Mandatory)] [string] $VmxPath, [Parameter(Mandatory)] [string] $VmxPath,
[int] $TimeoutSeconds = 120 [int] $TimeoutSeconds = 120,
# When set, skip vmrun getGuestIPAddress fallback and poll only
# guestinfo.ci-ip. Use when guestinfo.ip-assignment was injected into
# the VMX — avoids returning a transient DHCP address before
# ci-static-ip.ps1 has finished reconfiguring the NIC.
[switch] $GuestInfoOnly
) )
Write-Host "[Get-GuestIPAddress] Polling for VM IP (max ${TimeoutSeconds}s)..." $modeLabel = if ($GuestInfoOnly) { 'guestinfo only' } else { 'guestinfo + getGuestIPAddress' }
Write-Host "[Get-GuestIPAddress] Polling for VM IP (max ${TimeoutSeconds}s, mode: $modeLabel)..."
$deadline = (Get-Date).AddSeconds($TimeoutSeconds) $deadline = (Get-Date).AddSeconds($TimeoutSeconds)
$attempt = 0 $attempt = 0
@@ -279,15 +285,18 @@ function Get-GuestIPAddress {
return $ipOut return $ipOut
} }
# Fallback: vmrun getGuestIPAddress (VMware Tools / open-vm-tools required). # Fallback: vmrun getGuestIPAddress — skipped when GuestInfoOnly is set
$savedEap = $ErrorActionPreference; $ErrorActionPreference = 'Continue' # to avoid returning a transient DHCP address during static-IP reconfiguration.
$ipOut2 = (& $VmrunPath -T ws getGuestIPAddress $VmxPath 2>&1).Trim() if (-not $GuestInfoOnly) {
$ipRc2 = $LASTEXITCODE $savedEap = $ErrorActionPreference; $ErrorActionPreference = 'Continue'
$ErrorActionPreference = $savedEap $ipOut2 = (& $VmrunPath -T ws getGuestIPAddress $VmxPath 2>&1).Trim()
$ipRc2 = $LASTEXITCODE
$ErrorActionPreference = $savedEap
if ($ipRc2 -eq 0 -and $ipOut2 -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') { if ($ipRc2 -eq 0 -and $ipOut2 -match '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') {
Write-Host "[Get-GuestIPAddress] IP via getGuestIPAddress: $ipOut2" Write-Host "[Get-GuestIPAddress] IP via getGuestIPAddress: $ipOut2"
return $ipOut2 return $ipOut2
}
} }
Start-Sleep -Seconds 2 Start-Sleep -Seconds 2