154 lines
6.6 KiB
PowerShell
154 lines
6.6 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[ValidateRange(1, 1000)] [int]$FreeGiBFloor = 360,
|
|
[string]$RuntimeRoot = "D:\NDC_MISSIONCORE\runtime",
|
|
[string]$ContainerImage = "nvcr.io/nvidia/tritonserver:26.06-py3@sha256:58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794",
|
|
[string]$RuntimeName = "perception-e15-media-pyav180-lz445-v1"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$ProgressPreference = "SilentlyContinue"
|
|
|
|
function Assert-LastExitCode([string]$Operation) {
|
|
if ($LASTEXITCODE -ne 0) { throw "$Operation failed with exit code $LASTEXITCODE" }
|
|
}
|
|
|
|
function Resolve-DDirectory([string]$Path, [string]$Label) {
|
|
$item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
|
|
$root = [IO.Path]::GetPathRoot($item.FullName).TrimEnd("\")
|
|
if (-not $item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -or $root -ine "D:") {
|
|
throw "$Label must be a real D: directory"
|
|
}
|
|
return $item.FullName
|
|
}
|
|
|
|
function Convert-ToDockerPath([string]$Path) { return $Path.Replace("\", "/") }
|
|
|
|
function Assert-FreeSpace([string]$Phase) {
|
|
$free = [int64](Get-PSDrive -Name D).Free
|
|
$floor = [int64]$FreeGiBFloor * 1GB
|
|
Write-Host (
|
|
"DISK_GUARD PHASE={0} DRIVE=D FREE_BYTES={1} FREE_GIB={2} FLOOR_GIB={3}" -f
|
|
$Phase, $free, [math]::Round($free / 1GB, 3), $FreeGiBFloor
|
|
)
|
|
if ($free -lt ($floor + 2GB)) {
|
|
throw "D: lacks the guarded LAB E15 media-runtime reserve during $Phase"
|
|
}
|
|
return $free
|
|
}
|
|
|
|
function Get-PayloadDigest([string]$Root) {
|
|
$resolved = Resolve-DDirectory $Root "E15 media runtime"
|
|
$lines = @(
|
|
Get-ChildItem -LiteralPath $resolved -Recurse -File -Force |
|
|
Where-Object { $_.Name -ne "manifest.json" } |
|
|
Sort-Object FullName |
|
|
ForEach-Object {
|
|
$relative = $_.FullName.Substring($resolved.Length).TrimStart("\").Replace("\", "/")
|
|
$hash = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
"{0}`t{1}`t{2}" -f $relative, $_.Length, $hash
|
|
}
|
|
)
|
|
if ($lines.Count -lt 4) { throw "E15 media runtime payload is incomplete" }
|
|
$bytes = [Text.Encoding]::UTF8.GetBytes(($lines -join "`n") + "`n")
|
|
$hasher = [Security.Cryptography.SHA256]::Create()
|
|
try {
|
|
return ([BitConverter]::ToString($hasher.ComputeHash($bytes))).Replace("-", "").ToLowerInvariant()
|
|
}
|
|
finally { $hasher.Dispose() }
|
|
}
|
|
|
|
function Assert-Runtime([string]$Path) {
|
|
$root = Resolve-DDirectory $Path "E15 media runtime"
|
|
$manifestPath = Join-Path $root "manifest.json"
|
|
if (-not (Test-Path -LiteralPath $manifestPath -PathType Leaf)) {
|
|
throw "E15 media runtime manifest is missing"
|
|
}
|
|
$manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json
|
|
if (
|
|
$manifest.schema_version -ne "missioncore.e15-media-runtime/v1" -or
|
|
$manifest.runtime_name -ne $RuntimeName -or
|
|
$manifest.container_image -ne $ContainerImage -or
|
|
$manifest.packages.av -ne "18.0.0" -or
|
|
$manifest.packages.lz4 -ne "4.4.5" -or
|
|
$manifest.payload_sha256 -ne (Get-PayloadDigest $root)
|
|
) { throw "E15 media runtime identity changed" }
|
|
|
|
$dockerRoot = Convert-ToDockerPath $root
|
|
$verifyCode = "import av,lz4.version;print(av.__version__);print(lz4.version.version)"
|
|
$verifyOutput = @(& docker run --rm --network none --read-only `
|
|
--security-opt "no-new-privileges:true" --cap-drop ALL --pids-limit 64 `
|
|
--tmpfs "/tmp:rw,noexec,nosuid,size=64m" `
|
|
-e "PYTHONPATH=/opt/media" -e "PYTHONDONTWRITEBYTECODE=1" `
|
|
-v ("{0}:/opt/media:ro" -f $dockerRoot) `
|
|
--entrypoint python3 $ContainerImage -c $verifyCode)
|
|
Assert-LastExitCode "E15 media runtime verification"
|
|
if ($verifyOutput.Count -ne 2 -or $verifyOutput[0] -ne "18.0.0" -or $verifyOutput[1] -ne "4.4.5") {
|
|
throw "E15 media runtime package versions changed"
|
|
}
|
|
Write-Host "MEDIA_RUNTIME_OK pyav=18.0.0 lz4=4.4.5"
|
|
return $root
|
|
}
|
|
|
|
$runtime = Resolve-DDirectory $RuntimeRoot "Runtime root"
|
|
$derived = Resolve-DDirectory (Join-Path $runtime "derived") "Runtime derived root"
|
|
$destination = Join-Path $derived $RuntimeName
|
|
$freeBefore = Assert-FreeSpace "media-runtime-preflight"
|
|
|
|
& docker image inspect $ContainerImage *> $null
|
|
Assert-LastExitCode "Pinned container image inspection"
|
|
|
|
if (Test-Path -LiteralPath $destination) {
|
|
$resolved = Assert-Runtime $destination
|
|
Write-Output "STATE=existing-verified"
|
|
Write-Output ("MEDIA_RUNTIME_ROOT={0}" -f $resolved)
|
|
Write-Output ("DISK_FREE_BYTES_BEFORE={0}" -f $freeBefore)
|
|
Write-Output ("DISK_FREE_BYTES_AFTER={0}" -f ([int64](Get-PSDrive -Name D).Free))
|
|
return
|
|
}
|
|
|
|
$token = [Guid]::NewGuid().ToString("N")
|
|
$staging = Join-Path $derived (".{0}-{1}.tmp" -f $RuntimeName, $token)
|
|
$null = New-Item -ItemType Directory -Path $staging
|
|
$completed = $false
|
|
try {
|
|
$dockerStaging = Convert-ToDockerPath $staging
|
|
Write-Output "PHASE=media-runtime-install-start"
|
|
& docker run --rm --network bridge --read-only `
|
|
--security-opt "no-new-privileges:true" --cap-drop ALL --pids-limit 128 `
|
|
--tmpfs "/tmp:rw,nosuid,size=1g" `
|
|
-e "PIP_DISABLE_PIP_VERSION_CHECK=1" -e "PYTHONDONTWRITEBYTECODE=1" `
|
|
-v ("{0}:/target:rw" -f $dockerStaging) `
|
|
--entrypoint python3 $ContainerImage -m pip install `
|
|
--no-cache-dir --only-binary ":all:" --target /target `
|
|
"av==18.0.0" "lz4==4.4.5"
|
|
Assert-LastExitCode "E15 media runtime installation"
|
|
|
|
$payloadSha256 = Get-PayloadDigest $staging
|
|
$manifest = [ordered]@{
|
|
schema_version = "missioncore.e15-media-runtime/v1"
|
|
runtime_name = $RuntimeName
|
|
created_at_utc = [DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
|
|
container_image = $ContainerImage
|
|
packages = [ordered]@{ av = "18.0.0"; lz4 = "4.4.5" }
|
|
payload_sha256 = $payloadSha256
|
|
storage_scope = "D-only-immutable-runtime"
|
|
}
|
|
$manifest | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $staging "manifest.json") -Encoding utf8
|
|
$null = Assert-Runtime $staging
|
|
Move-Item -LiteralPath $staging -Destination $destination
|
|
$completed = $true
|
|
$resolved = Assert-Runtime $destination
|
|
$freeAfter = Assert-FreeSpace "media-runtime-published"
|
|
Write-Output "STATE=created-verified"
|
|
Write-Output ("MEDIA_RUNTIME_ROOT={0}" -f $resolved)
|
|
Write-Output ("PAYLOAD_SHA256={0}" -f $payloadSha256)
|
|
Write-Output ("DISK_FREE_BYTES_BEFORE={0}" -f $freeBefore)
|
|
Write-Output ("DISK_FREE_BYTES_AFTER={0}" -f $freeAfter)
|
|
}
|
|
finally {
|
|
if (-not $completed -and (Test-Path -LiteralPath $staging)) {
|
|
Remove-Item -LiteralPath $staging -Recurse -Force
|
|
}
|
|
}
|