feat(map): add cache-first Cesium gateway and AMD egress
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$Destination = 'C:\NODEDC\dc-amd-connector',
|
||||
[string]$NasAddress = '172.22.0.222',
|
||||
[string]$BindAddress = '172.22.0.183',
|
||||
[int]$Port = 8791,
|
||||
[bool]$EnableAutoStart = $true
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Require-Administrator {
|
||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
|
||||
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
throw 'Run this installer from an elevated PowerShell window.'
|
||||
}
|
||||
}
|
||||
|
||||
function Test-PackageChecksums([string]$Root) {
|
||||
$manifest = Join-Path $Root 'SHA256SUMS'
|
||||
if (-not (Test-Path -LiteralPath $manifest -PathType Leaf)) {
|
||||
throw "Checksum manifest not found: $manifest"
|
||||
}
|
||||
|
||||
foreach ($line in Get-Content -LiteralPath $manifest) {
|
||||
if ([string]::IsNullOrWhiteSpace($line)) { continue }
|
||||
$parts = $line -split '\s{2,}', 2
|
||||
if ($parts.Count -ne 2 -or $parts[0] -notmatch '^[a-f0-9]{64}$') {
|
||||
throw "Invalid checksum line: $line"
|
||||
}
|
||||
$relative = $parts[1] -replace '^\./', ''
|
||||
$file = Join-Path $Root $relative
|
||||
$actual = (Get-FileHash -LiteralPath $file -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
if ($actual -ne $parts[0]) { throw "Checksum mismatch: $relative" }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-DockerDesktopStartCommand([string]$DockerCliPath) {
|
||||
& $DockerCliPath desktop start --help 2>$null | Out-Null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
return "`"$DockerCliPath`" desktop start --detach"
|
||||
}
|
||||
|
||||
$dockerRoot = Split-Path (Split-Path (Split-Path $DockerCliPath -Parent) -Parent) -Parent
|
||||
$candidates = @(
|
||||
(Join-Path $dockerRoot 'Docker Desktop.exe'),
|
||||
(Join-Path $env:ProgramFiles 'Docker\Docker\Docker Desktop.exe'),
|
||||
(Join-Path $env:LOCALAPPDATA 'Programs\Docker\Docker\Docker Desktop.exe')
|
||||
) | Select-Object -Unique
|
||||
$desktopExe = $candidates | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | Select-Object -First 1
|
||||
if (-not $desktopExe) {
|
||||
throw 'Unable to find Docker Desktop start command or Docker Desktop.exe for restart recovery.'
|
||||
}
|
||||
return "start `"`" `"$desktopExe`""
|
||||
}
|
||||
|
||||
function New-DockerDesktopAutoStart([string]$StartCommand) {
|
||||
$startup = [Environment]::GetFolderPath([Environment+SpecialFolder]::Startup)
|
||||
if ([string]::IsNullOrWhiteSpace($startup)) { throw 'Unable to resolve the current user Startup folder.' }
|
||||
|
||||
$launcher = Join-Path $startup 'NODE.DC DC AMD Connector - Docker Desktop.cmd'
|
||||
if (Test-Path -LiteralPath $launcher) {
|
||||
throw "Docker Desktop auto-start launcher already exists: $launcher"
|
||||
}
|
||||
|
||||
@(
|
||||
'@echo off',
|
||||
'rem NODE.DC DC AMD Connector - starts Docker Desktop after this user signs in.',
|
||||
$StartCommand
|
||||
) | Set-Content -LiteralPath $launcher -Encoding ascii
|
||||
return $launcher
|
||||
}
|
||||
|
||||
Require-Administrator
|
||||
$source = Split-Path -Parent $PSCommandPath
|
||||
if (-not (Test-Path -LiteralPath (Join-Path $source 'VERSION') -PathType Leaf)) {
|
||||
throw 'Run install.ps1 from the DC AMD Connector package folder.'
|
||||
}
|
||||
Test-PackageChecksums $source
|
||||
|
||||
if (Test-Path -LiteralPath $Destination) {
|
||||
throw "Destination already exists; refusing to overwrite: $Destination"
|
||||
}
|
||||
|
||||
$null = [Net.IPAddress]::Parse($NasAddress)
|
||||
$null = [Net.IPAddress]::Parse($BindAddress)
|
||||
if ($Port -lt 1 -or $Port -gt 65535) {
|
||||
throw "Port must be between 1 and 65535: $Port"
|
||||
}
|
||||
|
||||
$dockerCli = (Get-Command docker -CommandType Application -ErrorAction Stop | Select-Object -First 1).Path
|
||||
if ([string]::IsNullOrWhiteSpace($dockerCli) -or -not (Test-Path -LiteralPath $dockerCli -PathType Leaf)) {
|
||||
throw 'Docker CLI executable could not be resolved.'
|
||||
}
|
||||
& $dockerCli version --format '{{.Server.Os}}/{{.Server.Arch}} {{.Server.Version}}' | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw 'Docker Desktop engine is not available. Start it and wait for Engine running.'
|
||||
}
|
||||
$dockerDesktopStartCommand = Get-DockerDesktopStartCommand $dockerCli
|
||||
|
||||
$destinationCreated = $false
|
||||
$firewallCreated = $false
|
||||
$autoStartLauncher = $null
|
||||
$parent = Split-Path -Parent $Destination
|
||||
try {
|
||||
New-Item -ItemType Directory -Force $parent | Out-Null
|
||||
Copy-Item -LiteralPath $source -Destination $Destination -Recurse
|
||||
$destinationCreated = $true
|
||||
Test-PackageChecksums $Destination
|
||||
Set-Location $Destination
|
||||
|
||||
New-Item -ItemType Directory -Force runtime | Out-Null
|
||||
$tokenPath = Join-Path $Destination 'runtime\connector-access'
|
||||
if (Test-Path -LiteralPath $tokenPath) { throw "Runtime token already exists: $tokenPath" }
|
||||
$bytes = New-Object byte[] 48
|
||||
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
|
||||
try { $rng.GetBytes($bytes) } finally { $rng.Dispose() }
|
||||
$token = [Convert]::ToBase64String($bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_')
|
||||
[IO.File]::WriteAllText($tokenPath, $token, [Text.UTF8Encoding]::new($false))
|
||||
|
||||
Copy-Item -LiteralPath (Join-Path $Destination '.env.example') -Destination (Join-Path $Destination '.env')
|
||||
@(
|
||||
"AMD_CONNECTOR_BIND_IP=$BindAddress",
|
||||
"AMD_CONNECTOR_PORT=$Port"
|
||||
) | Set-Content -LiteralPath (Join-Path $Destination '.env') -Encoding ascii
|
||||
|
||||
$ruleName = 'NODE.DC DC AMD Connector (NAS only)'
|
||||
if (Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue) {
|
||||
throw "Firewall rule already exists; refusing to replace: $ruleName"
|
||||
}
|
||||
New-NetFirewallRule -DisplayName $ruleName -Direction Inbound -Action Allow -Protocol TCP -Profile Any -LocalAddress $BindAddress -LocalPort $Port -RemoteAddress $NasAddress | Out-Null
|
||||
$firewallCreated = $true
|
||||
|
||||
if ($EnableAutoStart) {
|
||||
$autoStartLauncher = New-DockerDesktopAutoStart $dockerDesktopStartCommand
|
||||
}
|
||||
|
||||
& $dockerCli compose up -d --build
|
||||
$state = ''
|
||||
foreach ($attempt in 1..30) {
|
||||
$state = & $dockerCli inspect dc-amd-connector --format '{{.State.Status}} health={{if .State.Health}}{{.State.Health.Status}}{{end}}'
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Container inspection failed after Docker Compose apply.' }
|
||||
if ($state -eq 'running health=healthy') { break }
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
if ($state -ne 'running health=healthy') {
|
||||
throw "Connector did not become healthy: $state"
|
||||
}
|
||||
|
||||
Write-Host "DC AMD Connector installed: $state"
|
||||
Write-Host "Bound to $BindAddress`:$Port; inbound firewall scope is NAS $NasAddress."
|
||||
if ($autoStartLauncher) {
|
||||
Write-Host "Docker Desktop will start at the next sign-in through: $autoStartLauncher"
|
||||
}
|
||||
Write-Host 'The connector access token remains only in runtime\connector-access. Do not print or send it in chat.'
|
||||
}
|
||||
catch {
|
||||
if ($autoStartLauncher -and (Test-Path -LiteralPath $autoStartLauncher)) {
|
||||
Remove-Item -LiteralPath $autoStartLauncher -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
if ($firewallCreated) {
|
||||
Remove-NetFirewallRule -DisplayName 'NODE.DC DC AMD Connector (NAS only)' -ErrorAction SilentlyContinue
|
||||
}
|
||||
if ($destinationCreated -and (Test-Path -LiteralPath $Destination)) {
|
||||
Remove-Item -LiteralPath $Destination -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
throw
|
||||
}
|
||||
Reference in New Issue
Block a user