From e538c0c037fe36a33b9b3a66c4e82d6f821b02d5 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 25 May 2026 22:21:27 +0200 Subject: [PATCH] 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 --- scripts/Measure-CIBenchmark.ps1 | 36 +++++++++++++++++++++++++++++++-- scripts/_Common.psm1 | 29 +++++++++++++++++--------- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/scripts/Measure-CIBenchmark.ps1 b/scripts/Measure-CIBenchmark.ps1 index d51c103..9a74b63 100644 --- a/scripts/Measure-CIBenchmark.ps1 +++ b/scripts/Measure-CIBenchmark.ps1 @@ -89,7 +89,14 @@ param( '/var/lib/ci/logs/' } else { '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 @@ -138,9 +145,27 @@ if (-not (Test-Path $OutputDir)) { 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' $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 "=== CI Benchmark template: $(Split-Path $TemplatePath -Leaf) snapshot: $SnapshotName iterations: $Iterations ===" Write-Host "" @@ -186,6 +211,12 @@ for ($i = 1; $i -le $Iterations; $i++) { 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 ────────────────────────────────────────────────────── Write-Host "[bench] Starting VM..." $sw.Restart() @@ -198,7 +229,7 @@ for ($i = 1; $i -le $Iterations; $i++) { Write-Host "[bench] Waiting for guest IP..." $sw.Restart() $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" } $t.ip = [math]::Round($sw.Elapsed.TotalSeconds, 2) $t.vmIP = $vmIP @@ -250,6 +281,7 @@ for ($i = 1; $i -le $Iterations; $i++) { template = Split-Path $TemplatePath -Leaf snapshot = $SnapshotName guestOS = $resolvedGuestOS + staticIP = if ($useStaticIP) { $StaticIP } else { $null } cloneSec = $t.clone startSec = $t.start ipSec = $t.ip diff --git a/scripts/_Common.psm1 b/scripts/_Common.psm1 index db3dc84..20d9bdf 100644 --- a/scripts/_Common.psm1 +++ b/scripts/_Common.psm1 @@ -254,10 +254,16 @@ function Get-GuestIPAddress { param( [Parameter(Mandatory)] [string] $VmrunPath, [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) $attempt = 0 @@ -279,15 +285,18 @@ function Get-GuestIPAddress { return $ipOut } - # Fallback: vmrun getGuestIPAddress (VMware Tools / open-vm-tools required). - $savedEap = $ErrorActionPreference; $ErrorActionPreference = 'Continue' - $ipOut2 = (& $VmrunPath -T ws getGuestIPAddress $VmxPath 2>&1).Trim() - $ipRc2 = $LASTEXITCODE - $ErrorActionPreference = $savedEap + # Fallback: vmrun getGuestIPAddress — skipped when GuestInfoOnly is set + # to avoid returning a transient DHCP address during static-IP reconfiguration. + if (-not $GuestInfoOnly) { + $savedEap = $ErrorActionPreference; $ErrorActionPreference = 'Continue' + $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}$') { - Write-Host "[Get-GuestIPAddress] IP via getGuestIPAddress: $ipOut2" - return $ipOut2 + 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" + return $ipOut2 + } } Start-Sleep -Seconds 2