Files
aza/AzA march 2026/deploy/local_reset_and_start.ps1

212 lines
6.9 KiB
PowerShell
Raw Permalink Normal View History

2026-03-25 22:03:39 +01:00
<#
AZA Clean Local Start (no Docker)
Purpose:
- Ensure port 8000 is free (kills existing listener on :8000)
- Load auth tokens from deploy\.env
- Ensure AZA_SECRET_KEY is set (from .env or auto-generated for this run)
- Start the backend deterministically:
python -m uvicorn workforce_planner.api.app:app --host 127.0.0.1 --port 8000
Run (from project root):
powershell -ExecutionPolicy Bypass -File .\deploy\local_reset_and_start.ps1
Then (in a second terminal):
cd .\deploy
powershell -ExecutionPolicy Bypass -File .\authorized_test.ps1
#>
[CmdletBinding()]
param(
[string]$ProjectRoot = ".",
[string]$EnvFile = ".\deploy\.env",
[string]$BindHost = "127.0.0.1",
[int]$Port = 8000
)
function Load-DotEnv([string]$Path) {
if (-not (Test-Path -LiteralPath $Path)) {
throw "Missing .env file at: $Path"
}
$map = @{}
Get-Content -LiteralPath $Path | ForEach-Object {
$line = $_.Trim()
if ($line.Length -eq 0) { return }
if ($line.StartsWith("#")) { return }
$idx = $line.IndexOf("=")
if ($idx -lt 1) { return }
$k = $line.Substring(0, $idx).Trim()
$v = $line.Substring($idx + 1).Trim()
if (($v.StartsWith('"') -and $v.EndsWith('"')) -or ($v.StartsWith("'") -and $v.EndsWith("'"))) {
$v = $v.Substring(1, $v.Length - 2)
}
$map[$k] = $v
}
return $map
}
function Kill-PortListener([int]$p) {
$pids = @()
# Preferred (more reliable): Get-NetTCPConnection
try {
$conns = Get-NetTCPConnection -LocalPort $p -State Listen -ErrorAction Stop
foreach ($c in $conns) {
if ($c.OwningProcess -and $c.OwningProcess -is [int]) { $pids += $c.OwningProcess }
elseif ($c.OwningProcess -and ($c.OwningProcess.ToString() -match "^\d+$")) { $pids += [int]$c.OwningProcess }
}
} catch {
# Fallback: netstat parsing
try {
$lines = & netstat -ano | Select-String -Pattern (":$p\s") | ForEach-Object { $_.Line }
foreach ($ln in $lines) {
$parts = ($ln -split "\s+") | Where-Object { $_ -ne "" }
if ($parts.Count -ge 5) {
$state = $parts[3]
$listenerPid = $parts[4]
if ($state -eq "LISTENING" -and $listenerPid -match "^\d+$") {
$pids += [int]$listenerPid
}
}
}
} catch { }
}
$pids = $pids | Select-Object -Unique
if (-not $pids -or $pids.Count -eq 0) {
Write-Host "Port ${p}: no LISTENING pid found."
return
}
foreach ($procId in $pids) {
try {
Write-Host "Killing PID $procId on port ${p} ..."
& taskkill /PID $procId /F | Out-Null
} catch {
Write-Host "WARNING: failed to kill PID $procId"
}
}
Start-Sleep -Milliseconds 600
# Re-check
try {
$still = Get-NetTCPConnection -LocalPort $p -State Listen -ErrorAction SilentlyContinue
if ($still) {
$stillPids = @($still | ForEach-Object { $_.OwningProcess } | Select-Object -Unique)
Write-Host "WARNING: Port ${p} still has listener(s): $($stillPids -join ', ')"
} else {
Write-Host "Port ${p}: listener cleared."
}
} catch {
# ignore
}
}
Set-Location -LiteralPath $ProjectRoot
Write-Host "[AZA] Clean Local Start"
Write-Host " Root: $(Get-Location)"
Write-Host " Env: $EnvFile"
Write-Host " Bind: http://$BindHost`:$Port"
Write-Host ""
# 1) Free the port
Kill-PortListener -p $Port
Write-Host ""
# 2) Load .env
try {
$envMap = Load-DotEnv $EnvFile
} catch {
Write-Host "ERROR: $($_.Exception.Message)"
exit 1
}
# 3) Auth tokens (do NOT print them)
if ($envMap.ContainsKey("MEDWORK_API_TOKENS")) {
$env:MEDWORK_API_TOKENS = $envMap["MEDWORK_API_TOKENS"]
Write-Host " MEDWORK_API_TOKENS: set"
# Compatibility: some startup checks still require MEDWORK_API_TOKEN (singular).
$first = ($envMap["MEDWORK_API_TOKENS"] -split "[,\r\n]+" | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" } | Select-Object -First 1)
if ($first) {
$env:MEDWORK_API_TOKEN = $first
Write-Host " MEDWORK_API_TOKEN: set (first token, compatibility)"
}
} elseif ($envMap.ContainsKey("MEDWORK_API_TOKEN")) {
$env:MEDWORK_API_TOKEN = $envMap["MEDWORK_API_TOKEN"]
Write-Host " MEDWORK_API_TOKEN: set"
$first = $envMap["MEDWORK_API_TOKEN"].Trim()
} else {
Write-Host "ERROR: No MEDWORK_API_TOKENS or MEDWORK_API_TOKEN found in $EnvFile"
exit 1
}
# Ensure backend_token.txt matches the token used for local runs (some code paths may read this file).
try {
if ($first -and $first.Trim().Length -gt 0) {
$tokenFile = ".\backend_token.txt"
$desired = $first.Trim() + "`n"
$existing = ""
if (Test-Path -LiteralPath $tokenFile) {
try { $existing = (Get-Content -LiteralPath $tokenFile -Raw) } catch { $existing = "" }
if ($existing -ne $desired) {
$bak = ".\backend_token.txt.bak"
try { Copy-Item -LiteralPath $tokenFile -Destination $bak -Force | Out-Null } catch { }
}
}
Set-Content -LiteralPath $tokenFile -Value $desired -Encoding ASCII
Write-Host " backend_token.txt: synced (local auth consistency)"
}
} catch {
Write-Host "WARN: Could not write backend_token.txt (continuing)."
}
# 4) Secret key (hard guarantee for local run)
if ($envMap.ContainsKey("AZA_SECRET_KEY") -and $envMap["AZA_SECRET_KEY"].Trim().Length -ge 32) {
$env:AZA_SECRET_KEY = $envMap["AZA_SECRET_KEY"].Trim()
Write-Host " AZA_SECRET_KEY: set (from .env)"
} else {
$gen = & python -c "import secrets; print(secrets.token_hex(64))"
if (-not $gen -or $gen.Trim().Length -lt 32) {
Write-Host "ERROR: Could not generate AZA_SECRET_KEY via python."
exit 1
}
$env:AZA_SECRET_KEY = $gen.Trim()
Write-Host " AZA_SECRET_KEY: generated for this local run"
}
# Optional: build label if present
if ($envMap.ContainsKey("AZA_BUILD")) { $env:AZA_BUILD = $envMap["AZA_BUILD"] }
Write-Host ""
Write-Host "Starting backend:"
Write-Host " python -m uvicorn backend_main:app --host $BindHost --port $Port"
Write-Host ""
Write-Host "NOTE: This window must stay open while you run authorized_test.ps1 in a second terminal."
Write-Host ""
# 5) Optionally launch Dev Status window
$devStatusScript = ".\tools\dev_status_window.py"
$devStatusEnabled = $true
if ($envMap.ContainsKey("DEV_STATUS_WINDOW") -and $envMap["DEV_STATUS_WINDOW"] -eq "0") {
$devStatusEnabled = $false
}
if ($devStatusEnabled -and (Test-Path -LiteralPath $devStatusScript)) {
$Root = (Get-Location).Path
Start-Process -FilePath "powershell.exe" -ArgumentList @("-NoExit","-ExecutionPolicy","Bypass","-Command","`$host.ui.RawUI.WindowTitle = 'AZA Dev Status'; cd `"$Root`"; python .\tools\dev_status_window.py") -WindowStyle Normal
Write-Host " Dev status window: started"
} elseif ($devStatusEnabled) {
Write-Host " Dev status window: missing ($devStatusScript not found)"
} else {
Write-Host " Dev status window: disabled"
}
# 6) Start AZA backend (foreground)
$target = "backend_main:app"
Write-Host "Uvicorn target: $target"
Write-Host ""
& python -m uvicorn $target --host $BindHost --port $Port
exit $LASTEXITCODE