param( [string]$DockerHost = "ssh://docker-gpu", [string]$SshTarget = "docker-gpu", [string]$Report = "reports/model-chat/preflight.json", [switch]$SkipDockerConfig, [switch]$CheckLive ) $ErrorActionPreference = "Stop" $root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path) $reportPath = Join-Path $root $Report $steps = @() function Invoke-ExternalStep { param( [Parameter(Mandatory = $true)][string]$Name, [Parameter(Mandatory = $true)][string]$Command, [string[]]$Arguments = @() ) Write-Host "" Write-Host "== $Name" $started = Get-Date $output = @(& $Command @Arguments 2>&1 | ForEach-Object { "$_" }) $exitCode = if ($null -ne $global:LASTEXITCODE) { $global:LASTEXITCODE } else { 0 } $status = if ($exitCode -eq 0) { "ok" } else { "failed" } foreach ($line in $output) { Write-Host $line } [pscustomobject]@{ name = $Name status = $status exit_code = $exitCode duration_ms = [int]((Get-Date) - $started).TotalMilliseconds command = @($Command) + $Arguments output = $output } } function Invoke-HttpStep { param( [Parameter(Mandatory = $true)][string]$Name, [Parameter(Mandatory = $true)][string]$Url ) Write-Host "" Write-Host "== $Name" $started = Get-Date try { $response = Invoke-RestMethod -Uri $Url -TimeoutSec 20 Write-Host "ok: $Url" [pscustomobject]@{ name = $Name status = "ok" exit_code = 0 duration_ms = [int]((Get-Date) - $started).TotalMilliseconds url = $Url summary = $response.status } } catch { Write-Host "failed: $Url" Write-Host $_.Exception.Message [pscustomobject]@{ name = $Name status = "failed" exit_code = 1 duration_ms = [int]((Get-Date) - $started).TotalMilliseconds url = $Url error = $_.Exception.Message } } } Push-Location $root try { $steps += Invoke-ExternalStep -Name "GPU profiles" -Command "python" -Arguments @("scripts\validate_gpu_profiles.py", "--print") $steps += Invoke-ExternalStep -Name "PowerShell syntax" -Command "python" -Arguments @( "scripts\check_powershell_scripts.py", "scripts\deploy_model_chat_ui.ps1", "scripts\switch_gpu_profile.ps1", "scripts\manage_model_service.ps1" ) $steps += Invoke-ExternalStep -Name "UI archive" -Command "powershell" -Arguments @( "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "scripts\deploy_model_chat_ui.ps1", "-DockerHost", $DockerHost, "-SshTarget", $SshTarget, "-ArchiveOnly" ) if (-not $SkipDockerConfig) { $steps += Invoke-ExternalStep -Name "Compose config" -Command "powershell" -Arguments @( "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "scripts\deploy_model_chat_ui.ps1", "-DockerHost", $DockerHost, "-SshTarget", $SshTarget, "-ConfigOnly" ) } if ($CheckLive) { $steps += Invoke-HttpStep -Name "Live health" -Url "http://192.168.220.91:8765/api/health" $steps += Invoke-HttpStep -Name "Live catalog" -Url "http://192.168.220.91:8765/api/catalog" } } finally { Pop-Location } $failed = @($steps | Where-Object { $_.status -ne "ok" }) $reportObject = [pscustomobject]@{ created_at = (Get-Date).ToUniversalTime().ToString("o") status = if ($failed.Count) { "failed" } else { "ok" } docker_host = $DockerHost ssh_target = $SshTarget steps = $steps } New-Item -ItemType Directory -Force (Split-Path -Parent $reportPath) | Out-Null $reportObject | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $reportPath -Encoding UTF8 Write-Host "" Write-Host "Model Chat UI preflight: $($reportObject.status)" Write-Host "Report: $reportPath" if ($failed.Count) { exit 1 }