@kapeta/local-cluster-service 0.11.1 → 0.12.1
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/definitions.d.ts +7 -0
- package/dist/cjs/src/config/routes.js +1 -1
- package/dist/cjs/src/containerManager.d.ts +3 -2
- package/dist/cjs/src/containerManager.js +127 -34
- package/dist/cjs/src/definitionsManager.d.ts +1 -0
- package/dist/cjs/src/definitionsManager.js +7 -4
- package/dist/cjs/src/instanceManager.d.ts +8 -1
- package/dist/cjs/src/instanceManager.js +56 -21
- package/dist/cjs/src/instances/routes.js +2 -0
- package/dist/cjs/src/operatorManager.d.ts +2 -0
- package/dist/cjs/src/operatorManager.js +70 -67
- package/dist/cjs/src/socketManager.d.ts +1 -0
- package/dist/cjs/src/socketManager.js +3 -0
- package/dist/cjs/src/types.d.ts +1 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.js +2 -3
- package/dist/esm/src/config/routes.js +1 -1
- package/dist/esm/src/containerManager.d.ts +3 -2
- package/dist/esm/src/containerManager.js +128 -35
- package/dist/esm/src/definitionsManager.d.ts +1 -0
- package/dist/esm/src/definitionsManager.js +8 -5
- package/dist/esm/src/instanceManager.d.ts +8 -1
- package/dist/esm/src/instanceManager.js +56 -21
- package/dist/esm/src/instances/routes.js +2 -0
- package/dist/esm/src/operatorManager.d.ts +2 -0
- package/dist/esm/src/operatorManager.js +68 -65
- package/dist/esm/src/socketManager.d.ts +1 -0
- package/dist/esm/src/socketManager.js +3 -0
- package/dist/esm/src/types.d.ts +1 -0
- package/dist/esm/src/utils/BlockInstanceRunner.js +2 -3
- package/dist/esm/src/utils/utils.js +1 -1
- package/package.json +1 -1
- package/src/config/routes.ts +1 -1
- package/src/containerManager.ts +181 -60
- package/src/definitionsManager.ts +9 -5
- package/src/instanceManager.ts +82 -42
- package/src/instances/routes.ts +3 -1
- package/src/operatorManager.ts +73 -69
- package/src/socketManager.ts +4 -0
- package/src/types.ts +1 -1
- package/src/utils/BlockInstanceRunner.ts +12 -24
- package/src/utils/utils.ts +2 -2
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.operatorManager = void 0;
|
6
|
+
exports.operatorManager = exports.KIND_OPERATOR = void 0;
|
7
7
|
const path_1 = __importDefault(require("path"));
|
8
8
|
const md5_1 = __importDefault(require("md5"));
|
9
9
|
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
@@ -14,7 +14,8 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
14
14
|
const definitionsManager_1 = require("./definitionsManager");
|
15
15
|
const utils_1 = require("./utils/utils");
|
16
16
|
const lodash_1 = __importDefault(require("lodash"));
|
17
|
-
const
|
17
|
+
const async_lock_1 = __importDefault(require("async-lock"));
|
18
|
+
exports.KIND_OPERATOR = 'core/resource-type-operator';
|
18
19
|
class Operator {
|
19
20
|
_data;
|
20
21
|
constructor(data) {
|
@@ -29,6 +30,7 @@ class Operator {
|
|
29
30
|
}
|
30
31
|
class OperatorManager {
|
31
32
|
_mountDir;
|
33
|
+
operatorLock = new async_lock_1.default();
|
32
34
|
constructor() {
|
33
35
|
this._mountDir = path_1.default.join(storageService_1.storageService.getKapetaBasedir(), 'mounts');
|
34
36
|
fs_extra_1.default.mkdirpSync(this._mountDir);
|
@@ -44,7 +46,7 @@ class OperatorManager {
|
|
44
46
|
* @return {Operator}
|
45
47
|
*/
|
46
48
|
getOperator(resourceType, version) {
|
47
|
-
const operators = definitionsManager_1.definitionsManager.getDefinitions(KIND_OPERATOR);
|
49
|
+
const operators = definitionsManager_1.definitionsManager.getDefinitions(exports.KIND_OPERATOR);
|
48
50
|
const operator = operators.find((operator) => operator.definition &&
|
49
51
|
operator.definition.metadata &&
|
50
52
|
operator.definition.metadata.name &&
|
@@ -113,74 +115,75 @@ class OperatorManager {
|
|
113
115
|
* @return {Promise<ContainerInfo>}
|
114
116
|
*/
|
115
117
|
async ensureResource(systemId, resourceType, version) {
|
116
|
-
|
117
|
-
const
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
containerPortInfo =
|
127
|
-
|
128
|
-
|
129
|
-
|
118
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
119
|
+
const key = `${systemId}#${resourceType}:${version}`;
|
120
|
+
return await this.operatorLock.acquire(key, async () => {
|
121
|
+
const operator = this.getOperator(resourceType, version);
|
122
|
+
const operatorData = operator.getData();
|
123
|
+
const portTypes = Object.keys(operatorData.ports);
|
124
|
+
portTypes.sort();
|
125
|
+
const ports = {};
|
126
|
+
for (let i = 0; i < portTypes.length; i++) {
|
127
|
+
const portType = portTypes[i];
|
128
|
+
let containerPortInfo = operatorData.ports[portType];
|
129
|
+
const hostPort = await serviceManager_1.serviceManager.ensureServicePort(systemId, resourceType, portType);
|
130
|
+
if (typeof containerPortInfo === 'number' || typeof containerPortInfo === 'string') {
|
131
|
+
containerPortInfo = { port: containerPortInfo, type: 'tcp' };
|
132
|
+
}
|
133
|
+
if (!containerPortInfo.type) {
|
134
|
+
containerPortInfo.type = 'tcp';
|
135
|
+
}
|
136
|
+
const portId = containerPortInfo.port + '/' + containerPortInfo.type;
|
137
|
+
ports[portId] = {
|
138
|
+
type: portType,
|
139
|
+
hostPort,
|
140
|
+
};
|
130
141
|
}
|
131
|
-
const
|
132
|
-
|
133
|
-
|
134
|
-
|
142
|
+
const mounts = await containerManager_1.containerManager.createMounts(systemId, resourceType, operatorData.mounts);
|
143
|
+
const nameParts = [systemId, resourceType.toLowerCase(), version];
|
144
|
+
const containerName = `kapeta-resource-${(0, md5_1.default)(nameParts.join('_'))}`;
|
145
|
+
const PortBindings = {};
|
146
|
+
const Env = [];
|
147
|
+
const Labels = {
|
148
|
+
kapeta: 'true',
|
135
149
|
};
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
150
|
+
const bindHost = (0, utils_1.getBindHost)();
|
151
|
+
const ExposedPorts = {};
|
152
|
+
lodash_1.default.forEach(ports, (portInfo, containerPort) => {
|
153
|
+
ExposedPorts['' + containerPort] = {};
|
154
|
+
PortBindings['' + containerPort] = [
|
155
|
+
{
|
156
|
+
HostPort: '' + portInfo.hostPort,
|
157
|
+
HostIp: bindHost,
|
158
|
+
},
|
159
|
+
];
|
160
|
+
Labels[containerManager_1.CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
|
161
|
+
});
|
162
|
+
const Mounts = containerManager_1.containerManager.toDockerMounts(mounts);
|
163
|
+
lodash_1.default.forEach(operatorData.env, (value, name) => {
|
164
|
+
Env.push(name + '=' + value);
|
165
|
+
});
|
166
|
+
let HealthCheck = undefined;
|
167
|
+
if (operatorData.health) {
|
168
|
+
HealthCheck = containerManager_1.containerManager.toDockerHealth(operatorData.health);
|
169
|
+
}
|
170
|
+
const container = await containerManager_1.containerManager.ensureContainer({
|
171
|
+
name: containerName,
|
172
|
+
Image: operatorData.image,
|
173
|
+
Hostname: containerName + '.kapeta',
|
174
|
+
Labels,
|
175
|
+
Cmd: operatorData.cmd,
|
176
|
+
ExposedPorts,
|
177
|
+
Env,
|
178
|
+
HealthCheck,
|
179
|
+
HostConfig: {
|
180
|
+
PortBindings,
|
181
|
+
Mounts,
|
157
182
|
},
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
const Mounts = containerManager_1.containerManager.toDockerMounts(mounts);
|
162
|
-
lodash_1.default.forEach(operatorData.env, (value, name) => {
|
163
|
-
Env.push(name + '=' + value);
|
164
|
-
});
|
165
|
-
let HealthCheck = undefined;
|
166
|
-
if (operatorData.health) {
|
167
|
-
HealthCheck = containerManager_1.containerManager.toDockerHealth(operatorData.health);
|
168
|
-
}
|
169
|
-
const container = await containerManager_1.containerManager.ensureContainer({
|
170
|
-
name: containerName,
|
171
|
-
Image: operatorData.image,
|
172
|
-
Hostname: containerName + '.kapeta',
|
173
|
-
Labels,
|
174
|
-
Cmd: operatorData.cmd,
|
175
|
-
ExposedPorts,
|
176
|
-
Env,
|
177
|
-
HealthCheck,
|
178
|
-
HostConfig: {
|
179
|
-
PortBindings,
|
180
|
-
Mounts,
|
181
|
-
},
|
183
|
+
});
|
184
|
+
await containerManager_1.containerManager.waitForReady(container);
|
185
|
+
return new containerManager_1.ContainerInfo(container);
|
182
186
|
});
|
183
|
-
return new containerManager_1.ContainerInfo(container);
|
184
187
|
}
|
185
188
|
}
|
186
189
|
exports.operatorManager = new OperatorManager();
|
@@ -7,6 +7,7 @@ export declare class SocketManager {
|
|
7
7
|
isAlive(): boolean;
|
8
8
|
private get io();
|
9
9
|
emit(context: string, type: string, payload: any): void;
|
10
|
+
emitGlobal(type: string, payload: any): void;
|
10
11
|
_bindIO(): void;
|
11
12
|
_handleSocketCreated(socket: Socket): void;
|
12
13
|
_bindSocket(socket: Socket): void;
|
@@ -29,6 +29,9 @@ class SocketManager {
|
|
29
29
|
emit(context, type, payload) {
|
30
30
|
this.io.to(context).emit(type, { context, payload });
|
31
31
|
}
|
32
|
+
emitGlobal(type, payload) {
|
33
|
+
this.io.emit(type, { payload });
|
34
|
+
}
|
32
35
|
_bindIO() {
|
33
36
|
this.io.on('connection', (socket) => this._handleSocketCreated(socket));
|
34
37
|
}
|
package/dist/cjs/src/types.d.ts
CHANGED
@@ -200,7 +200,7 @@ class BlockInstanceRunner {
|
|
200
200
|
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
|
201
201
|
...Object.entries({
|
202
202
|
...env,
|
203
|
-
...addonEnv
|
203
|
+
...addonEnv,
|
204
204
|
}).map(([key, value]) => `${key}=${value}`),
|
205
205
|
],
|
206
206
|
HostConfig: {
|
@@ -324,13 +324,12 @@ class BlockInstanceRunner {
|
|
324
324
|
}
|
325
325
|
async ensureContainer(opts) {
|
326
326
|
const container = await containerManager_1.containerManager.ensureContainer(opts);
|
327
|
-
await containerManager_1.containerManager.waitForReady(container);
|
328
327
|
return this._handleContainer(container);
|
329
328
|
}
|
330
329
|
async _handleContainer(container) {
|
331
330
|
return {
|
332
331
|
type: types_1.InstanceType.DOCKER,
|
333
|
-
pid: container.id
|
332
|
+
pid: container.id,
|
334
333
|
};
|
335
334
|
}
|
336
335
|
}
|
@@ -32,7 +32,7 @@ router.put('/instance', async (req, res) => {
|
|
32
32
|
if (req.kapeta.instanceId) {
|
33
33
|
configManager.setConfigForSection(req.kapeta.systemId, req.kapeta.instanceId, config);
|
34
34
|
//Restart the instance if it is running after config change
|
35
|
-
await instanceManager.
|
35
|
+
await instanceManager.prepareForRestart(req.kapeta.systemId, req.kapeta.instanceId);
|
36
36
|
}
|
37
37
|
else {
|
38
38
|
configManager.setConfigForSystem(req.kapeta.systemId, config);
|
@@ -1,6 +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
|
3
|
+
import { InstanceInfo, LogEntry } from './types';
|
4
4
|
type StringMap = {
|
5
5
|
[key: string]: string;
|
6
6
|
};
|
@@ -49,6 +49,7 @@ declare class ContainerManager {
|
|
49
49
|
private _alive;
|
50
50
|
private _mountDir;
|
51
51
|
private _version;
|
52
|
+
private _lastDockerAccessCheck;
|
52
53
|
constructor();
|
53
54
|
initialize(): Promise<void>;
|
54
55
|
checkAlive(): Promise<boolean>;
|
@@ -58,7 +59,7 @@ declare class ContainerManager {
|
|
58
59
|
ping(): Promise<void>;
|
59
60
|
docker(): Docker;
|
60
61
|
getContainerByName(containerName: string): Promise<ContainerInfo | undefined>;
|
61
|
-
pull(image: string
|
62
|
+
pull(image: string): Promise<boolean>;
|
62
63
|
toDockerMounts(mounts: StringMap): DockerMounts[];
|
63
64
|
toDockerHealth(health: Health): {
|
64
65
|
Test: string[];
|
@@ -8,13 +8,14 @@ import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
|
8
8
|
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
9
9
|
import uuid from 'node-uuid';
|
10
10
|
import md5 from 'md5';
|
11
|
-
import { getBlockInstanceContainerName } from
|
11
|
+
import { getBlockInstanceContainerName } from './utils/utils';
|
12
|
+
import { socketManager } from './socketManager';
|
13
|
+
import { KapetaAPI } from '@kapeta/nodejs-api-client';
|
14
|
+
const EVENT_IMAGE_PULL = 'docker-image-pull';
|
12
15
|
export const CONTAINER_LABEL_PORT_PREFIX = 'kapeta_port-';
|
13
16
|
const NANO_SECOND = 1000000;
|
14
17
|
const HEALTH_CHECK_INTERVAL = 3000;
|
15
18
|
const HEALTH_CHECK_MAX = 20;
|
16
|
-
const IMAGE_PULL_CACHE_TTL = 30 * 60 * 1000;
|
17
|
-
const IMAGE_PULL_CACHE = {};
|
18
19
|
export const HEALTH_CHECK_TIMEOUT = HEALTH_CHECK_INTERVAL * HEALTH_CHECK_MAX * 2;
|
19
20
|
const promisifyStream = (stream, handler) => new Promise((resolve, reject) => {
|
20
21
|
stream.on('data', handler);
|
@@ -26,6 +27,7 @@ class ContainerManager {
|
|
26
27
|
_alive;
|
27
28
|
_mountDir;
|
28
29
|
_version;
|
30
|
+
_lastDockerAccessCheck = 0;
|
29
31
|
constructor() {
|
30
32
|
this._docker = null;
|
31
33
|
this._alive = false;
|
@@ -141,17 +143,11 @@ class ContainerManager {
|
|
141
143
|
}
|
142
144
|
return undefined;
|
143
145
|
}
|
144
|
-
async pull(image
|
146
|
+
async pull(image) {
|
145
147
|
let [imageName, tag] = image.split(/:/);
|
146
148
|
if (!tag) {
|
147
149
|
tag = 'latest';
|
148
150
|
}
|
149
|
-
if (IMAGE_PULL_CACHE[image]) {
|
150
|
-
const timeSince = Date.now() - IMAGE_PULL_CACHE[image];
|
151
|
-
if (timeSince < cacheForMS) {
|
152
|
-
return false;
|
153
|
-
}
|
154
|
-
}
|
155
151
|
const imageTagList = (await this.docker().image.list())
|
156
152
|
.map((image) => image.data)
|
157
153
|
.filter((imageData) => !!imageData.RepoTags)
|
@@ -160,17 +156,120 @@ class ContainerManager {
|
|
160
156
|
console.log('Image found: %s', image);
|
161
157
|
return false;
|
162
158
|
}
|
163
|
-
|
164
|
-
|
165
|
-
|
159
|
+
const timeStarted = Date.now();
|
160
|
+
socketManager.emitGlobal(EVENT_IMAGE_PULL, { image, percent: -1 });
|
161
|
+
const api = new KapetaAPI();
|
162
|
+
const accessToken = await api.getAccessToken();
|
163
|
+
const auth = image.startsWith('docker.kapeta.com/')
|
164
|
+
? {
|
165
|
+
username: 'kapeta',
|
166
|
+
password: accessToken,
|
167
|
+
serveraddress: 'docker.kapeta.com',
|
168
|
+
}
|
169
|
+
: {};
|
170
|
+
const stream = (await this.docker().image.create(auth, {
|
166
171
|
fromImage: imageName,
|
167
172
|
tag: tag,
|
173
|
+
}));
|
174
|
+
const chunks = {};
|
175
|
+
let lastEmitted = Date.now();
|
176
|
+
await promisifyStream(stream, (rawData) => {
|
177
|
+
const lines = rawData.toString().trim().split('\n');
|
178
|
+
lines.forEach((line) => {
|
179
|
+
const data = JSON.parse(line);
|
180
|
+
if (![
|
181
|
+
'Waiting',
|
182
|
+
'Downloading',
|
183
|
+
'Extracting',
|
184
|
+
'Download complete',
|
185
|
+
'Pull complete',
|
186
|
+
'Already exists',
|
187
|
+
].includes(data.status)) {
|
188
|
+
return;
|
189
|
+
}
|
190
|
+
if (!chunks[data.id]) {
|
191
|
+
chunks[data.id] = {
|
192
|
+
downloading: {
|
193
|
+
total: 0,
|
194
|
+
current: 0,
|
195
|
+
},
|
196
|
+
extracting: {
|
197
|
+
total: 0,
|
198
|
+
current: 0,
|
199
|
+
},
|
200
|
+
done: false,
|
201
|
+
};
|
202
|
+
}
|
203
|
+
const chunk = chunks[data.id];
|
204
|
+
switch (data.status) {
|
205
|
+
case 'Downloading':
|
206
|
+
chunk.downloading = data.progressDetail;
|
207
|
+
break;
|
208
|
+
case 'Extracting':
|
209
|
+
chunk.extracting = data.progressDetail;
|
210
|
+
break;
|
211
|
+
case 'Download complete':
|
212
|
+
chunk.downloading.current = chunks[data.id].downloading.total;
|
213
|
+
break;
|
214
|
+
case 'Pull complete':
|
215
|
+
chunk.extracting.current = chunks[data.id].extracting.total;
|
216
|
+
chunk.done = true;
|
217
|
+
break;
|
218
|
+
case 'Already exists':
|
219
|
+
// Force layer to be done
|
220
|
+
chunk.downloading.current = 1;
|
221
|
+
chunk.downloading.total = 1;
|
222
|
+
chunk.extracting.current = 1;
|
223
|
+
chunk.extracting.total = 1;
|
224
|
+
chunk.done = true;
|
225
|
+
break;
|
226
|
+
}
|
227
|
+
});
|
228
|
+
if (Date.now() - lastEmitted < 1000) {
|
229
|
+
return;
|
230
|
+
}
|
231
|
+
const chunkList = Object.values(chunks);
|
232
|
+
let totals = {
|
233
|
+
downloading: {
|
234
|
+
total: 0,
|
235
|
+
current: 0,
|
236
|
+
},
|
237
|
+
extracting: {
|
238
|
+
total: 0,
|
239
|
+
current: 0,
|
240
|
+
},
|
241
|
+
total: chunkList.length,
|
242
|
+
done: 0,
|
243
|
+
};
|
244
|
+
chunkList.forEach((chunk) => {
|
245
|
+
if (chunk.downloading.current > 0) {
|
246
|
+
totals.downloading.current += chunk.downloading.current;
|
247
|
+
}
|
248
|
+
if (chunk.downloading.total > 0) {
|
249
|
+
totals.downloading.total += chunk.downloading.total;
|
250
|
+
}
|
251
|
+
if (chunk.extracting.current > 0) {
|
252
|
+
totals.extracting.current += chunk.extracting.current;
|
253
|
+
}
|
254
|
+
if (chunk.extracting.total > 0) {
|
255
|
+
totals.extracting.total += chunk.extracting.total;
|
256
|
+
}
|
257
|
+
if (chunk.done) {
|
258
|
+
totals.done++;
|
259
|
+
}
|
260
|
+
});
|
261
|
+
const percent = totals.total > 0 ? (totals.done / totals.total) * 100 : 0;
|
262
|
+
//We emit at most every second to not spam the client
|
263
|
+
socketManager.emitGlobal(EVENT_IMAGE_PULL, {
|
264
|
+
image,
|
265
|
+
percent,
|
266
|
+
status: totals,
|
267
|
+
timeTaken: Date.now() - timeStarted,
|
268
|
+
});
|
269
|
+
lastEmitted = Date.now();
|
270
|
+
//console.log('Pulling image %s: %s % [done: %s, total: %s]', image, Math.round(percent), totals.done, totals.total);
|
168
271
|
});
|
169
|
-
|
170
|
-
console.log('Data from docker: "%s"', chunk.toString());
|
171
|
-
});
|
172
|
-
IMAGE_PULL_CACHE[image] = Date.now();
|
173
|
-
console.log('Image pulled: %s', image);
|
272
|
+
socketManager.emitGlobal(EVENT_IMAGE_PULL, { image, percent: 100, timeTaken: Date.now() - timeStarted });
|
174
273
|
return true;
|
175
274
|
}
|
176
275
|
toDockerMounts(mounts) {
|
@@ -205,18 +304,10 @@ class ContainerManager {
|
|
205
304
|
dockerOpts.Labels.HASH = hash;
|
206
305
|
}
|
207
306
|
async ensureContainer(opts) {
|
208
|
-
|
209
|
-
await this.waitForReady(container);
|
210
|
-
return container;
|
307
|
+
return await this.createOrUpdateContainer(opts);
|
211
308
|
}
|
212
309
|
async createOrUpdateContainer(opts) {
|
213
|
-
let imagePulled =
|
214
|
-
try {
|
215
|
-
imagePulled = await this.pull(opts.Image);
|
216
|
-
}
|
217
|
-
catch (e) {
|
218
|
-
console.warn('Failed to pull image. Continuing...', e);
|
219
|
-
}
|
310
|
+
let imagePulled = await this.pull(opts.Image);
|
220
311
|
this.applyHash(opts);
|
221
312
|
if (!opts.name) {
|
222
313
|
console.log('Starting unnamed container: %s', opts.Image);
|
@@ -341,12 +432,14 @@ class ContainerManager {
|
|
341
432
|
const containerName = getBlockInstanceContainerName(instance.systemId, instance.instanceId);
|
342
433
|
const containerInfo = await this.getContainerByName(containerName);
|
343
434
|
if (!containerInfo) {
|
344
|
-
return [
|
345
|
-
|
346
|
-
|
435
|
+
return [
|
436
|
+
{
|
437
|
+
source: 'stdout',
|
438
|
+
level: 'ERROR',
|
347
439
|
time: Date.now(),
|
348
|
-
message:
|
349
|
-
}
|
440
|
+
message: 'Container not found',
|
441
|
+
},
|
442
|
+
];
|
350
443
|
}
|
351
444
|
return containerInfo.getLogs();
|
352
445
|
}
|
@@ -434,13 +527,13 @@ export class ContainerInfo {
|
|
434
527
|
return ports;
|
435
528
|
}
|
436
529
|
async getLogs() {
|
437
|
-
const logStream = await this.native.logs({
|
530
|
+
const logStream = (await this.native.logs({
|
438
531
|
stdout: true,
|
439
532
|
stderr: true,
|
440
533
|
follow: false,
|
441
534
|
tail: 100,
|
442
535
|
timestamps: true,
|
443
|
-
});
|
536
|
+
}));
|
444
537
|
const out = [];
|
445
538
|
await promisifyStream(logStream, (data) => {
|
446
539
|
const buf = data;
|
@@ -7,6 +7,7 @@ declare class DefinitionsManager {
|
|
7
7
|
getDefinitions(kindFilter?: string | string[]): DefinitionInfo[];
|
8
8
|
exists(ref: string): boolean;
|
9
9
|
getProviderDefinitions(): DefinitionInfo[];
|
10
|
+
getDefinition(ref: string): DefinitionInfo | undefined;
|
10
11
|
}
|
11
12
|
export declare const definitionsManager: DefinitionsManager;
|
12
13
|
export {};
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
2
|
-
import { parseKapetaUri } from
|
2
|
+
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
3
3
|
const CACHE_TTL = 60 * 1000; // 1 min
|
4
4
|
class DefinitionsManager {
|
5
5
|
cache = {};
|
@@ -33,13 +33,16 @@ class DefinitionsManager {
|
|
33
33
|
return this.doCached(key, () => ClusterConfiguration.getDefinitions(kindFilter));
|
34
34
|
}
|
35
35
|
exists(ref) {
|
36
|
-
|
37
|
-
return !!this.getDefinitions().find((d) => {
|
38
|
-
return parseKapetaUri(`${d.definition.metadata.name}:${d.version}`).id === uri.id;
|
39
|
-
});
|
36
|
+
return !!this.getDefinition(ref);
|
40
37
|
}
|
41
38
|
getProviderDefinitions() {
|
42
39
|
return this.doCached('providers', () => ClusterConfiguration.getProviderDefinitions());
|
43
40
|
}
|
41
|
+
getDefinition(ref) {
|
42
|
+
const uri = parseKapetaUri(ref);
|
43
|
+
return this.getDefinitions().find((d) => {
|
44
|
+
return parseKapetaUri(`${d.definition.metadata.name}:${d.version}`).id === uri.id;
|
45
|
+
});
|
46
|
+
}
|
44
47
|
}
|
45
48
|
export const definitionsManager = new DefinitionsManager();
|
@@ -23,7 +23,14 @@ export declare class InstanceManager {
|
|
23
23
|
private stopInner;
|
24
24
|
stopAllForPlan(systemId: string): Promise<void>;
|
25
25
|
start(systemId: string, instanceId: string): Promise<InstanceInfo>;
|
26
|
-
|
26
|
+
/**
|
27
|
+
* Stops an instance but does not remove it from the list of active instances
|
28
|
+
*
|
29
|
+
* It will be started again next time the system checks the status of the instance
|
30
|
+
*
|
31
|
+
* We do it this way to not cause the user to wait for the instance to start again
|
32
|
+
*/
|
33
|
+
prepareForRestart(systemId: string, instanceId: string): Promise<void>;
|
27
34
|
stopAll(): Promise<void>;
|
28
35
|
private stopInstances;
|
29
36
|
private save;
|