@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
@@ -0,0 +1,365 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.containerManager = exports.ContainerInfo = void 0;
|
7
|
+
const path_1 = __importDefault(require("path"));
|
8
|
+
const storageService_1 = require("./storageService");
|
9
|
+
const os_1 = __importDefault(require("os"));
|
10
|
+
const lodash_1 = __importDefault(require("lodash"));
|
11
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
12
|
+
const node_docker_api_1 = require("node-docker-api");
|
13
|
+
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
14
|
+
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
15
|
+
const LABEL_PORT_PREFIX = 'kapeta_port-';
|
16
|
+
const NANO_SECOND = 1000000;
|
17
|
+
const HEALTH_CHECK_INTERVAL = 2000;
|
18
|
+
const HEALTH_CHECK_MAX = 30;
|
19
|
+
const IMAGE_PULL_CACHE_TTL = 30 * 60 * 1000;
|
20
|
+
const IMAGE_PULL_CACHE = {};
|
21
|
+
const promisifyStream = (stream) => new Promise((resolve, reject) => {
|
22
|
+
stream.on('data', (d) => console.log(d.toString()));
|
23
|
+
stream.on('end', resolve);
|
24
|
+
stream.on('error', reject);
|
25
|
+
});
|
26
|
+
class ContainerManager {
|
27
|
+
_docker;
|
28
|
+
_alive;
|
29
|
+
_mountDir;
|
30
|
+
constructor() {
|
31
|
+
this._docker = null;
|
32
|
+
this._alive = false;
|
33
|
+
this._mountDir = path_1.default.join(storageService_1.storageService.getKapetaBasedir(), 'mounts');
|
34
|
+
fs_extra_1.default.mkdirpSync(this._mountDir);
|
35
|
+
}
|
36
|
+
async initialize() {
|
37
|
+
// Use the value from cluster-service.yml if configured
|
38
|
+
const dockerConfig = local_cluster_config_1.default.getDockerConfig();
|
39
|
+
const connectOptions = Object.keys(dockerConfig).length > 0
|
40
|
+
? [dockerConfig]
|
41
|
+
: [
|
42
|
+
// use defaults: DOCKER_HOST etc from env, if available
|
43
|
+
undefined,
|
44
|
+
// default linux
|
45
|
+
{ socketPath: '/var/run/docker.sock' },
|
46
|
+
// default macOS
|
47
|
+
{
|
48
|
+
socketPath: path_1.default.join(os_1.default.homedir(), '.docker/run/docker.sock'),
|
49
|
+
},
|
50
|
+
// Default http
|
51
|
+
{ protocol: 'http', host: 'localhost', port: 2375 },
|
52
|
+
{ protocol: 'https', host: 'localhost', port: 2376 },
|
53
|
+
{ protocol: 'http', host: '127.0.0.1', port: 2375 },
|
54
|
+
{ protocol: 'https', host: '127.0.0.1', port: 2376 },
|
55
|
+
];
|
56
|
+
for (const opts of connectOptions) {
|
57
|
+
try {
|
58
|
+
const client = new node_docker_api_1.Docker(opts);
|
59
|
+
await client.ping();
|
60
|
+
this._docker = client;
|
61
|
+
this._alive = true;
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
catch (err) {
|
65
|
+
// silently ignore bad configs
|
66
|
+
}
|
67
|
+
}
|
68
|
+
throw new Error('Could not connect to docker daemon. Please make sure docker is running and working.');
|
69
|
+
}
|
70
|
+
isAlive() {
|
71
|
+
return this._alive;
|
72
|
+
}
|
73
|
+
getMountPoint(kind, mountName) {
|
74
|
+
const kindUri = (0, nodejs_utils_1.parseKapetaUri)(kind);
|
75
|
+
return path_1.default.join(this._mountDir, kindUri.handle, kindUri.name, mountName);
|
76
|
+
}
|
77
|
+
createMounts(kind, mountOpts) {
|
78
|
+
const mounts = {};
|
79
|
+
lodash_1.default.forEach(mountOpts, (containerPath, mountName) => {
|
80
|
+
const hostPath = this.getMountPoint(kind, mountName);
|
81
|
+
fs_extra_1.default.mkdirpSync(hostPath);
|
82
|
+
mounts[containerPath] = hostPath;
|
83
|
+
});
|
84
|
+
return mounts;
|
85
|
+
}
|
86
|
+
async ping() {
|
87
|
+
try {
|
88
|
+
const pingResult = await this.docker().ping();
|
89
|
+
if (pingResult !== 'OK') {
|
90
|
+
throw new Error(`Ping failed: ${pingResult}`);
|
91
|
+
}
|
92
|
+
}
|
93
|
+
catch (e) {
|
94
|
+
throw new Error(`Docker not running. Please start the docker daemon before running this command. Error: ${e.message}`);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
docker() {
|
98
|
+
if (!this._docker) {
|
99
|
+
throw new Error(`Docker not running`);
|
100
|
+
}
|
101
|
+
return this._docker;
|
102
|
+
}
|
103
|
+
async getContainerByName(containerName) {
|
104
|
+
const containers = await this.docker().container.list({ all: true });
|
105
|
+
return containers.find((container) => {
|
106
|
+
return container.data.Names.indexOf(`/${containerName}`) > -1;
|
107
|
+
});
|
108
|
+
}
|
109
|
+
async pull(image, cacheForMS = IMAGE_PULL_CACHE_TTL) {
|
110
|
+
let [imageName, tag] = image.split(/:/);
|
111
|
+
if (!tag) {
|
112
|
+
tag = 'latest';
|
113
|
+
}
|
114
|
+
if (tag !== 'latest') {
|
115
|
+
if (IMAGE_PULL_CACHE[image]) {
|
116
|
+
const timeSince = Date.now() - IMAGE_PULL_CACHE[image];
|
117
|
+
if (timeSince < cacheForMS) {
|
118
|
+
return;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
const imageTagList = (await this.docker().image.list())
|
122
|
+
.map((image) => image.data)
|
123
|
+
.filter((imageData) => !!imageData.RepoTags)
|
124
|
+
.map((imageData) => imageData.RepoTags);
|
125
|
+
if (imageTagList.some((imageTags) => imageTags.indexOf(image) > -1)) {
|
126
|
+
console.log('Image found: %s', image);
|
127
|
+
return;
|
128
|
+
}
|
129
|
+
console.log('Image not found: %s', image);
|
130
|
+
}
|
131
|
+
console.log('Pulling image: %s', image);
|
132
|
+
await this.docker()
|
133
|
+
.image.create({}, {
|
134
|
+
fromImage: imageName,
|
135
|
+
tag: tag,
|
136
|
+
})
|
137
|
+
.then((stream) => promisifyStream(stream));
|
138
|
+
IMAGE_PULL_CACHE[image] = Date.now();
|
139
|
+
console.log('Image pulled: %s', image);
|
140
|
+
}
|
141
|
+
toDockerMounts(mounts) {
|
142
|
+
const Mounts = [];
|
143
|
+
lodash_1.default.forEach(mounts, (Source, Target) => {
|
144
|
+
Mounts.push({
|
145
|
+
Target,
|
146
|
+
Source,
|
147
|
+
Type: 'bind',
|
148
|
+
ReadOnly: false,
|
149
|
+
Consistency: 'consistent',
|
150
|
+
});
|
151
|
+
});
|
152
|
+
return Mounts;
|
153
|
+
}
|
154
|
+
toDockerHealth(health) {
|
155
|
+
return {
|
156
|
+
Test: ['CMD-SHELL', health.cmd],
|
157
|
+
Interval: health.interval ? health.interval * NANO_SECOND : 5000 * NANO_SECOND,
|
158
|
+
Timeout: health.timeout ? health.timeout * NANO_SECOND : 15000 * NANO_SECOND,
|
159
|
+
Retries: health.retries || 10,
|
160
|
+
};
|
161
|
+
}
|
162
|
+
async run(image, name, opts) {
|
163
|
+
const PortBindings = {};
|
164
|
+
const Env = [];
|
165
|
+
const Labels = {
|
166
|
+
kapeta: 'true',
|
167
|
+
};
|
168
|
+
await this.pull(image);
|
169
|
+
const ExposedPorts = {};
|
170
|
+
lodash_1.default.forEach(opts.ports, (portInfo, containerPort) => {
|
171
|
+
ExposedPorts['' + containerPort] = {};
|
172
|
+
PortBindings['' + containerPort] = [
|
173
|
+
{
|
174
|
+
HostPort: '' + portInfo.hostPort,
|
175
|
+
HostIp: '127.0.0.1',
|
176
|
+
},
|
177
|
+
];
|
178
|
+
Labels[LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
|
179
|
+
});
|
180
|
+
const Mounts = this.toDockerMounts(opts.mounts);
|
181
|
+
lodash_1.default.forEach(opts.env, (value, name) => {
|
182
|
+
Env.push(name + '=' + value);
|
183
|
+
});
|
184
|
+
let HealthCheck = undefined;
|
185
|
+
if (opts.health) {
|
186
|
+
HealthCheck = this.toDockerHealth(opts.health);
|
187
|
+
}
|
188
|
+
const dockerContainer = await this.startContainer({
|
189
|
+
name: name,
|
190
|
+
Image: image,
|
191
|
+
Hostname: name + '.kapeta',
|
192
|
+
Labels,
|
193
|
+
Cmd: opts.cmd,
|
194
|
+
ExposedPorts,
|
195
|
+
Env,
|
196
|
+
HealthCheck,
|
197
|
+
HostConfig: {
|
198
|
+
PortBindings,
|
199
|
+
Mounts,
|
200
|
+
},
|
201
|
+
});
|
202
|
+
if (opts.health) {
|
203
|
+
await this.waitForHealthy(dockerContainer);
|
204
|
+
}
|
205
|
+
return new ContainerInfo(dockerContainer);
|
206
|
+
}
|
207
|
+
async startContainer(opts) {
|
208
|
+
const dockerContainer = await this.docker().container.create(opts);
|
209
|
+
await dockerContainer.start();
|
210
|
+
return dockerContainer;
|
211
|
+
}
|
212
|
+
async waitForReady(container, attempt = 0) {
|
213
|
+
if (!attempt) {
|
214
|
+
attempt = 0;
|
215
|
+
}
|
216
|
+
if (attempt >= HEALTH_CHECK_MAX) {
|
217
|
+
throw new Error('Container did not become ready within the timeout');
|
218
|
+
}
|
219
|
+
if (await this._isReady(container)) {
|
220
|
+
return;
|
221
|
+
}
|
222
|
+
return new Promise((resolve, reject) => {
|
223
|
+
setTimeout(async () => {
|
224
|
+
try {
|
225
|
+
await this.waitForReady(container, attempt + 1);
|
226
|
+
resolve();
|
227
|
+
}
|
228
|
+
catch (err) {
|
229
|
+
reject(err);
|
230
|
+
}
|
231
|
+
}, HEALTH_CHECK_INTERVAL);
|
232
|
+
});
|
233
|
+
}
|
234
|
+
async waitForHealthy(container, attempt) {
|
235
|
+
if (!attempt) {
|
236
|
+
attempt = 0;
|
237
|
+
}
|
238
|
+
if (attempt >= HEALTH_CHECK_MAX) {
|
239
|
+
throw new Error('Container did not become healthy within the timeout');
|
240
|
+
}
|
241
|
+
if (await this._isHealthy(container)) {
|
242
|
+
return;
|
243
|
+
}
|
244
|
+
return new Promise((resolve, reject) => {
|
245
|
+
setTimeout(async () => {
|
246
|
+
try {
|
247
|
+
await this.waitForHealthy(container, (attempt ?? 0) + 1);
|
248
|
+
resolve();
|
249
|
+
}
|
250
|
+
catch (err) {
|
251
|
+
reject(err);
|
252
|
+
}
|
253
|
+
}, HEALTH_CHECK_INTERVAL);
|
254
|
+
});
|
255
|
+
}
|
256
|
+
async _isReady(container) {
|
257
|
+
const info = await container.status();
|
258
|
+
const infoData = info?.data;
|
259
|
+
if (infoData?.State?.Status === 'exited') {
|
260
|
+
throw new Error('Container exited unexpectedly');
|
261
|
+
}
|
262
|
+
return infoData?.State?.Running ?? false;
|
263
|
+
}
|
264
|
+
async _isHealthy(container) {
|
265
|
+
const info = await container.status();
|
266
|
+
const infoData = info?.data;
|
267
|
+
return infoData?.State?.Health?.Status === 'healthy';
|
268
|
+
}
|
269
|
+
/**
|
270
|
+
*
|
271
|
+
* @param name
|
272
|
+
* @return {Promise<ContainerInfo>}
|
273
|
+
*/
|
274
|
+
async get(name) {
|
275
|
+
let dockerContainer = null;
|
276
|
+
try {
|
277
|
+
dockerContainer = await this.docker().container.get(name);
|
278
|
+
await dockerContainer.status();
|
279
|
+
}
|
280
|
+
catch (err) {
|
281
|
+
//Ignore
|
282
|
+
dockerContainer = null;
|
283
|
+
}
|
284
|
+
if (!dockerContainer) {
|
285
|
+
return null;
|
286
|
+
}
|
287
|
+
return new ContainerInfo(dockerContainer);
|
288
|
+
}
|
289
|
+
}
|
290
|
+
class ContainerInfo {
|
291
|
+
_container;
|
292
|
+
/**
|
293
|
+
*
|
294
|
+
* @param {Container} dockerContainer
|
295
|
+
*/
|
296
|
+
constructor(dockerContainer) {
|
297
|
+
/**
|
298
|
+
*
|
299
|
+
* @type {Container}
|
300
|
+
* @private
|
301
|
+
*/
|
302
|
+
this._container = dockerContainer;
|
303
|
+
}
|
304
|
+
get native() {
|
305
|
+
return this._container;
|
306
|
+
}
|
307
|
+
async isRunning() {
|
308
|
+
const inspectResult = await this.getStatus();
|
309
|
+
if (!inspectResult || !inspectResult.State) {
|
310
|
+
return false;
|
311
|
+
}
|
312
|
+
return inspectResult.State.Running || inspectResult.State.Restarting;
|
313
|
+
}
|
314
|
+
async start() {
|
315
|
+
await this._container.start();
|
316
|
+
}
|
317
|
+
async restart() {
|
318
|
+
await this._container.restart();
|
319
|
+
}
|
320
|
+
async stop() {
|
321
|
+
await this._container.stop();
|
322
|
+
}
|
323
|
+
async remove(opts) {
|
324
|
+
await this._container.delete({ force: !!opts?.force });
|
325
|
+
}
|
326
|
+
async getPort(type) {
|
327
|
+
const ports = await this.getPorts();
|
328
|
+
if (ports && ports[type]) {
|
329
|
+
return ports[type];
|
330
|
+
}
|
331
|
+
return null;
|
332
|
+
}
|
333
|
+
async getStatus() {
|
334
|
+
const result = await this._container.status();
|
335
|
+
return result ? result.data : null;
|
336
|
+
}
|
337
|
+
async getPorts() {
|
338
|
+
const inspectResult = await this.getStatus();
|
339
|
+
if (!inspectResult || !inspectResult.Config || !inspectResult.Config.Labels) {
|
340
|
+
return false;
|
341
|
+
}
|
342
|
+
const portTypes = {};
|
343
|
+
const ports = {};
|
344
|
+
lodash_1.default.forEach(inspectResult.Config.Labels, (portType, name) => {
|
345
|
+
if (!name.startsWith(LABEL_PORT_PREFIX)) {
|
346
|
+
return;
|
347
|
+
}
|
348
|
+
const hostPort = name.substr(LABEL_PORT_PREFIX.length);
|
349
|
+
portTypes[hostPort] = portType;
|
350
|
+
});
|
351
|
+
lodash_1.default.forEach(inspectResult.HostConfig.PortBindings, (portBindings, containerPortSpec) => {
|
352
|
+
let [containerPort, protocol] = containerPortSpec.split(/\//);
|
353
|
+
const hostPort = portBindings[0].HostPort;
|
354
|
+
const portType = portTypes[hostPort];
|
355
|
+
ports[portType] = {
|
356
|
+
containerPort,
|
357
|
+
protocol,
|
358
|
+
hostPort,
|
359
|
+
};
|
360
|
+
});
|
361
|
+
return ports;
|
362
|
+
}
|
363
|
+
}
|
364
|
+
exports.ContainerInfo = ContainerInfo;
|
365
|
+
exports.containerManager = new ContainerManager();
|
@@ -0,0 +1,69 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const express_promise_router_1 = __importDefault(require("express-promise-router"));
|
7
|
+
const stringBody_1 = require("../middleware/stringBody");
|
8
|
+
const filesystemManager_1 = require("../filesystemManager");
|
9
|
+
const cors_1 = require("../middleware/cors");
|
10
|
+
let router = (0, express_promise_router_1.default)();
|
11
|
+
router.use('/', cors_1.corsHandler);
|
12
|
+
router.get('/root', (req, res) => {
|
13
|
+
res.send(filesystemManager_1.filesystemManager.getRootFolder());
|
14
|
+
});
|
15
|
+
router.get('/project/root', (req, res) => {
|
16
|
+
res.send(filesystemManager_1.filesystemManager.getProjectRootFolder());
|
17
|
+
});
|
18
|
+
router.use('/project/root', stringBody_1.stringBody);
|
19
|
+
router.post('/project/root', (req, res) => {
|
20
|
+
filesystemManager_1.filesystemManager.setProjectRootFolder(req.stringBody ?? '');
|
21
|
+
res.sendStatus(204);
|
22
|
+
});
|
23
|
+
router.use('/', (req, res, next) => {
|
24
|
+
if (!req.query.path) {
|
25
|
+
res.status(400).send({ error: 'Missing required query parameter "path"' });
|
26
|
+
return;
|
27
|
+
}
|
28
|
+
next();
|
29
|
+
});
|
30
|
+
router.get('/list', async (req, res) => {
|
31
|
+
let pathArg = req.query.path;
|
32
|
+
try {
|
33
|
+
res.send(await filesystemManager_1.filesystemManager.readDirectory(pathArg));
|
34
|
+
}
|
35
|
+
catch (err) {
|
36
|
+
res.status(400).send({ error: '' + err });
|
37
|
+
}
|
38
|
+
});
|
39
|
+
router.get('/readfile', async (req, res) => {
|
40
|
+
let pathArg = req.query.path;
|
41
|
+
try {
|
42
|
+
res.send(await filesystemManager_1.filesystemManager.readFile(pathArg));
|
43
|
+
}
|
44
|
+
catch (err) {
|
45
|
+
res.status(400).send({ error: '' + err });
|
46
|
+
}
|
47
|
+
});
|
48
|
+
router.put('/mkdir', async (req, res) => {
|
49
|
+
let pathArg = req.query.path;
|
50
|
+
try {
|
51
|
+
await filesystemManager_1.filesystemManager.createFolder(pathArg);
|
52
|
+
res.sendStatus(204);
|
53
|
+
}
|
54
|
+
catch (err) {
|
55
|
+
res.status(400).send({ error: '' + err });
|
56
|
+
}
|
57
|
+
});
|
58
|
+
router.use('/writefile', stringBody_1.stringBody);
|
59
|
+
router.post('/writefile', async (req, res) => {
|
60
|
+
let pathArg = req.query.path;
|
61
|
+
try {
|
62
|
+
await filesystemManager_1.filesystemManager.writeFile(pathArg, req.stringBody ?? '');
|
63
|
+
res.sendStatus(204);
|
64
|
+
}
|
65
|
+
catch (err) {
|
66
|
+
res.status(400).send({ error: '' + err });
|
67
|
+
}
|
68
|
+
});
|
69
|
+
exports.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 {};
|
@@ -0,0 +1,87 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.filesystemManager = void 0;
|
7
|
+
const path_1 = __importDefault(require("path"));
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
10
|
+
const storageService_1 = require("./storageService");
|
11
|
+
const SECTION_ID = 'filesystem';
|
12
|
+
const PROJECT_ROOT = 'project_root';
|
13
|
+
function isFile(path) {
|
14
|
+
try {
|
15
|
+
return fs_1.default.statSync(path).isFile();
|
16
|
+
}
|
17
|
+
catch (error) {
|
18
|
+
return false;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
class FilesystemManager {
|
22
|
+
async writeFile(path, data) {
|
23
|
+
const dirName = path_1.default.dirname(path);
|
24
|
+
console.log('Dir name', dirName, path);
|
25
|
+
if (!fs_1.default.existsSync(dirName)) {
|
26
|
+
console.log('Making folder', dirName);
|
27
|
+
fs_extra_1.default.mkdirpSync(dirName, {});
|
28
|
+
}
|
29
|
+
fs_1.default.writeFileSync(path, data);
|
30
|
+
}
|
31
|
+
async createFolder(path) {
|
32
|
+
return new Promise((resolve, reject) => {
|
33
|
+
fs_1.default.mkdir(path, (err) => {
|
34
|
+
if (err) {
|
35
|
+
err.message += '. You can only create one single folder at a time.';
|
36
|
+
reject(err.message);
|
37
|
+
return;
|
38
|
+
}
|
39
|
+
resolve();
|
40
|
+
});
|
41
|
+
});
|
42
|
+
}
|
43
|
+
async readDirectory(path) {
|
44
|
+
return new Promise((resolve, reject) => {
|
45
|
+
let response = [];
|
46
|
+
fs_1.default.readdir(path, (err, files) => {
|
47
|
+
if (err) {
|
48
|
+
reject(new Error(err));
|
49
|
+
return;
|
50
|
+
}
|
51
|
+
files.forEach((file) => {
|
52
|
+
response.push({
|
53
|
+
path: path_1.default.join(path, file),
|
54
|
+
folder: fs_1.default.lstatSync(path_1.default.join(path, file)).isDirectory(),
|
55
|
+
});
|
56
|
+
});
|
57
|
+
resolve(response);
|
58
|
+
});
|
59
|
+
});
|
60
|
+
}
|
61
|
+
async readFile(path) {
|
62
|
+
return new Promise((resolve, reject) => {
|
63
|
+
if (!isFile(path)) {
|
64
|
+
reject(new Error('The path provided is invalid.Please check that the path and file name that were provided are spelled correctly. '));
|
65
|
+
}
|
66
|
+
else {
|
67
|
+
fs_1.default.readFile(path, (err, data) => {
|
68
|
+
if (err) {
|
69
|
+
reject(new Error(err.message));
|
70
|
+
return;
|
71
|
+
}
|
72
|
+
resolve(data);
|
73
|
+
});
|
74
|
+
}
|
75
|
+
});
|
76
|
+
}
|
77
|
+
getRootFolder() {
|
78
|
+
return require('os').homedir();
|
79
|
+
}
|
80
|
+
getProjectRootFolder() {
|
81
|
+
return storageService_1.storageService.get(SECTION_ID, PROJECT_ROOT);
|
82
|
+
}
|
83
|
+
setProjectRootFolder(folder) {
|
84
|
+
storageService_1.storageService.put(SECTION_ID, PROJECT_ROOT, folder);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
exports.filesystemManager = new FilesystemManager();
|
@@ -0,0 +1,18 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const express_promise_router_1 = __importDefault(require("express-promise-router"));
|
7
|
+
const nodejs_api_client_1 = require("@kapeta/nodejs-api-client");
|
8
|
+
const cors_1 = require("../middleware/cors");
|
9
|
+
const router = (0, express_promise_router_1.default)();
|
10
|
+
const api = new nodejs_api_client_1.KapetaAPI();
|
11
|
+
router.use('/', cors_1.corsHandler);
|
12
|
+
router.get('/current', async (req, res) => {
|
13
|
+
res.send(await api.getCurrentIdentity());
|
14
|
+
});
|
15
|
+
router.get('/:identityId/memberships', async (req, res) => {
|
16
|
+
res.send(await api.getMemberships(req.params.identityId));
|
17
|
+
});
|
18
|
+
exports.default = router;
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import { InstanceInfo, ProcessInfo } from './types';
|
2
|
+
declare class InstanceManager {
|
3
|
+
private _interval;
|
4
|
+
/**
|
5
|
+
* Contains an array of running instances that have self-registered with this
|
6
|
+
* cluster service. This is done by the Kapeta SDKs
|
7
|
+
*/
|
8
|
+
private _instances;
|
9
|
+
/**
|
10
|
+
* Contains the process info for the instances started by this manager. In memory only
|
11
|
+
* so can't be relied on for knowing everything that's running.
|
12
|
+
*
|
13
|
+
*/
|
14
|
+
private _processes;
|
15
|
+
constructor();
|
16
|
+
_save(): void;
|
17
|
+
_checkInstances(): Promise<void>;
|
18
|
+
_isRunning(instance: InstanceInfo): Promise<any>;
|
19
|
+
_getInstanceStatus(instance: InstanceInfo): Promise<string>;
|
20
|
+
getInstances(): InstanceInfo[];
|
21
|
+
getInstancesForPlan(systemId: string): InstanceInfo[];
|
22
|
+
/**
|
23
|
+
* Get instance information
|
24
|
+
*
|
25
|
+
* @param {string} systemId
|
26
|
+
* @param {string} instanceId
|
27
|
+
* @return {*}
|
28
|
+
*/
|
29
|
+
getInstance(systemId: string, instanceId: string): InstanceInfo | undefined;
|
30
|
+
/**
|
31
|
+
*
|
32
|
+
* @param {string} systemId
|
33
|
+
* @param {string} instanceId
|
34
|
+
* @param {InstanceInfo} info
|
35
|
+
* @return {Promise<void>}
|
36
|
+
*/
|
37
|
+
registerInstance(systemId: string, instanceId: string, info: Omit<InstanceInfo, 'systemId' | 'instanceId'>): Promise<void>;
|
38
|
+
setInstanceAsStopped(systemId: string, instanceId: string): void;
|
39
|
+
_emit(systemId: string, type: string, payload: any): void;
|
40
|
+
createProcessesForPlan(planRef: string): Promise<ProcessInfo[]>;
|
41
|
+
_stopInstance(instance: InstanceInfo): Promise<void>;
|
42
|
+
stopAllForPlan(planRef: string): Promise<void>;
|
43
|
+
createProcess(planRef: string, instanceId: string): Promise<ProcessInfo>;
|
44
|
+
/**
|
45
|
+
*
|
46
|
+
* @param {string} planRef
|
47
|
+
* @param {string} instanceId
|
48
|
+
* @return {ProcessInfo|null}
|
49
|
+
*/
|
50
|
+
getProcessForInstance(planRef: string, instanceId: string): ProcessInfo | null;
|
51
|
+
restartIfRunning(planRef: string, instanceId: string): Promise<ProcessInfo | undefined>;
|
52
|
+
stopProcess(planRef: string, instanceId: string): Promise<void>;
|
53
|
+
stopAllProcesses(): Promise<void>;
|
54
|
+
}
|
55
|
+
export declare const instanceManager: InstanceManager;
|
56
|
+
export {};
|