rightsize 0.1.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/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +255 -0
- package/dist/backend-docker/backend.d.ts +53 -0
- package/dist/backend-docker/backend.d.ts.map +1 -0
- package/dist/backend-docker/backend.js +336 -0
- package/dist/backend-docker/backend.js.map +1 -0
- package/dist/backend-docker/client.d.ts +82 -0
- package/dist/backend-docker/client.d.ts.map +1 -0
- package/dist/backend-docker/client.js +190 -0
- package/dist/backend-docker/client.js.map +1 -0
- package/dist/backend-docker/frames.d.ts +44 -0
- package/dist/backend-docker/frames.d.ts.map +1 -0
- package/dist/backend-docker/frames.js +105 -0
- package/dist/backend-docker/frames.js.map +1 -0
- package/dist/backend-docker/index.d.ts +5 -0
- package/dist/backend-docker/index.d.ts.map +1 -0
- package/dist/backend-docker/index.js +20 -0
- package/dist/backend-docker/index.js.map +1 -0
- package/dist/backend-docker/json.d.ts +13 -0
- package/dist/backend-docker/json.d.ts.map +1 -0
- package/dist/backend-docker/json.js +47 -0
- package/dist/backend-docker/json.js.map +1 -0
- package/dist/backend-docker/labels.d.ts +11 -0
- package/dist/backend-docker/labels.d.ts.map +1 -0
- package/dist/backend-docker/labels.js +13 -0
- package/dist/backend-docker/labels.js.map +1 -0
- package/dist/backend-docker/port-conflict.d.ts +9 -0
- package/dist/backend-docker/port-conflict.d.ts.map +1 -0
- package/dist/backend-docker/port-conflict.js +12 -0
- package/dist/backend-docker/port-conflict.js.map +1 -0
- package/dist/backend-docker/provider.d.ts +22 -0
- package/dist/backend-docker/provider.d.ts.map +1 -0
- package/dist/backend-docker/provider.js +36 -0
- package/dist/backend-docker/provider.js.map +1 -0
- package/dist/backend-msb/backend.d.ts +169 -0
- package/dist/backend-msb/backend.d.ts.map +1 -0
- package/dist/backend-msb/backend.js +664 -0
- package/dist/backend-msb/backend.js.map +1 -0
- package/dist/backend-msb/commands.d.ts +28 -0
- package/dist/backend-msb/commands.d.ts.map +1 -0
- package/dist/backend-msb/commands.js +67 -0
- package/dist/backend-msb/commands.js.map +1 -0
- package/dist/backend-msb/exec-tunnel.d.ts +33 -0
- package/dist/backend-msb/exec-tunnel.d.ts.map +1 -0
- package/dist/backend-msb/exec-tunnel.js +163 -0
- package/dist/backend-msb/exec-tunnel.js.map +1 -0
- package/dist/backend-msb/follow-replay.d.ts +14 -0
- package/dist/backend-msb/follow-replay.d.ts.map +1 -0
- package/dist/backend-msb/follow-replay.js +20 -0
- package/dist/backend-msb/follow-replay.js.map +1 -0
- package/dist/backend-msb/image-cache.d.ts +25 -0
- package/dist/backend-msb/image-cache.d.ts.map +1 -0
- package/dist/backend-msb/image-cache.js +27 -0
- package/dist/backend-msb/image-cache.js.map +1 -0
- package/dist/backend-msb/index.d.ts +6 -0
- package/dist/backend-msb/index.d.ts.map +1 -0
- package/dist/backend-msb/index.js +21 -0
- package/dist/backend-msb/index.js.map +1 -0
- package/dist/backend-msb/invoke.d.ts +24 -0
- package/dist/backend-msb/invoke.d.ts.map +1 -0
- package/dist/backend-msb/invoke.js +73 -0
- package/dist/backend-msb/invoke.js.map +1 -0
- package/dist/backend-msb/ls-json.d.ts +23 -0
- package/dist/backend-msb/ls-json.d.ts.map +1 -0
- package/dist/backend-msb/ls-json.js +113 -0
- package/dist/backend-msb/ls-json.js.map +1 -0
- package/dist/backend-msb/network-links.d.ts +7 -0
- package/dist/backend-msb/network-links.d.ts.map +1 -0
- package/dist/backend-msb/network-links.js +31 -0
- package/dist/backend-msb/network-links.js.map +1 -0
- package/dist/backend-msb/platform.d.ts +29 -0
- package/dist/backend-msb/platform.d.ts.map +1 -0
- package/dist/backend-msb/platform.js +128 -0
- package/dist/backend-msb/platform.js.map +1 -0
- package/dist/backend-msb/port-conflict.d.ts +10 -0
- package/dist/backend-msb/port-conflict.d.ts.map +1 -0
- package/dist/backend-msb/port-conflict.js +16 -0
- package/dist/backend-msb/port-conflict.js.map +1 -0
- package/dist/backend-msb/provider.d.ts +10 -0
- package/dist/backend-msb/provider.d.ts.map +1 -0
- package/dist/backend-msb/provider.js +40 -0
- package/dist/backend-msb/provider.js.map +1 -0
- package/dist/backend-msb/provisioner.d.ts +19 -0
- package/dist/backend-msb/provisioner.d.ts.map +1 -0
- package/dist/backend-msb/provisioner.js +332 -0
- package/dist/backend-msb/provisioner.js.map +1 -0
- package/dist/backend-msb/reaper.d.ts +10 -0
- package/dist/backend-msb/reaper.d.ts.map +1 -0
- package/dist/backend-msb/reaper.js +73 -0
- package/dist/backend-msb/reaper.js.map +1 -0
- package/dist/core/backend.d.ts +98 -0
- package/dist/core/backend.d.ts.map +1 -0
- package/dist/core/backend.js +2 -0
- package/dist/core/backend.js.map +1 -0
- package/dist/core/backends.d.ts +37 -0
- package/dist/core/backends.d.ts.map +1 -0
- package/dist/core/backends.js +127 -0
- package/dist/core/backends.js.map +1 -0
- package/dist/core/cleanup.d.ts +37 -0
- package/dist/core/cleanup.d.ts.map +1 -0
- package/dist/core/cleanup.js +86 -0
- package/dist/core/cleanup.js.map +1 -0
- package/dist/core/errors.d.ts +51 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +66 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/free-ports.d.ts +23 -0
- package/dist/core/free-ports.d.ts.map +1 -0
- package/dist/core/free-ports.js +63 -0
- package/dist/core/free-ports.js.map +1 -0
- package/dist/core/generic-container.d.ts +145 -0
- package/dist/core/generic-container.d.ts.map +1 -0
- package/dist/core/generic-container.js +385 -0
- package/dist/core/generic-container.js.map +1 -0
- package/dist/core/model.d.ts +60 -0
- package/dist/core/model.d.ts.map +1 -0
- package/dist/core/model.js +2 -0
- package/dist/core/model.js.map +1 -0
- package/dist/core/mountable-file.d.ts +25 -0
- package/dist/core/mountable-file.d.ts.map +1 -0
- package/dist/core/mountable-file.js +64 -0
- package/dist/core/mountable-file.js.map +1 -0
- package/dist/core/network.d.ts +58 -0
- package/dist/core/network.d.ts.map +1 -0
- package/dist/core/network.js +84 -0
- package/dist/core/network.js.map +1 -0
- package/dist/core/run-id.d.ts +18 -0
- package/dist/core/run-id.d.ts.map +1 -0
- package/dist/core/run-id.js +18 -0
- package/dist/core/run-id.js.map +1 -0
- package/dist/core/wait.d.ts +59 -0
- package/dist/core/wait.d.ts.map +1 -0
- package/dist/core/wait.js +239 -0
- package/dist/core/wait.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/arango.d.ts +14 -0
- package/dist/modules/arango.d.ts.map +1 -0
- package/dist/modules/arango.js +37 -0
- package/dist/modules/arango.js.map +1 -0
- package/dist/modules/clickhouse.d.ts +37 -0
- package/dist/modules/clickhouse.d.ts.map +1 -0
- package/dist/modules/clickhouse.js +69 -0
- package/dist/modules/clickhouse.js.map +1 -0
- package/dist/modules/flink.d.ts +65 -0
- package/dist/modules/flink.d.ts.map +1 -0
- package/dist/modules/flink.js +125 -0
- package/dist/modules/flink.js.map +1 -0
- package/dist/modules/floci.d.ts +46 -0
- package/dist/modules/floci.d.ts.map +1 -0
- package/dist/modules/floci.js +62 -0
- package/dist/modules/floci.js.map +1 -0
- package/dist/modules/index.d.ts +31 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +31 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/kafka.d.ts +11 -0
- package/dist/modules/kafka.d.ts.map +1 -0
- package/dist/modules/kafka.js +41 -0
- package/dist/modules/kafka.js.map +1 -0
- package/dist/modules/keycloak.d.ts +40 -0
- package/dist/modules/keycloak.d.ts.map +1 -0
- package/dist/modules/keycloak.js +67 -0
- package/dist/modules/keycloak.js.map +1 -0
- package/dist/modules/mariadb.d.ts +56 -0
- package/dist/modules/mariadb.d.ts.map +1 -0
- package/dist/modules/mariadb.js +89 -0
- package/dist/modules/mariadb.js.map +1 -0
- package/dist/modules/memcached.d.ts +24 -0
- package/dist/modules/memcached.d.ts.map +1 -0
- package/dist/modules/memcached.js +105 -0
- package/dist/modules/memcached.js.map +1 -0
- package/dist/modules/mongodb.d.ts +19 -0
- package/dist/modules/mongodb.d.ts.map +1 -0
- package/dist/modules/mongodb.js +69 -0
- package/dist/modules/mongodb.js.map +1 -0
- package/dist/modules/mysql.d.ts +61 -0
- package/dist/modules/mysql.d.ts.map +1 -0
- package/dist/modules/mysql.js +101 -0
- package/dist/modules/mysql.js.map +1 -0
- package/dist/modules/neo4j.d.ts +60 -0
- package/dist/modules/neo4j.d.ts.map +1 -0
- package/dist/modules/neo4j.js +83 -0
- package/dist/modules/neo4j.js.map +1 -0
- package/dist/modules/pinot.d.ts +30 -0
- package/dist/modules/pinot.d.ts.map +1 -0
- package/dist/modules/pinot.js +49 -0
- package/dist/modules/pinot.js.map +1 -0
- package/dist/modules/postgres.d.ts +29 -0
- package/dist/modules/postgres.d.ts.map +1 -0
- package/dist/modules/postgres.js +73 -0
- package/dist/modules/postgres.js.map +1 -0
- package/dist/modules/rabbitmq.d.ts +46 -0
- package/dist/modules/rabbitmq.d.ts.map +1 -0
- package/dist/modules/rabbitmq.js +68 -0
- package/dist/modules/rabbitmq.js.map +1 -0
- package/dist/modules/redis.d.ts +15 -0
- package/dist/modules/redis.d.ts.map +1 -0
- package/dist/modules/redis.js +24 -0
- package/dist/modules/redis.js.map +1 -0
- package/dist/modules/redpanda.d.ts +27 -0
- package/dist/modules/redpanda.d.ts.map +1 -0
- package/dist/modules/redpanda.js +58 -0
- package/dist/modules/redpanda.js.map +1 -0
- package/dist/modules/spring-cloud-config.d.ts +18 -0
- package/dist/modules/spring-cloud-config.d.ts.map +1 -0
- package/dist/modules/spring-cloud-config.js +28 -0
- package/dist/modules/spring-cloud-config.js.map +1 -0
- package/dist/modules/wiremock.d.ts +21 -0
- package/dist/modules/wiremock.d.ts.map +1 -0
- package/dist/modules/wiremock.js +32 -0
- package/dist/modules/wiremock.js.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Docker daemon's log-stream multiplexing frame format, present whenever
|
|
3
|
+
* a container is created without a TTY — this backend never allocates one,
|
|
4
|
+
* so this is the only shape `exec`/`logs`/`followLogs` ever see:
|
|
5
|
+
*
|
|
6
|
+
* frame = header ++ payload
|
|
7
|
+
* header = [ streamType: u8, 0u8, 0u8, 0u8, len: u32_be ] (8 bytes)
|
|
8
|
+
* payload = [u8; len]
|
|
9
|
+
* streamType: 0 = stdin, 1 = stdout, 2 = stderr
|
|
10
|
+
*
|
|
11
|
+
* `FrameDemuxer` accepts arbitrary Buffer chunks — frames straddle chunk
|
|
12
|
+
* boundaries with no relationship to how the daemon happened to flush its
|
|
13
|
+
* write buffer — and buffers a partial header/payload across `push()` calls,
|
|
14
|
+
* yielding only the frames a given chunk completes.
|
|
15
|
+
*/
|
|
16
|
+
export type StreamType = "stdin" | "stdout" | "stderr";
|
|
17
|
+
export interface Frame {
|
|
18
|
+
readonly streamType: StreamType;
|
|
19
|
+
readonly payload: Buffer;
|
|
20
|
+
}
|
|
21
|
+
/** Stateful frame reassembler: feed it raw bytes as they arrive, get back every frame a call completes. */
|
|
22
|
+
export declare class FrameDemuxer {
|
|
23
|
+
private buffered;
|
|
24
|
+
/** Appends `chunk` to the pending buffer and returns every frame now fully available. */
|
|
25
|
+
push(chunk: Buffer): Frame[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Reassembles complete lines out of a stream of text chunks whose
|
|
29
|
+
* boundaries are a chunking artifact, not a line break. A single log line
|
|
30
|
+
* can straddle two (or more) frames or Buffer reads with no relationship to
|
|
31
|
+
* where the actual `\n` falls; `feed` buffers a trailing partial line across
|
|
32
|
+
* calls and returns only the lines a given call completes. `flush` hands
|
|
33
|
+
* back that trailing fragment once at stream end — idempotent, since a
|
|
34
|
+
* terminal stream event (`end`/`close`) can legitimately fire more than once
|
|
35
|
+
* for the same close.
|
|
36
|
+
*/
|
|
37
|
+
export declare class LineAssembler {
|
|
38
|
+
private pending;
|
|
39
|
+
private flushedOnce;
|
|
40
|
+
feed(text: string): string[];
|
|
41
|
+
/** Returns the trailing unterminated fragment exactly once, or undefined if there was none (or this was already called). */
|
|
42
|
+
flush(): string | undefined;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=frames.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../src/backend-docker/frames.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAiBD,2GAA2G;AAC3G,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAA2B;IAE3C,yFAAyF;IACzF,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE;CAwB7B;AAED;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,WAAW,CAAS;IAE5B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAqB5B,4HAA4H;IAC5H,KAAK,IAAI,MAAM,GAAG,SAAS;CAY5B"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Docker daemon's log-stream multiplexing frame format, present whenever
|
|
3
|
+
* a container is created without a TTY — this backend never allocates one,
|
|
4
|
+
* so this is the only shape `exec`/`logs`/`followLogs` ever see:
|
|
5
|
+
*
|
|
6
|
+
* frame = header ++ payload
|
|
7
|
+
* header = [ streamType: u8, 0u8, 0u8, 0u8, len: u32_be ] (8 bytes)
|
|
8
|
+
* payload = [u8; len]
|
|
9
|
+
* streamType: 0 = stdin, 1 = stdout, 2 = stderr
|
|
10
|
+
*
|
|
11
|
+
* `FrameDemuxer` accepts arbitrary Buffer chunks — frames straddle chunk
|
|
12
|
+
* boundaries with no relationship to how the daemon happened to flush its
|
|
13
|
+
* write buffer — and buffers a partial header/payload across `push()` calls,
|
|
14
|
+
* yielding only the frames a given chunk completes.
|
|
15
|
+
*/
|
|
16
|
+
function streamTypeFromByte(b) {
|
|
17
|
+
switch (b) {
|
|
18
|
+
case 0:
|
|
19
|
+
return "stdin";
|
|
20
|
+
case 1:
|
|
21
|
+
return "stdout";
|
|
22
|
+
case 2:
|
|
23
|
+
return "stderr";
|
|
24
|
+
default:
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const HEADER_LEN = 8;
|
|
29
|
+
/** Stateful frame reassembler: feed it raw bytes as they arrive, get back every frame a call completes. */
|
|
30
|
+
export class FrameDemuxer {
|
|
31
|
+
buffered = Buffer.alloc(0);
|
|
32
|
+
/** Appends `chunk` to the pending buffer and returns every frame now fully available. */
|
|
33
|
+
push(chunk) {
|
|
34
|
+
this.buffered = this.buffered.length === 0 ? Buffer.from(chunk) : Buffer.concat([this.buffered, chunk]);
|
|
35
|
+
const frames = [];
|
|
36
|
+
for (;;) {
|
|
37
|
+
if (this.buffered.length < HEADER_LEN) {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
const len = this.buffered.readUInt32BE(4);
|
|
41
|
+
if (this.buffered.length < HEADER_LEN + len) {
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
const streamType = streamTypeFromByte(this.buffered.readUInt8(0));
|
|
45
|
+
const payload = this.buffered.subarray(HEADER_LEN, HEADER_LEN + len);
|
|
46
|
+
if (streamType !== undefined) {
|
|
47
|
+
frames.push({ streamType, payload: Buffer.from(payload) });
|
|
48
|
+
}
|
|
49
|
+
// An unrecognized stream-type byte is dropped rather than throwing —
|
|
50
|
+
// the frame's length prefix is still trustworthy, so skipping past it
|
|
51
|
+
// cleanly (instead of aborting the whole stream) is the same
|
|
52
|
+
// tolerant-of-drift posture as the msb ls-json scanner.
|
|
53
|
+
this.buffered = this.buffered.subarray(HEADER_LEN + len);
|
|
54
|
+
}
|
|
55
|
+
return frames;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reassembles complete lines out of a stream of text chunks whose
|
|
60
|
+
* boundaries are a chunking artifact, not a line break. A single log line
|
|
61
|
+
* can straddle two (or more) frames or Buffer reads with no relationship to
|
|
62
|
+
* where the actual `\n` falls; `feed` buffers a trailing partial line across
|
|
63
|
+
* calls and returns only the lines a given call completes. `flush` hands
|
|
64
|
+
* back that trailing fragment once at stream end — idempotent, since a
|
|
65
|
+
* terminal stream event (`end`/`close`) can legitimately fire more than once
|
|
66
|
+
* for the same close.
|
|
67
|
+
*/
|
|
68
|
+
export class LineAssembler {
|
|
69
|
+
pending = "";
|
|
70
|
+
flushedOnce = false;
|
|
71
|
+
feed(text) {
|
|
72
|
+
this.pending += text;
|
|
73
|
+
if (!this.pending.includes("\n")) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
const endsWithNewline = this.pending.endsWith("\n");
|
|
77
|
+
const parts = this.pending.split("\n");
|
|
78
|
+
// split("a\nb\n", "\n") => ["a","b",""] — the trailing "" is the
|
|
79
|
+
// "nothing pending" marker when the chunk ended exactly on a newline;
|
|
80
|
+
// split("a\nb", "\n") => ["a","b"], where "b" is genuinely pending.
|
|
81
|
+
// Either way the last element is never a completed line.
|
|
82
|
+
const tail = parts.pop() ?? "";
|
|
83
|
+
this.pending = endsWithNewline ? "" : tail;
|
|
84
|
+
// A genuinely-empty interior line (a blank line the workload printed) is
|
|
85
|
+
// real output and must be delivered — do not filter it out. Only the
|
|
86
|
+
// trailing "nothing pending" marker popped above is ever dropped; that's
|
|
87
|
+
// handled by the pop(), not by filtering here. Mirrors msb's replay
|
|
88
|
+
// contract in follow-replay.ts, so both backends agree on blank lines.
|
|
89
|
+
return parts;
|
|
90
|
+
}
|
|
91
|
+
/** Returns the trailing unterminated fragment exactly once, or undefined if there was none (or this was already called). */
|
|
92
|
+
flush() {
|
|
93
|
+
if (this.flushedOnce) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
this.flushedOnce = true;
|
|
97
|
+
if (this.pending.length === 0) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const tail = this.pending;
|
|
101
|
+
this.pending = "";
|
|
102
|
+
return tail;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frames.js","sourceRoot":"","sources":["../../src/backend-docker/frames.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DockerBackend } from "./backend.js";
|
|
2
|
+
export { DockerBackendProvider } from "./provider.js";
|
|
3
|
+
export { DockerClient, socketPathFromDockerHost } from "./client.js";
|
|
4
|
+
export type { DockerResponse, DockerStreamResponse } from "./client.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend-docker/index.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rightsize/backend-docker` — the Docker daemon backend.
|
|
3
|
+
*
|
|
4
|
+
* Importing this module registers `DockerBackendProvider` with the core
|
|
5
|
+
* registry as a side effect (`priority: 10` — used when msb isn't supported,
|
|
6
|
+
* or when `RIGHTSIZE_BACKEND=docker` is set). Talks to the daemon over a
|
|
7
|
+
* hand-rolled unix-socket HTTP client (`node:http` with `socketPath`) rather
|
|
8
|
+
* than a general-purpose Docker SDK, so this backend can only ever dial the
|
|
9
|
+
* daemon's real unix socket — never a TCP host a dependency bump elsewhere
|
|
10
|
+
* could misroute it onto.
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
import { registerBackend } from "../core/backends.js";
|
|
15
|
+
import { DockerBackendProvider } from "./provider.js";
|
|
16
|
+
registerBackend(new DockerBackendProvider());
|
|
17
|
+
export { DockerBackend } from "./backend.js";
|
|
18
|
+
export { DockerBackendProvider } from "./provider.js";
|
|
19
|
+
export { DockerClient, socketPathFromDockerHost } from "./client.js";
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend-docker/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,eAAe,CAAC,IAAI,qBAAqB,EAAE,CAAC,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tolerant field extraction for daemon response bodies. Request bodies in
|
|
3
|
+
* this backend are fixed-shape and built with `JSON.stringify` — no need for
|
|
4
|
+
* tolerance there. Responses go through `JSON.parse` too, but wrapped so a
|
|
5
|
+
* daemon-version field addition or a genuinely malformed body degrades to
|
|
6
|
+
* "field not found" instead of throwing, matching the msb `ls` parser's own
|
|
7
|
+
* tolerance of schema drift (see `../backend-msb/ls-json.ts`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function extractString(body: string, field: string): string | undefined;
|
|
10
|
+
export declare function extractNumber(body: string, field: string): number | undefined;
|
|
11
|
+
/** Every `Id` field from a JSON array of objects — used for the container/network list endpoints. */
|
|
12
|
+
export declare function extractIds(body: string): string[];
|
|
13
|
+
//# sourceMappingURL=json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/backend-docker/json.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO7E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO7E;AAED,qGAAqG;AACrG,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYjD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tolerant field extraction for daemon response bodies. Request bodies in
|
|
3
|
+
* this backend are fixed-shape and built with `JSON.stringify` — no need for
|
|
4
|
+
* tolerance there. Responses go through `JSON.parse` too, but wrapped so a
|
|
5
|
+
* daemon-version field addition or a genuinely malformed body degrades to
|
|
6
|
+
* "field not found" instead of throwing, matching the msb `ls` parser's own
|
|
7
|
+
* tolerance of schema drift (see `../backend-msb/ls-json.ts`).
|
|
8
|
+
*/
|
|
9
|
+
function parseOrUndefined(body) {
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(body);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function extractString(body, field) {
|
|
18
|
+
const parsed = parseOrUndefined(body);
|
|
19
|
+
if (parsed === undefined || parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const value = parsed[field];
|
|
23
|
+
return typeof value === "string" ? value : undefined;
|
|
24
|
+
}
|
|
25
|
+
export function extractNumber(body, field) {
|
|
26
|
+
const parsed = parseOrUndefined(body);
|
|
27
|
+
if (parsed === undefined || parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const value = parsed[field];
|
|
31
|
+
return typeof value === "number" ? value : undefined;
|
|
32
|
+
}
|
|
33
|
+
/** Every `Id` field from a JSON array of objects — used for the container/network list endpoints. */
|
|
34
|
+
export function extractIds(body) {
|
|
35
|
+
const parsed = parseOrUndefined(body);
|
|
36
|
+
if (!Array.isArray(parsed)) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const ids = [];
|
|
40
|
+
for (const entry of parsed) {
|
|
41
|
+
if (entry !== null && typeof entry === "object" && typeof entry["Id"] === "string") {
|
|
42
|
+
ids.push(entry["Id"]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return ids;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/backend-docker/json.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,SAAS,gBAAgB,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAa;IACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnG,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAI,MAAkC,CAAC,KAAK,CAAC,CAAC;IACzD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAa;IACvD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnG,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAI,MAAkC,CAAC,KAAK,CAAC,CAAC;IACzD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAQ,KAAiC,CAAC,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;YAChH,GAAG,CAAC,IAAI,CAAE,KAAiC,CAAC,IAAI,CAAW,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The label key every container this backend creates carries, so `close()`
|
|
3
|
+
* and the reaper can find exactly this run's containers without touching
|
|
4
|
+
* anyone else's. The literal wire-format string is part of the library's
|
|
5
|
+
* external contract: any tool or process that filters on this label sees
|
|
6
|
+
* consistent labels regardless of which rightsize release created them.
|
|
7
|
+
*/
|
|
8
|
+
export declare const RUN_ID_LABEL_KEY = "dev.rightsize.runId";
|
|
9
|
+
/** The `filters` query-string value for `GET /containers/json?filters=...`, scoped to one run id's label. */
|
|
10
|
+
export declare function labelFilterQuery(runId: string): string;
|
|
11
|
+
//# sourceMappingURL=labels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../src/backend-docker/labels.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,wBAAwB,CAAC;AAEtD,6GAA6G;AAC7G,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The label key every container this backend creates carries, so `close()`
|
|
3
|
+
* and the reaper can find exactly this run's containers without touching
|
|
4
|
+
* anyone else's. The literal wire-format string is part of the library's
|
|
5
|
+
* external contract: any tool or process that filters on this label sees
|
|
6
|
+
* consistent labels regardless of which rightsize release created them.
|
|
7
|
+
*/
|
|
8
|
+
export const RUN_ID_LABEL_KEY = "dev.rightsize.runId";
|
|
9
|
+
/** The `filters` query-string value for `GET /containers/json?filters=...`, scoped to one run id's label. */
|
|
10
|
+
export function labelFilterQuery(runId) {
|
|
11
|
+
return JSON.stringify({ label: [`${RUN_ID_LABEL_KEY}=${runId}`] });
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","sourceRoot":"","sources":["../../src/backend-docker/labels.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAEtD,6GAA6G;AAC7G,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,gBAAgB,IAAI,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon has no distinct exception type for a host-port bind conflict —
|
|
3
|
+
* only free-text in a 500 response body, such as "driver failed programming
|
|
4
|
+
* external connectivity: ... address already in use" or "Bind for
|
|
5
|
+
* 0.0.0.0:PORT failed: port is already allocated". Classify by message,
|
|
6
|
+
* case-insensitively.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isPortBindConflictMessage(message: string): boolean;
|
|
9
|
+
//# sourceMappingURL=port-conflict.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-conflict.d.ts","sourceRoot":"","sources":["../../src/backend-docker/port-conflict.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGlE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon has no distinct exception type for a host-port bind conflict —
|
|
3
|
+
* only free-text in a 500 response body, such as "driver failed programming
|
|
4
|
+
* external connectivity: ... address already in use" or "Bind for
|
|
5
|
+
* 0.0.0.0:PORT failed: port is already allocated". Classify by message,
|
|
6
|
+
* case-insensitively.
|
|
7
|
+
*/
|
|
8
|
+
export function isPortBindConflictMessage(message) {
|
|
9
|
+
const m = message.toLowerCase();
|
|
10
|
+
return m.includes("already in use") || m.includes("already allocated");
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=port-conflict.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-conflict.js","sourceRoot":"","sources":["../../src/backend-docker/port-conflict.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAe;IACvD,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAChC,OAAO,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BackendProvider, SandboxBackend } from "../core/backend.js";
|
|
2
|
+
/**
|
|
3
|
+
* `isSupported()` must be synchronous (the interface's contract — see
|
|
4
|
+
* `../core/backend.ts`), but the daemon's real reachability probe
|
|
5
|
+
* (`GET /_ping`) is inherently async over `node:http`. Rather than fake a
|
|
6
|
+
* synchronous HTTP round trip, this resolves to "the socket path exists and
|
|
7
|
+
* is a socket" via `fs.statSync().isSocket()`, deferring true reachability
|
|
8
|
+
* to first use — an existing-but-dead daemon surfaces a clear error the
|
|
9
|
+
* moment a real call is made. A blocking `/_ping` here would be the
|
|
10
|
+
* stronger check, but JS has no synchronous socket I/O to do it with, and
|
|
11
|
+
* the stat is behaviorally equivalent for backend resolution since a socket
|
|
12
|
+
* file present but genuinely unreachable is vanishingly rare.
|
|
13
|
+
*/
|
|
14
|
+
export declare class DockerBackendProvider implements BackendProvider {
|
|
15
|
+
/** `"docker"` — matched case-insensitively against `RIGHTSIZE_BACKEND`. */
|
|
16
|
+
readonly name = "docker";
|
|
17
|
+
readonly priority = 10;
|
|
18
|
+
isSupported(): boolean;
|
|
19
|
+
unsupportedReason(): string;
|
|
20
|
+
create(): SandboxBackend;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/backend-docker/provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAI1E;;;;;;;;;;;GAWG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,QAAQ,MAAM;IAEvB,WAAW,IAAI,OAAO;IAStB,iBAAiB,IAAI,MAAM;IAI3B,MAAM,IAAI,cAAc;CAGzB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import { DockerBackend } from "./backend.js";
|
|
3
|
+
import { DockerClient, socketPathFromDockerHost } from "./client.js";
|
|
4
|
+
/**
|
|
5
|
+
* `isSupported()` must be synchronous (the interface's contract — see
|
|
6
|
+
* `../core/backend.ts`), but the daemon's real reachability probe
|
|
7
|
+
* (`GET /_ping`) is inherently async over `node:http`. Rather than fake a
|
|
8
|
+
* synchronous HTTP round trip, this resolves to "the socket path exists and
|
|
9
|
+
* is a socket" via `fs.statSync().isSocket()`, deferring true reachability
|
|
10
|
+
* to first use — an existing-but-dead daemon surfaces a clear error the
|
|
11
|
+
* moment a real call is made. A blocking `/_ping` here would be the
|
|
12
|
+
* stronger check, but JS has no synchronous socket I/O to do it with, and
|
|
13
|
+
* the stat is behaviorally equivalent for backend resolution since a socket
|
|
14
|
+
* file present but genuinely unreachable is vanishingly rare.
|
|
15
|
+
*/
|
|
16
|
+
export class DockerBackendProvider {
|
|
17
|
+
/** `"docker"` — matched case-insensitively against `RIGHTSIZE_BACKEND`. */
|
|
18
|
+
name = "docker";
|
|
19
|
+
priority = 10;
|
|
20
|
+
isSupported() {
|
|
21
|
+
const socketPath = socketPathFromDockerHost(process.env["DOCKER_HOST"]);
|
|
22
|
+
try {
|
|
23
|
+
return fs.statSync(socketPath).isSocket();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
unsupportedReason() {
|
|
30
|
+
return "no reachable Docker-API socket (Docker/Podman/Colima not running?)";
|
|
31
|
+
}
|
|
32
|
+
create() {
|
|
33
|
+
return new DockerBackend(DockerClient.fromEnv());
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/backend-docker/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAErE;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,qBAAqB;IAChC,2EAA2E;IAClE,IAAI,GAAG,QAAQ,CAAC;IAChB,QAAQ,GAAG,EAAE,CAAC;IAEvB,WAAW;QACT,MAAM,UAAU,GAAG,wBAAwB,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC;YACH,OAAO,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,iBAAiB;QACf,OAAO,oEAAoE,CAAC;IAC9E,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,aAAa,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC;IACnD,CAAC;CACF"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type { SandboxBackend, SandboxHandle, FollowHandle, NetworkLink } from "../core/backend.js";
|
|
2
|
+
import type { ContainerSpec, ExecResult } from "../core/model.js";
|
|
3
|
+
/**
|
|
4
|
+
* The attached-mode CLI driver: every sandbox this backend starts runs as a
|
|
5
|
+
* held child process (`msb run`, no `-d`) because detached mode never
|
|
6
|
+
* executes the image's own ENTRYPOINT/CMD — only attached mode does.
|
|
7
|
+
* Readiness is never inferred from that child's own output; it comes from
|
|
8
|
+
* polling `msb ls --format json` until the name shows `"Running"`. The
|
|
9
|
+
* attached child's stdout/stderr carries msb's own boot diagnostics and is
|
|
10
|
+
* kept only for pre-Running failure messages — it is not a dependable
|
|
11
|
+
* workload-log source (on Windows it does not relay guest stdout at all);
|
|
12
|
+
* workload logs are always fetched through the `msb logs` channel.
|
|
13
|
+
*
|
|
14
|
+
* `create()` on the `BackendProvider` interface is synchronous, but locating
|
|
15
|
+
* (and possibly downloading) the pinned `msb` binary is inherently async.
|
|
16
|
+
* The seam: this backend holds a memoized `ensureInstalled()` promise and
|
|
17
|
+
* every method awaits it once before doing anything else, so construction
|
|
18
|
+
* stays cheap and the actual provisioning happens lazily on first use.
|
|
19
|
+
*/
|
|
20
|
+
export declare class MsbCliBackend implements SandboxBackend {
|
|
21
|
+
private readonly msbPathPromise;
|
|
22
|
+
/** `"microsandbox"` — matched against `RIGHTSIZE_BACKEND` and used in `dev.rightsize.runId`-style diagnostics. */
|
|
23
|
+
readonly name = "microsandbox";
|
|
24
|
+
readonly supportsNativeNetworks = false;
|
|
25
|
+
private readonly handles;
|
|
26
|
+
private readonly startedNames;
|
|
27
|
+
private resolvedMsbPath;
|
|
28
|
+
constructor(msbPathPromise: Promise<string>);
|
|
29
|
+
private msbPath;
|
|
30
|
+
create(spec: ContainerSpec): Promise<SandboxHandle>;
|
|
31
|
+
/**
|
|
32
|
+
* Boots via `bootOnce`; on a first failure carrying msb's image-cache-
|
|
33
|
+
* corruption signature (see `isImageCacheCorruption`), heals by removing
|
|
34
|
+
* just the affected image's cache entry (`msb image remove <image>`, result
|
|
35
|
+
* ignored — including "image not found", since the real signal is whether
|
|
36
|
+
* the retried boot succeeds, not whether removal reported success) and
|
|
37
|
+
* retries the boot exactly once. A second identical failure surfaces an
|
|
38
|
+
* error naming the image and the attempted heal instead of retrying
|
|
39
|
+
* further. The heal is scoped to the one image reference — never the whole
|
|
40
|
+
* cache directory, and never any sandbox state.
|
|
41
|
+
*
|
|
42
|
+
* The failed first attempt never reached Running, so `state.attached` and
|
|
43
|
+
* `startedNames` (both populated only on success, inside `bootOnce`) carry
|
|
44
|
+
* no state from it to double-register, and its child has already been
|
|
45
|
+
* reaped there.
|
|
46
|
+
*
|
|
47
|
+
* Two corruption shapes were found empirically and the same one command
|
|
48
|
+
* heals both: the failing image's manifest was never committed to msb's
|
|
49
|
+
* cache database (a concurrent pull lost the race for a shared base layer
|
|
50
|
+
* before its own manifest write landed) — `image remove` reports "image not
|
|
51
|
+
* found" and the retry succeeds anyway, because by then the concurrent
|
|
52
|
+
* winner has finished materializing the shared layer — or the manifest IS
|
|
53
|
+
* committed but the cache file backing one of its layers is gone, where
|
|
54
|
+
* `image remove` clears the stale entry and the retry re-pulls from
|
|
55
|
+
* scratch.
|
|
56
|
+
*/
|
|
57
|
+
start(handle: SandboxHandle): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* One boot attempt: spawns the attached `msb run` child and polls until the
|
|
60
|
+
* sandbox reaches Running. `state.attached` and `startedNames` are
|
|
61
|
+
* populated only on success; on any failure the child is reaped here (for
|
|
62
|
+
* the classified early-exit failures it has already exited; a readiness
|
|
63
|
+
* timeout leaves it alive and it is hard-killed) so a failed attempt leaves
|
|
64
|
+
* no live process or registered cleanup state behind — the caller owns
|
|
65
|
+
* retry policy, never cleanup. An early exit is classified from the child's
|
|
66
|
+
* combined output: the image-cache-corruption signature throws
|
|
67
|
+
* `ImageCacheCorruptionError` (the one failure `start()` heals and
|
|
68
|
+
* retries), a host-port bind conflict throws `PortBindConflictError`, and
|
|
69
|
+
* anything else surfaces the raw output.
|
|
70
|
+
*/
|
|
71
|
+
private bootOnce;
|
|
72
|
+
stop(handle: SandboxHandle): Promise<void>;
|
|
73
|
+
remove(handle: SandboxHandle): Promise<void>;
|
|
74
|
+
private runningSandboxNames;
|
|
75
|
+
exec(handle: SandboxHandle, cmd: ReadonlyArray<string>): Promise<ExecResult>;
|
|
76
|
+
/**
|
|
77
|
+
* A fresh `msb logs <name> --tail 1000` invocation, same on every platform.
|
|
78
|
+
* This is the workload's own output, as distinct from the attached
|
|
79
|
+
* `msb run` child's pipe (drained in start() into a tail kept only for
|
|
80
|
+
* pre-Running crash diagnostics): on Windows the attached process does not
|
|
81
|
+
* relay guest stdout at all, while `msb logs` does everywhere, so this is
|
|
82
|
+
* the only channel this method can source from. Never rejects on a
|
|
83
|
+
* missing/removed sandbox — invoke() only rejects on spawn failure or
|
|
84
|
+
* timeout, never on exit code, so a failing `msb logs` call resolves with
|
|
85
|
+
* whatever (possibly empty) stdout it produced.
|
|
86
|
+
*/
|
|
87
|
+
logs(handle: SandboxHandle): Promise<string>;
|
|
88
|
+
/**
|
|
89
|
+
* `msb logs -f` never exits once the sandbox stops (confirmed against the
|
|
90
|
+
* real msb binary — it blocks on read forever instead of the documented
|
|
91
|
+
* clean exit). A watchdog polls `msb ls` in the background; the instant
|
|
92
|
+
* the sandbox leaves Running it quiesces the stuck follow child FIRST
|
|
93
|
+
* (kill it, wait for the reader to finish draining whatever was already
|
|
94
|
+
* buffered) so `delivered` reflects everything the live stream will ever
|
|
95
|
+
* produce, THEN does one authoritative non-follow `msb logs` fetch and
|
|
96
|
+
* replays only the lines after `delivered` — guarded so that replay can
|
|
97
|
+
* only ever happen once. An explicit `close()` never triggers a replay:
|
|
98
|
+
* closing means the caller asked delivery to stop, not "catch me up."
|
|
99
|
+
*
|
|
100
|
+
* On Windows hosts this routes to `followLogsByPolling` instead: there,
|
|
101
|
+
* `msb logs -f` stays alive for the sandbox's whole run but never relays a
|
|
102
|
+
* single line to its stdout pipe while the sandbox is Running (confirmed
|
|
103
|
+
* against the real binary on a hosted windows-2025 runner — the same lines
|
|
104
|
+
* are retrievable through non-follow `msb logs` the whole time), so a
|
|
105
|
+
* pipe-reading follow child can never deliver a live line on Windows.
|
|
106
|
+
*/
|
|
107
|
+
followLogs(handle: SandboxHandle, consumer: (line: string) => void): Promise<FollowHandle>;
|
|
108
|
+
/**
|
|
109
|
+
* Windows follow-logs path: no follow child at all. One async loop polls
|
|
110
|
+
* the non-follow `msb logs` fetch and delivers each fetch's not-yet-
|
|
111
|
+
* delivered lines, tracked by a monotonic `delivered` index — the same
|
|
112
|
+
* index-based diffing the POSIX watchdog's one-shot replay uses, made
|
|
113
|
+
* continuous. Delivery contract is identical to the POSIX path: in order,
|
|
114
|
+
* each line at most once, nothing after `close()`.
|
|
115
|
+
*
|
|
116
|
+
* A fetch's last line is held back only while the sandbox is Running AND
|
|
117
|
+
* the fetched text does not end with a newline: an unterminated tail may
|
|
118
|
+
* have been read mid-write, and delivering it early would split one
|
|
119
|
+
* workload line into two deliveries (the next fetch's index-diff would then
|
|
120
|
+
* skip its completed form). A newline-terminated tail is complete and
|
|
121
|
+
* delivers immediately — a workload that trickles complete lines while
|
|
122
|
+
* staying alive must see each line arrive live, not stall behind a
|
|
123
|
+
* holdback. Once the sandbox leaves Running, a final fetch (see
|
|
124
|
+
* `deliverTerminalTail`) delivers everything outstanding, including a
|
|
125
|
+
* trailing unterminated line.
|
|
126
|
+
*
|
|
127
|
+
* Every msb invocation this poller makes runs to completion strictly before
|
|
128
|
+
* the next one starts — exactly one in-flight child at a time from this
|
|
129
|
+
* code path. A failed `msb ls`/`msb logs` invocation — spawn error,
|
|
130
|
+
* timeout, or msb exiting non-zero (msb's own internal errors print to
|
|
131
|
+
* stderr and exit non-zero with EMPTY stdout, indistinguishable from a
|
|
132
|
+
* genuinely-empty response unless the exit code is checked) — is never read
|
|
133
|
+
* as "the sandbox stopped" or "the log is empty"; it retries.
|
|
134
|
+
*/
|
|
135
|
+
private followLogsByPolling;
|
|
136
|
+
/**
|
|
137
|
+
* Delivers everything outstanding once the sandbox is confirmed no longer
|
|
138
|
+
* Running: retries the `msb logs` fetch only while it keeps failing to
|
|
139
|
+
* invoke at all (bounded by `TERMINAL_FETCH_FAILURE_BUDGET_MS`), and
|
|
140
|
+
* delivers from the very first successful fetch — withholding nothing,
|
|
141
|
+
* since a stopped sandbox's log cannot grow, so there is no more mid-write
|
|
142
|
+
* risk. This is the one place a trailing unterminated line reaches the
|
|
143
|
+
* consumer on Windows.
|
|
144
|
+
*/
|
|
145
|
+
private deliverTerminalTail;
|
|
146
|
+
ensureNetwork(_networkId: string): Promise<void>;
|
|
147
|
+
removeNetwork(_networkId: string): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Networks are emulated because there is no bridge/subnet the current
|
|
150
|
+
* msb exposes on macOS — the only data path into a running sandbox is the
|
|
151
|
+
* exec channel. Four concerns, each its own guard: reject duplicate guest
|
|
152
|
+
* ports, validate every alias (they get shell-interpolated), probe for
|
|
153
|
+
* `nc`, then install `/etc/hosts` aliases and spawn one tunnel per link.
|
|
154
|
+
*/
|
|
155
|
+
installNetworkLinks(handle: SandboxHandle, links: ReadonlyArray<NetworkLink>): Promise<void>;
|
|
156
|
+
close(): Promise<void>;
|
|
157
|
+
/**
|
|
158
|
+
* Synchronous, blocking teardown for the process-exit path, where the
|
|
159
|
+
* event loop is not available to await this backend's normal async
|
|
160
|
+
* stop/remove. `spawnSync` is the one primitive Node offers that actually
|
|
161
|
+
* blocks the process here; failures are swallowed because the process is
|
|
162
|
+
* exiting regardless and there is no caller left to report them to.
|
|
163
|
+
*/
|
|
164
|
+
cleanupSync(id: string): void;
|
|
165
|
+
/** Remove leftover `rz-<other-runid>-*` sandboxes from a crashed prior run — never this run's own. */
|
|
166
|
+
sweepOrphans(): Promise<void>;
|
|
167
|
+
private silently;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/backend-msb/backend.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAwJlE;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,aAAc,YAAW,cAAc;IAatC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAZ3C,kHAAkH;IAClH,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,sBAAsB,SAAS;IAExC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAKlD,OAAO,CAAC,eAAe,CAAqB;gBAEf,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC;YAa9C,OAAO;IAIf,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAKzD;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACG,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCjD;;;;;;;;;;;;OAYG;YACW,QAAQ;IAyDhB,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAiD1C,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;YAOpC,mBAAmB;IAK3B,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAKlF;;;;;;;;;;OAUG;IACG,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAKlD;;;;;;;;;;;;;;;;;;OAkBG;IACG,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;IA+DhG;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,OAAO,CAAC,mBAAmB;IAyE3B;;;;;;;;OAQG;YACW,mBAAmB;IAmC3B,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD;;;;;;OAMG;IACG,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B5F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAU5B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAsB7B,sGAAsG;IAChG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAQrB,QAAQ;CAIvB"}
|