@agent-vm/agent-vm 0.0.77 → 0.0.79
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/cli/commands/controller-definition.d.ts.map +1 -1
- package/dist/cli/commands/controller-definition.js +7 -3
- package/dist/cli/commands/controller-definition.js.map +1 -1
- package/dist/cli/manual-templates.d.ts.map +1 -1
- package/dist/cli/manual-templates.js +8 -4
- package/dist/cli/manual-templates.js.map +1 -1
- package/dist/controller/controller-runtime-types.d.ts +4 -0
- package/dist/controller/controller-runtime-types.d.ts.map +1 -1
- package/dist/controller/controller-runtime.d.ts.map +1 -1
- package/dist/controller/controller-runtime.js +28 -3
- package/dist/controller/controller-runtime.js.map +1 -1
- package/dist/controller/http/controller-http-route-support.d.ts +12 -0
- package/dist/controller/http/controller-http-route-support.d.ts.map +1 -1
- package/dist/controller/http/controller-http-route-support.js +12 -0
- package/dist/controller/http/controller-http-route-support.js.map +1 -1
- package/dist/controller/http/controller-http-routes.d.ts +4 -1
- package/dist/controller/http/controller-http-routes.d.ts.map +1 -1
- package/dist/controller/http/controller-http-routes.js +75 -24
- package/dist/controller/http/controller-http-routes.js.map +1 -1
- package/dist/controller/http/controller-lease-response-types.d.ts +1 -0
- package/dist/controller/http/controller-lease-response-types.d.ts.map +1 -1
- package/dist/controller/http/controller-lease-response-types.js +1 -0
- package/dist/controller/http/controller-lease-response-types.js.map +1 -1
- package/dist/controller/http/controller-request-schemas.d.ts +1 -0
- package/dist/controller/http/controller-request-schemas.d.ts.map +1 -1
- package/dist/controller/http/controller-request-schemas.js +15 -1
- package/dist/controller/http/controller-request-schemas.js.map +1 -1
- package/dist/controller/http/controller-zone-operation-routes.d.ts +4 -2
- package/dist/controller/http/controller-zone-operation-routes.d.ts.map +1 -1
- package/dist/controller/http/controller-zone-operation-routes.js +50 -1
- package/dist/controller/http/controller-zone-operation-routes.js.map +1 -1
- package/dist/controller/leases/lease-manager.d.ts +17 -1
- package/dist/controller/leases/lease-manager.d.ts.map +1 -1
- package/dist/controller/leases/lease-manager.js +133 -34
- package/dist/controller/leases/lease-manager.js.map +1 -1
- package/dist/controller/leases/tcp-pool.d.ts +3 -0
- package/dist/controller/leases/tcp-pool.d.ts.map +1 -1
- package/dist/controller/leases/tcp-pool.js +12 -1
- package/dist/controller/leases/tcp-pool.js.map +1 -1
- package/dist/controller/leases/tool-vm-recovery.d.ts +31 -0
- package/dist/controller/leases/tool-vm-recovery.d.ts.map +1 -0
- package/dist/controller/leases/tool-vm-recovery.js +178 -0
- package/dist/controller/leases/tool-vm-recovery.js.map +1 -0
- package/dist/controller/leases/tool-vm-runtime-record.d.ts +59 -0
- package/dist/controller/leases/tool-vm-runtime-record.d.ts.map +1 -0
- package/dist/controller/leases/tool-vm-runtime-record.js +159 -0
- package/dist/controller/leases/tool-vm-runtime-record.js.map +1 -0
- package/dist/gateway/gateway-recovery.d.ts +8 -5
- package/dist/gateway/gateway-recovery.d.ts.map +1 -1
- package/dist/gateway/gateway-recovery.js +63 -123
- package/dist/gateway/gateway-recovery.js.map +1 -1
- package/dist/gateway/gateway-runtime-record.d.ts +24 -16
- package/dist/gateway/gateway-runtime-record.d.ts.map +1 -1
- package/dist/gateway/gateway-runtime-record.js +53 -68
- package/dist/gateway/gateway-runtime-record.js.map +1 -1
- package/dist/gateway/gateway-zone-orchestrator.d.ts +6 -0
- package/dist/gateway/gateway-zone-orchestrator.d.ts.map +1 -1
- package/dist/gateway/gateway-zone-orchestrator.js +157 -40
- package/dist/gateway/gateway-zone-orchestrator.js.map +1 -1
- package/dist/operations/controller-offline-cleanup.d.ts +3 -0
- package/dist/operations/controller-offline-cleanup.d.ts.map +1 -1
- package/dist/operations/controller-offline-cleanup.js +16 -6
- package/dist/operations/controller-offline-cleanup.js.map +1 -1
- package/dist/operations/destroy-zone.d.ts.map +1 -1
- package/dist/operations/destroy-zone.js +5 -0
- package/dist/operations/destroy-zone.js.map +1 -1
- package/dist/shared/managed-vm-process.d.ts +33 -0
- package/dist/shared/managed-vm-process.d.ts.map +1 -0
- package/dist/shared/managed-vm-process.js +248 -0
- package/dist/shared/managed-vm-process.js.map +1 -0
- package/dist/shared/port-owner.d.ts +18 -0
- package/dist/shared/port-owner.d.ts.map +1 -0
- package/dist/shared/port-owner.js +60 -0
- package/dist/shared/port-owner.js.map +1 -0
- package/package.json +11 -11
|
@@ -1,40 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { deleteGatewayRuntimeRecord,
|
|
4
|
-
const execFileAsync = promisify(execFile);
|
|
5
|
-
function isProcessAlive(pid) {
|
|
6
|
-
try {
|
|
7
|
-
process.kill(pid, 0);
|
|
8
|
-
return true;
|
|
9
|
-
}
|
|
10
|
-
catch (error) {
|
|
11
|
-
if (typeof error === 'object' && error !== null && 'code' in error) {
|
|
12
|
-
if (error.code === 'EPERM') {
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
if (error.code === 'ESRCH') {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
throw error;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
async function readProcessCommand(pid) {
|
|
23
|
-
try {
|
|
24
|
-
const { stdout } = await execFileAsync('ps', ['-p', String(pid), '-o', 'command=']);
|
|
25
|
-
const command = stdout.trim();
|
|
26
|
-
return command.length > 0 ? command : null;
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
if (typeof error === 'object' && error !== null && 'code' in error && error.code === 1) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function isManagedGatewayProcess(command) {
|
|
36
|
-
return /\b(qemu-system|krun)\b/u.test(command);
|
|
37
|
-
}
|
|
1
|
+
import { isManagedVmProcess, isProcessAlive, killOrphanedManagedVmProcess, killProcess, readProcessCommand, readProcessIdentity, sleep, } from '../shared/managed-vm-process.js';
|
|
2
|
+
import { readTcpListenPortOwner as defaultReadTcpListenPortOwner, } from '../shared/port-owner.js';
|
|
3
|
+
import { deleteGatewayRuntimeRecord, loadGatewayRuntimeRecordResult, } from './gateway-runtime-record.js';
|
|
38
4
|
function writeRecoveryLog(message) {
|
|
39
5
|
process.stderr.write(`[agent-vm] ${message}\n`);
|
|
40
6
|
}
|
|
@@ -42,13 +8,11 @@ function expectedGatewaySessionLabel(projectNamespace, zoneId) {
|
|
|
42
8
|
return `${projectNamespace}:${zoneId}:gateway`;
|
|
43
9
|
}
|
|
44
10
|
function validateRuntimeRecordCleanupScope(options) {
|
|
45
|
-
if (options.
|
|
46
|
-
options.runtimeRecord.configPath
|
|
47
|
-
return `Gateway runtime record at '${options.stateDir}' belongs to configPath '${options.runtimeRecord.configPath}', not '${options.legacyRecordDefaults.configPath}'. Refusing scoped cleanup.`;
|
|
11
|
+
if (options.runtimeRecord.configPath !== options.expectedConfigPath) {
|
|
12
|
+
return `Gateway runtime record at '${options.stateDir}' for zone '${options.runtimeRecord.zoneId}' belongs to configPath '${options.runtimeRecord.configPath}', not '${options.expectedConfigPath}'. Refusing scoped cleanup.`;
|
|
48
13
|
}
|
|
49
|
-
if (options.
|
|
50
|
-
options.runtimeRecord.controllerPort
|
|
51
|
-
return `Gateway runtime record at '${options.stateDir}' belongs to controllerPort '${options.runtimeRecord.controllerPort}', not '${options.legacyRecordDefaults.controllerPort}'. Refusing scoped cleanup.`;
|
|
14
|
+
if (options.runtimeRecord.controllerPort !== options.expectedControllerPort) {
|
|
15
|
+
return `Gateway runtime record at '${options.stateDir}' for zone '${options.runtimeRecord.zoneId}' belongs to controllerPort '${String(options.runtimeRecord.controllerPort)}', not '${String(options.expectedControllerPort)}'. Refusing scoped cleanup.`;
|
|
52
16
|
}
|
|
53
17
|
if (options.runtimeRecord.projectNamespace !== options.projectNamespace) {
|
|
54
18
|
return `Gateway runtime record at '${options.stateDir}' for zone '${options.runtimeRecord.zoneId}' belongs to projectNamespace '${options.runtimeRecord.projectNamespace}', not '${options.projectNamespace}'. Refusing scoped cleanup.`;
|
|
@@ -62,92 +26,55 @@ function validateRuntimeRecordCleanupScope(options) {
|
|
|
62
26
|
}
|
|
63
27
|
return null;
|
|
64
28
|
}
|
|
65
|
-
function killProcess(pid, signal) {
|
|
66
|
-
try {
|
|
67
|
-
process.kill(pid, signal);
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'ESRCH') {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'EPERM') {
|
|
74
|
-
throw new Error(`Permission denied while sending ${signal} to orphaned gateway pid ${pid}. The process is still running and may require elevated privileges to terminate.`, { cause: error });
|
|
75
|
-
}
|
|
76
|
-
throw error;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function isNoSuchProcessError(error) {
|
|
80
|
-
return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ESRCH';
|
|
81
|
-
}
|
|
82
|
-
async function sleep(delayMs) {
|
|
83
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
84
|
-
}
|
|
85
|
-
async function waitForExit(options) {
|
|
86
|
-
const deadline = Date.now() + options.timeoutMs;
|
|
87
|
-
while (Date.now() < deadline) {
|
|
88
|
-
if (!options.processIsAlive(options.pid)) {
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
// oxlint-disable-next-line no-await-in-loop -- polling loop must wait between liveness checks
|
|
92
|
-
await options.sleep(100);
|
|
93
|
-
}
|
|
94
|
-
return !options.processIsAlive(options.pid);
|
|
95
|
-
}
|
|
96
29
|
async function killOrphanedGatewayProcess(runtimeRecord, dependencies) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const processCommand = await dependencies.readProcessCommand(runtimeRecord.qemuPid);
|
|
101
|
-
if (!processCommand || !isManagedGatewayProcess(processCommand)) {
|
|
102
|
-
throw new Error(`Gateway runtime record for zone '${runtimeRecord.zoneId}' points at unexpected live process ${runtimeRecord.qemuPid}: ${processCommand ?? '(command unavailable)'}.`);
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
dependencies.killProcess(runtimeRecord.qemuPid, 'SIGTERM');
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
if (!isNoSuchProcessError(error)) {
|
|
109
|
-
throw error;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (await waitForExit({
|
|
30
|
+
return await killOrphanedManagedVmProcess({
|
|
31
|
+
contextLabel: `Gateway runtime record for zone '${runtimeRecord.zoneId}'`,
|
|
32
|
+
dependencies,
|
|
113
33
|
pid: runtimeRecord.qemuPid,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
dependencies.killProcess(runtimeRecord.qemuPid, 'SIGKILL');
|
|
34
|
+
recordedIdentity: runtimeRecord.processIdentity,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async function verifyGatewayPortOwnership(options) {
|
|
38
|
+
const portOwner = await options.readTcpListenPortOwner(options.runtimeRecord.ingressPort);
|
|
39
|
+
if (portOwner === null) {
|
|
40
|
+
return { kind: 'record-stale' };
|
|
122
41
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
42
|
+
if (portOwner.pid !== options.runtimeRecord.qemuPid) {
|
|
43
|
+
return {
|
|
44
|
+
kind: 'unproven',
|
|
45
|
+
warning: `Gateway runtime record for zone '${options.runtimeRecord.zoneId}' port ${String(options.runtimeRecord.ingressPort)} is held by pid ${String(portOwner.pid)}, expected pid ${String(options.runtimeRecord.qemuPid)}.`,
|
|
46
|
+
};
|
|
127
47
|
}
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
})) {
|
|
134
|
-
return runtimeRecord.qemuPid;
|
|
48
|
+
if (!isManagedVmProcess(portOwner.command)) {
|
|
49
|
+
return {
|
|
50
|
+
kind: 'unproven',
|
|
51
|
+
warning: `Gateway runtime record for zone '${options.runtimeRecord.zoneId}' port ${String(options.runtimeRecord.ingressPort)} is held by pid ${String(portOwner.pid)} but command is not a managed VM process: ${portOwner.command}.`,
|
|
52
|
+
};
|
|
135
53
|
}
|
|
136
|
-
|
|
54
|
+
return { kind: 'owned' };
|
|
137
55
|
}
|
|
138
56
|
export async function cleanupOrphanedGatewayIfPresent(options, dependencies = {}) {
|
|
139
57
|
const log = dependencies.log ?? writeRecoveryLog;
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
? { legacyRecordDefaults: options.legacyRecordDefaults }
|
|
143
|
-
: {}),
|
|
144
|
-
log,
|
|
145
|
-
});
|
|
146
|
-
if (!runtimeRecord) {
|
|
58
|
+
const runtimeRecordResult = await (dependencies.loadGatewayRuntimeRecordResult ?? loadGatewayRuntimeRecordResult)(options.stateDir);
|
|
59
|
+
if (runtimeRecordResult.kind === 'missing') {
|
|
147
60
|
return { cleanedUp: false, killedPid: null };
|
|
148
61
|
}
|
|
62
|
+
if (runtimeRecordResult.kind === 'parse-error') {
|
|
63
|
+
const cleanupWarning = `Malformed gateway runtime record '${runtimeRecordResult.path}': ${runtimeRecordResult.error.message}.`;
|
|
64
|
+
if (options.mode !== 'in-process-recovery') {
|
|
65
|
+
throw new Error(cleanupWarning, { cause: runtimeRecordResult.error });
|
|
66
|
+
}
|
|
67
|
+
log(`Skipping ${cleanupWarning}`);
|
|
68
|
+
return {
|
|
69
|
+
cleanedUp: false,
|
|
70
|
+
cleanupWarning,
|
|
71
|
+
killedPid: null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const runtimeRecord = runtimeRecordResult.record;
|
|
149
75
|
const scopeMismatch = validateRuntimeRecordCleanupScope({
|
|
150
|
-
|
|
76
|
+
expectedConfigPath: options.expectedConfigPath,
|
|
77
|
+
expectedControllerPort: options.expectedControllerPort,
|
|
151
78
|
projectNamespace: options.projectNamespace,
|
|
152
79
|
runtimeRecord,
|
|
153
80
|
stateDir: options.stateDir,
|
|
@@ -157,12 +84,8 @@ export async function cleanupOrphanedGatewayIfPresent(options, dependencies = {}
|
|
|
157
84
|
if (options.mode !== 'in-process-recovery') {
|
|
158
85
|
throw new Error(scopeMismatch);
|
|
159
86
|
}
|
|
160
|
-
const cleanupWarning = `${scopeMismatch}
|
|
87
|
+
const cleanupWarning = `${scopeMismatch} Skipping the stale runtime record without signaling its recorded process during in-process recovery.`;
|
|
161
88
|
log(cleanupWarning);
|
|
162
|
-
await (dependencies.quarantineGatewayRuntimeRecord ?? quarantineGatewayRuntimeRecord)(options.stateDir, {
|
|
163
|
-
log,
|
|
164
|
-
reason: cleanupWarning,
|
|
165
|
-
});
|
|
166
89
|
return {
|
|
167
90
|
cleanedUp: false,
|
|
168
91
|
cleanupWarning,
|
|
@@ -170,10 +93,27 @@ export async function cleanupOrphanedGatewayIfPresent(options, dependencies = {}
|
|
|
170
93
|
};
|
|
171
94
|
}
|
|
172
95
|
log(`Found persisted gateway runtime for zone '${runtimeRecord.zoneId}' (pid ${runtimeRecord.qemuPid}, vm ${runtimeRecord.vmId}).`);
|
|
96
|
+
const portOwnershipProof = await verifyGatewayPortOwnership({
|
|
97
|
+
readTcpListenPortOwner: dependencies.readTcpListenPortOwner ?? defaultReadTcpListenPortOwner,
|
|
98
|
+
runtimeRecord,
|
|
99
|
+
});
|
|
100
|
+
if (portOwnershipProof.kind === 'unproven') {
|
|
101
|
+
if (options.mode !== 'in-process-recovery') {
|
|
102
|
+
throw new Error(portOwnershipProof.warning);
|
|
103
|
+
}
|
|
104
|
+
const cleanupWarning = `Skipping ${portOwnershipProof.warning}`;
|
|
105
|
+
log(cleanupWarning);
|
|
106
|
+
return {
|
|
107
|
+
cleanedUp: false,
|
|
108
|
+
cleanupWarning,
|
|
109
|
+
killedPid: null,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
173
112
|
const killedPid = await killOrphanedGatewayProcess(runtimeRecord, {
|
|
174
113
|
isProcessAlive: dependencies.isProcessAlive ?? isProcessAlive,
|
|
175
114
|
killProcess: dependencies.killProcess ?? killProcess,
|
|
176
115
|
readProcessCommand: dependencies.readProcessCommand ?? readProcessCommand,
|
|
116
|
+
readProcessIdentity: dependencies.readProcessIdentity ?? readProcessIdentity,
|
|
177
117
|
sleep: dependencies.sleep ?? sleep,
|
|
178
118
|
});
|
|
179
119
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-recovery.js","sourceRoot":"","sources":["../../src/gateway/gateway-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"gateway-recovery.js","sourceRoot":"","sources":["../../src/gateway/gateway-recovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,36 +1,43 @@
|
|
|
1
1
|
import { type GatewayProcessSpec, type GatewayType } from '@agent-vm/gateway-interface';
|
|
2
2
|
import { type ManagedVm } from '@agent-vm/gondolin-adapter';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
import { readProcessIdentity as defaultReadProcessIdentity } from '../shared/managed-vm-process.js';
|
|
4
5
|
export declare const gatewayRuntimeRecordSchema: z.ZodObject<{
|
|
6
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
5
7
|
configPath: z.ZodString;
|
|
6
8
|
controllerPort: z.ZodNumber;
|
|
7
|
-
createdAt: z.
|
|
9
|
+
createdAt: z.ZodISODateTime;
|
|
8
10
|
gatewayType: z.ZodEnum<{
|
|
9
11
|
openclaw: "openclaw";
|
|
10
12
|
worker: "worker";
|
|
11
13
|
}>;
|
|
12
14
|
guestListenPort: z.ZodNumber;
|
|
13
15
|
ingressPort: z.ZodNumber;
|
|
16
|
+
processIdentity: z.ZodObject<{
|
|
17
|
+
command: z.ZodString;
|
|
18
|
+
lstart: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
14
20
|
projectNamespace: z.ZodString;
|
|
15
21
|
qemuPid: z.ZodNumber;
|
|
16
22
|
sessionLabel: z.ZodString;
|
|
17
23
|
vmId: z.ZodString;
|
|
18
24
|
zoneId: z.ZodString;
|
|
19
|
-
}, z.core.$
|
|
25
|
+
}, z.core.$strict>;
|
|
20
26
|
export type GatewayRuntimeRecord = z.infer<typeof gatewayRuntimeRecordSchema>;
|
|
21
|
-
export type
|
|
22
|
-
|
|
23
|
-
readonly
|
|
24
|
-
readonly
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
readonly
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
readonly
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
export type GatewayRuntimeRecordLoadResult = {
|
|
28
|
+
readonly kind: 'loaded';
|
|
29
|
+
readonly path: string;
|
|
30
|
+
readonly record: GatewayRuntimeRecord;
|
|
31
|
+
} | {
|
|
32
|
+
readonly kind: 'missing';
|
|
33
|
+
readonly path: string;
|
|
34
|
+
} | {
|
|
35
|
+
readonly error: Error;
|
|
36
|
+
readonly kind: 'parse-error';
|
|
37
|
+
readonly path: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function loadGatewayRuntimeRecordResult(stateDirectory: string): Promise<GatewayRuntimeRecordLoadResult>;
|
|
40
|
+
export declare function loadGatewayRuntimeRecord(stateDirectory: string): Promise<GatewayRuntimeRecord | null>;
|
|
34
41
|
export declare function writeGatewayRuntimeRecord(stateDirectory: string, record: GatewayRuntimeRecord): Promise<void>;
|
|
35
42
|
export declare function deleteGatewayRuntimeRecord(stateDirectory: string): Promise<void>;
|
|
36
43
|
export declare function buildGatewayRuntimeRecord(options: {
|
|
@@ -40,7 +47,8 @@ export declare function buildGatewayRuntimeRecord(options: {
|
|
|
40
47
|
readonly managedVm: ManagedVm;
|
|
41
48
|
readonly processSpec: GatewayProcessSpec;
|
|
42
49
|
readonly projectNamespace: string;
|
|
50
|
+
readonly readProcessIdentity?: typeof defaultReadProcessIdentity;
|
|
43
51
|
readonly systemConfigPath: string;
|
|
44
52
|
readonly zoneId: string;
|
|
45
|
-
}): GatewayRuntimeRecord
|
|
53
|
+
}): Promise<GatewayRuntimeRecord>;
|
|
46
54
|
//# sourceMappingURL=gateway-runtime-record.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-runtime-record.d.ts","sourceRoot":"","sources":["../../src/gateway/gateway-runtime-record.ts"],"names":[],"mappings":"AAGA,OAAO,EAGN,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,KAAK,SAAS,EAAuB,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAY,CAAC,EAAE,MAAM,KAAK,CAAC;AAElC,eAAO,MAAM,0BAA0B
|
|
1
|
+
{"version":3,"file":"gateway-runtime-record.d.ts","sourceRoot":"","sources":["../../src/gateway/gateway-runtime-record.ts"],"names":[],"mappings":"AAGA,OAAO,EAGN,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,KAAK,SAAS,EAAuB,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAY,CAAC,EAAE,MAAM,KAAK,CAAC;AAElC,OAAO,EAAE,mBAAmB,IAAI,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAEpG,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;kBAiBrC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,MAAM,MAAM,8BAA8B,GACvC;IACA,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;CACrC,GACD;IACA,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACrB,GACD;IACA,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACrB,CAAC;AAiBL,wBAAsB,8BAA8B,CACnD,cAAc,EAAE,MAAM,GACpB,OAAO,CAAC,8BAA8B,CAAC,CAwBzC;AAED,wBAAsB,wBAAwB,CAC7C,cAAc,EAAE,MAAM,GACpB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAStC;AAED,wBAAsB,yBAAyB,CAC9C,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,oBAAoB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,0BAA0B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;AAmBD,wBAAsB,yBAAyB,CAAC,OAAO,EAAE;IACxD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,0BAA0B,CAAC;IACjE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA0BhC"}
|
|
@@ -3,102 +3,79 @@ import path from 'node:path';
|
|
|
3
3
|
import { buildGatewaySessionLabel, gatewayTypeValues, } from '@agent-vm/gateway-interface';
|
|
4
4
|
import { writeFileAtomically } from '@agent-vm/gondolin-adapter';
|
|
5
5
|
import { ZodError, z } from 'zod';
|
|
6
|
-
|
|
6
|
+
import { readProcessIdentity as defaultReadProcessIdentity } from '../shared/managed-vm-process.js';
|
|
7
|
+
export const gatewayRuntimeRecordSchema = z.strictObject({
|
|
8
|
+
schemaVersion: z.literal(1),
|
|
7
9
|
configPath: z.string().min(1),
|
|
8
10
|
controllerPort: z.number().int().positive(),
|
|
9
|
-
createdAt: z.
|
|
11
|
+
createdAt: z.iso.datetime(),
|
|
10
12
|
gatewayType: z.enum(gatewayTypeValues),
|
|
11
13
|
guestListenPort: z.number().int().positive(),
|
|
12
14
|
ingressPort: z.number().int().positive(),
|
|
15
|
+
processIdentity: z.strictObject({
|
|
16
|
+
command: z.string().min(1),
|
|
17
|
+
lstart: z.string().min(1),
|
|
18
|
+
}),
|
|
13
19
|
projectNamespace: z.string().min(1),
|
|
14
20
|
qemuPid: z.number().int().positive(),
|
|
15
21
|
sessionLabel: z.string().min(1),
|
|
16
22
|
vmId: z.string().min(1),
|
|
17
23
|
zoneId: z.string().min(1),
|
|
18
24
|
});
|
|
19
|
-
const legacyGatewayRuntimeRecordSchema = gatewayRuntimeRecordSchema.omit({
|
|
20
|
-
configPath: true,
|
|
21
|
-
controllerPort: true,
|
|
22
|
-
});
|
|
23
25
|
const gatewayRuntimeRecordFileName = 'gateway-runtime.json';
|
|
24
26
|
function resolveGatewayRuntimeRecordPath(stateDirectory) {
|
|
25
27
|
return path.join(stateDirectory, gatewayRuntimeRecordFileName);
|
|
26
28
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
+
function parseGatewayRuntimeRecord(rawRuntimeRecord) {
|
|
30
|
+
const parsedRuntimeRecord = JSON.parse(rawRuntimeRecord);
|
|
31
|
+
return gatewayRuntimeRecordSchema.parse(parsedRuntimeRecord);
|
|
29
32
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
await fs.rename(runtimeRecordPath, invalidRuntimeRecordPath);
|
|
34
|
-
log(`Quarantined malformed gateway runtime record '${runtimeRecordPath}' to '${invalidRuntimeRecordPath}'.`);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
await fs.rm(runtimeRecordPath, { force: true });
|
|
39
|
-
log(`Deleted malformed gateway runtime record '${runtimeRecordPath}' after quarantine rename failed: ${error instanceof Error ? error.message : JSON.stringify(error)}`);
|
|
40
|
-
}
|
|
33
|
+
function runtimeRecordParseError(error) {
|
|
34
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
41
35
|
}
|
|
42
|
-
export async function
|
|
36
|
+
export async function loadGatewayRuntimeRecordResult(stateDirectory) {
|
|
43
37
|
const runtimeRecordPath = resolveGatewayRuntimeRecordPath(stateDirectory);
|
|
44
|
-
const quarantinedRuntimeRecordPath = path.join(stateDirectory, `gateway-runtime.quarantined.${Date.now()}.json`);
|
|
45
38
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
return {
|
|
40
|
+
kind: 'loaded',
|
|
41
|
+
path: runtimeRecordPath,
|
|
42
|
+
record: parseGatewayRuntimeRecord(await fs.readFile(runtimeRecordPath, 'utf8')),
|
|
43
|
+
};
|
|
48
44
|
}
|
|
49
45
|
catch (error) {
|
|
50
46
|
if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT') {
|
|
51
|
-
return
|
|
47
|
+
return {
|
|
48
|
+
kind: 'missing',
|
|
49
|
+
path: runtimeRecordPath,
|
|
50
|
+
};
|
|
52
51
|
}
|
|
53
|
-
throw error;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function writeGatewayRuntimeLog(message) {
|
|
57
|
-
process.stderr.write(`[agent-vm] ${message}\n`);
|
|
58
|
-
}
|
|
59
|
-
export async function loadGatewayRuntimeRecord(stateDirectory, options = {}) {
|
|
60
|
-
const runtimeRecordPath = resolveGatewayRuntimeRecordPath(stateDirectory);
|
|
61
|
-
let rawRuntimeRecord;
|
|
62
|
-
try {
|
|
63
|
-
rawRuntimeRecord = await fs.readFile(runtimeRecordPath, 'utf8');
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
if (typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT') {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
throw error;
|
|
70
|
-
}
|
|
71
|
-
try {
|
|
72
|
-
const parsedRuntimeRecord = JSON.parse(rawRuntimeRecord);
|
|
73
|
-
const currentRuntimeRecord = gatewayRuntimeRecordSchema.safeParse(parsedRuntimeRecord);
|
|
74
|
-
if (currentRuntimeRecord.success) {
|
|
75
|
-
return currentRuntimeRecord.data;
|
|
76
|
-
}
|
|
77
|
-
const legacyRuntimeRecord = legacyGatewayRuntimeRecordSchema.safeParse(parsedRuntimeRecord);
|
|
78
|
-
if (legacyRuntimeRecord.success && options.legacyRecordDefaults !== undefined) {
|
|
79
|
-
return gatewayRuntimeRecordSchema.parse({
|
|
80
|
-
...legacyRuntimeRecord.data,
|
|
81
|
-
configPath: options.legacyRecordDefaults.configPath,
|
|
82
|
-
controllerPort: options.legacyRecordDefaults.controllerPort,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
if (legacyRuntimeRecord.success) {
|
|
86
|
-
throw new Error(`Gateway runtime record '${runtimeRecordPath}' uses the legacy format and requires legacyRecordDefaults to supply configPath and controllerPort.`);
|
|
87
|
-
}
|
|
88
|
-
throw currentRuntimeRecord.error;
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
52
|
if (!(error instanceof SyntaxError) && !(error instanceof ZodError)) {
|
|
92
53
|
throw error;
|
|
93
54
|
}
|
|
94
|
-
|
|
55
|
+
return {
|
|
56
|
+
error: runtimeRecordParseError(error),
|
|
57
|
+
kind: 'parse-error',
|
|
58
|
+
path: runtimeRecordPath,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export async function loadGatewayRuntimeRecord(stateDirectory) {
|
|
63
|
+
const loadResult = await loadGatewayRuntimeRecordResult(stateDirectory);
|
|
64
|
+
if (loadResult.kind === 'missing') {
|
|
95
65
|
return null;
|
|
96
66
|
}
|
|
67
|
+
if (loadResult.kind === 'parse-error') {
|
|
68
|
+
throw loadResult.error;
|
|
69
|
+
}
|
|
70
|
+
return loadResult.record;
|
|
97
71
|
}
|
|
98
72
|
export async function writeGatewayRuntimeRecord(stateDirectory, record) {
|
|
73
|
+
const parsedRecord = gatewayRuntimeRecordSchema.parse(record);
|
|
99
74
|
const runtimeRecordPath = resolveGatewayRuntimeRecordPath(stateDirectory);
|
|
100
75
|
await fs.mkdir(stateDirectory, { recursive: true });
|
|
101
|
-
await writeFileAtomically(runtimeRecordPath, `${JSON.stringify(
|
|
76
|
+
await writeFileAtomically(runtimeRecordPath, `${JSON.stringify(parsedRecord, null, 2)}\n`, {
|
|
77
|
+
mode: 0o600,
|
|
78
|
+
});
|
|
102
79
|
}
|
|
103
80
|
export async function deleteGatewayRuntimeRecord(stateDirectory) {
|
|
104
81
|
await fs.rm(resolveGatewayRuntimeRecordPath(stateDirectory), { force: true });
|
|
@@ -116,20 +93,28 @@ function resolveManagedVmQemuPid(managedVm) {
|
|
|
116
93
|
}
|
|
117
94
|
return qemuPid;
|
|
118
95
|
}
|
|
119
|
-
export function buildGatewayRuntimeRecord(options) {
|
|
96
|
+
export async function buildGatewayRuntimeRecord(options) {
|
|
120
97
|
const gatewayType = gatewayRuntimeRecordSchema.shape.gatewayType.parse(options.gatewayType);
|
|
121
|
-
|
|
98
|
+
const qemuPid = resolveManagedVmQemuPid(options.managedVm);
|
|
99
|
+
const processIdentityReader = options.readProcessIdentity ?? defaultReadProcessIdentity;
|
|
100
|
+
const processIdentity = await processIdentityReader(qemuPid);
|
|
101
|
+
if (processIdentity === null) {
|
|
102
|
+
throw new Error(`Failed to capture process identity for gateway VM '${options.managedVm.id}' pid ${String(qemuPid)}.`);
|
|
103
|
+
}
|
|
104
|
+
return gatewayRuntimeRecordSchema.parse({
|
|
122
105
|
configPath: options.systemConfigPath,
|
|
123
106
|
controllerPort: options.controllerPort,
|
|
124
107
|
createdAt: new Date().toISOString(),
|
|
125
108
|
gatewayType,
|
|
126
109
|
guestListenPort: options.processSpec.guestListenPort,
|
|
127
110
|
ingressPort: options.ingressPort,
|
|
111
|
+
processIdentity,
|
|
128
112
|
projectNamespace: options.projectNamespace,
|
|
129
|
-
qemuPid
|
|
113
|
+
qemuPid,
|
|
114
|
+
schemaVersion: 1,
|
|
130
115
|
sessionLabel: buildGatewaySessionLabel(options.projectNamespace, options.zoneId),
|
|
131
116
|
vmId: options.managedVm.id,
|
|
132
117
|
zoneId: options.zoneId,
|
|
133
|
-
};
|
|
118
|
+
});
|
|
134
119
|
}
|
|
135
120
|
//# sourceMappingURL=gateway-runtime-record.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-runtime-record.js","sourceRoot":"","sources":["../../src/gateway/gateway-runtime-record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACN,wBAAwB,EACxB,iBAAiB,GAGjB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAkB,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAElC,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"gateway-runtime-record.js","sourceRoot":"","sources":["../../src/gateway/gateway-runtime-record.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import type { GatewayLifecycle, GatewayZoneConfig } from '@agent-vm/gateway-interface';
|
|
2
2
|
import { type ManagedVm } from '@agent-vm/gondolin-adapter';
|
|
3
|
+
import { cleanupOrphanedToolVmsIfPresent } from '../controller/leases/tool-vm-recovery.js';
|
|
3
4
|
import { type GatewayImageBuilderDependencies } from './gateway-image-builder.js';
|
|
4
5
|
import { cleanupOrphanedGatewayIfPresent } from './gateway-recovery.js';
|
|
5
6
|
import { type GatewayRuntimeRecord } from './gateway-runtime-record.js';
|
|
6
7
|
import { type GatewayManagedVmFactoryOptions, type GatewayZoneStartResult, type StartGatewayZoneOptions } from './gateway-zone-support.js';
|
|
7
8
|
export interface GatewayManagerDependencies extends GatewayImageBuilderDependencies {
|
|
8
9
|
readonly cleanupOrphanedGatewayIfPresent?: typeof cleanupOrphanedGatewayIfPresent;
|
|
10
|
+
readonly cleanupOrphanedToolVmsIfPresent?: typeof cleanupOrphanedToolVmsIfPresent;
|
|
9
11
|
readonly createManagedVm?: (options: GatewayManagedVmFactoryOptions) => Promise<ManagedVm>;
|
|
10
12
|
readonly gatewayReadinessMaxAttempts?: number;
|
|
11
13
|
readonly gatewayReadinessRetryDelayMs?: number;
|
|
12
14
|
readonly loadGatewayLifecycle?: (type: GatewayZoneConfig['gateway']['type']) => GatewayLifecycle;
|
|
15
|
+
readonly readProcessIdentity?: (pid: number) => Promise<{
|
|
16
|
+
readonly command: string;
|
|
17
|
+
readonly lstart: string;
|
|
18
|
+
} | null>;
|
|
13
19
|
readonly writeGatewayRuntimeRecord?: (stateDirectory: string, record: GatewayRuntimeRecord) => Promise<void>;
|
|
14
20
|
}
|
|
15
21
|
export declare function startGatewayZone(options: StartGatewayZoneOptions, dependencies?: GatewayManagerDependencies): Promise<GatewayZoneStartResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway-zone-orchestrator.d.ts","sourceRoot":"","sources":["../../src/gateway/gateway-zone-orchestrator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEX,gBAAgB,EAChB,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEN,KAAK,SAAS,EACd,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"gateway-zone-orchestrator.d.ts","sourceRoot":"","sources":["../../src/gateway/gateway-zone-orchestrator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEX,gBAAgB,EAChB,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEN,KAAK,SAAS,EACd,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,+BAA+B,EAAE,MAAM,0CAA0C,CAAC;AAK3F,OAAO,EAEN,KAAK,+BAA+B,EACpC,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAGN,KAAK,oBAAoB,EACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAIN,KAAK,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,MAAM,2BAA2B,CAAC;AASnC,MAAM,WAAW,0BAA2B,SAAQ,+BAA+B;IAClF,QAAQ,CAAC,+BAA+B,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAClF,QAAQ,CAAC,+BAA+B,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAClF,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,8BAA8B,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3F,QAAQ,CAAC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IAC9C,QAAQ,CAAC,4BAA4B,CAAC,EAAE,MAAM,CAAC;IAC/C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,gBAAgB,CAAC;IAGjG,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAC9B,GAAG,EAAE,MAAM,KACP,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC3E,QAAQ,CAAC,yBAAyB,CAAC,EAAE,CACpC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,oBAAoB,KACxB,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAsKD,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,uBAAuB,EAChC,YAAY,GAAE,0BAA+B,GAC3C,OAAO,CAAC,sBAAsB,CAAC,CA0UjC"}
|