fix: upload long deploy scripts before remote launch

This commit is contained in:
Codex
2026-05-16 12:56:23 +00:00
parent da25f5d2d6
commit f092fba4ce
+46 -1
View File
@@ -55,6 +55,13 @@ interface BackgroundPoll {
raw: unknown;
}
interface RemoteScriptUpload {
ok: boolean;
path: string;
error: string;
raw: unknown[];
}
interface ServiceRuntimeState {
serviceId: string;
ok: boolean;
@@ -964,6 +971,37 @@ async function runTargetCommand(config: UniDeskConfig, service: UniDeskMicroserv
return await dispatchSsh(config, service.providerId, command, cwd, waitMs, remoteTimeoutMs);
}
function splitFixed(value: string, size: number): string[] {
const chunks: string[] = [];
for (let index = 0; index < value.length; index += size) chunks.push(value.slice(index, index + size));
return chunks;
}
async function uploadRemoteShellScript(
config: UniDeskConfig,
service: UniDeskMicroserviceConfig,
script: string,
cwd: string,
name: string,
): Promise<RemoteScriptUpload> {
const remotePath = `/tmp/unidesk-deploy-${safeId(service.id)}-${safeId(name)}-${Date.now().toString(36)}-${Math.random().toString(16).slice(2, 8)}.sh`;
const b64Path = `${remotePath}.b64`;
const raw: unknown[] = [];
const init = await runTargetCommand(config, service, `umask 077; rm -f ${shellQuote(remotePath)} ${shellQuote(b64Path)}; : > ${shellQuote(b64Path)}`, cwd, shortDispatchWaitMs, shortRemoteTimeoutMs);
raw.push(init.raw);
if (!init.ok) return { ok: false, path: remotePath, error: init.stderr || init.stdout || "failed to initialize remote script upload", raw };
const encoded = Buffer.from(script, "utf8").toString("base64");
for (const chunk of splitFixed(encoded, 2400)) {
const append = await runTargetCommand(config, service, `printf %s ${shellQuote(chunk)} >> ${shellQuote(b64Path)}`, cwd, shortDispatchWaitMs, shortRemoteTimeoutMs);
raw.push(append.raw);
if (!append.ok) return { ok: false, path: remotePath, error: append.stderr || append.stdout || "failed to append remote script chunk", raw };
}
const finalize = await runTargetCommand(config, service, `base64 -d ${shellQuote(b64Path)} > ${shellQuote(remotePath)}; chmod 700 ${shellQuote(remotePath)}; rm -f ${shellQuote(b64Path)}; wc -c ${shellQuote(remotePath)}`, cwd, shortDispatchWaitMs, shortRemoteTimeoutMs);
raw.push(finalize.raw);
if (!finalize.ok) return { ok: false, path: remotePath, error: finalize.stderr || finalize.stdout || "failed to finalize remote script upload", raw };
return { ok: true, path: remotePath, error: "", raw };
}
async function launchRemoteBackground(
config: UniDeskConfig,
service: UniDeskMicroserviceConfig,
@@ -1029,7 +1067,14 @@ async function step(
const runId = `${Date.now().toString(36)}-${Math.random().toString(16).slice(2, 8)}`;
const logFile = `/tmp/unidesk-deploy-${safeId(service.id)}-${name}-${runId}.log`;
const sentinelFile = `/tmp/unidesk-deploy-${safeId(service.id)}-${name}-${runId}.done`;
const launch = await launchRemoteBackground(config, service, command, cwd ?? "/home/ubuntu", logFile, sentinelFile);
let launchCommand = command;
if (launchCommand.length > 1800) {
const upload = await uploadRemoteShellScript(config, service, command, cwd ?? "/home/ubuntu", name);
if (!upload.ok) return { step: name, ok: false, detail: upload.error, startedAt, finishedAt: nowIso(), raw: upload.raw };
launchCommand = `bash ${shellQuote(upload.path)}`;
progressLine(name, "remote script uploaded", { serviceId: service.id, path: upload.path, bytes: command.length });
}
const launch = await launchRemoteBackground(config, service, launchCommand, cwd ?? "/home/ubuntu", logFile, sentinelFile);
if (!launch.ok) return { step: name, ok: false, detail: launch.error, startedAt, finishedAt: nowIso(), raw: launch.raw };
progressLine(name, "remote background started", { serviceId: service.id, pid: launch.pid, logFile });
const deadline = Date.now() + timeoutMs;