@kapeta/local-cluster-service 0.34.2 → 0.36.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/.github/workflows/check-license.yml +0 -1
- package/CHANGELOG.md +14 -0
- package/dist/cjs/src/config/routes.js +9 -0
- package/dist/cjs/src/containerManager.d.ts +2 -8
- package/dist/cjs/src/containerManager.js +7 -7
- package/dist/cjs/src/instanceManager.d.ts +8 -3
- package/dist/cjs/src/instanceManager.js +147 -25
- package/dist/cjs/src/operatorManager.d.ts +9 -9
- package/dist/cjs/src/operatorManager.js +21 -26
- package/dist/cjs/src/serviceManager.d.ts +1 -0
- package/dist/cjs/src/serviceManager.js +9 -9
- package/dist/cjs/src/types.d.ts +40 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +2 -13
- package/dist/cjs/src/utils/BlockInstanceRunner.js +91 -79
- package/dist/cjs/src/utils/utils.d.ts +6 -2
- package/dist/cjs/src/utils/utils.js +35 -2
- package/dist/esm/src/config/routes.js +9 -0
- package/dist/esm/src/containerManager.d.ts +2 -8
- package/dist/esm/src/containerManager.js +7 -7
- package/dist/esm/src/instanceManager.d.ts +8 -3
- package/dist/esm/src/instanceManager.js +147 -25
- package/dist/esm/src/operatorManager.d.ts +9 -9
- package/dist/esm/src/operatorManager.js +21 -26
- package/dist/esm/src/serviceManager.d.ts +1 -0
- package/dist/esm/src/serviceManager.js +9 -9
- package/dist/esm/src/types.d.ts +40 -0
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +2 -13
- package/dist/esm/src/utils/BlockInstanceRunner.js +91 -79
- package/dist/esm/src/utils/utils.d.ts +6 -2
- package/dist/esm/src/utils/utils.js +35 -2
- package/package.json +1 -1
- package/src/config/routes.ts +15 -0
- package/src/containerManager.ts +8 -15
- package/src/instanceManager.ts +218 -34
- package/src/operatorManager.ts +26 -31
- package/src/serviceManager.ts +11 -8
- package/src/types.ts +36 -0
- package/src/utils/BlockInstanceRunner.ts +119 -92
- package/src/utils/utils.ts +40 -3
@@ -19,6 +19,7 @@ const clusterService_1 = require("../clusterService");
|
|
19
19
|
const types_1 = require("../types");
|
20
20
|
const definitionsManager_1 = require("../definitionsManager");
|
21
21
|
const node_os_1 = __importDefault(require("node:os"));
|
22
|
+
const taskManager_1 = require("../taskManager");
|
22
23
|
const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
|
23
24
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
24
25
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
@@ -155,7 +156,7 @@ class BlockInstanceRunner {
|
|
155
156
|
if (!dockerImage) {
|
156
157
|
throw new Error(`Missing docker image information: ${JSON.stringify(localContainer)}`);
|
157
158
|
}
|
158
|
-
const containerName = (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id);
|
159
|
+
const containerName = await (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id, targetKindUri.id);
|
159
160
|
const startCmd = localContainer.handlers?.onCreate ? localContainer.handlers.onCreate : '';
|
160
161
|
const dockerOpts = localContainer.options ?? {};
|
161
162
|
const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
|
@@ -241,7 +242,7 @@ class BlockInstanceRunner {
|
|
241
242
|
throw new Error(`Block type not found: ${kindUri.id}`);
|
242
243
|
}
|
243
244
|
const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion, providerVersion);
|
244
|
-
const containerName = (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id);
|
245
|
+
const containerName = await (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id, kindUri.id);
|
245
246
|
// For windows we need to default to root
|
246
247
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
|
247
248
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
@@ -268,15 +269,6 @@ class BlockInstanceRunner {
|
|
268
269
|
},
|
269
270
|
});
|
270
271
|
}
|
271
|
-
/**
|
272
|
-
*
|
273
|
-
* @param blockInstance
|
274
|
-
* @param blockUri
|
275
|
-
* @param providerDefinition
|
276
|
-
* @param {{[key:string]:string}} env
|
277
|
-
* @return {Promise<ProcessDetails>}
|
278
|
-
* @private
|
279
|
-
*/
|
280
272
|
async _startOperatorProcess(blockInstance, blockUri, providerDefinition, env) {
|
281
273
|
const { assetFile } = local_cluster_config_1.default.getRepositoryAssetInfoPath(blockUri.handle, blockUri.name, blockUri.version);
|
282
274
|
const kapetaYmlPath = assetFile;
|
@@ -288,79 +280,99 @@ class BlockInstanceRunner {
|
|
288
280
|
if (!spec?.local?.image) {
|
289
281
|
throw new Error(`Provider did not have local image: ${providerRef}`);
|
290
282
|
}
|
291
|
-
const
|
292
|
-
|
293
|
-
const
|
294
|
-
const
|
295
|
-
const
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
let HealthCheck = undefined;
|
300
|
-
let Mounts = [];
|
301
|
-
const localPorts = spec.local.ports;
|
302
|
-
const promises = Object.entries(localPorts).map(async ([portType, value]) => {
|
303
|
-
const dockerPort = `${value.port}/${value.type}`;
|
304
|
-
ExposedPorts[dockerPort] = {};
|
305
|
-
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = value.port;
|
306
|
-
const publicPort = await serviceManager_1.serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
|
307
|
-
PortBindings[dockerPort] = [
|
308
|
-
{
|
309
|
-
HostIp: bindHost,
|
310
|
-
HostPort: `${publicPort}`,
|
311
|
-
},
|
312
|
-
];
|
313
|
-
});
|
314
|
-
await Promise.all(promises);
|
315
|
-
if (spec.local?.env) {
|
316
|
-
Object.entries(spec.local.env).forEach(([key, value]) => {
|
317
|
-
addonEnv[key] = value;
|
318
|
-
});
|
319
|
-
}
|
320
|
-
if (spec.local?.mounts) {
|
321
|
-
const mounts = await containerManager_1.containerManager.createMounts(this._systemId, blockUri.id, spec.local.mounts);
|
322
|
-
Mounts = containerManager_1.containerManager.toDockerMounts(mounts);
|
323
|
-
}
|
324
|
-
if (spec.local?.health) {
|
325
|
-
HealthCheck = containerManager_1.containerManager.toDockerHealth(spec.local?.health);
|
283
|
+
const local = spec.local;
|
284
|
+
const dockerImage = local.image;
|
285
|
+
const operatorUri = local.singleton ? (0, nodejs_utils_1.parseKapetaUri)(providerRef) : blockUri;
|
286
|
+
const operatorId = local.singleton ? providerRef : blockInstance.id;
|
287
|
+
const operatorRef = local.singleton ? providerRef : blockInstance.ref;
|
288
|
+
if (local.singleton && env) {
|
289
|
+
env[KAPETA_BLOCK_REF] = operatorRef;
|
290
|
+
env[KAPETA_INSTANCE_ID] = operatorId;
|
326
291
|
}
|
327
|
-
|
328
|
-
const
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
292
|
+
const containerName = await (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id, providerRef);
|
293
|
+
const task = taskManager_1.taskManager.add(`container:start:${containerName}`, async () => {
|
294
|
+
const logs = new LogData_1.LogData();
|
295
|
+
const bindHost = (0, utils_1.getBindHost)();
|
296
|
+
const ExposedPorts = {};
|
297
|
+
const addonEnv = {};
|
298
|
+
const PortBindings = {};
|
299
|
+
let HealthCheck = undefined;
|
300
|
+
let Mounts = [];
|
301
|
+
const localPorts = local.ports ?? {};
|
302
|
+
const labels = {};
|
303
|
+
const promises = Object.entries(localPorts).map(async ([portType, value]) => {
|
304
|
+
const portInfo = (0, utils_1.toPortInfo)(value);
|
305
|
+
const dockerPort = `${portInfo.port}/${portInfo.type}`;
|
306
|
+
ExposedPorts[dockerPort] = {};
|
307
|
+
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = `${portInfo.port}`;
|
308
|
+
const publicPort = await serviceManager_1.serviceManager.ensureServicePort(this._systemId, operatorId, portType);
|
309
|
+
PortBindings[dockerPort] = [
|
310
|
+
{
|
311
|
+
HostIp: bindHost,
|
312
|
+
HostPort: `${publicPort}`,
|
313
|
+
},
|
314
|
+
];
|
315
|
+
labels[containerManager_1.CONTAINER_LABEL_PORT_PREFIX + publicPort] = portType;
|
316
|
+
});
|
317
|
+
await Promise.all(promises);
|
318
|
+
if (local.env) {
|
319
|
+
Object.entries(local.env).forEach(([key, value]) => {
|
320
|
+
addonEnv[key] = value;
|
321
|
+
});
|
322
|
+
}
|
323
|
+
if (local.mounts) {
|
324
|
+
Mounts = await containerManager_1.containerManager.createVolumes(this._systemId, operatorUri.id, local.mounts);
|
325
|
+
}
|
326
|
+
if (local.health) {
|
327
|
+
HealthCheck = containerManager_1.containerManager.toDockerHealth(local.health);
|
328
|
+
}
|
329
|
+
// For windows we need to default to root
|
330
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
|
331
|
+
const Binds = local.singleton
|
332
|
+
? [`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`]
|
333
|
+
: [
|
338
334
|
`${(0, containerManager_1.toLocalBindVolume)(kapetaYmlPath)}:/kapeta.yml:ro`,
|
339
335
|
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`,
|
336
|
+
];
|
337
|
+
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
338
|
+
console.log(`Ensuring container for operator block: ${containerName} [singleton: ${!!local.singleton}]`);
|
339
|
+
logs.addLog(`Ensuring container for operator block: ${containerName}`);
|
340
|
+
const out = await this.ensureContainer({
|
341
|
+
Image: dockerImage,
|
342
|
+
name: containerName,
|
343
|
+
ExposedPorts,
|
344
|
+
HealthCheck,
|
345
|
+
HostConfig: {
|
346
|
+
Binds,
|
347
|
+
PortBindings,
|
348
|
+
Mounts,
|
349
|
+
},
|
350
|
+
Labels: {
|
351
|
+
...labels,
|
352
|
+
instance: operatorId,
|
353
|
+
[containerManager_1.COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
|
354
|
+
[containerManager_1.COMPOSE_LABEL_SERVICE]: operatorUri.id.replace(/[^a-z0-9]/gi, '_'),
|
355
|
+
},
|
356
|
+
Env: [
|
357
|
+
`KAPETA_INSTANCE_NAME=${operatorRef}`,
|
358
|
+
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
|
359
|
+
...DOCKER_ENV_VARS,
|
360
|
+
...Object.entries({
|
361
|
+
...env,
|
362
|
+
...addonEnv,
|
363
|
+
}).map(([key, value]) => `${key}=${value}`),
|
340
364
|
],
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
}
|
349
|
-
|
350
|
-
`KAPETA_INSTANCE_NAME=${blockInstance.ref}`,
|
351
|
-
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
|
352
|
-
...DOCKER_ENV_VARS,
|
353
|
-
...Object.entries({
|
354
|
-
...env,
|
355
|
-
...addonEnv,
|
356
|
-
}).map(([key, value]) => `${key}=${value}`),
|
357
|
-
],
|
365
|
+
});
|
366
|
+
const portTypes = local.ports ? Object.keys(local.ports) : [];
|
367
|
+
if (portTypes.length > 0) {
|
368
|
+
out.portType = portTypes[0];
|
369
|
+
}
|
370
|
+
return out;
|
371
|
+
}, {
|
372
|
+
name: `Starting container for ${providerRef}`,
|
373
|
+
systemId: this._systemId,
|
358
374
|
});
|
359
|
-
|
360
|
-
if (portTypes.length > 0) {
|
361
|
-
out.portType = portTypes[0];
|
362
|
-
}
|
363
|
-
return out;
|
375
|
+
return task.wait();
|
364
376
|
}
|
365
377
|
async getDockerPortBindings(blockInstance, assetVersion, providerVersion) {
|
366
378
|
const bindHost = (0, utils_1.getBindHost)();
|
@@ -3,8 +3,12 @@
|
|
3
3
|
* SPDX-License-Identifier: BUSL-1.1
|
4
4
|
*/
|
5
5
|
import { EntityList } from '@kapeta/schemas';
|
6
|
-
import { AnyMap } from '../types';
|
7
|
-
export declare function getBlockInstanceContainerName(systemId: string, instanceId: string): string
|
6
|
+
import { AnyMap, PortInfo } from '../types';
|
7
|
+
export declare function getBlockInstanceContainerName(systemId: string, instanceId: string, blockType?: string): Promise<string>;
|
8
|
+
export declare function toPortInfo(port: PortInfo): {
|
9
|
+
port: number;
|
10
|
+
type: string;
|
11
|
+
};
|
8
12
|
export declare function getRemoteUrl(id: string, defautValue: string): any;
|
9
13
|
export declare function readYML(path: string): any;
|
10
14
|
export declare function isWindows(): boolean;
|
@@ -7,16 +7,49 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
8
8
|
};
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
10
|
-
exports.getResolvedConfiguration = exports.getBindHost = exports.isLinux = exports.isMac = exports.isWindows = exports.readYML = exports.getRemoteUrl = exports.getBlockInstanceContainerName = void 0;
|
10
|
+
exports.getResolvedConfiguration = exports.getBindHost = exports.isLinux = exports.isMac = exports.isWindows = exports.readYML = exports.getRemoteUrl = exports.toPortInfo = exports.getBlockInstanceContainerName = void 0;
|
11
11
|
const node_fs_1 = __importDefault(require("node:fs"));
|
12
12
|
const yaml_1 = __importDefault(require("yaml"));
|
13
13
|
const md5_1 = __importDefault(require("md5"));
|
14
14
|
const lodash_1 = __importDefault(require("lodash"));
|
15
15
|
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
16
|
-
|
16
|
+
const definitionsManager_1 = require("../definitionsManager");
|
17
|
+
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
18
|
+
const operatorManager_1 = require("../operatorManager");
|
19
|
+
const assetManager_1 = require("../assetManager");
|
20
|
+
async function getBlockInstanceContainerName(systemId, instanceId, blockType) {
|
21
|
+
if (!blockType) {
|
22
|
+
const instance = await assetManager_1.assetManager.getBlockInstance(systemId, instanceId);
|
23
|
+
if (!instance) {
|
24
|
+
throw new Error(`Instance ${instanceId} not found in plan ${systemId}`);
|
25
|
+
}
|
26
|
+
const block = await assetManager_1.assetManager.getAsset(instance.block.ref);
|
27
|
+
if (!block) {
|
28
|
+
throw new Error(`Block ${instance.block.ref} not found`);
|
29
|
+
}
|
30
|
+
blockType = block.data.kind;
|
31
|
+
}
|
32
|
+
const typeDefinition = await definitionsManager_1.definitionsManager.getDefinition(blockType);
|
33
|
+
if (!typeDefinition) {
|
34
|
+
throw new Error(`Block type ${blockType} not found`);
|
35
|
+
}
|
36
|
+
if ((0, nodejs_utils_1.parseKapetaUri)(typeDefinition.definition.kind).fullName === operatorManager_1.KIND_BLOCK_OPERATOR &&
|
37
|
+
typeDefinition.definition.spec?.local?.singleton) {
|
38
|
+
return `kapeta-instance-operator-${(0, md5_1.default)(systemId + blockType)}`;
|
39
|
+
}
|
17
40
|
return `kapeta-block-instance-${(0, md5_1.default)(systemId + instanceId)}`;
|
18
41
|
}
|
19
42
|
exports.getBlockInstanceContainerName = getBlockInstanceContainerName;
|
43
|
+
function toPortInfo(port) {
|
44
|
+
if (typeof port === 'number' || typeof port === 'string') {
|
45
|
+
return { port: parseInt(`${port}`), type: 'tcp' };
|
46
|
+
}
|
47
|
+
if (!port.type) {
|
48
|
+
port.type = 'tcp';
|
49
|
+
}
|
50
|
+
return port;
|
51
|
+
}
|
52
|
+
exports.toPortInfo = toPortInfo;
|
20
53
|
function getRemoteUrl(id, defautValue) {
|
21
54
|
const remoteConfig = local_cluster_config_1.default.getClusterConfig().remote;
|
22
55
|
return remoteConfig?.[id] ?? defautValue;
|
package/package.json
CHANGED
package/src/config/routes.ts
CHANGED
@@ -181,4 +181,19 @@ router.get('/consumes/:resourceName/:type', (req: KapetaRequest, res) => {
|
|
181
181
|
);
|
182
182
|
});
|
183
183
|
|
184
|
+
/**
|
185
|
+
* Used by services to information about a block operator
|
186
|
+
*
|
187
|
+
* If the remote service is not already running it will be started
|
188
|
+
*/
|
189
|
+
router.get('/operator/:instanceId', async (req: KapetaRequest, res) => {
|
190
|
+
const operatorInfo = await instanceManager.getInstanceOperator(
|
191
|
+
req.kapeta!.systemId,
|
192
|
+
req.params.instanceId,
|
193
|
+
req.kapeta!.environment
|
194
|
+
);
|
195
|
+
|
196
|
+
res.send(operatorInfo);
|
197
|
+
});
|
198
|
+
|
184
199
|
export default router;
|
package/src/containerManager.ts
CHANGED
@@ -14,7 +14,7 @@ import ClusterConfiguration from '@kapeta/local-cluster-config';
|
|
14
14
|
import uuid from 'node-uuid';
|
15
15
|
import md5 from 'md5';
|
16
16
|
import { getBlockInstanceContainerName } from './utils/utils';
|
17
|
-
import { InstanceInfo, LogEntry, LogSource } from './types';
|
17
|
+
import { Health, InstanceInfo, LogEntry, LogSource } from './types';
|
18
18
|
import { KapetaAPI } from '@kapeta/nodejs-api-client';
|
19
19
|
import { taskManager, Task } from './taskManager';
|
20
20
|
import { EventEmitter } from 'node:events';
|
@@ -76,13 +76,6 @@ interface JSONMessage<T = string> {
|
|
76
76
|
aux?: any;
|
77
77
|
}
|
78
78
|
|
79
|
-
interface Health {
|
80
|
-
cmd: string;
|
81
|
-
interval?: number;
|
82
|
-
timeout?: number;
|
83
|
-
retries?: number;
|
84
|
-
}
|
85
|
-
|
86
79
|
export const CONTAINER_LABEL_PORT_PREFIX = 'kapeta_port-';
|
87
80
|
const NANO_SECOND = 1000000;
|
88
81
|
const HEALTH_CHECK_INTERVAL = 3000;
|
@@ -255,7 +248,7 @@ class ContainerManager {
|
|
255
248
|
|
256
249
|
async createVolumes(
|
257
250
|
systemId: string,
|
258
|
-
|
251
|
+
serviceId: string,
|
259
252
|
mountOpts: StringMap | null | undefined
|
260
253
|
): Promise<DockerMounts[]> {
|
261
254
|
const Mounts: DockerMounts[] = [];
|
@@ -263,7 +256,7 @@ class ContainerManager {
|
|
263
256
|
if (mountOpts) {
|
264
257
|
const mountOptList = Object.entries(mountOpts);
|
265
258
|
for (const [mountName, containerPath] of mountOptList) {
|
266
|
-
const volumeName = `${systemId}_${
|
259
|
+
const volumeName = `${systemId}_${serviceId}_${mountName}`.replace(/[^a-z0-9]/gi, '_');
|
267
260
|
|
268
261
|
Mounts.push({
|
269
262
|
Target: containerPath,
|
@@ -273,7 +266,7 @@ class ContainerManager {
|
|
273
266
|
Consistency: 'consistent',
|
274
267
|
Labels: {
|
275
268
|
[COMPOSE_LABEL_PROJECT]: systemId.replace(/[^a-z0-9]/gi, '_'),
|
276
|
-
[COMPOSE_LABEL_SERVICE]:
|
269
|
+
[COMPOSE_LABEL_SERVICE]: serviceId.replace(/[^a-z0-9]/gi, '_'),
|
277
270
|
},
|
278
271
|
});
|
279
272
|
}
|
@@ -701,7 +694,7 @@ class ContainerManager {
|
|
701
694
|
}
|
702
695
|
|
703
696
|
async getLogs(instance: InstanceInfo): Promise<LogEntry[]> {
|
704
|
-
const containerName = getBlockInstanceContainerName(instance.systemId, instance.instanceId);
|
697
|
+
const containerName = await getBlockInstanceContainerName(instance.systemId, instance.instanceId);
|
705
698
|
const containerInfo = await this.getContainerByName(containerName);
|
706
699
|
if (!containerInfo) {
|
707
700
|
return [
|
@@ -718,7 +711,7 @@ class ContainerManager {
|
|
718
711
|
}
|
719
712
|
|
720
713
|
async stopLogListening(systemId: string, instanceId: string) {
|
721
|
-
const containerName = getBlockInstanceContainerName(systemId, instanceId);
|
714
|
+
const containerName = await getBlockInstanceContainerName(systemId, instanceId);
|
722
715
|
if (this.logStreams[containerName]) {
|
723
716
|
if (this.logStreams[containerName]?.timer) {
|
724
717
|
clearTimeout(this.logStreams[containerName].timer);
|
@@ -736,7 +729,7 @@ class ContainerManager {
|
|
736
729
|
}
|
737
730
|
|
738
731
|
async ensureLogListening(systemId: string, instanceId: string, handler: (log: LogEntry) => void) {
|
739
|
-
const containerName = getBlockInstanceContainerName(systemId, instanceId);
|
732
|
+
const containerName = await getBlockInstanceContainerName(systemId, instanceId);
|
740
733
|
try {
|
741
734
|
if (this.logStreams[containerName]?.stream) {
|
742
735
|
// Already listening - will shut itself down
|
@@ -997,7 +990,7 @@ export class ContainerInfo {
|
|
997
990
|
return;
|
998
991
|
}
|
999
992
|
|
1000
|
-
const hostPort = name.
|
993
|
+
const hostPort = name.substring(CONTAINER_LABEL_PORT_PREFIX.length);
|
1001
994
|
|
1002
995
|
portTypes[hostPort] = portType;
|
1003
996
|
});
|