Files
aza/AzA march 2026 - Kopie (18)/deploy/docker_smoke.ps1
2026-04-22 22:33:46 +02:00

218 lines
6.2 KiB
PowerShell

<#
AZA - Step 14: Docker/Compose Smoke-Test (PowerShell 5.1, ASCII-safe)
Build + start backend via docker compose, wait for /health 200,
then run smoke_suite.ps1 against the container.
Run (from project root OR from deploy folder):
cd "C:\Users\surov\Documents\AZA\backup 24.2.26"
powershell -ExecutionPolicy Bypass -File .\deploy\docker_smoke.ps1
Optional parameters:
-BaseUrl http://127.0.0.1:8000
-WaitSeconds 90
-DownAfter (stop containers after test)
#>
[CmdletBinding()]
param(
[string]$BaseUrl = 'http://127.0.0.1:8000',
[int]$WaitSeconds = 60,
[switch]$DownAfter
)
$ErrorActionPreference = 'Stop'
function Write-Info([string]$msg) { Write-Host $msg }
function Write-Fail([string]$msg) { Write-Host $msg; exit 1 }
function Test-DockerServer() {
try {
$out = & docker version 2>&1
if ($LASTEXITCODE -ne 0) { return $false }
if (($out -match 'Client:') -and ($out -match 'Server:')) {
if ($out -match 'failed to connect to the docker API') { return $false }
return $true
}
return $false
} catch { return $false }
}
function Get-DockerContexts() {
try {
$lines = & docker context ls --format '{{.Name}}' 2>$null
if ($LASTEXITCODE -ne 0) { return @() }
$ctx = @()
foreach ($l in $lines) {
$n = ($l | ForEach-Object { $_.Trim() })
if ($n) { $ctx += $n }
}
return $ctx
} catch { return @() }
}
function Ensure-DockerRunning([int]$timeoutSec = 180) {
if (Test-DockerServer) { return }
$contexts = Get-DockerContexts
$preferred = @('desktop-linux','desktop-windows')
foreach ($p in $preferred) {
if ($contexts -contains $p) {
cmd /c "docker context use $p >nul 2>nul"
if (Test-DockerServer) { return }
}
}
foreach ($c in $contexts) {
cmd /c "docker context use $c >nul 2>nul"
if (Test-DockerServer) { return }
}
$exeCandidates = @(
"$env:ProgramFiles\Docker\Docker\Docker Desktop.exe",
"${env:ProgramFiles(x86)}\Docker\Docker\Docker Desktop.exe"
)
$exe = $exeCandidates | Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1
if ($exe) {
try {
Write-Info '[DOCKER] Starting Docker Desktop...'
Start-Process -FilePath $exe | Out-Null
} catch { }
}
$deadline = (Get-Date).AddSeconds($timeoutSec)
while ((Get-Date) -lt $deadline) {
$contexts = Get-DockerContexts
foreach ($p in $preferred) {
if ($contexts -contains $p) {
cmd /c "docker context use $p >nul 2>nul"
if (Test-DockerServer) { return }
}
}
if (Test-DockerServer) { return }
Start-Sleep -Seconds 2
}
Write-Fail "[FAIL] Docker daemon not reachable after ${timeoutSec}s. Open Docker Desktop and wait until it shows 'Engine running', then rerun this script."
}
# Resolve project root robustly (works from root and from deploy/)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
if ((Split-Path -Leaf $ScriptDir) -eq 'deploy') {
$Root = Split-Path -Parent $ScriptDir
} else {
$Root = $ScriptDir
}
Set-Location -LiteralPath $Root
$ComposeFile = Join-Path $Root 'deploy\docker-compose.yml'
$EnvFile = Join-Path $Root 'deploy\.env'
$SmokeScript = Join-Path $Root 'deploy\smoke_suite.ps1'
Write-Host '[AZA] Step 14 - Docker/Compose Smoke'
Write-Host (' Root: ' + $Root)
Write-Host (' Compose: ' + $ComposeFile)
Write-Host (' EnvFile: ' + $EnvFile)
Write-Host (' BaseUrl: ' + $BaseUrl)
Write-Host (' Timeout: ' + $WaitSeconds + 's')
Write-Host ''
# Pre-flight checks
if (-not (Test-Path -LiteralPath $ComposeFile)) {
Write-Host '[FAIL] Compose file not found.'
exit 1
}
if (-not (Test-Path -LiteralPath $EnvFile)) {
Write-Host '[FAIL] .env file not found.'
exit 1
}
# Ensure docker daemon is reachable (auto-start + wait + context fix)
Ensure-DockerRunning -timeoutSec 180
Write-Host '[OK] Docker daemon reachable.'
# Step 1: Build and start
Write-Host '[DOCKER] docker compose up -d --build'
& docker compose -f $ComposeFile --env-file $EnvFile up -d --build
if ($LASTEXITCODE -ne 0) {
Write-Host '[FAIL] docker compose up --build failed.'
exit 1
}
Write-Host '[DOCKER] UP'
Write-Host ''
# Step 2: Wait for /health 200
$base = $BaseUrl.TrimEnd('/')
$healthUrl = $base + '/health'
Write-Host ('[WAIT] Waiting for ' + $healthUrl + ' (max ' + $WaitSeconds + 's)...')
$healthy = $false
for ($i = 0; $i -lt $WaitSeconds; $i++) {
try {
$resp = Invoke-WebRequest -Method GET -Uri $healthUrl -TimeoutSec 5 -UseBasicParsing
if ([int]$resp.StatusCode -eq 200) {
$healthy = $true
break
}
} catch {
# Not ready yet
}
Start-Sleep -Seconds 1
if (($i % 10) -eq 9) {
Write-Host (' ... ' + ($i + 1) + 's elapsed')
}
}
if (-not $healthy) {
Write-Host ''
Write-Host '[WAIT] TIMEOUT - backend did not become healthy.'
Write-Host ''
Write-Host 'Container logs (last 80 lines):'
try { & docker compose -f $ComposeFile logs --tail 80 } catch { }
Write-Host ''
Write-Host 'Hint: containers are still running so you can inspect logs:'
Write-Host (' docker compose -f "' + $ComposeFile + '" logs --follow')
Write-Host (' docker compose -f "' + $ComposeFile + '" down')
Write-Host ''
Write-Host '[RESULT] FAIL'
exit 1
}
Write-Host '[WAIT] HEALTH OK'
Write-Host ''
# Step 3: Run smoke suite
if (-not (Test-Path -LiteralPath $SmokeScript)) {
Write-Host '[FAIL] smoke_suite.ps1 not found.'
exit 1
}
Write-Host '[SMOKE] Running smoke_suite.ps1 against docker...'
& powershell -ExecutionPolicy Bypass -File $SmokeScript -BaseUrl $base -EnvFile $EnvFile
$smokeExit = $LASTEXITCODE
Write-Host ''
# Optional: stop containers
if ($DownAfter) {
Write-Host '[DOCKER] DownAfter set - stopping containers...'
try { & docker compose -f $ComposeFile down } catch { }
Write-Host '[DOCKER] DOWN'
Write-Host ''
}
if ($smokeExit -ne 0) {
Write-Host '[SMOKE] FAIL'
if (-not $DownAfter) {
Write-Host ''
Write-Host 'Hint: containers are still running for inspection:'
Write-Host (' docker compose -f "' + $ComposeFile + '" logs --follow')
Write-Host (' docker compose -f "' + $ComposeFile + '" down')
}
Write-Host ''
Write-Host '[RESULT] FAIL'
exit 1
}
Write-Host '[SMOKE] PASS'
Write-Host ''
Write-Host '[RESULT] PASS - Step 14 Docker/Compose smoke test complete.'
exit 0