fix(sentinel): harden post-deploy report and ssh summaries
This commit is contained in:
@@ -130,6 +130,10 @@ export function runWebProbeRemoteArtifactJob(options: WebProbeRemoteArtifactJobO
|
||||
}
|
||||
}
|
||||
|
||||
const stop = pollFailure !== null && manifest === null
|
||||
? stopRemoteJob(options.route, remoteDir)
|
||||
: { payload: { attempted: false, reason: "not-needed", remoteDir, valuesRedacted: true }, result: null };
|
||||
if (stop.result !== null) commandResults.push(stop.result);
|
||||
const cleanup = cleanupRemoteDir(options.route, remoteDir, keepRemote);
|
||||
if (cleanup.result !== null) commandResults.push(cleanup.result);
|
||||
const manifestExitCode = manifest?.exitCode ?? null;
|
||||
@@ -164,6 +168,7 @@ export function runWebProbeRemoteArtifactJob(options: WebProbeRemoteArtifactJobO
|
||||
submitStdoutBytes: Buffer.byteLength(submit.stdout, "utf8"),
|
||||
submitStderrBytes: Buffer.byteLength(submit.stderr, "utf8"),
|
||||
},
|
||||
stop: stop.payload,
|
||||
valuesRedacted: true,
|
||||
};
|
||||
return {
|
||||
@@ -177,6 +182,25 @@ export function runWebProbeRemoteArtifactJob(options: WebProbeRemoteArtifactJobO
|
||||
};
|
||||
}
|
||||
|
||||
function stopRemoteJob(route: string, remoteDir: string): { payload: Record<string, unknown>; result: CommandResult | null } {
|
||||
const result = runCommand([transPath(), route, "sh", "--", remoteArtifactStopScript(remoteDir)], repoRoot, { timeoutMs: 30_000 });
|
||||
const parsed = parseTabStatus(result.stdout);
|
||||
return {
|
||||
payload: {
|
||||
attempted: true,
|
||||
ok: result.exitCode === 0,
|
||||
remoteDir,
|
||||
status: parsed.status ?? null,
|
||||
pid: parsed.pid ?? null,
|
||||
exitCode: result.exitCode,
|
||||
stdoutTail: result.stdout.slice(-1000),
|
||||
stderrTail: result.stderr.slice(-1000),
|
||||
valuesRedacted: true,
|
||||
},
|
||||
result,
|
||||
};
|
||||
}
|
||||
|
||||
function pollRemoteManifest(
|
||||
route: string,
|
||||
remoteDir: string,
|
||||
@@ -300,6 +324,27 @@ function remoteArtifactStatusScript(remoteDir: string): string {
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function remoteArtifactStopScript(remoteDir: string): string {
|
||||
return [
|
||||
"set +e",
|
||||
`remote_dir=${shellQuote(remoteDir)}`,
|
||||
'pid_file="$remote_dir/pid"',
|
||||
'if [ ! -f "$pid_file" ]; then printf "status\\tno-pid\\nremote_dir\\t%s\\n" "$remote_dir"; exit 0; fi',
|
||||
'pid="$(cat "$pid_file" 2>/dev/null | tr -cd "0-9")"',
|
||||
'if [ -z "$pid" ]; then printf "status\\tinvalid-pid\\nremote_dir\\t%s\\n" "$remote_dir"; exit 0; fi',
|
||||
'children_of() { command -v pgrep >/dev/null 2>&1 && pgrep -P "$1" 2>/dev/null || true; }',
|
||||
'term_tree() { _pid="$1"; for _child in $(children_of "$_pid"); do term_tree "$_child"; done; kill -TERM "$_pid" 2>/dev/null || true; }',
|
||||
'kill_tree() { _pid="$1"; for _child in $(children_of "$_pid"); do kill_tree "$_child"; done; kill -KILL "$_pid" 2>/dev/null || true; }',
|
||||
'if ! kill -0 "$pid" >/dev/null 2>&1; then printf "status\\tnot-running\\nremote_dir\\t%s\\npid\\t%s\\n" "$remote_dir" "$pid"; exit 0; fi',
|
||||
'term_tree "$pid"',
|
||||
"sleep 1",
|
||||
'if kill -0 "$pid" >/dev/null 2>&1; then kill_tree "$pid"; sleep 1; fi',
|
||||
'if kill -0 "$pid" >/dev/null 2>&1; then printf "status\\tstill-running\\nremote_dir\\t%s\\npid\\t%s\\n" "$remote_dir" "$pid"; exit 1; fi',
|
||||
'printf "status\\tstopped\\nremote_dir\\t%s\\npid\\t%s\\n" "$remote_dir" "$pid"',
|
||||
"exit 0",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function remoteArtifactRunnerScript(remoteDir: string, runId: string, stdoutTailBytes: number): string {
|
||||
return [
|
||||
"set -eu",
|
||||
@@ -434,6 +479,17 @@ function parseJsonObject(text: string): Record<string, unknown> {
|
||||
}
|
||||
}
|
||||
|
||||
function parseTabStatus(text: string): Record<string, string> {
|
||||
const out: Record<string, string> = {};
|
||||
for (const rawLine of text.split(/\r?\n/u)) {
|
||||
const line = rawLine.trimEnd();
|
||||
if (line.length === 0) continue;
|
||||
const [key, ...rest] = line.split("\t");
|
||||
if (key) out[key] = rest.join("\t");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function numberOrNull(value: unknown): number | null {
|
||||
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user