You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

153 lines
7.5 KiB

$ErrorActionPreference = 'Stop'
$project = Split-Path -Parent $PSScriptRoot
Start-Transcript -Path (Join-Path $project 'runtime/full-readiness-transfer.log') -Force | Out-Null
$binary = Join-Path $project 'build/linux-arm64/tera-clone-demo-api-full-readiness'
$webBinary = Join-Path $project 'build/linux-arm64/tera-clone-demo-web-full-readiness'
$timeBinary = Join-Path $project 'build/linux-arm64/tera-timed-full-readiness'
$alarmBinary = Join-Path $project 'build/linux-arm64/tera-clone-demo-alarmd-full-readiness'
$timeHash = (Get-FileHash -LiteralPath $timeBinary -Algorithm SHA256).Hash.ToLowerInvariant()
$alarmHash = (Get-FileHash -LiteralPath $alarmBinary -Algorithm SHA256).Hash.ToLowerInvariant()
$webHash = (Get-FileHash -LiteralPath $webBinary -Algorithm SHA256).Hash.ToLowerInvariant()
$hash = (Get-FileHash -LiteralPath $binary -Algorithm SHA256).Hash.ToLowerInvariant()
$script = @'
#!/bin/sh
set -eu
stage=/tmp/tera-full-readiness-20260909
mkdir -p "$stage"
wget -q -T 20 -O "$stage/api" http://192.168.0.100:9001/api
wget -q -T 20 -O "$stage/web" http://192.168.0.100:9001/web
wget -q -T 20 -O "$stage/timed" http://192.168.0.100:9001/timed
wget -q -T 20 -O "$stage/alarmd" http://192.168.0.100:9001/alarmd
echo '__TIMEHASH__ '"$stage/timed" | sha256sum -c -
echo '__ALARMHASH__ '"$stage/alarmd" | sha256sum -c -
echo '__HASH__ '"$stage/api" | sha256sum -c -
echo '__WEBHASH__ '"$stage/web" | sha256sum -c -
backup=/userdata/tera-backups/full-readiness-$(date +%Y%m%d-%H%M%S)
mkdir -p "$backup"
cp -p /usr/bin/tera-clone-demo-api "$backup/api"
cp -p /usr/bin/tera-clone-demo-web "$backup/web"
cp -p /usr/bin/tera-timed "$backup/timed"
cp -p /usr/bin/tera-clone-demo-alarmd "$backup/alarmd"
echo "BACKUP=$backup"
cp "$stage/api" /usr/bin/tera-clone-demo-api.next
cp "$stage/web" /usr/bin/tera-clone-demo-web.next
chmod 0755 /usr/bin/tera-clone-demo-api.next /usr/bin/tera-clone-demo-web.next
cp "$stage/timed" /usr/bin/tera-timed.next
cp "$stage/alarmd" /usr/bin/tera-clone-demo-alarmd.next
chmod 0755 /usr/bin/tera-timed.next /usr/bin/tera-clone-demo-alarmd.next
rollback() {
trap - EXIT
/etc/init.d/S61tera-clone-demo-web stop || true
/etc/init.d/S51tera-clone-demo-api stop || true
/etc/init.d/S48tera-clone-demo-alarmd stop || true
/etc/init.d/S45tera-timed stop || true
sleep 2
cp "$backup/api" /usr/bin/tera-clone-demo-api.restore
cp "$backup/web" /usr/bin/tera-clone-demo-web.restore
chmod 0755 /usr/bin/tera-clone-demo-api.restore /usr/bin/tera-clone-demo-web.restore
mv /usr/bin/tera-clone-demo-api.restore /usr/bin/tera-clone-demo-api
mv /usr/bin/tera-clone-demo-web.restore /usr/bin/tera-clone-demo-web
cp "$backup/timed" /usr/bin/tera-timed.restore
cp "$backup/alarmd" /usr/bin/tera-clone-demo-alarmd.restore
chmod 0755 /usr/bin/tera-timed.restore /usr/bin/tera-clone-demo-alarmd.restore
mv /usr/bin/tera-timed.restore /usr/bin/tera-timed
mv /usr/bin/tera-clone-demo-alarmd.restore /usr/bin/tera-clone-demo-alarmd
/etc/init.d/S45tera-timed start
/etc/init.d/S48tera-clone-demo-alarmd start
/etc/init.d/S51tera-clone-demo-api start
/etc/init.d/S61tera-clone-demo-web start
echo FULL_READINESS_ROLLED_BACK
}
trap rollback EXIT
/etc/init.d/S61tera-clone-demo-web stop
/etc/init.d/S51tera-clone-demo-api stop
/etc/init.d/S48tera-clone-demo-alarmd stop
/etc/init.d/S45tera-timed stop
sleep 2
mv /usr/bin/tera-clone-demo-api.next /usr/bin/tera-clone-demo-api
mv /usr/bin/tera-clone-demo-web.next /usr/bin/tera-clone-demo-web
mv /usr/bin/tera-timed.next /usr/bin/tera-timed
mv /usr/bin/tera-clone-demo-alarmd.next /usr/bin/tera-clone-demo-alarmd
/etc/init.d/S45tera-timed start
/etc/init.d/S48tera-clone-demo-alarmd start
(
set -a
. /etc/tera/tera-clone-demo-api.env
set +a
start-stop-daemon -S -q -b -m -p /run/tera-clone-demo-api.pid -c tera:tera -x /bin/sh -- -c 'exec /usr/bin/tera-clone-demo-api > /run/tera-clone-demo-api/full-readiness-startup.log 2>&1'
)
/etc/init.d/S61tera-clone-demo-web start
ready=0
for n in $(seq 1 120); do
if wget -q -T 2 -O "$stage/status" http://127.0.0.1:8083/login/backend-status; then
if grep -q '"ready":true' "$stage/status"; then ready=1; break; fi
if grep -q '"state":"failed"' "$stage/status"; then cat "$stage/status"; grep -E "startup|reconciliation" /run/tera-clone-demo-api/full-readiness-startup.log; exit 1; fi
fi
sleep 1
done
cat "$stage/status"
if [ "$ready" != 1 ]; then
grep -E "startup|reconciliation|observation" /run/tera-clone-demo-api/full-readiness-startup.log || true
exit 1
fi
wget -q -T 3 -O "$stage/login.js" http://127.0.0.1:8083/static/js/login.js
grep -q '/login/bootstrap-time' "$stage/login.js"
sha256sum /usr/bin/tera-clone-demo-api /usr/bin/tera-clone-demo-web /usr/bin/tera-timed /usr/bin/tera-clone-demo-alarmd
sync
trap - EXIT
echo FULL_READINESS_DEPLOY_OK
'@
$script = $script.Replace('__HASH__', $hash).Replace('__WEBHASH__', $webHash).Replace('__TIMEHASH__', $timeHash).Replace('__ALARMHASH__', $alarmHash).Replace("`r`n", "`n") + "`n"
$rule = 'TERA-full-readiness-' + [guid]::NewGuid().ToString('N')
$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add('http://192.168.0.100:9001/')
$serial = New-Object System.IO.Ports.SerialPort 'COM5',115200,'None',8,'One'
$serial.Encoding = [Text.Encoding]::UTF8
try {
New-NetFirewallRule -DisplayName $rule -Direction Inbound -Action Allow -Protocol TCP -LocalPort 9001 -RemoteAddress 192.168.0.223 | Out-Null
$listener.Start()
$serial.Open()
$serial.WriteLine('wget -q -O /tmp/deploy-full-readiness.sh http://192.168.0.100:9001/deploy.sh && sh /tmp/deploy-full-readiness.sh')
$deadline = [DateTime]::UtcNow.AddSeconds(360)
$output = ''
$pending = $listener.GetContextAsync()
while ([DateTime]::UtcNow -lt $deadline) {
if ($pending.IsCompleted) {
$context = $pending.GetAwaiter().GetResult()
if ($context.Request.RemoteEndPoint.Address.ToString() -ne '192.168.0.223') {
$context.Response.StatusCode = 403
$context.Response.Close()
} else {
$bytes = $null
switch ($context.Request.Url.AbsolutePath) {
'/deploy.sh' { $bytes = [Text.Encoding]::UTF8.GetBytes($script) }
'/web' { $bytes = [IO.File]::ReadAllBytes($webBinary) }
'/api' { $bytes = [IO.File]::ReadAllBytes($binary) }
'/timed' { $bytes = [IO.File]::ReadAllBytes($timeBinary) }
'/alarmd' { $bytes = [IO.File]::ReadAllBytes($alarmBinary) }
default { $context.Response.StatusCode = 404 }
}
if ($null -ne $bytes) {
$context.Response.ContentLength64 = $bytes.Length
$context.Response.OutputStream.Write($bytes, 0, $bytes.Length)
}
$context.Response.Close()
}
$pending = $listener.GetContextAsync()
}
$chunk = $serial.ReadExisting()
if ($chunk) { $output += $chunk; Write-Host -NoNewline $chunk }
if ($output.Contains('FULL_READINESS_ROLLED_BACK')) { throw 'Readiness failed; old pair restored.' }
if ($output.Contains('FULL_READINESS_DEPLOY_OK')) { break }
Start-Sleep -Milliseconds 100
}
if (-not $output.Contains('FULL_READINESS_DEPLOY_OK')) { throw 'Deployment did not report success; inspect device console.' }
if (-not $output.Contains($hash) -or -not $output.Contains($webHash) -or -not $output.Contains($timeHash) -or -not $output.Contains($alarmHash)) { throw 'Deployed hash missing from console output.' }
Write-Output "VERIFIED deployed SHA256=$hash and API login-policy endpoint"
} finally {
if ($serial.IsOpen) { $serial.Close() }
$serial.Dispose()
$listener.Close()
Remove-NetFirewallRule -DisplayName $rule -ErrorAction SilentlyContinue
Stop-Transcript | Out-Null
}