refactor(deploy): stream shell scripts over SSH and support binary-only updates

This commit is contained in:
lda committed 2026-10-19 18:44:12 +07:00 Verified
1 parent eb55554806
commit 134738cd32
6 files changed
+319 -131

No files matched your search

+80 -95
View File
@@ -4,6 +4,9 @@
param(
[ValidateSet("cargo", "cross")]
[string]$Cargo = "cargo",
[ValidateSet("wakey", "wakey-agent")]
[ValidateNotNullOrEmpty()]
[string[]]$Package = @("wakey", "wakey-agent"),
[string]$Pass,
[string]$HostName = "192.168.100.1",
[int]$Port = 22,
@@ -17,6 +20,7 @@ param(
[string]$HostKey,
[switch]$ForcePassword,
[switch]$SkipInitScript,
[switch]$BinariesOnly,
[switch]$Restart = $true,
[switch]$Quiet = $true
)
@@ -26,109 +30,90 @@ try { $PSStyle.OutputRendering = 'Host' } catch {}
. "$PSScriptRoot/lib.ps1"
$Pass = Get-DefaultPassword $Pass
function Build-Packages {
param([string[]]$Packages)
$buildArgs = @('build', '--release', '--target', $Target)
foreach ($pkg in $Packages) { $buildArgs += @('-p', $pkg) }
Write-Host "[build] $Cargo $($buildArgs -join ' ')" -ForegroundColor Cyan
& $Cargo @buildArgs
if ($LASTEXITCODE -ne 0) { throw "$Cargo build failed ($LASTEXITCODE)" }
}
function New-DeploymentPlan {
param([string[]]$Packages)
# Keep CLI first so replacing both binaries restarts the service only once.
$binaries = @(
@{ Package = 'wakey'; Name = $BinName; Destination = $RemotePath }
@{ Package = 'wakey-agent'; Name = $AgentBinName; Destination = $AgentRemotePath }
) | Where-Object { $_.Package -in $Packages } | ForEach-Object {
[pscustomobject]@{
Local = Join-Path $repoRoot "target/$Target/release/$($_.Name)"
Temp = "$($_.Destination).tmp"
Destination = $_.Destination
}
}
$support = @(
if (-not $BinariesOnly) {
if (-not $SkipInitScript) {
@{ Source = 'init/openwrt/wakey'; Temp = '/var/tmp/wakey.init.tmp'; Destination = $RemoteInitPath }
}
@{ Source = 'hotplug/openwrt/dhcp/95-wakey'; Temp = '/var/tmp/wakey.hotplug.dhcp.tmp'; Destination = '/etc/hotplug.d/dhcp/95-wakey' }
@{ Source = 'hotplug/openwrt/neigh/95-wakey'; Temp = '/var/tmp/wakey.hotplug.neigh.tmp'; Destination = '/etc/hotplug.d/neigh/95-wakey' }
}
) | ForEach-Object {
$local = Join-Path $PSScriptRoot $_.Source
if (Test-Path -LiteralPath $local) {
[pscustomobject]@{ Local = $local; Temp = $_.Temp; Destination = $_.Destination }
}
}
foreach ($binary in $binaries) {
if (-not (Test-Path -LiteralPath $binary.Local)) { throw "binary not found: $($binary.Local)" }
}
[pscustomobject]@{ Binaries = @($binaries); Support = @($support) }
}
function Get-RemoteDeployment {
param($Plan)
$deployArgs = @('--batch')
for ($i = 0; $i -lt $Plan.Binaries.Count; $i++) {
$binary = $Plan.Binaries[$i]
$restartFlag = if ($Restart -and $i -eq $Plan.Binaries.Count - 1) { '1' } else { '0' }
$deployArgs += @('--binary', $binary.Temp, $binary.Destination, $restartFlag)
}
foreach ($file in $Plan.Support) {
$deployArgs += @('--install', $file.Temp, $file.Destination)
}
# Only data needs shell quoting; the checked-in shell program travels as stdin.
$command = 'sh -s -- ' + (($deployArgs | ForEach-Object { Quote-ShArg $_ }) -join ' ')
if ($Quiet) { $command += ' >/dev/null 2>&1' }
[pscustomobject]@{
Script = Get-Content -Raw -LiteralPath "$PSScriptRoot/remote_deploy_wakey.sh"
Command = $command
}
}
function Send-DeploymentFiles {
param($Plan)
foreach ($file in @($Plan.Binaries) + @($Plan.Support)) {
Invoke-Scp -Local $file.Local -Dest "$User@${HostName}:$($file.Temp)" -Pass $Pass -HostKey $HostKey -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
}
}
$Pass = Get-DefaultPassword $Pass
# Backward compatibility: allow HostName in the form host:port.
$hostPort = Split-HostPort -HostName $HostName -DefaultPort $Port
$HostName = $hostPort.Host
$Port = $hostPort.Port
function Get-DeployScript {
param($DeployPreferred, $DeployTmp, $RemoteTmp, $RemotePath, $RestartFlag)
return @"
DEPLOY=$DeployPreferred;
if [ ! -x "`$DEPLOY" ] && [ -f $DeployTmp ]; then
sed -i "s/\r$//" $DeployTmp 2>/dev/null || true
chmod +x $DeployTmp
DEPLOY=$DeployTmp
fi
sh "`$DEPLOY" $RemoteTmp $RemotePath $RestartFlag
"@
}
#---- Main Flow ----
$repoRoot = Split-Path -Parent $PSScriptRoot
Push-Location $repoRoot
try {
Write-Host "[build] $Cargo build --release --target $Target -p wakey -p wakey-agent" -ForegroundColor Cyan
. "$Cargo" build --release --target $Target -p wakey -p wakey-agent
if ($LASTEXITCODE -ne 0) { throw "$Cargo build failed ($LASTEXITCODE)" }
$localBin = Join-Path $repoRoot "target/$Target/release/$BinName"
$localAgentBin = Join-Path $repoRoot "target/$Target/release/$AgentBinName"
if (-not (Test-Path $localBin)) { throw "binary not found: $localBin" }
if (-not (Test-Path $localAgentBin)) { throw "binary not found: $localAgentBin" }
$remoteTmp = "$RemotePath.tmp"
$agentRemoteTmp = "$AgentRemotePath.tmp"
$destTmp = "$User@${HostName}:$remoteTmp"
$agentDestTmp = "$User@${HostName}:$agentRemoteTmp"
$initTmp = '/var/tmp/wakey.init.tmp'
$initDestTmp = "$User@${HostName}:$initTmp"
$localDeploy = Join-Path $repoRoot 'scripts/remote_deploy_wakey.sh'
$localInit = Join-Path $repoRoot 'scripts/init/openwrt/wakey'
$localDhcpHotplug = Join-Path $repoRoot 'scripts/hotplug/openwrt/dhcp/95-wakey'
$localNeighHotplug = Join-Path $repoRoot 'scripts/hotplug/openwrt/neigh/95-wakey'
$deployTmp = '/var/tmp/remote_deploy_wakey.sh'
$deployPreferred = '/root/.bin/remote_deploy_wakey.sh'
$dhcpHotplugTmp = '/var/tmp/wakey.hotplug.dhcp.tmp'
$neighHotplugTmp = '/var/tmp/wakey.hotplug.neigh.tmp'
# Push binaries
Invoke-Scp -Local $localBin -Dest $destTmp -Pass $Pass -HostKey $HostKey -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
Invoke-Scp -Local $localAgentBin -Dest $agentDestTmp -Pass $Pass -HostKey $HostKey -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
# Push OpenWrt init script unless explicitly skipped
if (-not $SkipInitScript -and (Test-Path $localInit)) {
Invoke-Scp -Local $localInit -Dest $initDestTmp -Pass $Pass -HostKey $HostKey -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
}
if (Test-Path $localDhcpHotplug) {
Invoke-Scp -Local $localDhcpHotplug -Dest "$User@${HostName}:$dhcpHotplugTmp" -Pass $Pass -HostKey $HostKey -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
}
if (Test-Path $localNeighHotplug) {
Invoke-Scp -Local $localNeighHotplug -Dest "$User@${HostName}:$neighHotplugTmp" -Pass $Pass -HostKey $HostKey -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
}
# Push deploy helper if exists
if (Test-Path $localDeploy) {
Invoke-Scp -Local $localDeploy -Dest "$User@${HostName}:$deployTmp" -Pass $Pass -HostKey $HostKey -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
}
# Build and run remote deploy command
$restartFlag = $(if ($Restart) { '1' } else { '0' })
$script = @"
$(Get-DeployScript $deployPreferred $deployTmp $remoteTmp $RemotePath 0)
$(Get-DeployScript $deployPreferred $deployTmp $agentRemoteTmp $AgentRemotePath $restartFlag)
$(if (-not $SkipInitScript) {
@"
if [ -f $initTmp ]; then
sed -i "s/\r$//" $initTmp 2>/dev/null || true
if command -v install >/dev/null 2>&1; then
install -m 0755 $initTmp $RemoteInitPath
else
cp -f $initTmp $RemoteInitPath
chmod 0755 $RemoteInitPath
fi
fi
"@
})
if [ -f $dhcpHotplugTmp ]; then
sed -i "s/\r$//" $dhcpHotplugTmp 2>/dev/null || true
mkdir -p /etc/hotplug.d/dhcp
cp -f $dhcpHotplugTmp /etc/hotplug.d/dhcp/95-wakey
fi
if [ -f $neighHotplugTmp ]; then
sed -i "s/\r$//" $neighHotplugTmp 2>/dev/null || true
mkdir -p /etc/hotplug.d/neigh
cp -f $neighHotplugTmp /etc/hotplug.d/neigh/95-wakey
fi
"@
$remoteCmd = "sh -lc '$($script -replace "`r",'')'"
if ($Quiet) { $remoteCmd += " >/dev/null 2>&1" }
Invoke-Ssh -Cmd $remoteCmd -User $User -Remote $HostName -Pass $Pass -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
Build-Packages ($Package | Select-Object -Unique)
$plan = New-DeploymentPlan $Package
# Prepare before uploading so missing local helpers fail without remote changes.
$deployment = Get-RemoteDeployment $plan
Send-DeploymentFiles $plan
Invoke-Ssh -Cmd $deployment.Command -Stdin $deployment.Script -User $User -Remote $HostName -Pass $Pass -Port $Port -Quiet:$Quiet -ForcePassword:$ForcePassword
Write-Host "done ✔" -ForegroundColor Green
}
finally {