mirror of
https://github.com/stablyai/orca.git
synced 2026-11-04 11:07:42 +00:00
perf(wsl): fold the first libc probe into the WSL host facts exec (#35324)
* perf(wsl): fold the first libc probe into the WSL host facts exec The WSL connect's facts exec now also runs the libc probe's first command after its own marker. resolveOrcadRemoteContext takes it (with the login home) as a known fact, answering that one probe; the fallbacks still run over the transport if it proves nothing. One fewer serial guest round trip per connect; SSH passes no known facts, so its probes are unchanged. * fix(wsl): run the libc fallbacks through the default exec With a folded first answer, the remaining libc probes used the fenced orcad runner; they now use the same plain execCommand the default probe does, so they match main exactly.
This commit is contained in:
@@ -3,6 +3,8 @@ import type { SshTarget } from '../../../shared/ssh-types'
|
||||
import type { OrcadActivationRecord } from '../activation/orcad-activation-record'
|
||||
import { readOrcadActivationRecord } from '../activation/orcad-activation-record-store'
|
||||
import { resolveOrcadRuntimeTarget } from '../lifecycle/orcad-runtime-target'
|
||||
import { LINUX_LIBC_FIRST_PROBE } from '../../node-runtime/linux-libc-probe'
|
||||
import { execCommand } from '../../ssh/remote-exec/remote-exec-command'
|
||||
import { prepareWindowsOrcadHost } from '../host-state/orcad-windows-host-preparation'
|
||||
import {
|
||||
isWslOrcadHostTarget,
|
||||
@@ -53,8 +55,11 @@ export async function resolveOrcadRemoteContext<Target extends OrcadHostTarget =
|
||||
connection: OrcadHostTransport,
|
||||
signal?: AbortSignal,
|
||||
detectedHost?: RemoteHostPlatform,
|
||||
/** A login home the caller already read on this host; only login-home placement uses it. */
|
||||
knownLoginHome?: string
|
||||
/**
|
||||
* Facts the caller already read on this host. `loginHome` serves only login-home placement;
|
||||
* `firstLibcProbeOutput` answers the libc probe's first command, whose fallbacks still run.
|
||||
*/
|
||||
known: { loginHome?: string; firstLibcProbeOutput?: string } = {}
|
||||
): Promise<OrcadRemoteContext<Target>> {
|
||||
const host = detectedHost ?? (await detectRemoteHostPlatform(connection, { signal }))
|
||||
if (!host) {
|
||||
@@ -68,12 +73,26 @@ export async function resolveOrcadRemoteContext<Target extends OrcadHostTarget =
|
||||
const { orcadHome: remoteHome, userDataDir } = await resolveOrcadMachineHome(
|
||||
remote,
|
||||
!isWslOrcadHostTarget(target),
|
||||
knownLoginHome
|
||||
known.loginHome
|
||||
)
|
||||
let firstLibcProbeOutput = known.firstLibcProbeOutput
|
||||
const serverTarget = await resolveOrcadRuntimeTarget({
|
||||
conn: connection,
|
||||
host,
|
||||
signal
|
||||
signal,
|
||||
...(firstLibcProbeOutput === undefined
|
||||
? {}
|
||||
: {
|
||||
exec: async (command: string) => {
|
||||
if (command === LINUX_LIBC_FIRST_PROBE && firstLibcProbeOutput !== undefined) {
|
||||
const output = firstLibcProbeOutput
|
||||
firstLibcProbeOutput = undefined
|
||||
return output
|
||||
}
|
||||
// The fallbacks run exactly as the default exec would.
|
||||
return execCommand(connection, command, { signal })
|
||||
}
|
||||
})
|
||||
})
|
||||
if (!isWslOrcadHostTarget(target)) {
|
||||
rememberSshHostPlatform(target.id, host, serverTarget)
|
||||
|
||||
@@ -292,10 +292,40 @@ describe('orcad remote context', () => {
|
||||
})
|
||||
const wslTarget = { kind: 'wsl', id: 'wsl:u', distro: 'U', label: 'U' } as const
|
||||
|
||||
const context = await resolveOrcadRemoteContext(wslTarget, conn, undefined, linux, '/home/u\n')
|
||||
const context = await resolveOrcadRemoteContext(wslTarget, conn, undefined, linux, {
|
||||
loginHome: '/home/u\n',
|
||||
firstLibcProbeOutput: 'ldd (Ubuntu GLIBC 2.39-0ubuntu8) 2.39\n'
|
||||
})
|
||||
|
||||
expect(context).toMatchObject({ remoteHome: '/home/u', userDataDir: '/home/u/.orca' })
|
||||
expect(context).toMatchObject({
|
||||
remoteHome: '/home/u',
|
||||
userDataDir: '/home/u/.orca',
|
||||
serverTarget: 'linux-x64-glibc'
|
||||
})
|
||||
expect(detectRemoteHostPlatform).not.toHaveBeenCalled()
|
||||
expect(commands.some((command) => command.includes('$HOME'))).toBe(false)
|
||||
expect(commands.some((command) => command.includes('ldd'))).toBe(false)
|
||||
})
|
||||
|
||||
it('runs the libc fallbacks when the folded first probe proves nothing', async () => {
|
||||
vi.mocked(detectRemoteHostPlatform).mockClear()
|
||||
const commands: string[] = []
|
||||
mockExec.mockImplementation(async (_conn, command: string) => {
|
||||
commands.push(command)
|
||||
return command.includes('getconf') ? 'glibc 2.39\n' : '__ORCAD_RECORD_ABSENT__\n'
|
||||
})
|
||||
const wslTarget = { kind: 'wsl', id: 'wsl:u', distro: 'U', label: 'U' } as const
|
||||
|
||||
const context = await resolveOrcadRemoteContext(wslTarget, conn, undefined, linux, {
|
||||
loginHome: '/home/u',
|
||||
firstLibcProbeOutput: 'sh: ldd: not found\n'
|
||||
})
|
||||
|
||||
expect(context.serverTarget).toBe('linux-x64-glibc')
|
||||
// The same plain exec the default probe uses, not the fenced orcad runner.
|
||||
expect(mockExec).toHaveBeenCalledWith(conn, expect.stringContaining('getconf'), {
|
||||
signal: undefined
|
||||
})
|
||||
expect(commands.some((command) => command.includes('ldd --version'))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -35,8 +35,11 @@ export function parseGlibcVersion(output: string): GlibcVersion | null {
|
||||
return match ? { major: Number(match[1]), minor: Number(match[2]) } : null
|
||||
}
|
||||
|
||||
/** The first probe, which answers on nearly every glibc or musl host; callers may run it early. */
|
||||
export const LINUX_LIBC_FIRST_PROBE = 'LC_ALL=C ldd --version 2>&1 || true'
|
||||
|
||||
const PROBES = [
|
||||
'LC_ALL=C ldd --version 2>&1 || true',
|
||||
LINUX_LIBC_FIRST_PROBE,
|
||||
'LC_ALL=C getconf GNU_LIBC_VERSION 2>/dev/null || true',
|
||||
// Appliances may omit both tools; newer GNU loaders can report their own version.
|
||||
'for loader in /lib/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2 /lib/ld-linux-aarch64.so.1; do ' +
|
||||
|
||||
@@ -110,7 +110,7 @@ function launch(kernel = '5.15.167.4-microsoft-standard-WSL2', options = {}) {
|
||||
mocks.exec.mockImplementation(async (_conn: unknown, command: string) => {
|
||||
if (command.includes('uname -r')) {
|
||||
mocks.steps.push('uname')
|
||||
return `__ORCA_WSL_KERNEL__ ${kernel}\n__ORCA_WSL_HOME__ /home/u\n\n__ORCA_REMOTE_PLATFORM__ Linux x86_64\n`
|
||||
return `__ORCA_WSL_KERNEL__ ${kernel}\n__ORCA_WSL_HOME__ /home/u\n\n__ORCA_REMOTE_PLATFORM__ Linux x86_64\n\n__ORCA_WSL_LIBC__\nldd (GNU libc) 2.39\n`
|
||||
}
|
||||
return '4242\n'
|
||||
})
|
||||
|
||||
@@ -86,8 +86,8 @@ function holderRejectingOn(gate: Promise<void>): WslDistroHolder {
|
||||
}
|
||||
|
||||
/** What WSL_HOST_FACTS_COMMAND prints. */
|
||||
function facts(kernel: string, home: string, uname: string): string {
|
||||
return `__ORCA_WSL_KERNEL__ ${kernel}\n__ORCA_WSL_HOME__ ${home}\n\n__ORCA_REMOTE_PLATFORM__ ${uname}\n`
|
||||
function facts(kernel: string, home: string, uname: string, libc = 'ldd (GNU libc) 2.39'): string {
|
||||
return `__ORCA_WSL_KERNEL__ ${kernel}\n__ORCA_WSL_HOME__ ${home}\n\n__ORCA_REMOTE_PLATFORM__ ${uname}\n\n__ORCA_WSL_LIBC__\n${libc}\n`
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -192,14 +192,14 @@ describe('the folded host facts probe', () => {
|
||||
expect(mocks.spawned.filter((label) => label === 'host-facts')).toHaveLength(1)
|
||||
expect(mocks.contextArgs).toEqual([
|
||||
expect.objectContaining({ os: 'linux', arch: 'x64' }),
|
||||
'/home/u'
|
||||
{ loginHome: '/home/u', firstLibcProbeOutput: 'ldd (GNU libc) 2.39\n' }
|
||||
])
|
||||
})
|
||||
|
||||
it('leaves the context to probe what the facts did not prove', async () => {
|
||||
await resolveWith(facts('5.15.167.4-microsoft-standard-WSL2', '', 'Linux sparc'))
|
||||
|
||||
expect(mocks.contextArgs).toEqual([undefined, undefined])
|
||||
expect(mocks.contextArgs).toEqual([undefined, { loginHome: undefined }])
|
||||
expect(mocks.spawned[0]).toBe('host-facts')
|
||||
expect(mocks.spawned).not.toContain('uname -r')
|
||||
})
|
||||
@@ -207,7 +207,7 @@ describe('the folded host facts probe', () => {
|
||||
it('falls back to the separate probes for a HOME with a newline, never a truncated path', async () => {
|
||||
await resolveWith(facts('5.15.167.4-microsoft-standard-WSL2', '/home/a\nb', 'Linux x86_64'))
|
||||
|
||||
expect(mocks.contextArgs).toEqual([undefined, undefined])
|
||||
expect(mocks.contextArgs).toEqual([undefined, { loginHome: undefined }])
|
||||
expect(mocks.spawned.slice(0, 2)).toEqual(['host-facts', 'uname -r'])
|
||||
})
|
||||
|
||||
@@ -216,10 +216,22 @@ describe('the folded host facts probe', () => {
|
||||
`Welcome to Ubuntu\n${facts('5.15.167.4-microsoft-standard-WSL2', '/home/u', 'Linux x86_64')}`
|
||||
)
|
||||
|
||||
expect(mocks.contextArgs).toEqual([undefined, undefined])
|
||||
expect(mocks.contextArgs).toEqual([undefined, { loginHome: undefined }])
|
||||
expect(mocks.spawned.slice(0, 2)).toEqual(['host-facts', 'uname -r'])
|
||||
})
|
||||
|
||||
it('keeps a multi-line libc answer whole, and rejects output missing the libc section', () => {
|
||||
const musl = 'musl libc (x86_64)\nVersion 1.2.4\nDynamic Program Loader'
|
||||
expect(
|
||||
readWslHostFacts(facts('5.15.167.4-microsoft-standard-WSL2', '/home/u', 'Linux x86_64', musl))
|
||||
).toMatchObject({ firstLibcProbeOutput: `${musl}\n` })
|
||||
expect(
|
||||
readWslHostFacts(
|
||||
'__ORCA_WSL_KERNEL__ 5.15\n__ORCA_WSL_HOME__ /home/u\n\n__ORCA_REMOTE_PLATFORM__ Linux x86_64\n'
|
||||
)
|
||||
).toBeNull()
|
||||
})
|
||||
|
||||
it('refuses WSL 1 from the kernel line before holding or probing', async () => {
|
||||
mocks.facts = facts('4.4.0-19041-Microsoft', '/home/u', 'Linux x86_64')
|
||||
const holder = heldNow()
|
||||
|
||||
@@ -7,15 +7,23 @@ import {
|
||||
UNAME_PLATFORM_PROBE_MARKER
|
||||
} from '../ssh/ssh-remote-platform-detection'
|
||||
import type { RemoteHostPlatform } from '../ssh/ssh-remote-platform'
|
||||
import { LINUX_LIBC_FIRST_PROBE } from '../node-runtime/linux-libc-probe'
|
||||
import type { WslDistroHolder } from './wsl-distro-holder'
|
||||
import { refuseMissingWslDistro, WslDistroVersion1Error } from './wsl-distro-unsupported'
|
||||
import type { WslOrcadHostTarget } from './wsl-orcad-host-target'
|
||||
|
||||
const KERNEL_MARKER = '__ORCA_WSL_KERNEL__ '
|
||||
const HOME_MARKER = '__ORCA_WSL_HOME__ '
|
||||
export const WSL_HOST_FACTS_COMMAND = `printf '${KERNEL_MARKER}%s\\n${HOME_MARKER}%s\\n' "$(uname -r)" "$HOME"; ${UNAME_PLATFORM_PROBE_COMMAND}`
|
||||
const LIBC_MARKER = '__ORCA_WSL_LIBC__'
|
||||
// The libc probe goes last: its output may span lines, so it takes everything after its marker.
|
||||
export const WSL_HOST_FACTS_COMMAND = `printf '${KERNEL_MARKER}%s\\n${HOME_MARKER}%s\\n' "$(uname -r)" "$HOME"; ${UNAME_PLATFORM_PROBE_COMMAND}; printf '\\n%s\\n' '${LIBC_MARKER}'; ${LINUX_LIBC_FIRST_PROBE}`
|
||||
|
||||
type WslHostFacts = { kernel: string; loginHome?: string; platform?: RemoteHostPlatform }
|
||||
type WslHostFacts = {
|
||||
kernel: string
|
||||
loginHome?: string
|
||||
platform?: RemoteHostPlatform
|
||||
firstLibcProbeOutput?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts only the exact shape the facts command prints; anything else (startup noise, a HOME
|
||||
@@ -23,13 +31,15 @@ type WslHostFacts = { kernel: string; loginHome?: string; platform?: RemoteHostP
|
||||
*/
|
||||
export function readWslHostFacts(output: string): WslHostFacts | null {
|
||||
const lines = output.split('\n')
|
||||
const [kernelLine = '', homeLine = '', gap, platformLine = '', ...rest] = lines
|
||||
const [kernelLine = '', homeLine = '', gap, platformLine = '', libcGap, libcMarker, ...libc] =
|
||||
lines
|
||||
if (
|
||||
!kernelLine.startsWith(KERNEL_MARKER) ||
|
||||
!homeLine.startsWith(HOME_MARKER) ||
|
||||
gap !== '' ||
|
||||
!platformLine.startsWith(UNAME_PLATFORM_PROBE_MARKER) ||
|
||||
rest.some((line) => line.trim() !== '')
|
||||
libcGap !== '' ||
|
||||
libcMarker !== LIBC_MARKER
|
||||
) {
|
||||
return null
|
||||
}
|
||||
@@ -37,7 +47,8 @@ export function readWslHostFacts(output: string): WslHostFacts | null {
|
||||
return {
|
||||
kernel: kernelLine.slice(KERNEL_MARKER.length).trim(),
|
||||
...(loginHome.trim() ? { loginHome } : {}),
|
||||
...withPlatform(remoteHostPlatformFromUnameProbe(`\n${platformLine}`))
|
||||
...withPlatform(remoteHostPlatformFromUnameProbe(`\n${platformLine}`)),
|
||||
firstLibcProbeOutput: libc.join('\n')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +96,11 @@ export async function holdWslDistroWithContext(
|
||||
probes.abort(error)
|
||||
throw error
|
||||
}),
|
||||
resolveOrcadRemoteContext(target, conn, probes.signal, facts.platform, facts.loginHome)
|
||||
resolveOrcadRemoteContext(target, conn, probes.signal, facts.platform, {
|
||||
loginHome: facts.loginHome,
|
||||
// Only with a proven platform: the libc answer belongs to the same host shape.
|
||||
...(facts.platform ? { firstLibcProbeOutput: facts.firstLibcProbeOutput } : {})
|
||||
})
|
||||
])
|
||||
return { held, context }
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user