@kapeta/local-cluster-service 0.10.0 → 0.11.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/CHANGELOG.md +14 -0
- package/dist/cjs/src/containerManager.d.ts +6 -4
- package/dist/cjs/src/containerManager.js +100 -45
- package/dist/cjs/src/definitionsManager.d.ts +1 -0
- package/dist/cjs/src/definitionsManager.js +7 -0
- package/dist/cjs/src/instanceManager.d.ts +2 -1
- package/dist/cjs/src/instanceManager.js +29 -46
- package/dist/cjs/src/instances/routes.js +10 -4
- package/dist/cjs/src/operatorManager.js +8 -6
- package/dist/cjs/src/repositoryManager.js +4 -4
- package/dist/cjs/src/types.d.ts +0 -9
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +3 -2
- package/dist/cjs/src/utils/BlockInstanceRunner.js +49 -95
- package/dist/cjs/src/utils/utils.d.ts +1 -1
- package/dist/cjs/src/utils/utils.js +3 -2
- package/dist/esm/src/containerManager.d.ts +6 -4
- package/dist/esm/src/containerManager.js +100 -45
- package/dist/esm/src/definitionsManager.d.ts +1 -0
- package/dist/esm/src/definitionsManager.js +7 -0
- package/dist/esm/src/instanceManager.d.ts +2 -1
- package/dist/esm/src/instanceManager.js +29 -46
- package/dist/esm/src/instances/routes.js +10 -4
- package/dist/esm/src/operatorManager.js +8 -6
- package/dist/esm/src/repositoryManager.js +4 -4
- package/dist/esm/src/types.d.ts +0 -9
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +3 -2
- package/dist/esm/src/utils/BlockInstanceRunner.js +49 -95
- package/dist/esm/src/utils/utils.d.ts +1 -1
- package/dist/esm/src/utils/utils.js +3 -2
- package/package.json +1 -1
- package/src/containerManager.ts +126 -49
- package/src/definitionsManager.ts +8 -0
- package/src/instanceManager.ts +35 -50
- package/src/instances/routes.ts +9 -4
- package/src/operatorManager.ts +9 -8
- package/src/repositoryManager.ts +5 -5
- package/src/types.ts +0 -7
- package/src/utils/BlockInstanceRunner.ts +74 -109
- package/src/utils/LogData.ts +1 -0
- package/src/utils/utils.ts +3 -2
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
# [0.11.0](https://github.com/kapetacom/local-cluster-service/compare/v0.10.1...v0.11.0) (2023-07-31)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* Always get logs from docker ([#53](https://github.com/kapetacom/local-cluster-service/issues/53)) ([5cab8cb](https://github.com/kapetacom/local-cluster-service/commit/5cab8cbf18b38edf99d538e1819e135f0a5bd7e3))
|
7
|
+
|
8
|
+
## [0.10.1](https://github.com/kapetacom/local-cluster-service/compare/v0.10.0...v0.10.1) (2023-07-27)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Include port bindings for non-local containers ([#51](https://github.com/kapetacom/local-cluster-service/issues/51)) ([64fd440](https://github.com/kapetacom/local-cluster-service/commit/64fd4409ea9e2dda8e2438d0ec85a8f5a2092b1e))
|
14
|
+
|
1
15
|
# [0.10.0](https://github.com/kapetacom/local-cluster-service/compare/v0.9.1...v0.10.0) (2023-07-26)
|
2
16
|
|
3
17
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Docker } from 'node-docker-api';
|
2
2
|
import { Container } from 'node-docker-api/lib/container';
|
3
|
+
import { InstanceInfo, LogEntry } from "./types";
|
3
4
|
type StringMap = {
|
4
5
|
[key: string]: string;
|
5
6
|
};
|
@@ -52,8 +53,8 @@ declare class ContainerManager {
|
|
52
53
|
initialize(): Promise<void>;
|
53
54
|
checkAlive(): Promise<boolean>;
|
54
55
|
isAlive(): boolean;
|
55
|
-
getMountPoint(
|
56
|
-
createMounts(kind: string, mountOpts: StringMap): StringMap
|
56
|
+
getMountPoint(systemId: string, ref: string, mountName: string): string;
|
57
|
+
createMounts(systemId: string, kind: string, mountOpts: StringMap | null | undefined): Promise<StringMap>;
|
57
58
|
ping(): Promise<void>;
|
58
59
|
docker(): Docker;
|
59
60
|
getContainerByName(containerName: string): Promise<ContainerInfo | undefined>;
|
@@ -67,11 +68,10 @@ declare class ContainerManager {
|
|
67
68
|
};
|
68
69
|
private applyHash;
|
69
70
|
ensureContainer(opts: any): Promise<Container>;
|
71
|
+
private createOrUpdateContainer;
|
70
72
|
startContainer(opts: any): Promise<Container>;
|
71
73
|
waitForReady(container: Container, attempt?: number): Promise<void>;
|
72
|
-
waitForHealthy(container: Container, attempt?: number): Promise<void>;
|
73
74
|
_isReady(container: Container): Promise<any>;
|
74
|
-
_isHealthy(container: Container): Promise<boolean>;
|
75
75
|
remove(container: Container, opts?: {
|
76
76
|
force?: boolean;
|
77
77
|
}): Promise<void>;
|
@@ -81,6 +81,7 @@ declare class ContainerManager {
|
|
81
81
|
* @return {Promise<ContainerInfo>}
|
82
82
|
*/
|
83
83
|
get(name: string): Promise<ContainerInfo | null>;
|
84
|
+
getLogs(instance: InstanceInfo): Promise<LogEntry[]>;
|
84
85
|
}
|
85
86
|
export declare class ContainerInfo {
|
86
87
|
private readonly _container;
|
@@ -105,6 +106,7 @@ export declare class ContainerInfo {
|
|
105
106
|
inspect(): Promise<any>;
|
106
107
|
status(): Promise<DockerState>;
|
107
108
|
getPorts(): Promise<PortMap | false>;
|
109
|
+
getLogs(): Promise<LogEntry[]>;
|
108
110
|
}
|
109
111
|
export declare function getExtraHosts(dockerVersion: string): string[] | undefined;
|
110
112
|
/**
|
@@ -14,6 +14,7 @@ const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
|
14
14
|
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
15
15
|
const node_uuid_1 = __importDefault(require("node-uuid"));
|
16
16
|
const md5_1 = __importDefault(require("md5"));
|
17
|
+
const utils_1 = require("./utils/utils");
|
17
18
|
exports.CONTAINER_LABEL_PORT_PREFIX = 'kapeta_port-';
|
18
19
|
const NANO_SECOND = 1000000;
|
19
20
|
const HEALTH_CHECK_INTERVAL = 3000;
|
@@ -21,8 +22,8 @@ const HEALTH_CHECK_MAX = 20;
|
|
21
22
|
const IMAGE_PULL_CACHE_TTL = 30 * 60 * 1000;
|
22
23
|
const IMAGE_PULL_CACHE = {};
|
23
24
|
exports.HEALTH_CHECK_TIMEOUT = HEALTH_CHECK_INTERVAL * HEALTH_CHECK_MAX * 2;
|
24
|
-
const promisifyStream = (stream) => new Promise((resolve, reject) => {
|
25
|
-
stream.on('data',
|
25
|
+
const promisifyStream = (stream, handler) => new Promise((resolve, reject) => {
|
26
|
+
stream.on('data', handler);
|
26
27
|
stream.on('end', resolve);
|
27
28
|
stream.on('error', reject);
|
28
29
|
});
|
@@ -101,17 +102,21 @@ class ContainerManager {
|
|
101
102
|
isAlive() {
|
102
103
|
return this._alive;
|
103
104
|
}
|
104
|
-
getMountPoint(
|
105
|
-
const kindUri = (0, nodejs_utils_1.parseKapetaUri)(
|
106
|
-
|
105
|
+
getMountPoint(systemId, ref, mountName) {
|
106
|
+
const kindUri = (0, nodejs_utils_1.parseKapetaUri)(ref);
|
107
|
+
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(systemId);
|
108
|
+
return path_1.default.join(this._mountDir, systemUri.handle, systemUri.name, systemUri.version, kindUri.handle, kindUri.name, kindUri.version, mountName);
|
107
109
|
}
|
108
|
-
createMounts(kind, mountOpts) {
|
110
|
+
async createMounts(systemId, kind, mountOpts) {
|
109
111
|
const mounts = {};
|
110
|
-
|
111
|
-
const
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
if (mountOpts) {
|
113
|
+
const mountOptList = Object.entries(mountOpts);
|
114
|
+
for (const [mountName, containerPath] of mountOptList) {
|
115
|
+
const hostPath = this.getMountPoint(systemId, kind, mountName);
|
116
|
+
await fs_extra_1.default.mkdirp(hostPath);
|
117
|
+
mounts[containerPath] = hostPath;
|
118
|
+
}
|
119
|
+
}
|
115
120
|
return mounts;
|
116
121
|
}
|
117
122
|
async ping() {
|
@@ -162,12 +167,14 @@ class ContainerManager {
|
|
162
167
|
return false;
|
163
168
|
}
|
164
169
|
console.log('Pulling image: %s', image);
|
165
|
-
await this.docker()
|
170
|
+
const stream = await this.docker()
|
166
171
|
.image.create({}, {
|
167
172
|
fromImage: imageName,
|
168
173
|
tag: tag,
|
169
|
-
})
|
170
|
-
|
174
|
+
});
|
175
|
+
await promisifyStream(stream, (chunk) => {
|
176
|
+
console.log('Data from docker: "%s"', chunk.toString());
|
177
|
+
});
|
171
178
|
IMAGE_PULL_CACHE[image] = Date.now();
|
172
179
|
console.log('Image pulled: %s', image);
|
173
180
|
return true;
|
@@ -204,6 +211,11 @@ class ContainerManager {
|
|
204
211
|
dockerOpts.Labels.HASH = hash;
|
205
212
|
}
|
206
213
|
async ensureContainer(opts) {
|
214
|
+
const container = await this.createOrUpdateContainer(opts);
|
215
|
+
await this.waitForReady(container);
|
216
|
+
return container;
|
217
|
+
}
|
218
|
+
async createOrUpdateContainer(opts) {
|
207
219
|
let imagePulled = false;
|
208
220
|
try {
|
209
221
|
imagePulled = await this.pull(opts.Image);
|
@@ -283,28 +295,6 @@ class ContainerManager {
|
|
283
295
|
}, HEALTH_CHECK_INTERVAL);
|
284
296
|
});
|
285
297
|
}
|
286
|
-
async waitForHealthy(container, attempt) {
|
287
|
-
if (!attempt) {
|
288
|
-
attempt = 0;
|
289
|
-
}
|
290
|
-
if (attempt >= HEALTH_CHECK_MAX) {
|
291
|
-
throw new Error('Container did not become healthy within the timeout');
|
292
|
-
}
|
293
|
-
if (await this._isHealthy(container)) {
|
294
|
-
return;
|
295
|
-
}
|
296
|
-
return new Promise((resolve, reject) => {
|
297
|
-
setTimeout(async () => {
|
298
|
-
try {
|
299
|
-
await this.waitForHealthy(container, (attempt ?? 0) + 1);
|
300
|
-
resolve();
|
301
|
-
}
|
302
|
-
catch (err) {
|
303
|
-
reject(err);
|
304
|
-
}
|
305
|
-
}, HEALTH_CHECK_INTERVAL);
|
306
|
-
});
|
307
|
-
}
|
308
298
|
async _isReady(container) {
|
309
299
|
let info;
|
310
300
|
try {
|
@@ -318,16 +308,12 @@ class ContainerManager {
|
|
318
308
|
if (state?.Status === 'exited' || state?.Status === 'removing' || state?.Status === 'dead') {
|
319
309
|
throw new Error('Container exited unexpectedly');
|
320
310
|
}
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
try {
|
325
|
-
const info = await container.status();
|
326
|
-
const infoData = info?.data;
|
327
|
-
return infoData?.State?.Health?.Status === 'healthy';
|
311
|
+
if (infoData?.State?.Health) {
|
312
|
+
// If container has health info - wait for it to become healthy
|
313
|
+
return infoData.State.Health.Status === 'healthy';
|
328
314
|
}
|
329
|
-
|
330
|
-
return false;
|
315
|
+
else {
|
316
|
+
return infoData?.State?.Running ?? false;
|
331
317
|
}
|
332
318
|
}
|
333
319
|
async remove(container, opts) {
|
@@ -357,6 +343,19 @@ class ContainerManager {
|
|
357
343
|
}
|
358
344
|
return new ContainerInfo(dockerContainer);
|
359
345
|
}
|
346
|
+
async getLogs(instance) {
|
347
|
+
const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.systemId, instance.instanceId);
|
348
|
+
const containerInfo = await this.getContainerByName(containerName);
|
349
|
+
if (!containerInfo) {
|
350
|
+
return [{
|
351
|
+
source: "stdout",
|
352
|
+
level: "ERROR",
|
353
|
+
time: Date.now(),
|
354
|
+
message: "Container not found"
|
355
|
+
}];
|
356
|
+
}
|
357
|
+
return containerInfo.getLogs();
|
358
|
+
}
|
360
359
|
}
|
361
360
|
class ContainerInfo {
|
362
361
|
_container;
|
@@ -440,6 +439,62 @@ class ContainerInfo {
|
|
440
439
|
});
|
441
440
|
return ports;
|
442
441
|
}
|
442
|
+
async getLogs() {
|
443
|
+
const logStream = await this.native.logs({
|
444
|
+
stdout: true,
|
445
|
+
stderr: true,
|
446
|
+
follow: false,
|
447
|
+
tail: 100,
|
448
|
+
timestamps: true,
|
449
|
+
});
|
450
|
+
const out = [];
|
451
|
+
await promisifyStream(logStream, (data) => {
|
452
|
+
const buf = data;
|
453
|
+
let offset = 0;
|
454
|
+
while (offset < buf.length) {
|
455
|
+
try {
|
456
|
+
// Read the docker log format - explained here:
|
457
|
+
// https://docs.docker.com/engine/api/v1.41/#operation/ContainerAttach
|
458
|
+
// or here : https://ahmet.im/blog/docker-logs-api-binary-format-explained/
|
459
|
+
// First byte is stream type
|
460
|
+
const streamTypeInt = buf.readInt8(offset);
|
461
|
+
const streamType = streamTypeInt === 1 ? 'stdout' : 'stderr';
|
462
|
+
// Bytes 4-8 is frame size
|
463
|
+
const messageLength = buf.readInt32BE(offset + 4);
|
464
|
+
// After that is the message - with the message length
|
465
|
+
const dataWithoutStreamType = buf.subarray(offset + 8, offset + 8 + messageLength);
|
466
|
+
const raw = dataWithoutStreamType.toString();
|
467
|
+
// Split the message into date and message
|
468
|
+
const firstSpaceIx = raw.indexOf(' ');
|
469
|
+
const dateString = raw.substring(0, firstSpaceIx);
|
470
|
+
const line = raw.substring(firstSpaceIx + 1);
|
471
|
+
offset = offset + messageLength + 8;
|
472
|
+
if (!dateString) {
|
473
|
+
continue;
|
474
|
+
}
|
475
|
+
out.push({
|
476
|
+
time: new Date(dateString).getTime(),
|
477
|
+
message: line,
|
478
|
+
level: 'INFO',
|
479
|
+
source: streamType,
|
480
|
+
});
|
481
|
+
}
|
482
|
+
catch (err) {
|
483
|
+
console.error('Error parsing log entry', err);
|
484
|
+
offset = buf.length;
|
485
|
+
}
|
486
|
+
}
|
487
|
+
});
|
488
|
+
if (out.length === 0) {
|
489
|
+
out.push({
|
490
|
+
time: Date.now(),
|
491
|
+
message: 'No logs found for container',
|
492
|
+
level: 'INFO',
|
493
|
+
source: 'stdout',
|
494
|
+
});
|
495
|
+
}
|
496
|
+
return out;
|
497
|
+
}
|
443
498
|
}
|
444
499
|
exports.ContainerInfo = ContainerInfo;
|
445
500
|
function getExtraHosts(dockerVersion) {
|
@@ -5,6 +5,7 @@ declare class DefinitionsManager {
|
|
5
5
|
clearCache(): void;
|
6
6
|
private doCached;
|
7
7
|
getDefinitions(kindFilter?: string | string[]): DefinitionInfo[];
|
8
|
+
exists(ref: string): boolean;
|
8
9
|
getProviderDefinitions(): DefinitionInfo[];
|
9
10
|
}
|
10
11
|
export declare const definitionsManager: DefinitionsManager;
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.definitionsManager = void 0;
|
7
7
|
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
8
|
+
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
8
9
|
const CACHE_TTL = 60 * 1000; // 1 min
|
9
10
|
class DefinitionsManager {
|
10
11
|
cache = {};
|
@@ -37,6 +38,12 @@ class DefinitionsManager {
|
|
37
38
|
const key = this.getKey(kindFilter);
|
38
39
|
return this.doCached(key, () => local_cluster_config_1.default.getDefinitions(kindFilter));
|
39
40
|
}
|
41
|
+
exists(ref) {
|
42
|
+
const uri = (0, nodejs_utils_1.parseKapetaUri)(ref);
|
43
|
+
return !!this.getDefinitions().find((d) => {
|
44
|
+
return (0, nodejs_utils_1.parseKapetaUri)(`${d.definition.metadata.name}:${d.version}`).id === uri.id;
|
45
|
+
});
|
46
|
+
}
|
40
47
|
getProviderDefinitions() {
|
41
48
|
return this.doCached('providers', () => local_cluster_config_1.default.getProviderDefinitions());
|
42
49
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { InstanceInfo } from './types';
|
1
|
+
import { InstanceInfo, LogEntry } from './types';
|
2
2
|
export declare class InstanceManager {
|
3
3
|
private _interval;
|
4
4
|
private readonly _instances;
|
@@ -7,6 +7,7 @@ export declare class InstanceManager {
|
|
7
7
|
getInstances(): InstanceInfo[];
|
8
8
|
getInstancesForPlan(systemId: string): InstanceInfo[];
|
9
9
|
getInstance(systemId: string, instanceId: string): InstanceInfo | undefined;
|
10
|
+
getLogs(systemId: string, instanceId: string): Promise<LogEntry[]>;
|
10
11
|
saveInternalInstance(instance: InstanceInfo): Promise<InstanceInfo>;
|
11
12
|
/**
|
12
13
|
* Method is called when instance is started from the Kapeta SDKs (e.g. NodeJS SDK)
|
@@ -56,6 +56,31 @@ class InstanceManager {
|
|
56
56
|
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
57
57
|
return this._instances.find((i) => i.systemId === systemId && i.instanceId === instanceId);
|
58
58
|
}
|
59
|
+
async getLogs(systemId, instanceId) {
|
60
|
+
const instance = this.getInstance(systemId, instanceId);
|
61
|
+
if (!instance) {
|
62
|
+
throw new Error(`Instance ${systemId}/${instanceId} not found`);
|
63
|
+
}
|
64
|
+
switch (instance.type) {
|
65
|
+
case types_1.InstanceType.DOCKER:
|
66
|
+
return await containerManager_1.containerManager.getLogs(instance);
|
67
|
+
case types_1.InstanceType.UNKNOWN:
|
68
|
+
return [{
|
69
|
+
level: 'INFO',
|
70
|
+
message: 'Instance is starting...',
|
71
|
+
time: Date.now(),
|
72
|
+
source: 'stdout',
|
73
|
+
}];
|
74
|
+
case types_1.InstanceType.LOCAL:
|
75
|
+
return [{
|
76
|
+
level: 'INFO',
|
77
|
+
message: 'Instance started outside Kapeta - logs not available...',
|
78
|
+
time: Date.now(),
|
79
|
+
source: 'stdout',
|
80
|
+
}];
|
81
|
+
}
|
82
|
+
return [];
|
83
|
+
}
|
59
84
|
async saveInternalInstance(instance) {
|
60
85
|
instance.systemId = (0, utils_1.normalizeKapetaUri)(instance.systemId);
|
61
86
|
if (instance.ref) {
|
@@ -106,7 +131,6 @@ class InstanceManager {
|
|
106
131
|
}
|
107
132
|
instance.desiredStatus = info.desiredStatus;
|
108
133
|
instance.owner = info.owner;
|
109
|
-
instance.internal = undefined;
|
110
134
|
instance.status = types_1.InstanceStatus.STARTING;
|
111
135
|
instance.startedAt = Date.now();
|
112
136
|
}
|
@@ -205,7 +229,7 @@ class InstanceManager {
|
|
205
229
|
this.save();
|
206
230
|
try {
|
207
231
|
if (instance.type === 'docker') {
|
208
|
-
const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.instanceId);
|
232
|
+
const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.systemId, instance.instanceId);
|
209
233
|
const container = await containerManager_1.containerManager.getContainerByName(containerName);
|
210
234
|
if (container) {
|
211
235
|
try {
|
@@ -281,7 +305,7 @@ class InstanceManager {
|
|
281
305
|
name: blockAsset.data.metadata.name,
|
282
306
|
desiredStatus: types_1.DesiredInstanceStatus.RUN,
|
283
307
|
owner: types_1.InstanceOwner.INTERNAL,
|
284
|
-
type: types_1.InstanceType.UNKNOWN,
|
308
|
+
type: existingInstance?.type ?? types_1.InstanceType.UNKNOWN,
|
285
309
|
status: types_1.InstanceStatus.STARTING,
|
286
310
|
startedAt: Date.now(),
|
287
311
|
};
|
@@ -301,41 +325,6 @@ class InstanceManager {
|
|
301
325
|
const startTime = Date.now();
|
302
326
|
try {
|
303
327
|
const processInfo = await runner.start(blockRef, instanceId, instanceConfig);
|
304
|
-
//emit stdout/stderr via sockets
|
305
|
-
processInfo.output.on('data', (data) => {
|
306
|
-
const payload = {
|
307
|
-
source: 'stdout',
|
308
|
-
level: 'INFO',
|
309
|
-
message: data.toString(),
|
310
|
-
time: Date.now(),
|
311
|
-
};
|
312
|
-
this.emitInstanceEvent(systemId, instanceId, EVENT_INSTANCE_LOG, payload);
|
313
|
-
});
|
314
|
-
processInfo.output.on('exit', (exitCode) => {
|
315
|
-
const timeRunning = Date.now() - startTime;
|
316
|
-
const instance = this.getInstance(systemId, instanceId);
|
317
|
-
if (instance?.status === types_1.InstanceStatus.READY) {
|
318
|
-
//It's already been running
|
319
|
-
return;
|
320
|
-
}
|
321
|
-
if (exitCode === 143 || exitCode === 137) {
|
322
|
-
//Process got SIGTERM (143) or SIGKILL (137)
|
323
|
-
//TODO: Windows?
|
324
|
-
return;
|
325
|
-
}
|
326
|
-
if (exitCode !== 0 || timeRunning < MIN_TIME_RUNNING) {
|
327
|
-
const instance = this.getInstance(systemId, instanceId);
|
328
|
-
if (instance) {
|
329
|
-
instance.status = types_1.InstanceStatus.FAILED;
|
330
|
-
this.save();
|
331
|
-
}
|
332
|
-
this.emitSystemEvent(systemId, EVENT_INSTANCE_EXITED, {
|
333
|
-
error: 'Failed to start instance',
|
334
|
-
status: EVENT_INSTANCE_EXITED,
|
335
|
-
instanceId: blockInstance.id,
|
336
|
-
});
|
337
|
-
}
|
338
|
-
});
|
339
328
|
instance.status = types_1.InstanceStatus.READY;
|
340
329
|
return this.saveInternalInstance({
|
341
330
|
...instance,
|
@@ -344,10 +333,6 @@ class InstanceManager {
|
|
344
333
|
health: null,
|
345
334
|
portType: processInfo.portType,
|
346
335
|
status: types_1.InstanceStatus.READY,
|
347
|
-
internal: {
|
348
|
-
logs: processInfo.logs,
|
349
|
-
output: processInfo.output,
|
350
|
-
},
|
351
336
|
});
|
352
337
|
}
|
353
338
|
catch (e) {
|
@@ -393,9 +378,7 @@ class InstanceManager {
|
|
393
378
|
save() {
|
394
379
|
try {
|
395
380
|
storageService_1.storageService.put('instances', this._instances.map((instance) => {
|
396
|
-
|
397
|
-
delete copy.internal;
|
398
|
-
return copy;
|
381
|
+
return { ...instance };
|
399
382
|
}));
|
400
383
|
}
|
401
384
|
catch (e) {
|
@@ -497,7 +480,7 @@ class InstanceManager {
|
|
497
480
|
}
|
498
481
|
async getExternalStatus(instance) {
|
499
482
|
if (instance.type === types_1.InstanceType.DOCKER) {
|
500
|
-
const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.instanceId);
|
483
|
+
const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.systemId, instance.instanceId);
|
501
484
|
const container = await containerManager_1.containerManager.getContainerByName(containerName);
|
502
485
|
if (!container) {
|
503
486
|
// If the container doesn't exist, we consider the instance stopped
|
@@ -67,15 +67,21 @@ router.post('/:systemId/:instanceId/stop', async (req, res) => {
|
|
67
67
|
/**
|
68
68
|
* Get logs for instance in a plan
|
69
69
|
*/
|
70
|
-
router.get('/:systemId/:instanceId/logs', (req, res) => {
|
70
|
+
router.get('/:systemId/:instanceId/logs', async (req, res) => {
|
71
71
|
const instanceInfo = instanceManager_1.instanceManager.getInstance(req.params.systemId, req.params.instanceId);
|
72
72
|
if (!instanceInfo) {
|
73
73
|
res.status(404).send({ ok: false });
|
74
74
|
return;
|
75
75
|
}
|
76
|
-
|
77
|
-
logs
|
78
|
-
|
76
|
+
try {
|
77
|
+
const logs = await instanceManager_1.instanceManager.getLogs(req.params.systemId, req.params.instanceId);
|
78
|
+
res.status(200).send({
|
79
|
+
logs,
|
80
|
+
});
|
81
|
+
}
|
82
|
+
catch (e) {
|
83
|
+
res.status(500).send({ ok: false, error: e.message });
|
84
|
+
}
|
79
85
|
});
|
80
86
|
/**
|
81
87
|
* Get public address for instance in a plan if available
|
@@ -117,13 +117,11 @@ class OperatorManager {
|
|
117
117
|
const operatorData = operator.getData();
|
118
118
|
const portTypes = Object.keys(operatorData.ports);
|
119
119
|
portTypes.sort();
|
120
|
-
const containerBaseName = 'kapeta-resource';
|
121
|
-
const nameParts = [resourceType.toLowerCase()];
|
122
120
|
const ports = {};
|
123
121
|
for (let i = 0; i < portTypes.length; i++) {
|
124
122
|
const portType = portTypes[i];
|
125
123
|
let containerPortInfo = operatorData.ports[portType];
|
126
|
-
const hostPort = await serviceManager_1.serviceManager.ensureServicePort(resourceType, portType);
|
124
|
+
const hostPort = await serviceManager_1.serviceManager.ensureServicePort(systemId, resourceType, portType);
|
127
125
|
if (typeof containerPortInfo === 'number' || typeof containerPortInfo === 'string') {
|
128
126
|
containerPortInfo = { port: containerPortInfo, type: 'tcp' };
|
129
127
|
}
|
@@ -131,14 +129,18 @@ class OperatorManager {
|
|
131
129
|
containerPortInfo.type = 'tcp';
|
132
130
|
}
|
133
131
|
const portId = containerPortInfo.port + '/' + containerPortInfo.type;
|
134
|
-
nameParts.push(portType + '-' + portId + '-' + hostPort);
|
135
132
|
ports[portId] = {
|
136
133
|
type: portType,
|
137
134
|
hostPort,
|
138
135
|
};
|
139
136
|
}
|
140
|
-
const mounts = containerManager_1.containerManager.createMounts(resourceType, operatorData.mounts);
|
141
|
-
const
|
137
|
+
const mounts = await containerManager_1.containerManager.createMounts(systemId, resourceType, operatorData.mounts);
|
138
|
+
const nameParts = [
|
139
|
+
systemId,
|
140
|
+
resourceType.toLowerCase(),
|
141
|
+
version
|
142
|
+
];
|
143
|
+
const containerName = `kapeta-resource-${(0, md5_1.default)(nameParts.join('_'))}`;
|
142
144
|
const PortBindings = {};
|
143
145
|
const Env = [];
|
144
146
|
const Labels = {
|
@@ -113,9 +113,11 @@ class RepositoryManager {
|
|
113
113
|
this._installQueue.push(async () => {
|
114
114
|
try {
|
115
115
|
const normalizedRefs = refs.map((ref) => (0, nodejs_utils_1.parseKapetaUri)(ref).id);
|
116
|
-
const filteredRefs = normalizedRefs
|
117
|
-
|
116
|
+
const filteredRefs = normalizedRefs
|
117
|
+
.filter((ref) => !INSTALL_ATTEMPTED[ref])
|
118
|
+
.filter((ref) => !definitionsManager_1.definitionsManager.exists(ref));
|
118
119
|
if (filteredRefs.length > 0) {
|
120
|
+
console.log(`Auto-installing dependencies: ${filteredRefs.join(', ')}`);
|
119
121
|
filteredRefs.forEach((ref) => (INSTALL_ATTEMPTED[ref] = true));
|
120
122
|
//Auto-install missing asset
|
121
123
|
try {
|
@@ -206,14 +208,12 @@ class RepositoryManager {
|
|
206
208
|
}
|
207
209
|
this._cache[ref] = true;
|
208
210
|
if (!installedAsset) {
|
209
|
-
console.log(`Auto-installing missing asset: ${ref}`);
|
210
211
|
await this._install([ref]);
|
211
212
|
}
|
212
213
|
else {
|
213
214
|
//Ensure dependencies are installed
|
214
215
|
const refs = assetVersion.dependencies.map((dep) => dep.name);
|
215
216
|
if (refs.length > 0) {
|
216
|
-
console.log(`Auto-installing dependencies: ${refs.join(', ')}`);
|
217
217
|
await this._install(refs);
|
218
218
|
}
|
219
219
|
}
|
package/dist/cjs/src/types.d.ts
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
/// <reference types="node" />
|
2
|
-
import EventEmitter from 'events';
|
3
1
|
import express from 'express';
|
4
2
|
import { Resource } from '@kapeta/schemas';
|
5
3
|
import { StringBodyRequest } from './middleware/stringBody';
|
@@ -50,10 +48,7 @@ export declare enum DesiredInstanceStatus {
|
|
50
48
|
export type ProcessInfo = {
|
51
49
|
type: InstanceType;
|
52
50
|
pid?: number | string | null;
|
53
|
-
output: EventEmitter;
|
54
51
|
portType?: string;
|
55
|
-
logs: () => LogEntry[];
|
56
|
-
stop: () => Promise<void> | void;
|
57
52
|
};
|
58
53
|
export type InstanceInfo = {
|
59
54
|
systemId: string;
|
@@ -69,10 +64,6 @@ export type InstanceInfo = {
|
|
69
64
|
health?: string | null;
|
70
65
|
pid?: number | string | null;
|
71
66
|
portType?: string;
|
72
|
-
internal?: {
|
73
|
-
output: EventEmitter;
|
74
|
-
logs: () => LogEntry[];
|
75
|
-
};
|
76
67
|
};
|
77
68
|
interface ResourceRef {
|
78
69
|
blockId: string;
|
@@ -14,8 +14,6 @@ export declare class BlockInstanceRunner {
|
|
14
14
|
* Starts local process
|
15
15
|
*/
|
16
16
|
private _startLocalProcess;
|
17
|
-
private ensureContainer;
|
18
|
-
private _handleContainer;
|
19
17
|
private _startDockerProcess;
|
20
18
|
/**
|
21
19
|
*
|
@@ -27,4 +25,7 @@ export declare class BlockInstanceRunner {
|
|
27
25
|
* @private
|
28
26
|
*/
|
29
27
|
_startOperatorProcess(blockInstance: BlockProcessParams, blockUri: KapetaURI, providerDefinition: DefinitionInfo, env: StringMap): Promise<ProcessInfo>;
|
28
|
+
private getDockerPortBindings;
|
29
|
+
private ensureContainer;
|
30
|
+
private _handleContainer;
|
30
31
|
}
|