@capsulos/provider-docker 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/docker.e2e.test.ts +21 -0
- package/src/index.ts +19 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CapsuleHandle, type CapsuleInfo, type CapsuleSpec, type Connection, type CreateOptions, type Provider } from '@capsulos/sdk';
|
|
1
|
+
import { type CapsuleHandle, type CapsuleInfo, type CapsuleSpec, type Connection, type CreateOptions, type Provider, type SnapshotResult } from '@capsulos/sdk';
|
|
2
2
|
export interface DockerProviderOptions {
|
|
3
3
|
/** Docker binary; defaults to `docker` on PATH. */
|
|
4
4
|
docker?: string;
|
|
@@ -16,5 +16,10 @@ export declare class DockerProvider implements Provider {
|
|
|
16
16
|
get(id: string): Promise<CapsuleInfo | null>;
|
|
17
17
|
list(): Promise<CapsuleInfo[]>;
|
|
18
18
|
terminate(id: string): Promise<void>;
|
|
19
|
+
/** `docker pause`: cgroup freezer, processes stop, memory stays. */
|
|
20
|
+
pause(id: string): Promise<void>;
|
|
21
|
+
resume(id: string): Promise<void>;
|
|
22
|
+
/** `docker commit`: the container's filesystem becomes an image named `name`, a template for `create()`. */
|
|
23
|
+
snapshot(id: string, name: string): Promise<SnapshotResult>;
|
|
19
24
|
connect(id: string): Promise<Connection>;
|
|
20
25
|
}
|
package/dist/index.js
CHANGED
|
@@ -91,6 +91,21 @@ export class DockerProvider {
|
|
|
91
91
|
async terminate(id) {
|
|
92
92
|
await this.cli('rm', '-f', id).catch(() => undefined);
|
|
93
93
|
}
|
|
94
|
+
/** `docker pause`: cgroup freezer, processes stop, memory stays. */
|
|
95
|
+
async pause(id) {
|
|
96
|
+
await this.cli('pause', id);
|
|
97
|
+
}
|
|
98
|
+
async resume(id) {
|
|
99
|
+
await this.cli('unpause', id);
|
|
100
|
+
}
|
|
101
|
+
/** `docker commit`: the container's filesystem becomes an image named `name`, a template for `create()`. */
|
|
102
|
+
async snapshot(id, name) {
|
|
103
|
+
if (!/^[a-z0-9][a-z0-9._\/-]*(:[A-Za-z0-9._-]+)?$/.test(name)) {
|
|
104
|
+
throw new CapsuleError(`snapshot name ${JSON.stringify(name)} is not a valid Docker image name`);
|
|
105
|
+
}
|
|
106
|
+
await this.cli('commit', '--pause=true', id, name);
|
|
107
|
+
return { template: name, provider: this.name };
|
|
108
|
+
}
|
|
94
109
|
async connect(id) {
|
|
95
110
|
const port = await this.cli('port', id, `${CAPSULOD_PORT}/tcp`);
|
|
96
111
|
// "127.0.0.1:49153" (may list several lines on dual-stack hosts)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,qEAAqE;AACrE,8EAA8E;AAC9E,gEAAgE;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,YAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,qEAAqE;AACrE,8EAA8E;AAC9E,gEAAgE;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,YAAY,GASb,MAAM,eAAe,CAAC;AAEvB,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAShC,MAAM,aAAa,GAAG,IAAI,CAAC;AAE3B,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,QAAQ,CAAC;IACR,MAAM,CAAS;IACf,KAAK,CAAS;IAE/B,YAAY,OAA8B,EAAE;QAC1C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC;IACxC,CAAC;IAEO,KAAK,CAAC,GAAG,CAAC,GAAG,IAAc;QACjC,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACzE,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,GAA2C,CAAC;YACtD,MAAM,IAAI,YAAY,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,kGAAkG;IAClG,KAAK,CAAC,MAAM,CAAC,IAAiB,EAAE,QAAuB,EAAE;QACvD,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,cAAc,aAAa,EAAE,CAAC,CAAC;QACrG,gGAAgG;QAChG,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9E,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7G,IAAI,IAAI,CAAC,WAAW;YAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClD,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YAC1B,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACzB,MAAM,IAAI,YAAY,CAAC,yBAAyB,EAAE,sBAAsB,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1G,CAAC;QACD,yEAAyE;QACzE,8DAA8D;QAC9D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC;QAC9E,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACxE,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACzB,MAAM,IAAI,YAAY,CAAC,qCAAqC,MAAM,+CAA+C,OAAO,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,YAAY,IAAI,EAAE,CAAC,CAAC;QACtL,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1C,OAAO;YACL,EAAE;YACF,QAAQ,EAAE,IAAI,CAAC,IAAI;YACnB,KAAK,EAAE,SAAS;YAChB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,QAAQ,EAAE,UAAU,CAAC,OAAO;YAC5B,UAAU;SACX,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAU;QAClB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;YACrE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAIxB,CAAC;YACF,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACrH,OAAO;gBACL,EAAE;gBACF,QAAQ,EAAE,IAAI,CAAC,IAAI;gBACnB,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;gBAC9B,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK;gBACxB,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC9B,YAAY,EAAE,QAAQ;gBACtB,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aACpF,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,IAAI,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,iDAAiD,CAAC,CAAC;QAClJ,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAClC,MAAM,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACzE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3G,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACxD,CAAC;IAED,oEAAoE;IACpE,KAAK,CAAC,KAAK,CAAC,EAAU;QACpB,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,4GAA4G;IAC5G,KAAK,CAAC,QAAQ,CAAC,EAAU,EAAE,IAAY;QACrC,IAAI,CAAC,6CAA6C,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,YAAY,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;QACnG,CAAC;QACD,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACnD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,aAAa,MAAM,CAAC,CAAC;QAChE,iEAAiE;QACjE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACxC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,YAAY,CAAC,aAAa,EAAE,0BAA0B,aAAa,EAAE,CAAC,CAAC;QAChG,OAAO,EAAE,OAAO,EAAE,oBAAoB,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAChF,CAAC;CACF;AAED,SAAS,OAAO,CAAC,CAAS;IACxB,QAAQ,CAAC,EAAE,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,QAAQ;YACX,OAAO,WAAW,CAAC;QACrB,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM,CAAC;QACZ,KAAK,UAAU;YACb,OAAO,YAAY,CAAC;QACtB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capsulos/provider-docker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "capsulos provider for local Docker: the development and CI bench. Not an isolation boundary.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@capsulos/sdk": "0.
|
|
46
|
+
"@capsulos/sdk": "0.2.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^22.20.1",
|
package/src/docker.e2e.test.ts
CHANGED
|
@@ -56,6 +56,27 @@ describe.skipIf(!dockerHasImage(IMAGE))('docker provider e2e', () => {
|
|
|
56
56
|
expect((await capsule.files.list('/workspace/a')).map((e) => e.name)).toEqual(['b.txt']);
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
+
it('pauses and resumes: processes freeze, memory and files stay', async () => {
|
|
60
|
+
await capsule.files.write('/workspace/before-pause.txt', 'still here');
|
|
61
|
+
await capsule.pause();
|
|
62
|
+
expect((await provider.get(capsule.id))?.state).toBe('suspended');
|
|
63
|
+
await capsule.resume();
|
|
64
|
+
expect((await provider.get(capsule.id))?.state).toBe('running');
|
|
65
|
+
expect(await capsule.files.read('/workspace/before-pause.txt')).toBe('still here');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('snapshots a capsule into a template that new capsules start from', async () => {
|
|
69
|
+
await capsule.files.write('/workspace/seed.txt', 'from the snapshot');
|
|
70
|
+
const snap = await capsule.snapshot('capsulos-e2e-snapshot:latest');
|
|
71
|
+
const child = await Capsule.create(provider, { template: snap.template }, { readyTimeoutMs: 60_000 });
|
|
72
|
+
try {
|
|
73
|
+
expect(await child.files.read('/workspace/seed.txt')).toBe('from the snapshot');
|
|
74
|
+
} finally {
|
|
75
|
+
await child.kill();
|
|
76
|
+
execFileSync('docker', ['rmi', '-f', snap.template], { stdio: 'ignore' });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
59
80
|
it('lists and terminates capsules', async () => {
|
|
60
81
|
const before = await provider.list();
|
|
61
82
|
expect(before.map((c) => c.id)).toContain(capsule.id);
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type Connection,
|
|
14
14
|
type CreateOptions,
|
|
15
15
|
type Provider,
|
|
16
|
+
type SnapshotResult,
|
|
16
17
|
} from '@capsulos/sdk';
|
|
17
18
|
|
|
18
19
|
const run = promisify(execFile);
|
|
@@ -115,6 +116,24 @@ export class DockerProvider implements Provider {
|
|
|
115
116
|
await this.cli('rm', '-f', id).catch(() => undefined);
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
/** `docker pause`: cgroup freezer, processes stop, memory stays. */
|
|
120
|
+
async pause(id: string): Promise<void> {
|
|
121
|
+
await this.cli('pause', id);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async resume(id: string): Promise<void> {
|
|
125
|
+
await this.cli('unpause', id);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** `docker commit`: the container's filesystem becomes an image named `name`, a template for `create()`. */
|
|
129
|
+
async snapshot(id: string, name: string): Promise<SnapshotResult> {
|
|
130
|
+
if (!/^[a-z0-9][a-z0-9._\/-]*(:[A-Za-z0-9._-]+)?$/.test(name)) {
|
|
131
|
+
throw new CapsuleError(`snapshot name ${JSON.stringify(name)} is not a valid Docker image name`);
|
|
132
|
+
}
|
|
133
|
+
await this.cli('commit', '--pause=true', id, name);
|
|
134
|
+
return { template: name, provider: this.name };
|
|
135
|
+
}
|
|
136
|
+
|
|
118
137
|
async connect(id: string): Promise<Connection> {
|
|
119
138
|
const port = await this.cli('port', id, `${CAPSULOD_PORT}/tcp`);
|
|
120
139
|
// "127.0.0.1:49153" (may list several lines on dual-stack hosts)
|