@action-llama/action-llama 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +1 -1
- package/dist/cloud/gcp/artifact-registry-api.d.ts +26 -0
- package/dist/cloud/gcp/artifact-registry-api.d.ts.map +1 -0
- package/dist/cloud/gcp/artifact-registry-api.js +64 -0
- package/dist/cloud/gcp/artifact-registry-api.js.map +1 -0
- package/dist/cloud/gcp/auth.d.ts +25 -0
- package/dist/cloud/gcp/auth.d.ts.map +1 -0
- package/dist/cloud/gcp/auth.js +73 -0
- package/dist/cloud/gcp/auth.js.map +1 -0
- package/dist/cloud/gcp/cloud-run-api.d.ts +96 -0
- package/dist/cloud/gcp/cloud-run-api.d.ts.map +1 -0
- package/dist/cloud/gcp/cloud-run-api.js +86 -0
- package/dist/cloud/gcp/cloud-run-api.js.map +1 -0
- package/dist/cloud/gcp/logging-api.d.ts +31 -0
- package/dist/cloud/gcp/logging-api.d.ts.map +1 -0
- package/dist/cloud/gcp/logging-api.js +44 -0
- package/dist/cloud/gcp/logging-api.js.map +1 -0
- package/dist/cloud/gcp/secret-manager-api.d.ts +10 -0
- package/dist/cloud/gcp/secret-manager-api.d.ts.map +1 -0
- package/dist/cloud/gcp/secret-manager-api.js +33 -0
- package/dist/cloud/gcp/secret-manager-api.js.map +1 -0
- package/dist/control/routes/stats.d.ts.map +1 -1
- package/dist/control/routes/stats.js +3 -2
- package/dist/control/routes/stats.js.map +1 -1
- package/dist/credentials/builtins/gcp-service-account.d.ts +4 -0
- package/dist/credentials/builtins/gcp-service-account.d.ts.map +1 -0
- package/dist/credentials/builtins/gcp-service-account.js +38 -0
- package/dist/credentials/builtins/gcp-service-account.js.map +1 -0
- package/dist/credentials/builtins/index.d.ts.map +1 -1
- package/dist/credentials/builtins/index.js +2 -0
- package/dist/credentials/builtins/index.js.map +1 -1
- package/dist/docker/cloud-run-runtime.d.ts +48 -0
- package/dist/docker/cloud-run-runtime.d.ts.map +1 -0
- package/dist/docker/cloud-run-runtime.js +490 -0
- package/dist/docker/cloud-run-runtime.js.map +1 -0
- package/dist/docker/host-user-runtime.d.ts.map +1 -1
- package/dist/docker/host-user-runtime.js +22 -14
- package/dist/docker/host-user-runtime.js.map +1 -1
- package/dist/docker/providers/index.d.ts +4 -0
- package/dist/docker/providers/index.d.ts.map +1 -1
- package/dist/docker/providers/index.js +38 -0
- package/dist/docker/providers/index.js.map +1 -1
- package/dist/docker/runtime.d.ts +7 -0
- package/dist/docker/runtime.d.ts.map +1 -1
- package/dist/docker/runtime.js.map +1 -1
- package/dist/frontend/assets/index-DONRFLlC.css +2 -0
- package/dist/frontend/assets/{index-Dp0WUSmO.js → index-DlsFK6yT.js} +3 -3
- package/dist/frontend/index.html +2 -2
- package/dist/gateway/frontend.d.ts.map +1 -1
- package/dist/gateway/frontend.js +1 -0
- package/dist/gateway/frontend.js.map +1 -1
- package/dist/shared/config/types.d.ts +12 -1
- package/dist/shared/config/types.d.ts.map +1 -1
- package/docker/bin/al-subagent +1 -2
- package/docker/bin/al-subagent-wait +1 -1
- package/package.json +1 -1
- package/dist/frontend/assets/index-CtDub1yn.css +0 -2
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Cloud Run Jobs runtime.
|
|
3
|
+
* Implements Runtime and ContainerRuntime by launching agents as Cloud Run Jobs.
|
|
4
|
+
*/
|
|
5
|
+
import { randomUUID } from "crypto";
|
|
6
|
+
import { spawn } from "child_process";
|
|
7
|
+
import { createJob, deleteJob, runJob, listJobs, listExecutions, pollExecutionUntilDone, } from "../cloud/gcp/cloud-run-api.js";
|
|
8
|
+
import { createSecret, addSecretVersion, deleteSecret, } from "../cloud/gcp/secret-manager-api.js";
|
|
9
|
+
import { listLogEntries, buildJobLogFilter, extractLogText, } from "../cloud/gcp/logging-api.js";
|
|
10
|
+
import { cleanupOldImages } from "../cloud/gcp/artifact-registry-api.js";
|
|
11
|
+
import { parseCredentialRef, getDefaultBackend } from "../shared/credentials.js";
|
|
12
|
+
import { CONSTANTS, VERSION, GIT_SHA } from "../shared/constants.js";
|
|
13
|
+
import { readFileSync, mkdtempSync, mkdirSync, writeFileSync, rmSync, } from "fs";
|
|
14
|
+
import { join, resolve, isAbsolute, dirname } from "path";
|
|
15
|
+
import { tmpdir } from "os";
|
|
16
|
+
import { parseBuildKitLine } from "./local-runtime.js";
|
|
17
|
+
/** Convert a memory string like "4g"/"4G"/"4096m" to Cloud Run "4Gi" format */
|
|
18
|
+
function parseMemoryForCloudRun(memory) {
|
|
19
|
+
if (!memory)
|
|
20
|
+
return "2Gi";
|
|
21
|
+
const lower = memory.toLowerCase();
|
|
22
|
+
const gbMatch = lower.match(/^(\d+(?:\.\d+)?)g(?:i?)$/);
|
|
23
|
+
if (gbMatch)
|
|
24
|
+
return `${gbMatch[1]}Gi`;
|
|
25
|
+
const mbMatch = lower.match(/^(\d+)m(?:i?)$/);
|
|
26
|
+
if (mbMatch)
|
|
27
|
+
return `${Math.ceil(parseInt(mbMatch[1]) / 1024)}Gi`;
|
|
28
|
+
return memory;
|
|
29
|
+
}
|
|
30
|
+
export class CloudRunRuntime {
|
|
31
|
+
needsGateway = true;
|
|
32
|
+
config;
|
|
33
|
+
/** Map from jobId -> executionName (to support waitForExit) */
|
|
34
|
+
executionNames = new Map();
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.config = config;
|
|
37
|
+
}
|
|
38
|
+
get auth() { return this.config.auth; }
|
|
39
|
+
get project() { return this.config.project; }
|
|
40
|
+
get region() { return this.config.region; }
|
|
41
|
+
get artifactRegistry() { return this.config.artifactRegistry; }
|
|
42
|
+
// ── Credential management ────────────────────────────────────────────────
|
|
43
|
+
async prepareCredentials(credRefs) {
|
|
44
|
+
const backend = getDefaultBackend();
|
|
45
|
+
const bundle = {};
|
|
46
|
+
const secretRefs = [];
|
|
47
|
+
const runId = randomUUID().replace(/-/g, "").slice(0, 12);
|
|
48
|
+
for (const credRef of credRefs) {
|
|
49
|
+
const { type, instance } = parseCredentialRef(credRef);
|
|
50
|
+
const fields = await backend.readAll(type, instance);
|
|
51
|
+
if (!fields)
|
|
52
|
+
continue;
|
|
53
|
+
if (!bundle[type])
|
|
54
|
+
bundle[type] = {};
|
|
55
|
+
bundle[type][instance] = {};
|
|
56
|
+
for (const [field, value] of Object.entries(fields)) {
|
|
57
|
+
bundle[type][instance][field] = value;
|
|
58
|
+
// Create a unique secret ID for this field
|
|
59
|
+
const secretId = `al-cred-${runId}-${type}-${instance}-${field}`
|
|
60
|
+
.toLowerCase()
|
|
61
|
+
.replace(/[^a-z0-9-]/g, "-")
|
|
62
|
+
.slice(0, 255);
|
|
63
|
+
const mountPath = `/credentials/${type}/${instance}/${field}`;
|
|
64
|
+
try {
|
|
65
|
+
await createSecret(this.auth, this.project, secretId);
|
|
66
|
+
await addSecretVersion(this.auth, this.project, secretId, value);
|
|
67
|
+
secretRefs.push({ secretName: secretId, mountPath });
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
// Log and skip — don't fail the whole launch
|
|
71
|
+
console.error(`Failed to create Secret Manager secret for ${credRef}.${field}: ${err.message}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { strategy: "secret-manager", secretRefs, bundle };
|
|
76
|
+
}
|
|
77
|
+
cleanupCredentials(creds) {
|
|
78
|
+
if (creds.strategy !== "secret-manager")
|
|
79
|
+
return;
|
|
80
|
+
for (const { secretName } of creds.secretRefs) {
|
|
81
|
+
deleteSecret(this.auth, this.project, secretName).catch(() => {
|
|
82
|
+
// Best effort
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ── Image build & push ───────────────────────────────────────────────────
|
|
87
|
+
async buildImage(opts) {
|
|
88
|
+
opts.onProgress?.("Building image locally");
|
|
89
|
+
let content;
|
|
90
|
+
if (opts.dockerfileContent) {
|
|
91
|
+
content = opts.dockerfileContent;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const src = isAbsolute(opts.dockerfile)
|
|
95
|
+
? opts.dockerfile
|
|
96
|
+
: resolve(opts.contextDir, opts.dockerfile);
|
|
97
|
+
content = readFileSync(src, "utf-8");
|
|
98
|
+
}
|
|
99
|
+
if (opts.baseImage) {
|
|
100
|
+
content = content.replace(/^FROM\s+\S+/m, `FROM ${opts.baseImage}`);
|
|
101
|
+
}
|
|
102
|
+
const hasExtraFiles = opts.extraFiles && Object.keys(opts.extraFiles).length > 0;
|
|
103
|
+
if (hasExtraFiles && !content.includes("COPY static/ /app/static/")) {
|
|
104
|
+
const copyLine = "COPY static/ /app/static/";
|
|
105
|
+
const userIdx = content.indexOf("\nUSER ");
|
|
106
|
+
if (userIdx !== -1) {
|
|
107
|
+
content = content.slice(0, userIdx) + "\n" + copyLine + content.slice(userIdx);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
content += "\n" + copyLine + "\n";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const needsTempCtx = !!opts.dockerfileContent || hasExtraFiles || !!opts.baseImage;
|
|
114
|
+
const buildDir = needsTempCtx ? mkdtempSync(join(tmpdir(), "al-ctx-")) : undefined;
|
|
115
|
+
try {
|
|
116
|
+
let dockerfilePath;
|
|
117
|
+
let contextPath;
|
|
118
|
+
if (buildDir) {
|
|
119
|
+
writeFileSync(join(buildDir, "Dockerfile"), content);
|
|
120
|
+
dockerfilePath = join(buildDir, "Dockerfile");
|
|
121
|
+
contextPath = buildDir;
|
|
122
|
+
if (hasExtraFiles) {
|
|
123
|
+
const staticDir = join(buildDir, "static");
|
|
124
|
+
mkdirSync(staticDir, { recursive: true });
|
|
125
|
+
for (const [filename, fileContent] of Object.entries(opts.extraFiles)) {
|
|
126
|
+
const filePath = join(staticDir, filename);
|
|
127
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
128
|
+
writeFileSync(filePath, fileContent);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
dockerfilePath = isAbsolute(opts.dockerfile)
|
|
134
|
+
? opts.dockerfile
|
|
135
|
+
: resolve(opts.contextDir, opts.dockerfile);
|
|
136
|
+
contextPath = opts.contextDir;
|
|
137
|
+
}
|
|
138
|
+
await new Promise((res, rej) => {
|
|
139
|
+
const proc = spawn("docker", [
|
|
140
|
+
"build",
|
|
141
|
+
"-t", opts.tag,
|
|
142
|
+
"--build-arg", `GIT_SHA=${GIT_SHA}`,
|
|
143
|
+
"--build-arg", `VERSION=${VERSION}`,
|
|
144
|
+
"-f", dockerfilePath,
|
|
145
|
+
contextPath,
|
|
146
|
+
], {
|
|
147
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
148
|
+
env: { ...process.env, DOCKER_BUILDKIT: "1" },
|
|
149
|
+
});
|
|
150
|
+
let stderrBuf = "";
|
|
151
|
+
let stderrAll = "";
|
|
152
|
+
proc.stderr.on("data", (chunk) => {
|
|
153
|
+
const text = chunk.toString();
|
|
154
|
+
stderrAll += text;
|
|
155
|
+
stderrBuf += text;
|
|
156
|
+
const lines = stderrBuf.split("\n");
|
|
157
|
+
stderrBuf = lines.pop() || "";
|
|
158
|
+
for (const line of lines) {
|
|
159
|
+
const msg = parseBuildKitLine(line);
|
|
160
|
+
if (msg !== undefined)
|
|
161
|
+
opts.onProgress?.(msg);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
const timer = setTimeout(() => {
|
|
165
|
+
proc.kill();
|
|
166
|
+
rej(new Error("Docker build timed out after 300s"));
|
|
167
|
+
}, 300_000);
|
|
168
|
+
proc.on("close", (code) => {
|
|
169
|
+
clearTimeout(timer);
|
|
170
|
+
if (code === 0)
|
|
171
|
+
res();
|
|
172
|
+
else
|
|
173
|
+
rej(new Error(`Docker build failed (exit ${code}):\n${stderrAll}`));
|
|
174
|
+
});
|
|
175
|
+
proc.on("error", (err) => { clearTimeout(timer); rej(err); });
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
if (buildDir) {
|
|
180
|
+
try {
|
|
181
|
+
rmSync(buildDir, { recursive: true });
|
|
182
|
+
}
|
|
183
|
+
catch { }
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (opts.additionalTags) {
|
|
187
|
+
for (const alias of opts.additionalTags) {
|
|
188
|
+
await this._dockerExec(["tag", opts.tag, alias]);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return opts.tag;
|
|
192
|
+
}
|
|
193
|
+
async pushImage(localImage) {
|
|
194
|
+
const registry = `${this.region}-docker.pkg.dev`;
|
|
195
|
+
const registryUri = `${registry}/${this.project}/${this.artifactRegistry}/${localImage}`;
|
|
196
|
+
// Authenticate docker with Artifact Registry
|
|
197
|
+
const token = await this.auth.getAccessToken();
|
|
198
|
+
await this._dockerExec(["login", registry, "-u", "oauth2accesstoken", "-p", token]);
|
|
199
|
+
// Tag and push
|
|
200
|
+
await this._dockerExec(["tag", localImage, registryUri]);
|
|
201
|
+
await this._dockerExec(["push", registryUri]);
|
|
202
|
+
// Cleanup old images (keep 3 most recent)
|
|
203
|
+
try {
|
|
204
|
+
await cleanupOldImages(this.auth, this.project, this.region, this.artifactRegistry, localImage, 3);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Best effort
|
|
208
|
+
}
|
|
209
|
+
return registryUri;
|
|
210
|
+
}
|
|
211
|
+
_dockerExec(args) {
|
|
212
|
+
return new Promise((resolve, reject) => {
|
|
213
|
+
const proc = spawn("docker", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
214
|
+
let stderr = "";
|
|
215
|
+
proc.stderr.on("data", (chunk) => { stderr += chunk.toString(); });
|
|
216
|
+
proc.on("close", (code) => {
|
|
217
|
+
if (code === 0)
|
|
218
|
+
resolve();
|
|
219
|
+
else
|
|
220
|
+
reject(new Error(`docker ${args[0]} failed (exit ${code}): ${stderr}`));
|
|
221
|
+
});
|
|
222
|
+
proc.on("error", reject);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
// ── Launch & lifecycle ───────────────────────────────────────────────────
|
|
226
|
+
async launch(opts) {
|
|
227
|
+
const runId = randomUUID().slice(0, 8);
|
|
228
|
+
const jobId = CONSTANTS.containerName(opts.agentName, runId);
|
|
229
|
+
const envVars = Object.entries(opts.env).map(([name, value]) => ({ name, value }));
|
|
230
|
+
const memory = parseMemoryForCloudRun(opts.memory);
|
|
231
|
+
const cpus = opts.cpus ? String(opts.cpus) : "1";
|
|
232
|
+
// Build volumes and mounts from secret refs
|
|
233
|
+
const volumes = [];
|
|
234
|
+
const volumeMounts = [];
|
|
235
|
+
if (opts.credentials.strategy === "secret-manager") {
|
|
236
|
+
for (const { secretName, mountPath } of opts.credentials.secretRefs) {
|
|
237
|
+
const volName = secretName.replace(/[^a-zA-Z0-9-]/g, "-").slice(0, 63);
|
|
238
|
+
volumes.push({
|
|
239
|
+
name: volName,
|
|
240
|
+
secret: {
|
|
241
|
+
secret: `projects/${this.project}/secrets/${secretName}`,
|
|
242
|
+
items: [{ version: "latest", path: "value" }],
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
// Mount the secret as a file at the mountPath
|
|
246
|
+
// Cloud Run secrets mount the directory, with the file at the path key
|
|
247
|
+
const mountDir = mountPath.split("/").slice(0, -1).join("/");
|
|
248
|
+
const fileName = mountPath.split("/").pop();
|
|
249
|
+
volumeMounts.push({ name: volName, mountPath: mountDir });
|
|
250
|
+
// Re-construct items to have the file at the right path
|
|
251
|
+
volumes[volumes.length - 1].secret.items = [{ version: "latest", path: fileName }];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const container = {
|
|
255
|
+
image: opts.image,
|
|
256
|
+
env: envVars,
|
|
257
|
+
volumeMounts,
|
|
258
|
+
resources: { limits: { memory, cpu: cpus } },
|
|
259
|
+
};
|
|
260
|
+
const template = {
|
|
261
|
+
template: {
|
|
262
|
+
containers: [container],
|
|
263
|
+
volumes,
|
|
264
|
+
maxRetries: 0,
|
|
265
|
+
timeout: "3600s",
|
|
266
|
+
serviceAccount: this.config.serviceAccount,
|
|
267
|
+
},
|
|
268
|
+
labels: {
|
|
269
|
+
"started-by": "action-llama",
|
|
270
|
+
"agent-name": opts.agentName,
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
await createJob(this.auth, this.project, this.region, jobId, template);
|
|
274
|
+
const execOp = await runJob(this.auth, this.project, this.region, jobId);
|
|
275
|
+
// Extract execution name from the operation response
|
|
276
|
+
const executionName = execOp?.response?.name ?? execOp?.name ?? "";
|
|
277
|
+
if (executionName) {
|
|
278
|
+
this.executionNames.set(jobId, executionName);
|
|
279
|
+
}
|
|
280
|
+
return jobId;
|
|
281
|
+
}
|
|
282
|
+
async isAgentRunning(agentName) {
|
|
283
|
+
try {
|
|
284
|
+
const jobs = await listJobs(this.auth, this.project, this.region);
|
|
285
|
+
const prefix = `al-${agentName}-`;
|
|
286
|
+
const agentJobs = jobs.filter((j) => {
|
|
287
|
+
const shortName = j.name.split("/").pop() ?? "";
|
|
288
|
+
return shortName.startsWith(prefix);
|
|
289
|
+
});
|
|
290
|
+
if (agentJobs.length === 0)
|
|
291
|
+
return false;
|
|
292
|
+
for (const job of agentJobs) {
|
|
293
|
+
const jobId = job.name.split("/").pop();
|
|
294
|
+
const execs = await listExecutions(this.auth, this.project, this.region, jobId);
|
|
295
|
+
const running = execs.some((e) => !e.completionTime);
|
|
296
|
+
if (running)
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
async listRunningAgents() {
|
|
306
|
+
try {
|
|
307
|
+
const jobs = await listJobs(this.auth, this.project, this.region);
|
|
308
|
+
const agents = [];
|
|
309
|
+
for (const job of jobs) {
|
|
310
|
+
const jobId = job.name.split("/").pop();
|
|
311
|
+
if (!jobId.startsWith(CONSTANTS.CONTAINER_FILTER))
|
|
312
|
+
continue;
|
|
313
|
+
// Extract agentName from "al-<agentName>-<runId>"
|
|
314
|
+
const parts = jobId.split("-");
|
|
315
|
+
const agentName = parts.slice(1, -1).join("-");
|
|
316
|
+
const execs = await listExecutions(this.auth, this.project, this.region, jobId);
|
|
317
|
+
const runningExecs = execs.filter((e) => !e.completionTime);
|
|
318
|
+
for (const exec of runningExecs) {
|
|
319
|
+
agents.push({
|
|
320
|
+
agentName,
|
|
321
|
+
taskId: exec.name.split("/").pop(),
|
|
322
|
+
runtimeId: jobId,
|
|
323
|
+
status: "running",
|
|
324
|
+
startedAt: exec.createTime ? new Date(exec.createTime) : undefined,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return agents;
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async kill(runId) {
|
|
335
|
+
try {
|
|
336
|
+
await deleteJob(this.auth, this.project, this.region, runId);
|
|
337
|
+
this.executionNames.delete(runId);
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
// Already deleted or not found
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async remove(runId) {
|
|
344
|
+
return this.kill(runId);
|
|
345
|
+
}
|
|
346
|
+
// ── Logs ─────────────────────────────────────────────────────────────────
|
|
347
|
+
streamLogs(runId, onLine, _onStderr) {
|
|
348
|
+
let stopped = false;
|
|
349
|
+
let lastTimestamp;
|
|
350
|
+
const poll = async () => {
|
|
351
|
+
if (stopped)
|
|
352
|
+
return;
|
|
353
|
+
try {
|
|
354
|
+
const filter = buildJobLogFilter(this.region, runId, lastTimestamp);
|
|
355
|
+
const resp = await listLogEntries(this.auth, this.project, filter, 100, "timestamp asc");
|
|
356
|
+
for (const entry of resp.entries ?? []) {
|
|
357
|
+
const text = extractLogText(entry);
|
|
358
|
+
if (text) {
|
|
359
|
+
for (const line of text.split("\n")) {
|
|
360
|
+
if (line)
|
|
361
|
+
onLine(line);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (entry.timestamp)
|
|
365
|
+
lastTimestamp = entry.timestamp;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
// Ignore transient errors
|
|
370
|
+
}
|
|
371
|
+
if (!stopped) {
|
|
372
|
+
setTimeout(poll, 3000);
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
setTimeout(poll, 3000);
|
|
376
|
+
return {
|
|
377
|
+
stop: () => { stopped = true; },
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
async waitForExit(runId, timeoutSeconds) {
|
|
381
|
+
const executionName = this.executionNames.get(runId);
|
|
382
|
+
if (!executionName) {
|
|
383
|
+
throw new Error(`No execution found for job ${runId}`);
|
|
384
|
+
}
|
|
385
|
+
const exec = await pollExecutionUntilDone(this.auth, this.project, this.region, executionName, timeoutSeconds * 1000);
|
|
386
|
+
this.executionNames.delete(runId);
|
|
387
|
+
return this._extractExitCode(exec, runId);
|
|
388
|
+
}
|
|
389
|
+
async _extractExitCode(exec, runId) {
|
|
390
|
+
const completedCondition = exec.conditions?.find((c) => c.type === "Completed");
|
|
391
|
+
if (!completedCondition || completedCondition.state === "CONDITION_SUCCEEDED") {
|
|
392
|
+
// Check Cloud Logging for al-rerun exit code 42
|
|
393
|
+
try {
|
|
394
|
+
const filter = buildJobLogFilter(this.region, runId);
|
|
395
|
+
const resp = await listLogEntries(this.auth, this.project, filter, 100, "timestamp desc");
|
|
396
|
+
for (const entry of resp.entries ?? []) {
|
|
397
|
+
const text = extractLogText(entry);
|
|
398
|
+
if (text.includes("exit code 42") || text.includes("exitCode=42")) {
|
|
399
|
+
return 42;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
// Best effort
|
|
405
|
+
}
|
|
406
|
+
return 0;
|
|
407
|
+
}
|
|
408
|
+
if (completedCondition.state === "CONDITION_FAILED") {
|
|
409
|
+
// Try to extract exit code from message
|
|
410
|
+
const msg = completedCondition.message ?? "";
|
|
411
|
+
const match = msg.match(/exit code (\d+)/i) ?? msg.match(/exitCode=(\d+)/i);
|
|
412
|
+
if (match)
|
|
413
|
+
return parseInt(match[1]);
|
|
414
|
+
return 1;
|
|
415
|
+
}
|
|
416
|
+
return 0;
|
|
417
|
+
}
|
|
418
|
+
async fetchLogs(agentName, limit, _taskId) {
|
|
419
|
+
try {
|
|
420
|
+
const jobs = await listJobs(this.auth, this.project, this.region);
|
|
421
|
+
const prefix = `al-${agentName}-`;
|
|
422
|
+
const agentJobs = jobs.filter((j) => {
|
|
423
|
+
const id = j.name.split("/").pop() ?? "";
|
|
424
|
+
return id.startsWith(prefix);
|
|
425
|
+
});
|
|
426
|
+
const lines = [];
|
|
427
|
+
for (const job of agentJobs) {
|
|
428
|
+
const jobId = job.name.split("/").pop();
|
|
429
|
+
const filter = buildJobLogFilter(this.region, jobId);
|
|
430
|
+
const resp = await listLogEntries(this.auth, this.project, filter, limit, "timestamp desc");
|
|
431
|
+
for (const entry of resp.entries ?? []) {
|
|
432
|
+
const text = extractLogText(entry);
|
|
433
|
+
if (text)
|
|
434
|
+
lines.push(...text.split("\n").filter(Boolean));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return lines.slice(-limit);
|
|
438
|
+
}
|
|
439
|
+
catch {
|
|
440
|
+
return [];
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
followLogs(agentName, onLine, onStderr, _taskId) {
|
|
444
|
+
let stopped = false;
|
|
445
|
+
let lastTimestamp;
|
|
446
|
+
const poll = async () => {
|
|
447
|
+
if (stopped)
|
|
448
|
+
return;
|
|
449
|
+
try {
|
|
450
|
+
const jobs = await listJobs(this.auth, this.project, this.region);
|
|
451
|
+
const prefix = `al-${agentName}-`;
|
|
452
|
+
for (const job of jobs) {
|
|
453
|
+
const jobId = job.name.split("/").pop() ?? "";
|
|
454
|
+
if (!jobId.startsWith(prefix))
|
|
455
|
+
continue;
|
|
456
|
+
const filter = buildJobLogFilter(this.region, jobId, lastTimestamp);
|
|
457
|
+
const resp = await listLogEntries(this.auth, this.project, filter, 100, "timestamp asc");
|
|
458
|
+
for (const entry of resp.entries ?? []) {
|
|
459
|
+
const text = extractLogText(entry);
|
|
460
|
+
if (text) {
|
|
461
|
+
for (const line of text.split("\n")) {
|
|
462
|
+
if (line)
|
|
463
|
+
onLine(line);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (entry.timestamp)
|
|
467
|
+
lastTimestamp = entry.timestamp;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
catch {
|
|
472
|
+
// Ignore transient errors
|
|
473
|
+
}
|
|
474
|
+
if (!stopped) {
|
|
475
|
+
setTimeout(poll, 3000);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
setTimeout(poll, 3000);
|
|
479
|
+
return { stop: () => { stopped = true; } };
|
|
480
|
+
}
|
|
481
|
+
getTaskUrl(runId) {
|
|
482
|
+
return `https://console.cloud.google.com/run/jobs/details/${this.region}/${runId}/executions?project=${this.project}`;
|
|
483
|
+
}
|
|
484
|
+
async inspectContainer(_containerName) {
|
|
485
|
+
// Cloud Run Jobs don't support container-level inspect.
|
|
486
|
+
// Orphans will be killed rather than re-adopted.
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
//# sourceMappingURL=cloud-run-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-run-runtime.js","sourceRoot":"","sources":["../../src/docker/cloud-run-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-user-runtime.d.ts","sourceRoot":"","sources":["../../src/docker/host-user-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,OAAO,KAAK,EACV,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAC5B,YAAY,EAC/B,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"host-user-runtime.d.ts","sourceRoot":"","sources":["../../src/docker/host-user-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,OAAO,KAAK,EACV,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAC5B,YAAY,EAC/B,MAAM,cAAc,CAAC;AA+HtB,qBAAa,eAAgB,YAAW,OAAO;IAC7C,QAAQ,CAAC,YAAY,SAAS;IAE9B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,aAAa,CAA6B;gBAEtC,KAAK,GAAE,MAAmB,EAAE,MAAM,GAAE,MAAM,EAAO;IAKvD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoBnD,iBAAiB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAgD5C,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAoDzE,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAO7C,MAAM,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAuFtD;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAoBhC,UAAU,CACR,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC9B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GACjC;QAAE,IAAI,EAAE,MAAM,IAAI,CAAA;KAAE;IAmDvB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA+B7D,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgClC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASpC,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAuBpE,UAAU,CACR,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC/B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GACjC;QAAE,IAAI,EAAE,MAAM,IAAI,CAAA;KAAE;IAKvB,UAAU,IAAI,MAAM,GAAG,IAAI;IAIrB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;IAUtF,+EAA+E;IACzE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAKhC"}
|
|
@@ -21,10 +21,13 @@ import { join } from "path";
|
|
|
21
21
|
import { tmpdir } from "os";
|
|
22
22
|
import { parseCredentialRef, getDefaultBackend } from "../shared/credentials.js";
|
|
23
23
|
import { CONSTANTS } from "../shared/constants.js";
|
|
24
|
-
|
|
24
|
+
/** Returns the runs directory, honouring the AL_RUNS_DIR env var override. */
|
|
25
|
+
function getRunsDir() {
|
|
26
|
+
return process.env.AL_RUNS_DIR ?? join(tmpdir(), "al-runs");
|
|
27
|
+
}
|
|
25
28
|
const ORPHAN_POLL_MS = 500;
|
|
26
29
|
function pidFilePath(runId) {
|
|
27
|
-
return join(
|
|
30
|
+
return join(getRunsDir(), `${runId}.pid`);
|
|
28
31
|
}
|
|
29
32
|
function writePidFile(runId, data) {
|
|
30
33
|
try {
|
|
@@ -135,10 +138,10 @@ export class HostUserRuntime {
|
|
|
135
138
|
}
|
|
136
139
|
// Check PID files for orphaned processes from a previous scheduler session
|
|
137
140
|
try {
|
|
138
|
-
if (!existsSync(
|
|
141
|
+
if (!existsSync(getRunsDir()))
|
|
139
142
|
return false;
|
|
140
143
|
const prefix = `al-${agentName}-`;
|
|
141
|
-
for (const f of readdirSync(
|
|
144
|
+
for (const f of readdirSync(getRunsDir())) {
|
|
142
145
|
if (!f.startsWith(prefix) || !f.endsWith(".pid"))
|
|
143
146
|
continue;
|
|
144
147
|
const runId = f.slice(0, -4);
|
|
@@ -167,9 +170,9 @@ export class HostUserRuntime {
|
|
|
167
170
|
}
|
|
168
171
|
// Scan PID files for orphaned processes from a previous scheduler session
|
|
169
172
|
try {
|
|
170
|
-
if (!existsSync(
|
|
173
|
+
if (!existsSync(getRunsDir()))
|
|
171
174
|
return agents;
|
|
172
|
-
for (const file of readdirSync(
|
|
175
|
+
for (const file of readdirSync(getRunsDir())) {
|
|
173
176
|
if (!file.endsWith(".pid"))
|
|
174
177
|
continue;
|
|
175
178
|
const runId = file.slice(0, -4);
|
|
@@ -248,17 +251,22 @@ export class HostUserRuntime {
|
|
|
248
251
|
return { strategy: "host-user", stagingDir, bundle };
|
|
249
252
|
}
|
|
250
253
|
cleanupCredentials(creds) {
|
|
254
|
+
if (!('stagingDir' in creds))
|
|
255
|
+
return;
|
|
251
256
|
try {
|
|
252
257
|
rmSync(creds.stagingDir, { recursive: true, force: true });
|
|
253
258
|
}
|
|
254
259
|
catch { /* best effort */ }
|
|
255
260
|
}
|
|
256
261
|
async launch(opts) {
|
|
262
|
+
if (!('stagingDir' in opts.credentials)) {
|
|
263
|
+
throw new Error(`host-user runtime requires a stagingDir credential strategy, got: ${opts.credentials.strategy}`);
|
|
264
|
+
}
|
|
257
265
|
const runId = `al-${opts.agentName}-${randomUUID().slice(0, 8)}`;
|
|
258
266
|
// Ensure runs directory exists
|
|
259
|
-
mkdirSync(
|
|
267
|
+
mkdirSync(getRunsDir(), { recursive: true });
|
|
260
268
|
// Create working directory
|
|
261
|
-
const workDir = join(
|
|
269
|
+
const workDir = join(getRunsDir(), runId);
|
|
262
270
|
mkdirSync(workDir, { recursive: true, mode: 0o755 });
|
|
263
271
|
const uid = resolveUid(this.runAs);
|
|
264
272
|
const gid = resolveGid(this.runAs);
|
|
@@ -270,7 +278,7 @@ export class HostUserRuntime {
|
|
|
270
278
|
}
|
|
271
279
|
// Create log file — child writes directly to this fd so output survives
|
|
272
280
|
// scheduler restarts. streamLogs() tails this file using fs.watch().
|
|
273
|
-
const logPath = join(
|
|
281
|
+
const logPath = join(getRunsDir(), `${runId}.log`);
|
|
274
282
|
const logFd = openSync(logPath, "a");
|
|
275
283
|
// Build env vars for the child process
|
|
276
284
|
const env = {
|
|
@@ -345,7 +353,7 @@ export class HostUserRuntime {
|
|
|
345
353
|
return true;
|
|
346
354
|
}
|
|
347
355
|
streamLogs(runId, onLine, _onStderr) {
|
|
348
|
-
const logPath = join(
|
|
356
|
+
const logPath = join(getRunsDir(), `${runId}.log`);
|
|
349
357
|
if (!existsSync(logPath))
|
|
350
358
|
return { stop: () => { } };
|
|
351
359
|
let offset = 0;
|
|
@@ -459,7 +467,7 @@ export class HostUserRuntime {
|
|
|
459
467
|
}
|
|
460
468
|
async remove(runId) {
|
|
461
469
|
// Clean up working directory and PID file
|
|
462
|
-
const workDir = join(
|
|
470
|
+
const workDir = join(getRunsDir(), runId);
|
|
463
471
|
try {
|
|
464
472
|
rmSync(workDir, { recursive: true, force: true });
|
|
465
473
|
}
|
|
@@ -469,9 +477,9 @@ export class HostUserRuntime {
|
|
|
469
477
|
async fetchLogs(agentName, limit) {
|
|
470
478
|
// Read from log files in RUNS_DIR matching this agent
|
|
471
479
|
try {
|
|
472
|
-
if (!existsSync(
|
|
480
|
+
if (!existsSync(getRunsDir()))
|
|
473
481
|
return [];
|
|
474
|
-
const files = readdirSync(
|
|
482
|
+
const files = readdirSync(getRunsDir())
|
|
475
483
|
.filter(f => f.startsWith(`al-${agentName}-`) && f.endsWith(".log"))
|
|
476
484
|
.sort()
|
|
477
485
|
.reverse();
|
|
@@ -480,7 +488,7 @@ export class HostUserRuntime {
|
|
|
480
488
|
if (allLines.length >= limit)
|
|
481
489
|
break;
|
|
482
490
|
try {
|
|
483
|
-
const content = readFileSync(join(
|
|
491
|
+
const content = readFileSync(join(getRunsDir(), file), "utf-8");
|
|
484
492
|
allLines.push(...content.split("\n").filter(Boolean));
|
|
485
493
|
}
|
|
486
494
|
catch { /* file may be gone */ }
|