vmsan 0.1.0-alpha.14 → 0.1.0-alpha.15
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/_chunks/connect.mjs +55 -11
- package/dist/_chunks/context.mjs +39 -17
- package/dist/_chunks/create.mjs +1 -1
- package/dist/_chunks/download.mjs +4 -19
- package/dist/_chunks/errors.mjs +10 -4
- package/dist/_chunks/network.mjs +1 -1
- package/dist/_chunks/summary.mjs +2 -2
- package/dist/_chunks/upload.mjs +4 -19
- package/dist/_chunks/validation.mjs +1 -1
- package/dist/_chunks/vm-context.mjs +34 -0
- package/dist/_chunks/vm-state.mjs +27 -2
- package/dist/bin/cli.mjs +1 -1
- package/dist/index.d.mts +60 -6
- package/dist/index.mjs +60 -4
- package/package.json +1 -1
- package/dist/_chunks/connect2.mjs +0 -72
package/dist/_chunks/connect.mjs
CHANGED
|
@@ -1,13 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { n as vmsanPaths } from "./paths.mjs";
|
|
2
|
+
import { t as handleCommandError } from "./errors.mjs";
|
|
3
|
+
import { t as createCommandLogger } from "./logger.mjs";
|
|
4
|
+
import "./vm-state.mjs";
|
|
5
|
+
import { n as waitForAgent, t as resolveVmState } from "./vm-context.mjs";
|
|
6
|
+
import { t as ShellSession } from "./shell.mjs";
|
|
7
|
+
import { consola } from "consola";
|
|
8
|
+
import { defineCommand } from "citty";
|
|
9
|
+
const connectCommand = defineCommand({
|
|
10
|
+
meta: {
|
|
11
|
+
name: "connect",
|
|
12
|
+
description: "Connect to a running VM"
|
|
13
|
+
},
|
|
14
|
+
args: {
|
|
15
|
+
vmId: {
|
|
16
|
+
type: "positional",
|
|
17
|
+
description: "VM ID to connect to",
|
|
18
|
+
required: true
|
|
19
|
+
},
|
|
20
|
+
session: {
|
|
21
|
+
type: "string",
|
|
22
|
+
alias: "s",
|
|
23
|
+
description: "Attach to an existing shell session ID",
|
|
24
|
+
required: false
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
async run({ args }) {
|
|
28
|
+
const cmdLog = createCommandLogger("connect");
|
|
29
|
+
const paths = vmsanPaths();
|
|
6
30
|
try {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
31
|
+
const { state, guestIp, port } = resolveVmState(args.vmId, paths);
|
|
32
|
+
const log = consola.withTag(args.vmId);
|
|
33
|
+
consola.debug(`Agent endpoint: ${guestIp}:${port}`);
|
|
34
|
+
log.start("Waiting for agent to become ready...");
|
|
35
|
+
await waitForAgent(guestIp, port);
|
|
36
|
+
log.success("Agent is ready. Connecting via PTY shell...");
|
|
37
|
+
const shell = new ShellSession({
|
|
38
|
+
host: guestIp,
|
|
39
|
+
port,
|
|
40
|
+
token: state.agentToken,
|
|
41
|
+
sessionId: args.session
|
|
42
|
+
});
|
|
43
|
+
const closeInfo = await shell.connect();
|
|
44
|
+
cmdLog.set({
|
|
45
|
+
vmId: args.vmId,
|
|
46
|
+
method: "pty"
|
|
47
|
+
});
|
|
48
|
+
cmdLog.emit();
|
|
49
|
+
if (!closeInfo.sessionDestroyed && shell.sessionId) process.stderr.write(`\n[2mResume this session with:\n vmsan connect ${args.vmId} --session ${shell.sessionId}[0m\n`);
|
|
50
|
+
process.exit(0);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
handleCommandError(error, cmdLog);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
10
55
|
}
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
export { waitForAgent as t };
|
|
56
|
+
});
|
|
57
|
+
export { connectCommand as default };
|
package/dist/_chunks/context.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as vmsanPaths } from "./paths.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { B as mutuallyExclusiveFlagsError, C as vmNotStoppedError, S as vmNotRunningError, U as VmsanError, _ as chrootNotFoundError, a as noKernelDirError, d as socketTimeoutError, i as noExt4RootfsError, o as noKernelError, p as defaultInterfaceNotFoundError, r as missingBinaryError, s as noRootfsDirError, u as lockTimeoutError, x as vmNotFoundError, y as snapshotNotFoundError } from "./errors.mjs";
|
|
3
3
|
import { c as safeKill, f as toError, i as generateVmId, t as FileVmStateStore } from "./vm-state.mjs";
|
|
4
4
|
import { t as FirecrackerClient } from "./firecracker.mjs";
|
|
5
5
|
import { createHooks } from "hookable";
|
|
@@ -1825,6 +1825,37 @@ function ensureSeccompFilter(paths) {
|
|
|
1825
1825
|
return null;
|
|
1826
1826
|
}
|
|
1827
1827
|
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Spawn a detached bash process that kills the VM after timeout.
|
|
1830
|
+
* The process sleeps for the timeout duration, then verifies the VM
|
|
1831
|
+
* is still running with the expected PID before sending SIGTERM.
|
|
1832
|
+
*/
|
|
1833
|
+
function spawnTimeoutKiller(opts) {
|
|
1834
|
+
const { vmId, pid, timeoutMs, stateFile } = opts;
|
|
1835
|
+
const timeoutSec = String(Math.ceil(timeoutMs / 1e3));
|
|
1836
|
+
const killer = spawn("bash", [
|
|
1837
|
+
"-c",
|
|
1838
|
+
[
|
|
1839
|
+
"sleep \"$1\"",
|
|
1840
|
+
"STATE=$(cat -- \"$2\" 2>/dev/null) || exit 0",
|
|
1841
|
+
"echo \"$STATE\" | grep -q '\"status\":\"running\"' || exit 0",
|
|
1842
|
+
"echo \"$STATE\" | grep -q \"\"pid\":$3\" || exit 0",
|
|
1843
|
+
"[ -d \"/proc/$3\" ] || exit 0",
|
|
1844
|
+
"grep -aq -- \"$4\" \"/proc/$3/cmdline\" 2>/dev/null || exit 0",
|
|
1845
|
+
"kill -- \"$3\" 2>/dev/null"
|
|
1846
|
+
].join(" && "),
|
|
1847
|
+
"bash",
|
|
1848
|
+
timeoutSec,
|
|
1849
|
+
stateFile,
|
|
1850
|
+
String(pid),
|
|
1851
|
+
vmId
|
|
1852
|
+
], {
|
|
1853
|
+
detached: true,
|
|
1854
|
+
stdio: "ignore"
|
|
1855
|
+
});
|
|
1856
|
+
killer.unref();
|
|
1857
|
+
return killer;
|
|
1858
|
+
}
|
|
1828
1859
|
var VMService = class {
|
|
1829
1860
|
paths;
|
|
1830
1861
|
store;
|
|
@@ -1988,21 +2019,12 @@ var VMService = class {
|
|
|
1988
2019
|
pid
|
|
1989
2020
|
});
|
|
1990
2021
|
log.success(`VM ${vmId} is running (PID: ${pid || "unknown"})`);
|
|
1991
|
-
if (timeoutMs && pid) {
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
`echo "$STATE" | grep -q '"pid":${pid}' || exit 0`,
|
|
1998
|
-
`[ -d /proc/${pid} ] || exit 0`,
|
|
1999
|
-
`grep -q "${vmId}" /proc/${pid}/cmdline 2>/dev/null || exit 0`,
|
|
2000
|
-
`kill ${pid} 2>/dev/null`
|
|
2001
|
-
].join(" && ")], {
|
|
2002
|
-
detached: true,
|
|
2003
|
-
stdio: "ignore"
|
|
2004
|
-
}).unref();
|
|
2005
|
-
}
|
|
2022
|
+
if (timeoutMs && pid) spawnTimeoutKiller({
|
|
2023
|
+
vmId,
|
|
2024
|
+
pid,
|
|
2025
|
+
timeoutMs,
|
|
2026
|
+
stateFile: join(paths.vmsDir, `${vmId}.json`)
|
|
2027
|
+
});
|
|
2006
2028
|
const finalState = this.store.load(vmId);
|
|
2007
2029
|
await hooks.callHook("vm:afterCreate", finalState);
|
|
2008
2030
|
return {
|
|
@@ -2372,4 +2394,4 @@ async function createVmsan(options) {
|
|
|
2372
2394
|
if (options?.plugins) for (const plugin of options.plugins) await plugin.setup(ctx);
|
|
2373
2395
|
return vmsan;
|
|
2374
2396
|
}
|
|
2375
|
-
export {
|
|
2397
|
+
export { createDefaultLogger as C, NetworkManager as S, validateEnvironment as _, ensureSeccompFilter as a, detectCgroupVersion as b, cleanupChroot as c, markVmAsError as d, assertSnapshotExists as f, getVmPid as g, getVmJailerPid as h, compileSeccompFilter as i, cleanupNetwork as l, findRootfs as m, VMService as n, resolveImageRootfs as o, findKernel as p, spawnTimeoutKiller as r, buildInitialVmState as s, createVmsan as t, killOrphanVmProcess as u, waitForSocket as v, createSilentLogger as w, FileLock as x, Jailer as y };
|
package/dist/_chunks/create.mjs
CHANGED
|
@@ -4,10 +4,10 @@ import { i as initVmsanLogger, n as createScopedLogger, t as createCommandLogger
|
|
|
4
4
|
import "./vm-state.mjs";
|
|
5
5
|
import { t as createVmsan } from "./context.mjs";
|
|
6
6
|
import "./firecracker.mjs";
|
|
7
|
+
import { n as waitForAgent } from "./vm-context.mjs";
|
|
7
8
|
import { t as ShellSession } from "./shell.mjs";
|
|
8
9
|
import { a as parseImageReference, t as parseBandwidth } from "./validation.mjs";
|
|
9
10
|
import { n as parseCreateInput, t as buildCreateSummaryLines } from "./summary.mjs";
|
|
10
|
-
import { t as waitForAgent } from "./connect.mjs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { consola } from "consola";
|
|
13
13
|
import { defineCommand } from "citty";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as vmsanPaths } from "./paths.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { t as handleCommandError } from "./errors.mjs";
|
|
3
3
|
import { t as createCommandLogger } from "./logger.mjs";
|
|
4
|
-
import
|
|
4
|
+
import "./vm-state.mjs";
|
|
5
5
|
import { t as AgentClient } from "./agent.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { n as waitForAgent, t as resolveVmState } from "./vm-context.mjs";
|
|
7
7
|
import { basename, join, resolve } from "node:path";
|
|
8
8
|
import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs";
|
|
9
9
|
import { consola } from "consola";
|
|
@@ -29,23 +29,8 @@ const downloadCommand = defineCommand({
|
|
|
29
29
|
const cmdLog = createCommandLogger("download");
|
|
30
30
|
const paths = vmsanPaths();
|
|
31
31
|
try {
|
|
32
|
-
const state =
|
|
33
|
-
if (!state) throw vmNotFoundError(args.vmId);
|
|
34
|
-
if (state.status !== "running") {
|
|
35
|
-
consola.error(`VM ${args.vmId} is not running (status: ${state.status})`);
|
|
36
|
-
cmdLog.emit();
|
|
37
|
-
process.exitCode = 1;
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (!state.agentToken) {
|
|
41
|
-
consola.error("VM has no agent token. Cannot download files without the agent.");
|
|
42
|
-
cmdLog.emit();
|
|
43
|
-
process.exitCode = 1;
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
32
|
+
const { state, guestIp, port } = resolveVmState(args.vmId, paths);
|
|
46
33
|
const log = consola.withTag(args.vmId);
|
|
47
|
-
const guestIp = state.network.guestIp;
|
|
48
|
-
const port = state.agentPort || paths.agentPort;
|
|
49
34
|
consola.debug(`Agent endpoint: ${guestIp}:${port}`);
|
|
50
35
|
log.start("Waiting for agent...");
|
|
51
36
|
await waitForAgent(guestIp, port);
|
package/dist/_chunks/errors.mjs
CHANGED
|
@@ -122,10 +122,16 @@ const chrootNotFoundError = (vmId) => new VmError("ERR_VM_CHROOT_NOT_FOUND", {
|
|
|
122
122
|
fix: "The VM must be recreated with 'vmsan create'."
|
|
123
123
|
});
|
|
124
124
|
const networkSlotsExhaustedError = () => new VmError("ERR_VM_NETWORK_SLOTS_EXHAUSTED", { message: "No available network slots (max 255 VMs)" });
|
|
125
|
-
const vmNotRunningError = (vmId) => new VmError("ERR_VM_NOT_RUNNING", {
|
|
125
|
+
const vmNotRunningError = (vmId, currentStatus) => new VmError("ERR_VM_NOT_RUNNING", {
|
|
126
126
|
vmId,
|
|
127
|
-
message: `VM ${vmId} is not running`,
|
|
128
|
-
fix: "The VM must be running
|
|
127
|
+
message: currentStatus ? `VM ${vmId} is not running (current status: ${currentStatus})` : `VM ${vmId} is not running`,
|
|
128
|
+
fix: "The VM must be running. Start it with 'vmsan start <vm-id>'."
|
|
129
|
+
});
|
|
130
|
+
const vmNoAgentTokenError = (vmId) => new VmError("ERR_VM_NO_AGENT_TOKEN", {
|
|
131
|
+
vmId,
|
|
132
|
+
message: `VM ${vmId} has no agent token`,
|
|
133
|
+
why: "The vmsan-agent binary was not found at ~/.vmsan/bin/vmsan-agent when this VM was created.",
|
|
134
|
+
fix: "Install the agent binary into ~/.vmsan/bin/vmsan-agent and recreate the VM with 'vmsan create'."
|
|
129
135
|
});
|
|
130
136
|
const snapshotNotFoundError = (snapshotId) => new VmError("ERR_VM_SNAPSHOT_NOT_FOUND", { message: `Snapshot not found: ${snapshotId}` });
|
|
131
137
|
var FirecrackerApiError = class extends VmsanError {
|
|
@@ -229,4 +235,4 @@ function handleCommandError(error, cmdLog) {
|
|
|
229
235
|
if (error.link) consola.log(` More: ${error.link}`);
|
|
230
236
|
} else consola.error(error instanceof Error ? error.message : String(error));
|
|
231
237
|
}
|
|
232
|
-
export {
|
|
238
|
+
export { invalidDiskSizeRangeError as A, mutuallyExclusiveFlagsError as B, vmNotStoppedError as C, invalidCidrOctetError as D, invalidCidrFormatError as E, invalidImageRefTagError as F, portConflictError as H, invalidIntegerFlagError as I, invalidNetworkPolicyError as L, invalidDomainPatternError as M, invalidDurationError as N, invalidCidrPrefixError as O, invalidImageRefEmptyError as P, invalidPortError as R, vmNotRunningError as S, ValidationError as T, VmsanError as U, policyConflictError as V, chrootNotFoundError as _, noKernelDirError as a, vmNoAgentTokenError as b, TimeoutError as c, socketTimeoutError as d, NetworkError as f, VmError as g, firecrackerApiError as h, noExt4RootfsError as i, invalidDomainError as j, invalidDiskSizeFormatError as k, agentTimeoutError as l, FirecrackerApiError as m, SetupError as n, noKernelError as o, defaultInterfaceNotFoundError as p, missingBinaryError as r, noRootfsDirError as s, handleCommandError as t, lockTimeoutError as u, networkSlotsExhaustedError as v, vmStateNotFoundError as w, vmNotFoundError as x, snapshotNotFoundError as y, invalidRuntimeError as z };
|
package/dist/_chunks/network.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./paths.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { V as policyConflictError, t as handleCommandError } from "./errors.mjs";
|
|
3
3
|
import { r as getOutputMode, t as createCommandLogger } from "./logger.mjs";
|
|
4
4
|
import "./vm-state.mjs";
|
|
5
5
|
import { t as createVmsan } from "./context.mjs";
|
package/dist/_chunks/summary.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { V as policyConflictError } from "./errors.mjs";
|
|
2
2
|
import { s as parseDuration } from "./vm-state.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { f as assertSnapshotExists } from "./context.mjs";
|
|
4
4
|
import { c as parsePublishedPorts, d as validateCidr, f as validatePublishedPortsAvailable, i as parseDomains, l as parseRuntime, n as parseCidrList, o as parseMemoryMib, r as parseDiskSizeGb, s as parseNetworkPolicy, u as parseVcpuCount } from "./validation.mjs";
|
|
5
5
|
function parseCreateInput(args, paths) {
|
|
6
6
|
const vcpus = parseVcpuCount(args.vcpus);
|
package/dist/_chunks/upload.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as vmsanPaths } from "./paths.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { t as handleCommandError } from "./errors.mjs";
|
|
3
3
|
import { t as createCommandLogger } from "./logger.mjs";
|
|
4
|
-
import
|
|
4
|
+
import "./vm-state.mjs";
|
|
5
5
|
import { t as AgentClient } from "./agent.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { n as waitForAgent, t as resolveVmState } from "./vm-context.mjs";
|
|
7
7
|
import { basename } from "node:path";
|
|
8
8
|
import { readFileSync } from "node:fs";
|
|
9
9
|
import { consola } from "consola";
|
|
@@ -30,23 +30,8 @@ const uploadCommand = defineCommand({
|
|
|
30
30
|
const cmdLog = createCommandLogger("upload");
|
|
31
31
|
const paths = vmsanPaths();
|
|
32
32
|
try {
|
|
33
|
-
const state =
|
|
34
|
-
if (!state) throw vmNotFoundError(args.vmId);
|
|
35
|
-
if (state.status !== "running") {
|
|
36
|
-
consola.error(`VM ${args.vmId} is not running (status: ${state.status})`);
|
|
37
|
-
cmdLog.emit();
|
|
38
|
-
process.exitCode = 1;
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (!state.agentToken) {
|
|
42
|
-
consola.error("VM has no agent token. Cannot upload files without the agent.");
|
|
43
|
-
cmdLog.emit();
|
|
44
|
-
process.exitCode = 1;
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
33
|
+
const { state, guestIp, port } = resolveVmState(args.vmId, paths);
|
|
47
34
|
const log = consola.withTag(args.vmId);
|
|
48
|
-
const guestIp = state.network.guestIp;
|
|
49
|
-
const port = state.agentPort || paths.agentPort;
|
|
50
35
|
consola.debug(`Agent endpoint: ${guestIp}:${port}`);
|
|
51
36
|
log.start("Waiting for agent...");
|
|
52
37
|
await waitForAgent(guestIp, port);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as invalidDiskSizeRangeError, D as invalidCidrOctetError, E as invalidCidrFormatError, F as invalidImageRefTagError, H as portConflictError, I as invalidIntegerFlagError, L as invalidNetworkPolicyError, M as invalidDomainPatternError, O as invalidCidrPrefixError, P as invalidImageRefEmptyError, R as invalidPortError, j as invalidDomainError, k as invalidDiskSizeFormatError, z as invalidRuntimeError } from "./errors.mjs";
|
|
2
2
|
import { t as FileVmStateStore } from "./vm-state.mjs";
|
|
3
3
|
const VALID_RUNTIMES = [
|
|
4
4
|
"base",
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { S as vmNotRunningError, b as vmNoAgentTokenError, l as agentTimeoutError, x as vmNotFoundError } from "./errors.mjs";
|
|
2
|
+
import { t as FileVmStateStore } from "./vm-state.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* Load VM state and validate it's running with an agent token.
|
|
5
|
+
* Throws VmError on failure (handled by handleCommandError in the caller).
|
|
6
|
+
*/
|
|
7
|
+
function resolveVmState(vmId, paths) {
|
|
8
|
+
const store = new FileVmStateStore(paths.vmsDir);
|
|
9
|
+
const state = store.load(vmId);
|
|
10
|
+
if (!state) throw vmNotFoundError(vmId);
|
|
11
|
+
if (state.status !== "running") throw vmNotRunningError(vmId, state.status);
|
|
12
|
+
if (!state.agentToken) throw vmNoAgentTokenError(vmId);
|
|
13
|
+
return {
|
|
14
|
+
state,
|
|
15
|
+
guestIp: state.network.guestIp,
|
|
16
|
+
port: state.agentPort || paths.agentPort,
|
|
17
|
+
store
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Poll the agent health endpoint until it responds OK.
|
|
22
|
+
*/
|
|
23
|
+
async function waitForAgent(guestIp, port, timeoutMs = 6e4) {
|
|
24
|
+
const start = Date.now();
|
|
25
|
+
const url = `http://${guestIp}:${port}/health`;
|
|
26
|
+
while (Date.now() - start < timeoutMs) {
|
|
27
|
+
try {
|
|
28
|
+
if ((await fetch(url, { signal: AbortSignal.timeout(2e3) })).ok) return;
|
|
29
|
+
} catch {}
|
|
30
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
31
|
+
}
|
|
32
|
+
throw agentTimeoutError(guestIp, timeoutMs);
|
|
33
|
+
}
|
|
34
|
+
export { waitForAgent as n, resolveVmState as t };
|
|
@@ -1,9 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { N as invalidDurationError, v as networkSlotsExhaustedError, w as vmStateNotFoundError } from "./errors.mjs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { execSync } from "node:child_process";
|
|
4
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { chmodSync, chownSync, existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { randomBytes } from "node:crypto";
|
|
6
6
|
import { stripAnsi } from "consola/utils";
|
|
7
|
+
/**
|
|
8
|
+
* Resolve the UID/GID of the real (non-root) user when running under sudo.
|
|
9
|
+
* Returns null when not running under sudo or when env vars are missing.
|
|
10
|
+
*/
|
|
11
|
+
function getSudoOwner() {
|
|
12
|
+
const uid = process.env.SUDO_UID;
|
|
13
|
+
const gid = process.env.SUDO_GID;
|
|
14
|
+
if (!uid || !gid) return null;
|
|
15
|
+
const numUid = Number(uid);
|
|
16
|
+
const numGid = Number(gid);
|
|
17
|
+
if (!Number.isInteger(numUid) || !Number.isInteger(numGid)) return null;
|
|
18
|
+
return {
|
|
19
|
+
uid: numUid,
|
|
20
|
+
gid: numGid
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function chownToSudoUser(path) {
|
|
24
|
+
const owner = getSudoOwner();
|
|
25
|
+
if (!owner) return;
|
|
26
|
+
try {
|
|
27
|
+
chownSync(path, owner.uid, owner.gid);
|
|
28
|
+
} catch {}
|
|
29
|
+
}
|
|
7
30
|
function toError(err) {
|
|
8
31
|
return err instanceof Error ? err : new Error(String(err));
|
|
9
32
|
}
|
|
@@ -83,6 +106,7 @@ function mkdirSecure(path) {
|
|
|
83
106
|
} catch (error) {
|
|
84
107
|
if (error.code !== "ENOENT") throw error;
|
|
85
108
|
}
|
|
109
|
+
chownToSudoUser(path);
|
|
86
110
|
}
|
|
87
111
|
function writeSecure(path, contents) {
|
|
88
112
|
writeFileSync(path, contents, { mode: 384 });
|
|
@@ -91,6 +115,7 @@ function writeSecure(path, contents) {
|
|
|
91
115
|
} catch (error) {
|
|
92
116
|
if (error.code !== "ENOENT") throw error;
|
|
93
117
|
}
|
|
118
|
+
chownToSudoUser(path);
|
|
94
119
|
}
|
|
95
120
|
const TIME_UNITS = [
|
|
96
121
|
[
|
package/dist/bin/cli.mjs
CHANGED
|
@@ -56,7 +56,7 @@ runMain(defineCommand({
|
|
|
56
56
|
stop: () => import("../_chunks/stop.mjs").then((m) => m.default),
|
|
57
57
|
remove: () => import("../_chunks/remove.mjs").then((m) => m.default),
|
|
58
58
|
rm: () => import("../_chunks/remove.mjs").then((m) => m.default),
|
|
59
|
-
connect: () => import("../_chunks/
|
|
59
|
+
connect: () => import("../_chunks/connect.mjs").then((m) => m.default),
|
|
60
60
|
upload: () => import("../_chunks/upload.mjs").then((m) => m.default),
|
|
61
61
|
download: () => import("../_chunks/download.mjs").then((m) => m.default),
|
|
62
62
|
network: () => import("../_chunks/network.mjs").then((m) => m.default)
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Hookable } from "hookable";
|
|
2
|
+
import { ChildProcess } from "node:child_process";
|
|
2
3
|
import { ErrorOptions, EvlogError, RequestLogger } from "evlog";
|
|
3
4
|
import { ConsolaInstance } from "consola";
|
|
4
5
|
|
|
@@ -213,7 +214,7 @@ declare function parseDiskSizeGb(value: string | undefined): number;
|
|
|
213
214
|
//#endregion
|
|
214
215
|
//#region src/errors/codes.d.ts
|
|
215
216
|
type ValidationErrorCode = "ERR_VALIDATION_INTEGER" | "ERR_VALIDATION_RUNTIME" | "ERR_VALIDATION_NETWORK_POLICY" | "ERR_VALIDATION_PORT" | "ERR_VALIDATION_PORT_CONFLICT" | "ERR_VALIDATION_DOMAIN" | "ERR_VALIDATION_CIDR" | "ERR_VALIDATION_IMAGE_REF" | "ERR_VALIDATION_DISK_SIZE" | "ERR_VALIDATION_DURATION" | "ERR_VALIDATION_FLAGS" | "ERR_VALIDATION_POLICY_CONFLICT";
|
|
216
|
-
type VmErrorCode = "ERR_VM_NOT_FOUND" | "ERR_VM_STATE_NOT_FOUND" | "ERR_VM_NOT_STOPPED" | "ERR_VM_NOT_RUNNING" | "ERR_VM_CHROOT_NOT_FOUND" | "ERR_VM_NETWORK_SLOTS_EXHAUSTED" | "ERR_VM_SNAPSHOT_NOT_FOUND";
|
|
217
|
+
type VmErrorCode = "ERR_VM_NOT_FOUND" | "ERR_VM_STATE_NOT_FOUND" | "ERR_VM_NOT_STOPPED" | "ERR_VM_NOT_RUNNING" | "ERR_VM_NO_AGENT_TOKEN" | "ERR_VM_CHROOT_NOT_FOUND" | "ERR_VM_NETWORK_SLOTS_EXHAUSTED" | "ERR_VM_SNAPSHOT_NOT_FOUND";
|
|
217
218
|
type FirecrackerErrorCode = "ERR_FIRECRACKER_API";
|
|
218
219
|
type NetworkErrorCode = "ERR_NETWORK_DEFAULT_INTERFACE";
|
|
219
220
|
type TimeoutErrorCode = "ERR_TIMEOUT_SOCKET" | "ERR_TIMEOUT_LOCK" | "ERR_TIMEOUT_AGENT";
|
|
@@ -266,7 +267,8 @@ declare const vmStateNotFoundError: (vmId: string) => VmError;
|
|
|
266
267
|
declare const vmNotStoppedError: (vmId: string, currentStatus: string) => VmError;
|
|
267
268
|
declare const chrootNotFoundError: (vmId: string) => VmError;
|
|
268
269
|
declare const networkSlotsExhaustedError: () => VmError;
|
|
269
|
-
declare const vmNotRunningError: (vmId: string) => VmError;
|
|
270
|
+
declare const vmNotRunningError: (vmId: string, currentStatus?: string) => VmError;
|
|
271
|
+
declare const vmNoAgentTokenError: (vmId: string) => VmError;
|
|
270
272
|
declare const snapshotNotFoundError: (snapshotId: string) => VmError;
|
|
271
273
|
//#endregion
|
|
272
274
|
//#region src/errors/firecracker.d.ts
|
|
@@ -2822,6 +2824,61 @@ declare class AgentClient {
|
|
|
2822
2824
|
readFile(path: string): Promise<Buffer | null>;
|
|
2823
2825
|
}
|
|
2824
2826
|
//#endregion
|
|
2827
|
+
//#region src/lib/timeout-extender.d.ts
|
|
2828
|
+
interface TimeoutExtenderOptions {
|
|
2829
|
+
vmId: string;
|
|
2830
|
+
store: VmStateStore;
|
|
2831
|
+
paths: VmsanPaths;
|
|
2832
|
+
intervalMs?: number;
|
|
2833
|
+
signal?: AbortSignal;
|
|
2834
|
+
}
|
|
2835
|
+
declare class TimeoutExtender {
|
|
2836
|
+
private _timer;
|
|
2837
|
+
private _previousKillerPid;
|
|
2838
|
+
private readonly _vmId;
|
|
2839
|
+
private readonly _store;
|
|
2840
|
+
private readonly _paths;
|
|
2841
|
+
private readonly _intervalMs;
|
|
2842
|
+
private readonly _signal?;
|
|
2843
|
+
constructor(opts: TimeoutExtenderOptions);
|
|
2844
|
+
start(): void;
|
|
2845
|
+
stop(): void;
|
|
2846
|
+
private _extend;
|
|
2847
|
+
}
|
|
2848
|
+
//#endregion
|
|
2849
|
+
//#region src/lib/timeout-killer.d.ts
|
|
2850
|
+
interface SpawnTimeoutKillerOpts {
|
|
2851
|
+
vmId: string;
|
|
2852
|
+
pid: number;
|
|
2853
|
+
timeoutMs: number;
|
|
2854
|
+
stateFile: string;
|
|
2855
|
+
}
|
|
2856
|
+
/**
|
|
2857
|
+
* Spawn a detached bash process that kills the VM after timeout.
|
|
2858
|
+
* The process sleeps for the timeout duration, then verifies the VM
|
|
2859
|
+
* is still running with the expected PID before sending SIGTERM.
|
|
2860
|
+
*/
|
|
2861
|
+
declare function spawnTimeoutKiller(opts: SpawnTimeoutKillerOpts): ChildProcess;
|
|
2862
|
+
//#endregion
|
|
2863
|
+
//#region src/lib/vm-context.d.ts
|
|
2864
|
+
interface RunningVmContext {
|
|
2865
|
+
state: VmState & {
|
|
2866
|
+
agentToken: string;
|
|
2867
|
+
};
|
|
2868
|
+
guestIp: string;
|
|
2869
|
+
port: number;
|
|
2870
|
+
store: FileVmStateStore;
|
|
2871
|
+
}
|
|
2872
|
+
/**
|
|
2873
|
+
* Load VM state and validate it's running with an agent token.
|
|
2874
|
+
* Throws VmError on failure (handled by handleCommandError in the caller).
|
|
2875
|
+
*/
|
|
2876
|
+
declare function resolveVmState(vmId: string, paths: VmsanPaths): RunningVmContext;
|
|
2877
|
+
/**
|
|
2878
|
+
* Poll the agent health endpoint until it responds OK.
|
|
2879
|
+
*/
|
|
2880
|
+
declare function waitForAgent(guestIp: string, port: number, timeoutMs?: number): Promise<void>;
|
|
2881
|
+
//#endregion
|
|
2825
2882
|
//#region src/stores/memory.d.ts
|
|
2826
2883
|
declare class MemoryVmStateStore implements VmStateStore {
|
|
2827
2884
|
private states;
|
|
@@ -3006,9 +3063,6 @@ declare function waitForSocket(socketPath: string, timeoutMs?: number): Promise<
|
|
|
3006
3063
|
declare function getVmPid(vmId: string): number | null;
|
|
3007
3064
|
declare function getVmJailerPid(vmId: string): number | null;
|
|
3008
3065
|
//#endregion
|
|
3009
|
-
//#region src/commands/create/connect.d.ts
|
|
3010
|
-
declare function waitForAgent(guestIp: string, port: number, timeoutMs?: number): Promise<void>;
|
|
3011
|
-
//#endregion
|
|
3012
3066
|
//#region src/commands/create/cleanup.d.ts
|
|
3013
3067
|
declare function killOrphanVmProcess(vmId: string): void;
|
|
3014
3068
|
declare function markVmAsError(vmId: string, error: unknown, paths: VmsanPaths): void;
|
|
@@ -3038,4 +3092,4 @@ declare function resolveImageRootfs(imageRef: ImageReference, registryDir: strin
|
|
|
3038
3092
|
//#region src/index.d.ts
|
|
3039
3093
|
declare function getFirecrackerVersion(dir?: string): Promise<string | undefined>;
|
|
3040
3094
|
//#endregion
|
|
3041
|
-
export { AgentClient, type CgroupConfig, type CommandLogger, type CreateCommandRuntimeArgs, type CreateLifecycleState, type CreateSummaryInput, type CreateVmOptions, type CreateVmResult, FileLock, FileVmStateStore, FirecrackerApiError, FirecrackerClient, type components as FirecrackerComponents, type FirecrackerErrorCode, type paths as FirecrackerPaths, type ImageReference, type InitialVmStateInput, Jailer, type JailerPaths, MemoryVmStateStore, type NetworkConfig, NetworkError, type NetworkErrorCode, NetworkManager, type NetworkPolicy, type OutputMode, type ParsedCreateInput, PidFile, type PrepareChrootConfig, type RunEvent, type RunParams, type Runtime, type SessionInfo, SetupError, type SetupErrorCode, ShellSession, type ShellSessionOptions, type SpawnJailerConfig, type StartVmResult, type StopResult, TimeoutError, type TimeoutErrorCode, type UpdatePolicyResult, type VALID_NETWORK_POLICIES, type VALID_RUNTIMES, VMService, ValidationError, type ValidationErrorCode, VmError, type VmErrorCode, type VmNetwork, type VmPhase, type VmState, type VmStateStore, type VmsanContext, VmsanError, type VmsanErrorCode, type VmsanHooks, type VmsanLogger, type VmsanOptions, type VmsanPaths, type VmsanPlugin, type WriteFileEntry, agentTimeoutError, buildCreateSummaryLines, buildInitialVmState, chrootNotFoundError, cleanupChroot, cleanupNetwork, compileSeccompFilter, connectShell, createCommandLogger, createDefaultLogger, createScopedLogger, createSilentLogger, createVmsan, defaultInterfaceNotFoundError, definePlugin, detectCgroupVersion, ensureSeccompFilter, findFreeNetworkSlot, findKernel, findRootfs, firecrackerApiError, firecrackerFetch, generateVmId, getActiveTapSlots, getFirecrackerVersion, getOutputMode, getVmJailerPid, getVmPid, handleCommandError, initVmsanLogger, invalidCidrFormatError, invalidCidrOctetError, invalidCidrPrefixError, invalidDiskSizeFormatError, invalidDiskSizeRangeError, invalidDomainError, invalidDomainPatternError, invalidDurationError, invalidImageRefEmptyError, invalidImageRefTagError, invalidIntegerFlagError, invalidNetworkPolicyError, invalidPortError, invalidRuntimeError, isProcessAlive, killOrphanVmProcess, lockTimeoutError, markVmAsError, missingBinaryError, mkdirSecure, mutuallyExclusiveFlagsError, networkSlotsExhaustedError, noExt4RootfsError, noKernelDirError, noKernelError, noRootfsDirError, parseBandwidth, parseCidrList, parseCreateInput, parseDiskSizeGb, parseDomains, parseDuration, parseImageReference, parseMemoryMib, parseNetworkPolicy, parsePublishedPorts, parseRuntime, parseVcpuCount, policyConflictError, portConflictError, resolveImageRootfs, safeKill, snapshotNotFoundError, socketTimeoutError, table, timeAgo, timeRemaining, toError, validateCidr, validateEnvironment, validatePublishedPortsAvailable, vmNotFoundError, vmNotRunningError, vmNotStoppedError, vmStateNotFoundError, vmsanPaths, waitForAgent, waitForSocket, writeSecure };
|
|
3095
|
+
export { AgentClient, type CgroupConfig, type CommandLogger, type CreateCommandRuntimeArgs, type CreateLifecycleState, type CreateSummaryInput, type CreateVmOptions, type CreateVmResult, FileLock, FileVmStateStore, FirecrackerApiError, FirecrackerClient, type components as FirecrackerComponents, type FirecrackerErrorCode, type paths as FirecrackerPaths, type ImageReference, type InitialVmStateInput, Jailer, type JailerPaths, MemoryVmStateStore, type NetworkConfig, NetworkError, type NetworkErrorCode, NetworkManager, type NetworkPolicy, type OutputMode, type ParsedCreateInput, PidFile, type PrepareChrootConfig, type RunEvent, type RunParams, type RunningVmContext, type Runtime, type SessionInfo, SetupError, type SetupErrorCode, ShellSession, type ShellSessionOptions, type SpawnJailerConfig, type SpawnTimeoutKillerOpts, type StartVmResult, type StopResult, TimeoutError, type TimeoutErrorCode, TimeoutExtender, type TimeoutExtenderOptions, type UpdatePolicyResult, type VALID_NETWORK_POLICIES, type VALID_RUNTIMES, VMService, ValidationError, type ValidationErrorCode, VmError, type VmErrorCode, type VmNetwork, type VmPhase, type VmState, type VmStateStore, type VmsanContext, VmsanError, type VmsanErrorCode, type VmsanHooks, type VmsanLogger, type VmsanOptions, type VmsanPaths, type VmsanPlugin, type WriteFileEntry, agentTimeoutError, buildCreateSummaryLines, buildInitialVmState, chrootNotFoundError, cleanupChroot, cleanupNetwork, compileSeccompFilter, connectShell, createCommandLogger, createDefaultLogger, createScopedLogger, createSilentLogger, createVmsan, defaultInterfaceNotFoundError, definePlugin, detectCgroupVersion, ensureSeccompFilter, findFreeNetworkSlot, findKernel, findRootfs, firecrackerApiError, firecrackerFetch, generateVmId, getActiveTapSlots, getFirecrackerVersion, getOutputMode, getVmJailerPid, getVmPid, handleCommandError, initVmsanLogger, invalidCidrFormatError, invalidCidrOctetError, invalidCidrPrefixError, invalidDiskSizeFormatError, invalidDiskSizeRangeError, invalidDomainError, invalidDomainPatternError, invalidDurationError, invalidImageRefEmptyError, invalidImageRefTagError, invalidIntegerFlagError, invalidNetworkPolicyError, invalidPortError, invalidRuntimeError, isProcessAlive, killOrphanVmProcess, lockTimeoutError, markVmAsError, missingBinaryError, mkdirSecure, mutuallyExclusiveFlagsError, networkSlotsExhaustedError, noExt4RootfsError, noKernelDirError, noKernelError, noRootfsDirError, parseBandwidth, parseCidrList, parseCreateInput, parseDiskSizeGb, parseDomains, parseDuration, parseImageReference, parseMemoryMib, parseNetworkPolicy, parsePublishedPorts, parseRuntime, parseVcpuCount, policyConflictError, portConflictError, resolveImageRootfs, resolveVmState, safeKill, snapshotNotFoundError, socketTimeoutError, spawnTimeoutKiller, table, timeAgo, timeRemaining, toError, validateCidr, validateEnvironment, validatePublishedPortsAvailable, vmNoAgentTokenError, vmNotFoundError, vmNotRunningError, vmNotStoppedError, vmStateNotFoundError, vmsanPaths, waitForAgent, waitForSocket, writeSecure };
|
package/dist/index.mjs
CHANGED
|
@@ -1,18 +1,74 @@
|
|
|
1
1
|
import { n as vmsanPaths } from "./_chunks/paths.mjs";
|
|
2
|
-
import { A as
|
|
2
|
+
import { A as invalidDiskSizeRangeError, B as mutuallyExclusiveFlagsError, C as vmNotStoppedError, D as invalidCidrOctetError, E as invalidCidrFormatError, F as invalidImageRefTagError, H as portConflictError, I as invalidIntegerFlagError, L as invalidNetworkPolicyError, M as invalidDomainPatternError, N as invalidDurationError, O as invalidCidrPrefixError, P as invalidImageRefEmptyError, R as invalidPortError, S as vmNotRunningError, T as ValidationError, U as VmsanError, V as policyConflictError, _ as chrootNotFoundError, a as noKernelDirError, b as vmNoAgentTokenError, c as TimeoutError, d as socketTimeoutError, f as NetworkError, g as VmError, h as firecrackerApiError, i as noExt4RootfsError, j as invalidDomainError, k as invalidDiskSizeFormatError, l as agentTimeoutError, m as FirecrackerApiError, n as SetupError, o as noKernelError, p as defaultInterfaceNotFoundError, r as missingBinaryError, s as noRootfsDirError, t as handleCommandError, u as lockTimeoutError, v as networkSlotsExhaustedError, w as vmStateNotFoundError, x as vmNotFoundError, y as snapshotNotFoundError, z as invalidRuntimeError } from "./_chunks/errors.mjs";
|
|
3
3
|
import { i as initVmsanLogger, n as createScopedLogger, r as getOutputMode, t as createCommandLogger } from "./_chunks/logger.mjs";
|
|
4
4
|
import { a as isProcessAlive, c as safeKill, d as timeRemaining, f as toError, i as generateVmId, l as table, n as findFreeNetworkSlot, o as mkdirSecure, p as writeSecure, r as getActiveTapSlots, s as parseDuration, t as FileVmStateStore, u as timeAgo } from "./_chunks/vm-state.mjs";
|
|
5
|
-
import { C as
|
|
5
|
+
import { C as createDefaultLogger, S as NetworkManager, _ as validateEnvironment, a as ensureSeccompFilter, b as detectCgroupVersion, c as cleanupChroot, d as markVmAsError, g as getVmPid, h as getVmJailerPid, i as compileSeccompFilter, l as cleanupNetwork, m as findRootfs, n as VMService, o as resolveImageRootfs, p as findKernel, r as spawnTimeoutKiller, s as buildInitialVmState, t as createVmsan, u as killOrphanVmProcess, v as waitForSocket, w as createSilentLogger, x as FileLock, y as Jailer } from "./_chunks/context.mjs";
|
|
6
6
|
import { n as firecrackerFetch, t as FirecrackerClient } from "./_chunks/firecracker.mjs";
|
|
7
7
|
import { t as AgentClient } from "./_chunks/agent.mjs";
|
|
8
|
+
import { n as waitForAgent, t as resolveVmState } from "./_chunks/vm-context.mjs";
|
|
8
9
|
import { n as connectShell, t as ShellSession } from "./_chunks/shell.mjs";
|
|
9
10
|
import { a as parseImageReference, c as parsePublishedPorts, d as validateCidr, f as validatePublishedPortsAvailable, i as parseDomains, l as parseRuntime, n as parseCidrList, o as parseMemoryMib, r as parseDiskSizeGb, s as parseNetworkPolicy, t as parseBandwidth, u as parseVcpuCount } from "./_chunks/validation.mjs";
|
|
10
11
|
import { n as parseCreateInput, t as buildCreateSummaryLines } from "./_chunks/summary.mjs";
|
|
11
|
-
import {
|
|
12
|
+
import { join } from "node:path";
|
|
12
13
|
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
13
14
|
function definePlugin(plugin) {
|
|
14
15
|
return plugin;
|
|
15
16
|
}
|
|
17
|
+
const DEFAULT_INTERVAL_MS = 300 * 1e3;
|
|
18
|
+
var TimeoutExtender = class {
|
|
19
|
+
_timer = null;
|
|
20
|
+
_previousKillerPid = null;
|
|
21
|
+
_vmId;
|
|
22
|
+
_store;
|
|
23
|
+
_paths;
|
|
24
|
+
_intervalMs;
|
|
25
|
+
_signal;
|
|
26
|
+
constructor(opts) {
|
|
27
|
+
this._vmId = opts.vmId;
|
|
28
|
+
this._store = opts.store;
|
|
29
|
+
this._paths = opts.paths;
|
|
30
|
+
this._intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
31
|
+
this._signal = opts.signal;
|
|
32
|
+
}
|
|
33
|
+
start() {
|
|
34
|
+
if (this._timer) return;
|
|
35
|
+
if (this._signal) {
|
|
36
|
+
this._signal.addEventListener("abort", () => this.stop(), { once: true });
|
|
37
|
+
if (this._signal.aborted) {
|
|
38
|
+
this.stop();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
this._extend();
|
|
43
|
+
this._timer = setInterval(() => this._extend(), this._intervalMs);
|
|
44
|
+
}
|
|
45
|
+
stop() {
|
|
46
|
+
if (this._timer) {
|
|
47
|
+
clearInterval(this._timer);
|
|
48
|
+
this._timer = null;
|
|
49
|
+
}
|
|
50
|
+
if (this._previousKillerPid !== null) {
|
|
51
|
+
safeKill(this._previousKillerPid);
|
|
52
|
+
this._previousKillerPid = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
_extend() {
|
|
56
|
+
const state = this._store.load(this._vmId);
|
|
57
|
+
if (!state || state.status !== "running" || !state.timeoutMs) return;
|
|
58
|
+
const timeoutAt = new Date(Date.now() + state.timeoutMs).toISOString();
|
|
59
|
+
this._store.update(this._vmId, { timeoutAt });
|
|
60
|
+
if (this._previousKillerPid !== null) {
|
|
61
|
+
safeKill(this._previousKillerPid);
|
|
62
|
+
this._previousKillerPid = null;
|
|
63
|
+
}
|
|
64
|
+
if (state.pid) this._previousKillerPid = spawnTimeoutKiller({
|
|
65
|
+
vmId: this._vmId,
|
|
66
|
+
pid: state.pid,
|
|
67
|
+
timeoutMs: state.timeoutMs,
|
|
68
|
+
stateFile: join(this._paths.vmsDir, `${this._vmId}.json`)
|
|
69
|
+
}).pid ?? null;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
16
72
|
var MemoryVmStateStore = class {
|
|
17
73
|
states = /* @__PURE__ */ new Map();
|
|
18
74
|
save(state) {
|
|
@@ -64,4 +120,4 @@ async function getFirecrackerVersion(dir) {
|
|
|
64
120
|
const { FirecrackerClient: FC } = await import("./_chunks/firecracker.mjs").then((n) => n.r);
|
|
65
121
|
return FC.getVersion(dir || paths().baseDir);
|
|
66
122
|
}
|
|
67
|
-
export { AgentClient, FileLock, FileVmStateStore, FirecrackerApiError, FirecrackerClient, Jailer, MemoryVmStateStore, NetworkError, NetworkManager, PidFile, SetupError, ShellSession, TimeoutError, VMService, ValidationError, VmError, VmsanError, agentTimeoutError, buildCreateSummaryLines, buildInitialVmState, chrootNotFoundError, cleanupChroot, cleanupNetwork, compileSeccompFilter, connectShell, createCommandLogger, createDefaultLogger, createScopedLogger, createSilentLogger, createVmsan, defaultInterfaceNotFoundError, definePlugin, detectCgroupVersion, ensureSeccompFilter, findFreeNetworkSlot, findKernel, findRootfs, firecrackerApiError, firecrackerFetch, generateVmId, getActiveTapSlots, getFirecrackerVersion, getOutputMode, getVmJailerPid, getVmPid, handleCommandError, initVmsanLogger, invalidCidrFormatError, invalidCidrOctetError, invalidCidrPrefixError, invalidDiskSizeFormatError, invalidDiskSizeRangeError, invalidDomainError, invalidDomainPatternError, invalidDurationError, invalidImageRefEmptyError, invalidImageRefTagError, invalidIntegerFlagError, invalidNetworkPolicyError, invalidPortError, invalidRuntimeError, isProcessAlive, killOrphanVmProcess, lockTimeoutError, markVmAsError, missingBinaryError, mkdirSecure, mutuallyExclusiveFlagsError, networkSlotsExhaustedError, noExt4RootfsError, noKernelDirError, noKernelError, noRootfsDirError, parseBandwidth, parseCidrList, parseCreateInput, parseDiskSizeGb, parseDomains, parseDuration, parseImageReference, parseMemoryMib, parseNetworkPolicy, parsePublishedPorts, parseRuntime, parseVcpuCount, policyConflictError, portConflictError, resolveImageRootfs, safeKill, snapshotNotFoundError, socketTimeoutError, table, timeAgo, timeRemaining, toError, validateCidr, validateEnvironment, validatePublishedPortsAvailable, vmNotFoundError, vmNotRunningError, vmNotStoppedError, vmStateNotFoundError, vmsanPaths, waitForAgent, waitForSocket, writeSecure };
|
|
123
|
+
export { AgentClient, FileLock, FileVmStateStore, FirecrackerApiError, FirecrackerClient, Jailer, MemoryVmStateStore, NetworkError, NetworkManager, PidFile, SetupError, ShellSession, TimeoutError, TimeoutExtender, VMService, ValidationError, VmError, VmsanError, agentTimeoutError, buildCreateSummaryLines, buildInitialVmState, chrootNotFoundError, cleanupChroot, cleanupNetwork, compileSeccompFilter, connectShell, createCommandLogger, createDefaultLogger, createScopedLogger, createSilentLogger, createVmsan, defaultInterfaceNotFoundError, definePlugin, detectCgroupVersion, ensureSeccompFilter, findFreeNetworkSlot, findKernel, findRootfs, firecrackerApiError, firecrackerFetch, generateVmId, getActiveTapSlots, getFirecrackerVersion, getOutputMode, getVmJailerPid, getVmPid, handleCommandError, initVmsanLogger, invalidCidrFormatError, invalidCidrOctetError, invalidCidrPrefixError, invalidDiskSizeFormatError, invalidDiskSizeRangeError, invalidDomainError, invalidDomainPatternError, invalidDurationError, invalidImageRefEmptyError, invalidImageRefTagError, invalidIntegerFlagError, invalidNetworkPolicyError, invalidPortError, invalidRuntimeError, isProcessAlive, killOrphanVmProcess, lockTimeoutError, markVmAsError, missingBinaryError, mkdirSecure, mutuallyExclusiveFlagsError, networkSlotsExhaustedError, noExt4RootfsError, noKernelDirError, noKernelError, noRootfsDirError, parseBandwidth, parseCidrList, parseCreateInput, parseDiskSizeGb, parseDomains, parseDuration, parseImageReference, parseMemoryMib, parseNetworkPolicy, parsePublishedPorts, parseRuntime, parseVcpuCount, policyConflictError, portConflictError, resolveImageRootfs, resolveVmState, safeKill, snapshotNotFoundError, socketTimeoutError, spawnTimeoutKiller, table, timeAgo, timeRemaining, toError, validateCidr, validateEnvironment, validatePublishedPortsAvailable, vmNoAgentTokenError, vmNotFoundError, vmNotRunningError, vmNotStoppedError, vmStateNotFoundError, vmsanPaths, waitForAgent, waitForSocket, writeSecure };
|
package/package.json
CHANGED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { n as vmsanPaths } from "./paths.mjs";
|
|
2
|
-
import { b as vmNotFoundError, t as handleCommandError } from "./errors.mjs";
|
|
3
|
-
import { t as createCommandLogger } from "./logger.mjs";
|
|
4
|
-
import { t as FileVmStateStore } from "./vm-state.mjs";
|
|
5
|
-
import { t as ShellSession } from "./shell.mjs";
|
|
6
|
-
import { t as waitForAgent } from "./connect.mjs";
|
|
7
|
-
import { consola } from "consola";
|
|
8
|
-
import { defineCommand } from "citty";
|
|
9
|
-
const connectCommand = defineCommand({
|
|
10
|
-
meta: {
|
|
11
|
-
name: "connect",
|
|
12
|
-
description: "Connect to a running VM"
|
|
13
|
-
},
|
|
14
|
-
args: {
|
|
15
|
-
vmId: {
|
|
16
|
-
type: "positional",
|
|
17
|
-
description: "VM ID to connect to",
|
|
18
|
-
required: true
|
|
19
|
-
},
|
|
20
|
-
session: {
|
|
21
|
-
type: "string",
|
|
22
|
-
alias: "s",
|
|
23
|
-
description: "Attach to an existing shell session ID",
|
|
24
|
-
required: false
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
async run({ args }) {
|
|
28
|
-
const cmdLog = createCommandLogger("connect");
|
|
29
|
-
const paths = vmsanPaths();
|
|
30
|
-
try {
|
|
31
|
-
const state = new FileVmStateStore(paths.vmsDir).load(args.vmId);
|
|
32
|
-
if (!state) throw vmNotFoundError(args.vmId);
|
|
33
|
-
if (state.status !== "running") {
|
|
34
|
-
consola.error(`VM ${args.vmId} is not running (status: ${state.status})`);
|
|
35
|
-
cmdLog.emit();
|
|
36
|
-
process.exitCode = 1;
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const log = consola.withTag(args.vmId);
|
|
40
|
-
const guestIp = state.network.guestIp;
|
|
41
|
-
const port = state.agentPort || paths.agentPort;
|
|
42
|
-
consola.debug(`Agent endpoint: ${guestIp}:${port}`);
|
|
43
|
-
if (!state.agentToken) {
|
|
44
|
-
consola.error(`VM ${args.vmId} has no agent token. The agent is required for shell access.`);
|
|
45
|
-
cmdLog.emit();
|
|
46
|
-
process.exitCode = 1;
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
log.start("Waiting for agent to become ready...");
|
|
50
|
-
await waitForAgent(guestIp, port);
|
|
51
|
-
log.success("Agent is ready. Connecting via PTY shell...");
|
|
52
|
-
const shell = new ShellSession({
|
|
53
|
-
host: guestIp,
|
|
54
|
-
port,
|
|
55
|
-
token: state.agentToken,
|
|
56
|
-
sessionId: args.session
|
|
57
|
-
});
|
|
58
|
-
const closeInfo = await shell.connect();
|
|
59
|
-
cmdLog.set({
|
|
60
|
-
vmId: args.vmId,
|
|
61
|
-
method: "pty"
|
|
62
|
-
});
|
|
63
|
-
cmdLog.emit();
|
|
64
|
-
if (!closeInfo.sessionDestroyed && shell.sessionId) process.stderr.write(`\n[2mResume this session with:\n vmsan connect ${args.vmId} --session ${shell.sessionId}[0m\n`);
|
|
65
|
-
process.exit(0);
|
|
66
|
-
} catch (error) {
|
|
67
|
-
handleCommandError(error, cmdLog);
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
export { connectCommand as default };
|