@cloud-cli/vm 1.0.3 → 1.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/dist/index.d.ts +8 -2
- package/dist/index.js +28 -16
- package/package.json +1 -1
- package/src/index.spec.ts +23 -4
- package/src/index.ts +37 -16
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
interface NameOption {
|
|
2
2
|
name: string;
|
|
3
3
|
}
|
|
4
|
+
interface NameAndPathOption {
|
|
5
|
+
name: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
}
|
|
4
8
|
declare function list(): Promise<string[]>;
|
|
9
|
+
declare function ls(options: NameAndPathOption): Promise<string[]>;
|
|
5
10
|
declare function show(options: NameOption): Promise<{
|
|
6
11
|
name: any;
|
|
7
12
|
createdAt: any;
|
|
8
13
|
labels: any;
|
|
9
14
|
}>;
|
|
10
|
-
declare function add(options: NameOption): Promise<
|
|
11
|
-
declare function remove(options: NameOption): Promise<
|
|
15
|
+
declare function add(options: NameOption): Promise<boolean>;
|
|
16
|
+
declare function remove(options: NameOption): Promise<boolean>;
|
|
12
17
|
declare function prune(): Promise<string>;
|
|
13
18
|
declare const _default: {
|
|
14
19
|
add: typeof add;
|
|
@@ -16,5 +21,6 @@ declare const _default: {
|
|
|
16
21
|
list: typeof list;
|
|
17
22
|
show: typeof show;
|
|
18
23
|
prune: typeof prune;
|
|
24
|
+
ls: typeof ls;
|
|
19
25
|
};
|
|
20
26
|
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { exec } from "@cloud-cli/exec";
|
|
2
3
|
const nameRe = /^[a-z][a-z0-9-]+$/;
|
|
3
4
|
const isValidName = (name) => nameRe.test(name);
|
|
4
|
-
const invalidNameError = new Error(
|
|
5
|
+
const invalidNameError = new Error("Invalid name");
|
|
5
6
|
async function list() {
|
|
6
|
-
const output = await exec(
|
|
7
|
+
const output = await exec("docker", ["volume", "ls", "--format={{.Name}}"]);
|
|
7
8
|
if (!output.ok) {
|
|
8
|
-
throw new Error(
|
|
9
|
+
throw new Error("Unable to list volumes");
|
|
9
10
|
}
|
|
10
|
-
return output.stdout.trim().split(
|
|
11
|
+
return output.stdout.trim().split("\n");
|
|
12
|
+
}
|
|
13
|
+
async function ls(options) {
|
|
14
|
+
const { name, path = "" } = options;
|
|
15
|
+
const output = await exec("docker", ["volume", "inspect", name]);
|
|
16
|
+
const volumes = JSON.parse(output.stdout);
|
|
17
|
+
if (!volumes.length) {
|
|
18
|
+
throw new Error("Volume not found");
|
|
19
|
+
}
|
|
20
|
+
const root = volumes[0].Mountpoint;
|
|
21
|
+
const files = await exec("ls", ["-1", join(root, path)]);
|
|
22
|
+
return files.stdout.trim().split("\n");
|
|
11
23
|
}
|
|
12
24
|
async function show(options) {
|
|
13
25
|
if (!isValidName(options.name)) {
|
|
14
26
|
throw invalidNameError;
|
|
15
27
|
}
|
|
16
|
-
const output = await exec(
|
|
28
|
+
const output = await exec("docker", ["volume", "inspect", options.name]);
|
|
17
29
|
const list = JSON.parse(output.stdout);
|
|
18
30
|
if (!list.length) {
|
|
19
|
-
throw new Error(
|
|
31
|
+
throw new Error("Volume not found");
|
|
20
32
|
}
|
|
21
33
|
const { Name, Labels, CreatedAt } = list[0];
|
|
22
34
|
return {
|
|
@@ -29,24 +41,24 @@ async function add(options) {
|
|
|
29
41
|
if (!isValidName(options.name)) {
|
|
30
42
|
throw invalidNameError;
|
|
31
43
|
}
|
|
32
|
-
const output = await exec(
|
|
44
|
+
const output = await exec("docker", ["volume", "create", options.name]);
|
|
33
45
|
if (output.ok) {
|
|
34
|
-
return
|
|
46
|
+
return true;
|
|
35
47
|
}
|
|
36
|
-
throw new Error(
|
|
48
|
+
throw new Error("Unable to create volume");
|
|
37
49
|
}
|
|
38
50
|
async function remove(options) {
|
|
39
51
|
if (!isValidName(options.name)) {
|
|
40
52
|
throw invalidNameError;
|
|
41
53
|
}
|
|
42
|
-
const output = await exec(
|
|
54
|
+
const output = await exec("docker", ["volume", "rm", options.name]);
|
|
43
55
|
if (output.ok) {
|
|
44
|
-
return
|
|
56
|
+
return true;
|
|
45
57
|
}
|
|
46
|
-
throw new Error(
|
|
58
|
+
throw new Error("Unable to remove volume");
|
|
47
59
|
}
|
|
48
60
|
async function prune() {
|
|
49
|
-
await exec(
|
|
50
|
-
return
|
|
61
|
+
await exec("docker", ["volume", "prune"]);
|
|
62
|
+
return "";
|
|
51
63
|
}
|
|
52
|
-
export default { add, remove, list, show, prune };
|
|
64
|
+
export default { add, remove, list, show, prune, ls };
|
package/package.json
CHANGED
package/src/index.spec.ts
CHANGED
|
@@ -44,6 +44,25 @@ describe('volume manager', () => {
|
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
+
describe('ls', () => {
|
|
48
|
+
it('should list files of a volume and path', async () => {
|
|
49
|
+
const outputs = [inspectOutput, 'dir', inspectOutput, 'a.txt\nb.txt'];
|
|
50
|
+
execMocks.exec = jest.fn().mockImplementation(() => ({ ok: true, stdout: outputs.shift() }));
|
|
51
|
+
|
|
52
|
+
await expect(vm.ls({ name: 'test' })).resolves.toEqual(['dir']);
|
|
53
|
+
await expect(vm.ls({ name: 'test', path: 'dir' })).resolves.toEqual(['a.txt', 'b.txt']);
|
|
54
|
+
|
|
55
|
+
expect(exec.exec).toHaveBeenCalledWith('docker', ['volume', 'inspect', 'test']);
|
|
56
|
+
expect(exec.exec).toHaveBeenCalledWith('ls', ['-1', '/var/lib/docker/volumes/test/_data']);
|
|
57
|
+
expect(exec.exec).toHaveBeenCalledWith('ls', ['-1', '/var/lib/docker/volumes/test/_data/dir']);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should throw an error if volume name is invalid', async () => {
|
|
61
|
+
execMocks.exec = jest.fn().mockImplementation(() => ({ ok: true, stdout: '[]' }));
|
|
62
|
+
await expect(vm.ls({ name: 'notfound' })).rejects.toThrowError('Volume not found');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
47
66
|
describe('show', () => {
|
|
48
67
|
it('should show details of a volume', async () => {
|
|
49
68
|
const execOutput = { ok: true, stdout: inspectOutput };
|
|
@@ -61,7 +80,7 @@ describe('volume manager', () => {
|
|
|
61
80
|
expect(exec.exec).toHaveBeenCalledWith('docker', ['volume', 'inspect', 'test']);
|
|
62
81
|
});
|
|
63
82
|
|
|
64
|
-
it('should throw error if volume name is invalid', async () => {
|
|
83
|
+
it('should throw an error if volume name is invalid', async () => {
|
|
65
84
|
execMocks.exec = jest.fn();
|
|
66
85
|
await expect(vm.show({ name: 'In$%valid' })).rejects.toThrowError('Invalid name');
|
|
67
86
|
expect(exec.exec).not.toHaveBeenCalled();
|
|
@@ -80,7 +99,7 @@ describe('volume manager', () => {
|
|
|
80
99
|
const execOutput = { ok: true, stdout: 'test' };
|
|
81
100
|
execMocks.exec = jest.fn().mockResolvedValue(execOutput);
|
|
82
101
|
|
|
83
|
-
await expect(vm.add({ name: 'test' })).resolves.toEqual(
|
|
102
|
+
await expect(vm.add({ name: 'test' })).resolves.toEqual(true);
|
|
84
103
|
|
|
85
104
|
expect(exec.exec).toHaveBeenCalledWith('docker', ['volume', 'create', 'test']);
|
|
86
105
|
});
|
|
@@ -99,12 +118,12 @@ describe('volume manager', () => {
|
|
|
99
118
|
});
|
|
100
119
|
});
|
|
101
120
|
|
|
102
|
-
describe('
|
|
121
|
+
describe('remove', () => {
|
|
103
122
|
it('should add a volume', async () => {
|
|
104
123
|
const execOutput = { ok: true, stdout: '' };
|
|
105
124
|
execMocks.exec = jest.fn().mockResolvedValue(execOutput);
|
|
106
125
|
|
|
107
|
-
await expect(vm.remove({ name: 'test' })).resolves.toEqual(
|
|
126
|
+
await expect(vm.remove({ name: 'test' })).resolves.toEqual(true);
|
|
108
127
|
|
|
109
128
|
expect(exec.exec).toHaveBeenCalledWith('docker', ['volume', 'rm', 'test']);
|
|
110
129
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,21 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { exec } from "@cloud-cli/exec";
|
|
2
3
|
|
|
3
4
|
const nameRe = /^[a-z][a-z0-9-]+$/;
|
|
4
5
|
const isValidName = (name) => nameRe.test(name);
|
|
5
|
-
const invalidNameError = new Error(
|
|
6
|
+
const invalidNameError = new Error("Invalid name");
|
|
6
7
|
|
|
7
8
|
interface NameOption {
|
|
8
9
|
name: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
interface NameAndPathOption {
|
|
13
|
+
name: string;
|
|
14
|
+
path?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
async function list() {
|
|
12
|
-
const output = await exec(
|
|
18
|
+
const output = await exec("docker", ["volume", "ls", "--format={{.Name}}"]);
|
|
13
19
|
|
|
14
20
|
if (!output.ok) {
|
|
15
|
-
throw new Error(
|
|
21
|
+
throw new Error("Unable to list volumes");
|
|
16
22
|
}
|
|
17
23
|
|
|
18
|
-
return output.stdout.trim().split(
|
|
24
|
+
return output.stdout.trim().split("\n");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function ls(options: NameAndPathOption) {
|
|
28
|
+
const { name, path = "" } = options;
|
|
29
|
+
const output = await exec("docker", ["volume", "inspect", name]);
|
|
30
|
+
const volumes = JSON.parse(output.stdout);
|
|
31
|
+
|
|
32
|
+
if (!volumes.length) {
|
|
33
|
+
throw new Error("Volume not found");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const root = volumes[0].Mountpoint;
|
|
37
|
+
const files = await exec("ls", ["-1", join(root, path)]);
|
|
38
|
+
|
|
39
|
+
return files.stdout.trim().split("\n");
|
|
19
40
|
}
|
|
20
41
|
|
|
21
42
|
async function show(options: NameOption) {
|
|
@@ -23,11 +44,11 @@ async function show(options: NameOption) {
|
|
|
23
44
|
throw invalidNameError;
|
|
24
45
|
}
|
|
25
46
|
|
|
26
|
-
const output = await exec(
|
|
47
|
+
const output = await exec("docker", ["volume", "inspect", options.name]);
|
|
27
48
|
const list = JSON.parse(output.stdout);
|
|
28
49
|
|
|
29
50
|
if (!list.length) {
|
|
30
|
-
throw new Error(
|
|
51
|
+
throw new Error("Volume not found");
|
|
31
52
|
}
|
|
32
53
|
|
|
33
54
|
const { Name, Labels, CreatedAt } = list[0];
|
|
@@ -44,13 +65,13 @@ async function add(options: NameOption) {
|
|
|
44
65
|
throw invalidNameError;
|
|
45
66
|
}
|
|
46
67
|
|
|
47
|
-
const output = await exec(
|
|
68
|
+
const output = await exec("docker", ["volume", "create", options.name]);
|
|
48
69
|
|
|
49
70
|
if (output.ok) {
|
|
50
|
-
return
|
|
71
|
+
return true;
|
|
51
72
|
}
|
|
52
73
|
|
|
53
|
-
throw new Error(
|
|
74
|
+
throw new Error("Unable to create volume");
|
|
54
75
|
}
|
|
55
76
|
|
|
56
77
|
async function remove(options: NameOption) {
|
|
@@ -58,18 +79,18 @@ async function remove(options: NameOption) {
|
|
|
58
79
|
throw invalidNameError;
|
|
59
80
|
}
|
|
60
81
|
|
|
61
|
-
const output = await exec(
|
|
82
|
+
const output = await exec("docker", ["volume", "rm", options.name]);
|
|
62
83
|
|
|
63
84
|
if (output.ok) {
|
|
64
|
-
return
|
|
85
|
+
return true;
|
|
65
86
|
}
|
|
66
87
|
|
|
67
|
-
throw new Error(
|
|
88
|
+
throw new Error("Unable to remove volume");
|
|
68
89
|
}
|
|
69
90
|
|
|
70
91
|
async function prune() {
|
|
71
|
-
await exec(
|
|
72
|
-
return
|
|
92
|
+
await exec("docker", ["volume", "prune"]);
|
|
93
|
+
return "";
|
|
73
94
|
}
|
|
74
95
|
|
|
75
|
-
export default { add, remove, list, show, prune };
|
|
96
|
+
export default { add, remove, list, show, prune, ls };
|