Files
llm/scripts/deploy_1c_adapter_stack.ps1
T
2026-08-14 09:40:51 +03:00

299 lines
10 KiB
PowerShell

param(
[string]$RestDockerHost = "ssh://docker.cin.su",
[string]$McpDockerHost = "ssh://docker.cin.su",
[string]$RestComposePath = "core/deploy/docker/adapter-1c/compose.yaml",
[string]$McpComposePath = "core/deploy/docker/adapter-1c-mcp/compose.yaml",
[string]$RestEnvFile,
[string]$McpEnvFile,
[string]$RestServiceName = "adapter-1c-rest",
[string]$RestAuditServiceName = "adapter-1c-audit",
[string]$McpServiceName = "adapter-1c-mcp",
[string]$McpAuditServiceName = "adapter-1c-mcp-audit",
[string[]]$BaseId,
[string]$AdapterUrl = "http://docker.cin.su:8011",
[string]$McpUrl = "http://docker.cin.su:8021",
[string]$ObjectRef,
[string]$ObjectKind,
[string]$ObjectName,
[string]$ObjectGuid,
[ValidateSet("ConfigSave", "ConfigCASSave")]
[string]$SavedStateTable = "ConfigSave",
[int]$TimeoutSec = 120,
[switch]$NoBuild,
[switch]$SkipRest,
[switch]$SkipMcp,
[switch]$SkipVerify,
[switch]$SkipDrainCheck,
[switch]$SkipWritePlanSafetySmoke,
[switch]$SkipWriteRollbackSafetySmoke,
[switch]$SkipSavedStateDiffSmoke,
[switch]$SkipSavedStateWriteSmoke,
[switch]$SkipCodeWriteSavedStateSmoke,
[switch]$RequireSavedStateWriteSmoke,
[switch]$RequireSelectorChainWritePlanComposition
)
$ErrorActionPreference = "Stop"
function Invoke-CheckedCommand {
param(
[string]$Label,
[string[]]$Command
)
Write-Host "[run] $Label"
$exe = $Command[0]
$args = $Command[1..($Command.Length - 1)]
Write-Host ("[cmd] {0} {1}" -f $exe, ($args -join " "))
& $exe @args
if ($LASTEXITCODE -ne 0) {
throw "$Label failed with code=$LASTEXITCODE"
}
}
function Invoke-ComposeUp {
param(
[string]$Label,
[string]$DockerHost,
[string]$ComposePath,
[string]$EnvFile,
[string]$ServiceName
)
$command = @("docker", "--host", $DockerHost, "compose", "-f", $ComposePath, "up", "-d", "--no-deps")
if ($EnvFile) {
$command = @("docker", "--host", $DockerHost, "compose", "--env-file", $EnvFile, "-f", $ComposePath, "up", "-d", "--no-deps")
}
if (-not $NoBuild) {
$command += "--build"
}
$command += $ServiceName
Invoke-CheckedCommand -Label $Label -Command $command
}
function Wait-RestAdapterIdle {
if ($SkipDrainCheck) {
Write-Host "[skip] REST drain check was explicitly skipped"
return
}
$deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSec)
$lastIssue = ""
while ([DateTime]::UtcNow -lt $deadline) {
try {
$health = Invoke-RestMethod -Method Get -Uri ($AdapterUrl.TrimEnd('/') + "/health") -TimeoutSec 10
$runtime = $health.runtime
if (-not $runtime) {
Write-Warning "REST adapter is a legacy image without runtime drain telemetry; proceeding with this one transition deployment"
return
}
if ($runtime -and $runtime.state -eq "ready" -and [int]$runtime.active_rpc_count -eq 0) {
Write-Host "[ready] REST adapter has no active RPC calls"
return
}
$lastIssue = "state=$($runtime.state) active_rpc_count=$($runtime.active_rpc_count)"
} catch {
$lastIssue = $_.Exception.Message
}
Start-Sleep -Seconds 2
}
throw "REST adapter did not become idle before deployment: $lastIssue. Re-run later or pass -SkipDrainCheck only after confirming no write is active."
}
function Ensure-RestServiceToken {
if ($env:ONEC_ADAPTER_SERVICE_TOKEN) {
return
}
if ($env:ONEC_ADAPTER_ALLOW_UNAUTHENTICATED_ADMIN -match '^(?i:true|1|yes|on)$') {
Write-Host "[security] Test profile: deploying without REST service token because ONEC_ADAPTER_ALLOW_UNAUTHENTICATED_ADMIN is enabled"
return
}
$inspectJson = & docker --host $RestDockerHost inspect $RestServiceName 2>$null
if ($LASTEXITCODE -eq 0 -and $inspectJson) {
$container = @($inspectJson | ConvertFrom-Json)[0]
$tokenEntry = @($container.Config.Env | Where-Object { $_ -like "ONEC_ADAPTER_SERVICE_TOKEN=*" })[0]
if ($tokenEntry) {
$existingToken = ($tokenEntry -split "=", 2)[1]
if ($existingToken) {
$env:ONEC_ADAPTER_SERVICE_TOKEN = $existingToken
Write-Host "[security] Reusing the existing REST service token without printing or persisting it"
return
}
}
}
throw "ONEC_ADAPTER_SERVICE_TOKEN is empty and no protected existing REST container token can be reused. Refusing to deploy an unauthenticated adapter."
}
function Write-ContainerSummary {
param(
[string]$Label,
[string]$DockerHost,
[string]$ServiceName
)
Write-Host "[status] $Label"
& docker --host $DockerHost ps --filter "name=$ServiceName" --format "name={{.Names}} image={{.Image}} status={{.Status}} ports={{.Ports}}"
if ($LASTEXITCODE -ne 0) {
throw "$Label status failed with code=$LASTEXITCODE"
}
}
function Get-DuplicateValues {
param(
[string[]]$Values
)
$seen = @{}
$duplicates = New-Object System.Collections.Generic.HashSet[string]
foreach ($value in $Values) {
if ($seen.ContainsKey($value)) {
[void]$duplicates.Add($value)
} else {
$seen[$value] = $true
}
}
return @($duplicates | Sort-Object)
}
function Normalize-BaseIds {
param(
[string[]]$Values
)
$result = @()
foreach ($value in $Values) {
foreach ($part in ($value -split ",")) {
$trimmed = $part.Trim()
if ($trimmed) {
$result += $trimmed
}
}
}
return $result
}
try {
if (-not $SkipRest) {
if (-not $env:ONEC_ADAPTER_ALLOW_UNAUTHENTICATED_ADMIN) {
$env:ONEC_ADAPTER_ALLOW_UNAUTHENTICATED_ADMIN = "true"
}
Ensure-RestServiceToken
Wait-RestAdapterIdle
Invoke-ComposeUp `
-Label "Deploy REST adapter" `
-DockerHost $RestDockerHost `
-ComposePath $RestComposePath `
-EnvFile $RestEnvFile `
-ServiceName $RestServiceName
Write-ContainerSummary `
-Label "REST adapter container" `
-DockerHost $RestDockerHost `
-ServiceName $RestServiceName
Invoke-ComposeUp `
-Label "Deploy REST audit analyzer" `
-DockerHost $RestDockerHost `
-ComposePath $RestComposePath `
-EnvFile $RestEnvFile `
-ServiceName $RestAuditServiceName
Write-ContainerSummary `
-Label "REST audit analyzer container" `
-DockerHost $RestDockerHost `
-ServiceName $RestAuditServiceName
}
if (-not $SkipMcp) {
Invoke-ComposeUp `
-Label "Deploy MCP proxy" `
-DockerHost $McpDockerHost `
-ComposePath $McpComposePath `
-EnvFile $McpEnvFile `
-ServiceName $McpServiceName
Write-ContainerSummary `
-Label "MCP proxy container" `
-DockerHost $McpDockerHost `
-ServiceName $McpServiceName
Invoke-ComposeUp `
-Label "Deploy MCP audit analyzer" `
-DockerHost $McpDockerHost `
-ComposePath $McpComposePath `
-EnvFile $McpEnvFile `
-ServiceName $McpAuditServiceName
Write-ContainerSummary `
-Label "MCP audit analyzer container" `
-DockerHost $McpDockerHost `
-ServiceName $McpAuditServiceName
}
if (-not $SkipVerify) {
$baseIds = @(Normalize-BaseIds -Values $BaseId)
if (-not $baseIds) {
Write-Host "[skip] BaseId was not provided; live verification skipped"
} else {
$duplicateBaseIds = @(Get-DuplicateValues -Values $baseIds)
if ($duplicateBaseIds) {
throw "Duplicate BaseId value(s): $($duplicateBaseIds -join ', ')"
}
$verifyCommand = @(
"powershell",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"scripts/verify_1c_adapter_deployment.ps1",
"-BaseId"
)
$verifyCommand += ($baseIds -join ",")
$verifyCommand += @(
"-AdapterUrl",
$AdapterUrl,
"-McpUrl",
$McpUrl,
"-TimeoutSec",
$TimeoutSec.ToString(),
"-SavedStateTable",
$SavedStateTable
)
if ($ObjectRef) {
$verifyCommand += @("-ObjectRef", $ObjectRef)
}
if ($ObjectKind) {
$verifyCommand += @("-ObjectKind", $ObjectKind)
}
if ($ObjectName) {
$verifyCommand += @("-ObjectName", $ObjectName)
}
if ($ObjectGuid) {
$verifyCommand += @("-ObjectGuid", $ObjectGuid)
}
if ($SkipRest) {
$verifyCommand += "-SkipRest"
}
if ($SkipMcp) {
$verifyCommand += "-SkipMcp"
}
if ($SkipWritePlanSafetySmoke) {
$verifyCommand += "-SkipWritePlanSafetySmoke"
}
if ($SkipWriteRollbackSafetySmoke) {
$verifyCommand += "-SkipWriteRollbackSafetySmoke"
}
if ($SkipSavedStateDiffSmoke) {
$verifyCommand += "-SkipSavedStateDiffSmoke"
}
if ($SkipSavedStateWriteSmoke) {
$verifyCommand += "-SkipSavedStateWriteSmoke"
}
if ($SkipCodeWriteSavedStateSmoke) {
$verifyCommand += "-SkipCodeWriteSavedStateSmoke"
}
if ($RequireSavedStateWriteSmoke) {
$verifyCommand += "-RequireSavedStateWriteSmoke"
}
if ($RequireSelectorChainWritePlanComposition) {
$verifyCommand += "-RequireSelectorChainWritePlanComposition"
}
Invoke-CheckedCommand -Label "Verify 1C adapter deployment" -Command $verifyCommand
}
}
Write-Host "[done] 1C adapter stack deploy finished"
exit 0
} catch {
Write-Error $_
exit 1
}