@kapeta/local-cluster-service 0.6.0 → 0.7.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/.eslintrc.cjs +17 -0
- package/.github/workflows/main.yml +22 -22
- package/.prettierignore +4 -0
- package/.vscode/launch.json +2 -4
- package/CHANGELOG.md +14 -0
- package/definitions.d.ts +17 -35
- package/dist/cjs/index.d.ts +27 -0
- package/dist/cjs/index.js +126 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/src/assetManager.d.ts +31 -0
- package/dist/cjs/src/assetManager.js +153 -0
- package/dist/cjs/src/assets/routes.d.ts +3 -0
- package/dist/cjs/src/assets/routes.js +117 -0
- package/dist/cjs/src/clusterService.d.ts +40 -0
- package/dist/cjs/src/clusterService.js +114 -0
- package/dist/cjs/src/codeGeneratorManager.d.ts +8 -0
- package/dist/cjs/src/codeGeneratorManager.js +53 -0
- package/dist/cjs/src/config/routes.d.ts +3 -0
- package/dist/cjs/src/config/routes.js +126 -0
- package/dist/cjs/src/configManager.d.ts +36 -0
- package/dist/cjs/src/configManager.js +110 -0
- package/dist/cjs/src/containerManager.d.ts +89 -0
- package/dist/cjs/src/containerManager.js +365 -0
- package/dist/cjs/src/filesystem/routes.d.ts +3 -0
- package/dist/cjs/src/filesystem/routes.js +69 -0
- package/dist/cjs/src/filesystemManager.d.ts +15 -0
- package/dist/cjs/src/filesystemManager.js +87 -0
- package/dist/cjs/src/identities/routes.d.ts +3 -0
- package/dist/cjs/src/identities/routes.js +18 -0
- package/dist/cjs/src/instanceManager.d.ts +56 -0
- package/dist/cjs/src/instanceManager.js +424 -0
- package/dist/cjs/src/instances/routes.d.ts +3 -0
- package/dist/cjs/src/instances/routes.js +134 -0
- package/dist/cjs/src/middleware/cors.d.ts +2 -0
- package/dist/cjs/src/middleware/cors.js +10 -0
- package/dist/cjs/src/middleware/kapeta.d.ts +11 -0
- package/dist/cjs/src/middleware/kapeta.js +17 -0
- package/dist/cjs/src/middleware/stringBody.d.ts +5 -0
- package/dist/cjs/src/middleware/stringBody.js +14 -0
- package/dist/cjs/src/networkManager.d.ts +32 -0
- package/dist/cjs/src/networkManager.js +109 -0
- package/dist/cjs/src/operatorManager.d.ts +36 -0
- package/dist/cjs/src/operatorManager.js +165 -0
- package/dist/cjs/src/progressListener.d.ts +20 -0
- package/dist/cjs/src/progressListener.js +91 -0
- package/dist/cjs/src/providerManager.d.ts +9 -0
- package/dist/cjs/src/providerManager.js +51 -0
- package/dist/cjs/src/providers/routes.d.ts +3 -0
- package/dist/cjs/src/providers/routes.js +42 -0
- package/dist/cjs/src/proxy/routes.d.ts +3 -0
- package/dist/cjs/src/proxy/routes.js +111 -0
- package/dist/cjs/src/proxy/types/rest.d.ts +4 -0
- package/dist/cjs/src/proxy/types/rest.js +114 -0
- package/dist/cjs/src/proxy/types/web.d.ts +4 -0
- package/dist/cjs/src/proxy/types/web.js +53 -0
- package/dist/cjs/src/repositoryManager.d.ts +17 -0
- package/dist/cjs/src/repositoryManager.js +215 -0
- package/dist/cjs/src/serviceManager.d.ts +29 -0
- package/dist/cjs/src/serviceManager.js +99 -0
- package/dist/cjs/src/socketManager.d.ts +14 -0
- package/dist/cjs/src/socketManager.js +53 -0
- package/dist/cjs/src/storageService.d.ts +17 -0
- package/dist/cjs/src/storageService.js +74 -0
- package/dist/cjs/src/traffic/routes.d.ts +3 -0
- package/dist/cjs/src/traffic/routes.js +18 -0
- package/dist/cjs/src/types.d.ts +88 -0
- package/dist/cjs/src/types.js +2 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +29 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.js +468 -0
- package/dist/cjs/src/utils/LogData.d.ts +19 -0
- package/dist/cjs/src/utils/LogData.js +43 -0
- package/dist/cjs/src/utils/pathTemplateParser.d.ts +26 -0
- package/dist/cjs/src/utils/pathTemplateParser.js +121 -0
- package/dist/cjs/src/utils/utils.d.ts +1 -0
- package/dist/cjs/src/utils/utils.js +18 -0
- package/dist/cjs/start.d.ts +1 -0
- package/dist/cjs/start.js +12 -0
- package/dist/esm/index.d.ts +27 -0
- package/dist/esm/index.js +121 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/src/assetManager.d.ts +31 -0
- package/{src → dist/esm/src}/assetManager.js +22 -60
- package/dist/esm/src/assets/routes.d.ts +3 -0
- package/{src → dist/esm/src}/assets/routes.js +21 -36
- package/dist/esm/src/clusterService.d.ts +40 -0
- package/{src → dist/esm/src}/clusterService.js +14 -37
- package/dist/esm/src/codeGeneratorManager.d.ts +8 -0
- package/{src → dist/esm/src}/codeGeneratorManager.js +15 -24
- package/dist/esm/src/config/routes.d.ts +3 -0
- package/dist/esm/src/config/routes.js +121 -0
- package/dist/esm/src/configManager.d.ts +36 -0
- package/{src → dist/esm/src}/configManager.js +11 -40
- package/dist/esm/src/containerManager.d.ts +89 -0
- package/{src → dist/esm/src}/containerManager.js +81 -182
- package/dist/esm/src/filesystem/routes.d.ts +3 -0
- package/dist/esm/src/filesystem/routes.js +64 -0
- package/dist/esm/src/filesystemManager.d.ts +15 -0
- package/{src → dist/esm/src}/filesystemManager.js +20 -28
- package/dist/esm/src/identities/routes.d.ts +3 -0
- package/dist/esm/src/identities/routes.js +13 -0
- package/dist/esm/src/instanceManager.d.ts +56 -0
- package/{src → dist/esm/src}/instanceManager.js +94 -175
- package/dist/esm/src/instances/routes.d.ts +3 -0
- package/{src → dist/esm/src}/instances/routes.js +31 -70
- package/dist/esm/src/middleware/cors.d.ts +2 -0
- package/{src → dist/esm/src}/middleware/cors.js +2 -3
- package/dist/esm/src/middleware/kapeta.d.ts +11 -0
- package/{src → dist/esm/src}/middleware/kapeta.js +3 -7
- package/dist/esm/src/middleware/stringBody.d.ts +5 -0
- package/{src → dist/esm/src}/middleware/stringBody.js +2 -3
- package/dist/esm/src/networkManager.d.ts +32 -0
- package/{src → dist/esm/src}/networkManager.js +16 -33
- package/dist/esm/src/operatorManager.d.ts +36 -0
- package/{src → dist/esm/src}/operatorManager.js +35 -91
- package/dist/esm/src/progressListener.d.ts +20 -0
- package/dist/esm/src/progressListener.js +88 -0
- package/dist/esm/src/providerManager.d.ts +9 -0
- package/dist/esm/src/providerManager.js +45 -0
- package/dist/esm/src/providers/routes.d.ts +3 -0
- package/{src → dist/esm/src}/providers/routes.js +10 -16
- package/dist/esm/src/proxy/routes.d.ts +3 -0
- package/dist/esm/src/proxy/routes.js +106 -0
- package/dist/esm/src/proxy/types/rest.d.ts +4 -0
- package/dist/esm/src/proxy/types/rest.js +107 -0
- package/dist/esm/src/proxy/types/web.d.ts +4 -0
- package/{src → dist/esm/src}/proxy/types/web.js +13 -35
- package/dist/esm/src/repositoryManager.d.ts +17 -0
- package/dist/esm/src/repositoryManager.js +209 -0
- package/dist/esm/src/serviceManager.d.ts +29 -0
- package/{src → dist/esm/src}/serviceManager.js +12 -42
- package/dist/esm/src/socketManager.d.ts +14 -0
- package/{src → dist/esm/src}/socketManager.js +19 -23
- package/dist/esm/src/storageService.d.ts +17 -0
- package/{src → dist/esm/src}/storageService.js +8 -27
- package/dist/esm/src/traffic/routes.d.ts +3 -0
- package/{src → dist/esm/src}/traffic/routes.js +4 -9
- package/dist/esm/src/types.d.ts +88 -0
- package/dist/esm/src/types.js +1 -0
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +29 -0
- package/{src → dist/esm/src}/utils/BlockInstanceRunner.js +137 -256
- package/dist/esm/src/utils/LogData.d.ts +19 -0
- package/{src → dist/esm/src}/utils/LogData.js +11 -22
- package/dist/esm/src/utils/pathTemplateParser.d.ts +26 -0
- package/{src → dist/esm/src}/utils/pathTemplateParser.js +21 -40
- package/dist/esm/src/utils/utils.d.ts +1 -0
- package/dist/esm/src/utils/utils.js +11 -0
- package/dist/esm/start.d.ts +1 -0
- package/dist/esm/start.js +7 -0
- package/index.ts +147 -0
- package/package.json +106 -74
- package/src/assetManager.ts +191 -0
- package/src/assets/routes.ts +132 -0
- package/src/clusterService.ts +134 -0
- package/src/codeGeneratorManager.ts +57 -0
- package/src/config/routes.ts +159 -0
- package/src/configManager.ts +148 -0
- package/src/containerManager.ts +466 -0
- package/src/filesystem/routes.ts +74 -0
- package/src/filesystemManager.ts +93 -0
- package/src/identities/routes.ts +20 -0
- package/src/instanceManager.ts +503 -0
- package/src/instances/routes.ts +164 -0
- package/src/middleware/cors.ts +9 -0
- package/src/middleware/kapeta.ts +27 -0
- package/src/middleware/stringBody.ts +16 -0
- package/src/networkManager.ts +137 -0
- package/src/operatorManager.ts +221 -0
- package/src/progressListener.ts +102 -0
- package/src/{providerManager.js → providerManager.ts} +15 -31
- package/src/providers/routes.ts +46 -0
- package/src/proxy/routes.ts +148 -0
- package/src/proxy/types/{rest.js → rest.ts} +30 -30
- package/src/proxy/types/web.ts +60 -0
- package/src/{repositoryManager.js → repositoryManager.ts} +45 -73
- package/src/serviceManager.ts +120 -0
- package/src/socketManager.ts +57 -0
- package/src/storageService.ts +88 -0
- package/src/traffic/routes.ts +18 -0
- package/src/types.ts +97 -0
- package/src/utils/BlockInstanceRunner.ts +555 -0
- package/src/utils/LogData.ts +47 -0
- package/src/utils/pathTemplateParser.ts +138 -0
- package/src/utils/utils.ts +12 -0
- package/start.ts +8 -0
- package/tsconfig.json +13 -0
- package/index.js +0 -127
- package/src/config/routes.js +0 -160
- package/src/filesystem/routes.js +0 -74
- package/src/identities/routes.js +0 -19
- package/src/progressListener.js +0 -82
- package/src/proxy/routes.js +0 -126
- package/src/utils/utils.js +0 -13
- package/start.js +0 -7
@@ -1,62 +1,52 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
const ClusterConfiguration = require('@kapeta/local-cluster-config').default;
|
11
|
-
|
1
|
+
import Path from 'path';
|
2
|
+
import { storageService } from './storageService';
|
3
|
+
import os from 'os';
|
4
|
+
import _ from 'lodash';
|
5
|
+
import FSExtra from 'fs-extra';
|
6
|
+
import { Docker } from 'node-docker-api';
|
7
|
+
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
8
|
+
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
12
9
|
const LABEL_PORT_PREFIX = 'kapeta_port-';
|
13
|
-
|
14
10
|
const NANO_SECOND = 1000000;
|
15
11
|
const HEALTH_CHECK_INTERVAL = 2000;
|
16
12
|
const HEALTH_CHECK_MAX = 30;
|
17
13
|
const IMAGE_PULL_CACHE_TTL = 30 * 60 * 1000;
|
18
14
|
const IMAGE_PULL_CACHE = {};
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
stream.on('end', resolve);
|
25
|
-
stream.on('error', reject);
|
26
|
-
});
|
27
|
-
|
15
|
+
const promisifyStream = (stream) => new Promise((resolve, reject) => {
|
16
|
+
stream.on('data', (d) => console.log(d.toString()));
|
17
|
+
stream.on('end', resolve);
|
18
|
+
stream.on('error', reject);
|
19
|
+
});
|
28
20
|
class ContainerManager {
|
21
|
+
_docker;
|
22
|
+
_alive;
|
23
|
+
_mountDir;
|
29
24
|
constructor() {
|
30
25
|
this._docker = null;
|
31
26
|
this._alive = false;
|
32
27
|
this._mountDir = Path.join(storageService.getKapetaBasedir(), 'mounts');
|
33
|
-
|
28
|
+
FSExtra.mkdirpSync(this._mountDir);
|
34
29
|
}
|
35
|
-
|
36
30
|
async initialize() {
|
37
31
|
// Use the value from cluster-service.yml if configured
|
38
32
|
const dockerConfig = ClusterConfiguration.getDockerConfig();
|
39
|
-
const connectOptions =
|
40
|
-
|
41
|
-
|
42
|
-
:
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
{ protocol: 'https', host: 'localhost', port: 2376 },
|
57
|
-
{ protocol: 'http', host: '127.0.0.1', port: 2375 },
|
58
|
-
{ protocol: 'https', host: '127.0.0.1', port: 2376 },
|
59
|
-
];
|
33
|
+
const connectOptions = Object.keys(dockerConfig).length > 0
|
34
|
+
? [dockerConfig]
|
35
|
+
: [
|
36
|
+
// use defaults: DOCKER_HOST etc from env, if available
|
37
|
+
undefined,
|
38
|
+
// default linux
|
39
|
+
{ socketPath: '/var/run/docker.sock' },
|
40
|
+
// default macOS
|
41
|
+
{
|
42
|
+
socketPath: Path.join(os.homedir(), '.docker/run/docker.sock'),
|
43
|
+
},
|
44
|
+
// Default http
|
45
|
+
{ protocol: 'http', host: 'localhost', port: 2375 },
|
46
|
+
{ protocol: 'https', host: 'localhost', port: 2376 },
|
47
|
+
{ protocol: 'http', host: '127.0.0.1', port: 2375 },
|
48
|
+
{ protocol: 'https', host: '127.0.0.1', port: 2376 },
|
49
|
+
];
|
60
50
|
for (const opts of connectOptions) {
|
61
51
|
try {
|
62
52
|
const client = new Docker(opts);
|
@@ -64,49 +54,38 @@ class ContainerManager {
|
|
64
54
|
this._docker = client;
|
65
55
|
this._alive = true;
|
66
56
|
return;
|
67
|
-
}
|
57
|
+
}
|
58
|
+
catch (err) {
|
68
59
|
// silently ignore bad configs
|
69
60
|
}
|
70
61
|
}
|
71
|
-
|
72
62
|
throw new Error('Could not connect to docker daemon. Please make sure docker is running and working.');
|
73
63
|
}
|
74
|
-
|
75
64
|
isAlive() {
|
76
65
|
return this._alive;
|
77
66
|
}
|
78
|
-
|
79
67
|
getMountPoint(kind, mountName) {
|
80
68
|
const kindUri = parseKapetaUri(kind);
|
81
|
-
return Path.join(
|
82
|
-
this._mountDir,
|
83
|
-
kindUri.handle,
|
84
|
-
kindUri.name,
|
85
|
-
mountName
|
86
|
-
);
|
69
|
+
return Path.join(this._mountDir, kindUri.handle, kindUri.name, mountName);
|
87
70
|
}
|
88
|
-
|
89
71
|
createMounts(kind, mountOpts) {
|
90
72
|
const mounts = {};
|
91
|
-
|
92
73
|
_.forEach(mountOpts, (containerPath, mountName) => {
|
93
74
|
const hostPath = this.getMountPoint(kind, mountName);
|
94
|
-
|
75
|
+
FSExtra.mkdirpSync(hostPath);
|
95
76
|
mounts[containerPath] = hostPath;
|
96
77
|
});
|
97
78
|
return mounts;
|
98
79
|
}
|
99
|
-
|
100
80
|
async ping() {
|
101
81
|
try {
|
102
82
|
const pingResult = await this.docker().ping();
|
103
83
|
if (pingResult !== 'OK') {
|
104
84
|
throw new Error(`Ping failed: ${pingResult}`);
|
105
85
|
}
|
106
|
-
}
|
107
|
-
|
108
|
-
|
109
|
-
);
|
86
|
+
}
|
87
|
+
catch (e) {
|
88
|
+
throw new Error(`Docker not running. Please start the docker daemon before running this command. Error: ${e.message}`);
|
110
89
|
}
|
111
90
|
}
|
112
91
|
docker() {
|
@@ -115,20 +94,17 @@ class ContainerManager {
|
|
115
94
|
}
|
116
95
|
return this._docker;
|
117
96
|
}
|
118
|
-
|
119
97
|
async getContainerByName(containerName) {
|
120
98
|
const containers = await this.docker().container.list({ all: true });
|
121
99
|
return containers.find((container) => {
|
122
100
|
return container.data.Names.indexOf(`/${containerName}`) > -1;
|
123
101
|
});
|
124
102
|
}
|
125
|
-
|
126
103
|
async pull(image, cacheForMS = IMAGE_PULL_CACHE_TTL) {
|
127
104
|
let [imageName, tag] = image.split(/:/);
|
128
105
|
if (!tag) {
|
129
106
|
tag = 'latest';
|
130
107
|
}
|
131
|
-
|
132
108
|
if (tag !== 'latest') {
|
133
109
|
if (IMAGE_PULL_CACHE[image]) {
|
134
110
|
const timeSince = Date.now() - IMAGE_PULL_CACHE[image];
|
@@ -136,33 +112,26 @@ class ContainerManager {
|
|
136
112
|
return;
|
137
113
|
}
|
138
114
|
}
|
139
|
-
|
140
115
|
const imageTagList = (await this.docker().image.list())
|
141
|
-
.
|
142
|
-
.
|
116
|
+
.map((image) => image.data)
|
117
|
+
.filter((imageData) => !!imageData.RepoTags)
|
118
|
+
.map((imageData) => imageData.RepoTags);
|
143
119
|
if (imageTagList.some((imageTags) => imageTags.indexOf(image) > -1)) {
|
144
120
|
console.log('Image found: %s', image);
|
145
121
|
return;
|
146
122
|
}
|
147
123
|
console.log('Image not found: %s', image);
|
148
124
|
}
|
149
|
-
|
150
125
|
console.log('Pulling image: %s', image);
|
151
126
|
await this.docker()
|
152
|
-
.image.create(
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
tag: tag,
|
157
|
-
}
|
158
|
-
)
|
127
|
+
.image.create({}, {
|
128
|
+
fromImage: imageName,
|
129
|
+
tag: tag,
|
130
|
+
})
|
159
131
|
.then((stream) => promisifyStream(stream));
|
160
|
-
|
161
132
|
IMAGE_PULL_CACHE[image] = Date.now();
|
162
|
-
|
163
133
|
console.log('Image pulled: %s', image);
|
164
134
|
}
|
165
|
-
|
166
135
|
toDockerMounts(mounts) {
|
167
136
|
const Mounts = [];
|
168
137
|
_.forEach(mounts, (Source, Target) => {
|
@@ -174,41 +143,24 @@ class ContainerManager {
|
|
174
143
|
Consistency: 'consistent',
|
175
144
|
});
|
176
145
|
});
|
177
|
-
|
178
146
|
return Mounts;
|
179
147
|
}
|
180
|
-
|
181
148
|
toDockerHealth(health) {
|
182
149
|
return {
|
183
150
|
Test: ['CMD-SHELL', health.cmd],
|
184
|
-
Interval: health.interval
|
185
|
-
|
186
|
-
: 5000 * NANO_SECOND,
|
187
|
-
Timeout: health.timeout
|
188
|
-
? health.timeout * NANO_SECOND
|
189
|
-
: 15000 * NANO_SECOND,
|
151
|
+
Interval: health.interval ? health.interval * NANO_SECOND : 5000 * NANO_SECOND,
|
152
|
+
Timeout: health.timeout ? health.timeout * NANO_SECOND : 15000 * NANO_SECOND,
|
190
153
|
Retries: health.retries || 10,
|
191
154
|
};
|
192
155
|
}
|
193
|
-
|
194
|
-
/**
|
195
|
-
*
|
196
|
-
* @param {string} image
|
197
|
-
* @param {string} name
|
198
|
-
* @param {{ports:{},mounts:{},env:{}}} opts
|
199
|
-
* @return {Promise<ContainerInfo>}
|
200
|
-
*/
|
201
156
|
async run(image, name, opts) {
|
202
157
|
const PortBindings = {};
|
203
158
|
const Env = [];
|
204
159
|
const Labels = {
|
205
160
|
kapeta: 'true',
|
206
161
|
};
|
207
|
-
|
208
162
|
await this.pull(image);
|
209
|
-
|
210
163
|
const ExposedPorts = {};
|
211
|
-
|
212
164
|
_.forEach(opts.ports, (portInfo, containerPort) => {
|
213
165
|
ExposedPorts['' + containerPort] = {};
|
214
166
|
PortBindings['' + containerPort] = [
|
@@ -217,18 +169,13 @@ class ContainerManager {
|
|
217
169
|
HostIp: '127.0.0.1',
|
218
170
|
},
|
219
171
|
];
|
220
|
-
|
221
172
|
Labels[LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
|
222
173
|
});
|
223
|
-
|
224
174
|
const Mounts = this.toDockerMounts(opts.mounts);
|
225
|
-
|
226
175
|
_.forEach(opts.env, (value, name) => {
|
227
176
|
Env.push(name + '=' + value);
|
228
177
|
});
|
229
|
-
|
230
178
|
let HealthCheck = undefined;
|
231
|
-
|
232
179
|
if (opts.health) {
|
233
180
|
HealthCheck = this.toDockerHealth(opts.health);
|
234
181
|
}
|
@@ -238,7 +185,6 @@ class ContainerManager {
|
|
238
185
|
Hostname: name + '.kapeta',
|
239
186
|
Labels,
|
240
187
|
Cmd: opts.cmd,
|
241
|
-
|
242
188
|
ExposedPorts,
|
243
189
|
Env,
|
244
190
|
HealthCheck,
|
@@ -247,86 +193,73 @@ class ContainerManager {
|
|
247
193
|
Mounts,
|
248
194
|
},
|
249
195
|
});
|
250
|
-
|
251
196
|
if (opts.health) {
|
252
197
|
await this.waitForHealthy(dockerContainer);
|
253
198
|
}
|
254
|
-
|
255
199
|
return new ContainerInfo(dockerContainer);
|
256
200
|
}
|
257
|
-
|
258
201
|
async startContainer(opts) {
|
259
202
|
const dockerContainer = await this.docker().container.create(opts);
|
260
203
|
await dockerContainer.start();
|
261
204
|
return dockerContainer;
|
262
205
|
}
|
263
|
-
|
264
|
-
async waitForReady(container, attempt) {
|
206
|
+
async waitForReady(container, attempt = 0) {
|
265
207
|
if (!attempt) {
|
266
208
|
attempt = 0;
|
267
209
|
}
|
268
|
-
|
269
210
|
if (attempt >= HEALTH_CHECK_MAX) {
|
270
|
-
throw new Error(
|
271
|
-
'Container did not become ready within the timeout'
|
272
|
-
);
|
211
|
+
throw new Error('Container did not become ready within the timeout');
|
273
212
|
}
|
274
|
-
|
275
213
|
if (await this._isReady(container)) {
|
276
214
|
return;
|
277
215
|
}
|
278
|
-
|
279
216
|
return new Promise((resolve, reject) => {
|
280
217
|
setTimeout(async () => {
|
281
218
|
try {
|
282
219
|
await this.waitForReady(container, attempt + 1);
|
283
220
|
resolve();
|
284
|
-
}
|
221
|
+
}
|
222
|
+
catch (err) {
|
285
223
|
reject(err);
|
286
224
|
}
|
287
225
|
}, HEALTH_CHECK_INTERVAL);
|
288
226
|
});
|
289
227
|
}
|
290
|
-
|
291
228
|
async waitForHealthy(container, attempt) {
|
292
229
|
if (!attempt) {
|
293
230
|
attempt = 0;
|
294
231
|
}
|
295
|
-
|
296
232
|
if (attempt >= HEALTH_CHECK_MAX) {
|
297
|
-
throw new Error(
|
298
|
-
'Container did not become healthy within the timeout'
|
299
|
-
);
|
233
|
+
throw new Error('Container did not become healthy within the timeout');
|
300
234
|
}
|
301
|
-
|
302
235
|
if (await this._isHealthy(container)) {
|
303
236
|
return;
|
304
237
|
}
|
305
|
-
|
306
238
|
return new Promise((resolve, reject) => {
|
307
239
|
setTimeout(async () => {
|
308
240
|
try {
|
309
|
-
await this.waitForHealthy(container, attempt + 1);
|
241
|
+
await this.waitForHealthy(container, (attempt ?? 0) + 1);
|
310
242
|
resolve();
|
311
|
-
}
|
243
|
+
}
|
244
|
+
catch (err) {
|
312
245
|
reject(err);
|
313
246
|
}
|
314
247
|
}, HEALTH_CHECK_INTERVAL);
|
315
248
|
});
|
316
249
|
}
|
317
|
-
|
318
250
|
async _isReady(container) {
|
319
251
|
const info = await container.status();
|
320
|
-
|
252
|
+
const infoData = info?.data;
|
253
|
+
if (infoData?.State?.Status === 'exited') {
|
321
254
|
throw new Error('Container exited unexpectedly');
|
322
255
|
}
|
323
|
-
return
|
256
|
+
return infoData?.State?.Running ?? false;
|
324
257
|
}
|
325
258
|
async _isHealthy(container) {
|
326
259
|
const info = await container.status();
|
327
|
-
|
260
|
+
const infoData = info?.data;
|
261
|
+
return infoData?.State?.Health?.Status === 'healthy';
|
328
262
|
}
|
329
|
-
|
330
263
|
/**
|
331
264
|
*
|
332
265
|
* @param name
|
@@ -334,24 +267,22 @@ class ContainerManager {
|
|
334
267
|
*/
|
335
268
|
async get(name) {
|
336
269
|
let dockerContainer = null;
|
337
|
-
|
338
270
|
try {
|
339
271
|
dockerContainer = await this.docker().container.get(name);
|
340
272
|
await dockerContainer.status();
|
341
|
-
}
|
273
|
+
}
|
274
|
+
catch (err) {
|
342
275
|
//Ignore
|
343
276
|
dockerContainer = null;
|
344
277
|
}
|
345
|
-
|
346
278
|
if (!dockerContainer) {
|
347
279
|
return null;
|
348
280
|
}
|
349
|
-
|
350
281
|
return new ContainerInfo(dockerContainer);
|
351
282
|
}
|
352
283
|
}
|
353
|
-
|
354
|
-
|
284
|
+
export class ContainerInfo {
|
285
|
+
_container;
|
355
286
|
/**
|
356
287
|
*
|
357
288
|
* @param {Container} dockerContainer
|
@@ -364,96 +295,64 @@ class ContainerInfo {
|
|
364
295
|
*/
|
365
296
|
this._container = dockerContainer;
|
366
297
|
}
|
367
|
-
|
368
298
|
get native() {
|
369
299
|
return this._container;
|
370
300
|
}
|
371
|
-
|
372
301
|
async isRunning() {
|
373
302
|
const inspectResult = await this.getStatus();
|
374
|
-
|
375
303
|
if (!inspectResult || !inspectResult.State) {
|
376
304
|
return false;
|
377
305
|
}
|
378
|
-
|
379
306
|
return inspectResult.State.Running || inspectResult.State.Restarting;
|
380
307
|
}
|
381
|
-
|
382
308
|
async start() {
|
383
309
|
await this._container.start();
|
384
310
|
}
|
385
|
-
|
386
311
|
async restart() {
|
387
312
|
await this._container.restart();
|
388
313
|
}
|
389
|
-
|
390
314
|
async stop() {
|
391
315
|
await this._container.stop();
|
392
316
|
}
|
393
|
-
|
394
317
|
async remove(opts) {
|
395
|
-
await this._container.delete({ force: !!opts
|
318
|
+
await this._container.delete({ force: !!opts?.force });
|
396
319
|
}
|
397
|
-
|
398
320
|
async getPort(type) {
|
399
321
|
const ports = await this.getPorts();
|
400
|
-
|
401
|
-
if (ports[type]) {
|
322
|
+
if (ports && ports[type]) {
|
402
323
|
return ports[type];
|
403
324
|
}
|
404
|
-
|
405
325
|
return null;
|
406
326
|
}
|
407
|
-
|
408
327
|
async getStatus() {
|
409
328
|
const result = await this._container.status();
|
410
|
-
|
411
329
|
return result ? result.data : null;
|
412
330
|
}
|
413
|
-
|
414
331
|
async getPorts() {
|
415
332
|
const inspectResult = await this.getStatus();
|
416
|
-
|
417
|
-
if (
|
418
|
-
!inspectResult ||
|
419
|
-
!inspectResult.Config ||
|
420
|
-
!inspectResult.Config.Labels
|
421
|
-
) {
|
333
|
+
if (!inspectResult || !inspectResult.Config || !inspectResult.Config.Labels) {
|
422
334
|
return false;
|
423
335
|
}
|
424
|
-
|
425
336
|
const portTypes = {};
|
426
337
|
const ports = {};
|
427
|
-
|
428
338
|
_.forEach(inspectResult.Config.Labels, (portType, name) => {
|
429
339
|
if (!name.startsWith(LABEL_PORT_PREFIX)) {
|
430
340
|
return;
|
431
341
|
}
|
432
|
-
|
433
342
|
const hostPort = name.substr(LABEL_PORT_PREFIX.length);
|
434
|
-
|
435
343
|
portTypes[hostPort] = portType;
|
436
344
|
});
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
ports[portType] = {
|
448
|
-
containerPort,
|
449
|
-
protocol,
|
450
|
-
hostPort,
|
451
|
-
};
|
452
|
-
}
|
453
|
-
);
|
454
|
-
|
345
|
+
_.forEach(inspectResult.HostConfig.PortBindings, (portBindings, containerPortSpec) => {
|
346
|
+
let [containerPort, protocol] = containerPortSpec.split(/\//);
|
347
|
+
const hostPort = portBindings[0].HostPort;
|
348
|
+
const portType = portTypes[hostPort];
|
349
|
+
ports[portType] = {
|
350
|
+
containerPort,
|
351
|
+
protocol,
|
352
|
+
hostPort,
|
353
|
+
};
|
354
|
+
});
|
455
355
|
return ports;
|
456
356
|
}
|
457
357
|
}
|
458
|
-
|
459
|
-
module.exports = new ContainerManager();
|
358
|
+
export const containerManager = new ContainerManager();
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import Router from 'express-promise-router';
|
2
|
+
import { stringBody } from '../middleware/stringBody';
|
3
|
+
import { filesystemManager } from '../filesystemManager';
|
4
|
+
import { corsHandler } from '../middleware/cors';
|
5
|
+
let router = Router();
|
6
|
+
router.use('/', corsHandler);
|
7
|
+
router.get('/root', (req, res) => {
|
8
|
+
res.send(filesystemManager.getRootFolder());
|
9
|
+
});
|
10
|
+
router.get('/project/root', (req, res) => {
|
11
|
+
res.send(filesystemManager.getProjectRootFolder());
|
12
|
+
});
|
13
|
+
router.use('/project/root', stringBody);
|
14
|
+
router.post('/project/root', (req, res) => {
|
15
|
+
filesystemManager.setProjectRootFolder(req.stringBody ?? '');
|
16
|
+
res.sendStatus(204);
|
17
|
+
});
|
18
|
+
router.use('/', (req, res, next) => {
|
19
|
+
if (!req.query.path) {
|
20
|
+
res.status(400).send({ error: 'Missing required query parameter "path"' });
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
next();
|
24
|
+
});
|
25
|
+
router.get('/list', async (req, res) => {
|
26
|
+
let pathArg = req.query.path;
|
27
|
+
try {
|
28
|
+
res.send(await filesystemManager.readDirectory(pathArg));
|
29
|
+
}
|
30
|
+
catch (err) {
|
31
|
+
res.status(400).send({ error: '' + err });
|
32
|
+
}
|
33
|
+
});
|
34
|
+
router.get('/readfile', async (req, res) => {
|
35
|
+
let pathArg = req.query.path;
|
36
|
+
try {
|
37
|
+
res.send(await filesystemManager.readFile(pathArg));
|
38
|
+
}
|
39
|
+
catch (err) {
|
40
|
+
res.status(400).send({ error: '' + err });
|
41
|
+
}
|
42
|
+
});
|
43
|
+
router.put('/mkdir', async (req, res) => {
|
44
|
+
let pathArg = req.query.path;
|
45
|
+
try {
|
46
|
+
await filesystemManager.createFolder(pathArg);
|
47
|
+
res.sendStatus(204);
|
48
|
+
}
|
49
|
+
catch (err) {
|
50
|
+
res.status(400).send({ error: '' + err });
|
51
|
+
}
|
52
|
+
});
|
53
|
+
router.use('/writefile', stringBody);
|
54
|
+
router.post('/writefile', async (req, res) => {
|
55
|
+
let pathArg = req.query.path;
|
56
|
+
try {
|
57
|
+
await filesystemManager.writeFile(pathArg, req.stringBody ?? '');
|
58
|
+
res.sendStatus(204);
|
59
|
+
}
|
60
|
+
catch (err) {
|
61
|
+
res.status(400).send({ error: '' + err });
|
62
|
+
}
|
63
|
+
});
|
64
|
+
export default router;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
declare class FilesystemManager {
|
3
|
+
writeFile(path: string, data: string | Buffer): Promise<void>;
|
4
|
+
createFolder(path: string): Promise<void>;
|
5
|
+
readDirectory(path: string): Promise<{
|
6
|
+
path: string;
|
7
|
+
folder: boolean;
|
8
|
+
}[]>;
|
9
|
+
readFile(path: string): Promise<Buffer>;
|
10
|
+
getRootFolder(): string;
|
11
|
+
getProjectRootFolder(): string | undefined;
|
12
|
+
setProjectRootFolder(folder: string): void;
|
13
|
+
}
|
14
|
+
export declare const filesystemManager: FilesystemManager;
|
15
|
+
export {};
|