mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
fix(orcad): a managed SSH/WSL server falls back when port 6768 is taken; WSL lane skips the MSI on 3.0.1 images (#29522)
* ci(wsl-orcad): skip the WSL MSI when the image already has 3.0.1 windows-2025 image 20261007.264.1 ships WSL 3.0.1.0, and reinstalling the pinned 3.0.1 MSI over it exits 1603, failing every run. Install only when the image is older, print the msiexec log on failure, and gate on >= 3.0.1 after. * fix(orcad): let a managed launch fall back when its default port is taken #29432 made any --port mandatory, but managed SSH/WSL launches pass the default 6768 as a preference and read the bound port from readiness. WSL2 distros share one VM loopback, so a second distro's orcad now failed with pinned_port_unavailable. Only an operator --port is required now.
This commit is contained in:
@@ -80,20 +80,32 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
# The image ships WSL 2.7.14, where stopping a systemd distro drops the VM-wide WSLInterop
|
||||
# entry (microsoft/WSL#13885, fixed in 3.0.1). The lane asserts the fixed behavior, so it
|
||||
# installs a pinned 3.0.1 MSI; `wsl --update` asks the GitHub API and gets rate-limited (403).
|
||||
# WSL before 3.0.1 drops the VM-wide WSLInterop entry when a systemd distro stops
|
||||
# (microsoft/WSL#13885). Images from 20261007 ship 3.0.1, where reinstalling the MSI fails
|
||||
# with 1603, so install only when older; `wsl --update` gets rate-limited by the GitHub API.
|
||||
- name: Check the installed WSL version
|
||||
id: wsl-version
|
||||
run: |
|
||||
"ImageOS=$env:ImageOS ImageVersion=$env:ImageVersion"
|
||||
$details = (wsl.exe --version) -join "`n"
|
||||
$details
|
||||
$match = [regex]::Match($details, '(?m)^WSL version:\s*(\d+(?:\.\d+){2,3})\s*$')
|
||||
# Inbox WSL has no --version, so an unreadable version means the package is needed.
|
||||
$installed = if ($LASTEXITCODE -eq 0 -and $match.Success) { [version]$match.Groups[1].Value } else { [version]'0.0.0' }
|
||||
$needsInstall = $installed -lt [version]'3.0.1'
|
||||
"Installed WSL $installed; minimum 3.0.1; install needed: $needsInstall"
|
||||
"needs-install=$($needsInstall.ToString().ToLowerInvariant())" >> $env:GITHUB_OUTPUT
|
||||
- name: Restore the pinned WSL package
|
||||
id: wsl-msi-cache
|
||||
if: steps.wsl-version.outputs.needs-install == 'true'
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: ${{ runner.temp }}/wsl-msi
|
||||
key: wsl-orcad-msi-${{ env.WSL_MSI_SHA256 }}
|
||||
- name: Install WSL 3.0.1
|
||||
if: steps.wsl-version.outputs.needs-install == 'true'
|
||||
timeout-minutes: 8
|
||||
run: |
|
||||
"ImageOS=$env:ImageOS ImageVersion=$env:ImageVersion"
|
||||
wsl.exe --version
|
||||
$dir = Join-Path $env:RUNNER_TEMP 'wsl-msi'
|
||||
New-Item -ItemType Directory -Force $dir | Out-Null
|
||||
$msi = Join-Path $dir 'wsl.msi'
|
||||
@@ -101,18 +113,34 @@ jobs:
|
||||
if ((Get-FileHash $msi -Algorithm SHA256).Hash.ToLowerInvariant() -ne $env:WSL_MSI_SHA256) {
|
||||
Remove-Item $msi; throw 'WSL package checksum mismatch'
|
||||
}
|
||||
$install = Start-Process msiexec.exe -ArgumentList @('/i', $msi, '/qn', '/norestart', '/l*v', (Join-Path $env:RUNNER_TEMP 'wsl-msi.log')) -Wait -PassThru
|
||||
if ($install.ExitCode -notin 0, 3010) { throw "WSL install failed: $($install.ExitCode)" }
|
||||
# Kept beside the receipts so the always() upload carries it.
|
||||
New-Item -ItemType Directory -Force $env:ORCA_WSL_ORCAD_LANE_RECEIPTS | Out-Null
|
||||
$log = Join-Path $env:ORCA_WSL_ORCAD_LANE_RECEIPTS 'wsl-msi-install.log'
|
||||
$install = Start-Process msiexec.exe -ArgumentList @('/i', $msi, '/qn', '/norestart', '/l*v', $log) -Wait -PassThru
|
||||
if ($install.ExitCode -notin 0, 3010) {
|
||||
if (Test-Path $log) {
|
||||
$lines = @(Get-Content $log)
|
||||
$failed = ($lines | Select-String -SimpleMatch 'Return value 3' | Select-Object -First 1).LineNumber
|
||||
if ($failed) { '--- msiexec log before the failing action'; $lines[[math]::Max(0, $failed - 40)..($failed - 1)] }
|
||||
'--- msiexec log tail'; $lines | Select-Object -Last 60
|
||||
}
|
||||
throw "WSL install failed: $($install.ExitCode)"
|
||||
}
|
||||
wsl.exe --shutdown
|
||||
$version = [version](((wsl.exe --version) -join "`n") -replace '(?s)^\D*?(\d+\.\d+\.\d+).*$', '$1')
|
||||
wsl.exe --version
|
||||
if ($version -lt [version]'3.0.1') { throw "WSL $version is older than 3.0.1" }
|
||||
- name: Save the pinned WSL package
|
||||
if: steps.wsl-msi-cache.outputs.cache-hit != 'true'
|
||||
if: steps.wsl-version.outputs.needs-install == 'true' && steps.wsl-msi-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: ${{ runner.temp }}/wsl-msi
|
||||
key: wsl-orcad-msi-${{ env.WSL_MSI_SHA256 }}
|
||||
- name: Verify WSL is at least 3.0.1
|
||||
run: |
|
||||
$details = (wsl.exe --version) -join "`n"
|
||||
if ($LASTEXITCODE -ne 0) { throw "Could not read the WSL version: $details" }
|
||||
$details
|
||||
$match = [regex]::Match($details, '(?m)^WSL version:\s*(\d+(?:\.\d+){2,3})\s*$')
|
||||
if (-not $match.Success) { throw 'Could not parse the WSL version' }
|
||||
if ([version]$match.Groups[1].Value -lt [version]'3.0.1') { throw "WSL $($match.Groups[1].Value) is older than 3.0.1" }
|
||||
- name: Restore the pinned rootfs
|
||||
id: rootfs-cache
|
||||
uses: actions/cache/restore@v5
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
import { stampRuntimeSourceEnv } from '../../shared/runtime-source-env'
|
||||
import { adoptWslHostLoginEnvironment } from './orcad-wsl-host-login-environment'
|
||||
import { installOrcadProcessErrorGuards } from './orcad-process-error-guards'
|
||||
import { orcadWsPortOptions } from './orcad-ws-port-policy'
|
||||
|
||||
export { parseArgs }
|
||||
|
||||
@@ -340,9 +341,7 @@ async function startOrcadRuntime(
|
||||
// once a device has connected, so a loopback deployment would silently go wide one
|
||||
// restart after its first client paired.
|
||||
pinnedBindHost: bindHost,
|
||||
...(options.port !== undefined
|
||||
? { wsPort: options.port, preferPinnedWsPort: true, requirePinnedWsPort: true }
|
||||
: {})
|
||||
...orcadWsPortOptions(options.port)
|
||||
})
|
||||
// Stops first: no RPC may write while the rest of the runtime is torn down.
|
||||
registerCleanup(() => rpc.stop())
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { ORCAD_MANAGED_ACTIVATION_ROOT_ENV } from '../../shared/orcad-managed-launch-env'
|
||||
import { orcadWsPortOptions } from './orcad-ws-port-policy'
|
||||
|
||||
describe('orcadWsPortOptions', () => {
|
||||
it('leaves the default port and its fallback alone without --port', () => {
|
||||
expect(orcadWsPortOptions(undefined, {})).toEqual({})
|
||||
})
|
||||
|
||||
it('requires an operator --port', () => {
|
||||
expect(orcadWsPortOptions(7001, {})).toEqual({
|
||||
wsPort: 7001,
|
||||
preferPinnedWsPort: true,
|
||||
requirePinnedWsPort: true
|
||||
})
|
||||
})
|
||||
|
||||
it('lets a managed launch fall back when its port is taken', () => {
|
||||
expect(
|
||||
orcadWsPortOptions(6768, { [ORCAD_MANAGED_ACTIVATION_ROOT_ENV]: '/home/u/.orca-remote' })
|
||||
).toEqual({ wsPort: 6768, preferPinnedWsPort: true })
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ORCAD_MANAGED_ACTIVATION_ROOT_ENV } from '../../shared/orcad-managed-launch-env'
|
||||
|
||||
export type OrcadWsPortOptions = {
|
||||
wsPort?: number
|
||||
preferPinnedWsPort?: boolean
|
||||
requirePinnedWsPort?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* An operator's `--port` must bind exactly that port. A managed launch passes the default port as
|
||||
* a preference and reads the bound port back from readiness: WSL2 distros share one VM loopback,
|
||||
* and an SSH host's 6768 may already be taken, so it must keep the fallback ladder.
|
||||
*/
|
||||
export function orcadWsPortOptions(
|
||||
port: number | undefined,
|
||||
env: NodeJS.ProcessEnv = process.env
|
||||
): OrcadWsPortOptions {
|
||||
if (port === undefined) {
|
||||
return {}
|
||||
}
|
||||
const managed = Boolean(env[ORCAD_MANAGED_ACTIVATION_ROOT_ENV])
|
||||
return {
|
||||
wsPort: port,
|
||||
preferPinnedWsPort: true,
|
||||
...(managed ? {} : { requirePinnedWsPort: true })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user