@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.
Files changed (39) hide show
  1. package/.github/workflows/check-license.yml +0 -1
  2. package/CHANGELOG.md +14 -0
  3. package/dist/cjs/src/config/routes.js +9 -0
  4. package/dist/cjs/src/containerManager.d.ts +2 -8
  5. package/dist/cjs/src/containerManager.js +7 -7
  6. package/dist/cjs/src/instanceManager.d.ts +8 -3
  7. package/dist/cjs/src/instanceManager.js +147 -25
  8. package/dist/cjs/src/operatorManager.d.ts +9 -9
  9. package/dist/cjs/src/operatorManager.js +21 -26
  10. package/dist/cjs/src/serviceManager.d.ts +1 -0
  11. package/dist/cjs/src/serviceManager.js +9 -9
  12. package/dist/cjs/src/types.d.ts +40 -0
  13. package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +2 -13
  14. package/dist/cjs/src/utils/BlockInstanceRunner.js +91 -79
  15. package/dist/cjs/src/utils/utils.d.ts +6 -2
  16. package/dist/cjs/src/utils/utils.js +35 -2
  17. package/dist/esm/src/config/routes.js +9 -0
  18. package/dist/esm/src/containerManager.d.ts +2 -8
  19. package/dist/esm/src/containerManager.js +7 -7
  20. package/dist/esm/src/instanceManager.d.ts +8 -3
  21. package/dist/esm/src/instanceManager.js +147 -25
  22. package/dist/esm/src/operatorManager.d.ts +9 -9
  23. package/dist/esm/src/operatorManager.js +21 -26
  24. package/dist/esm/src/serviceManager.d.ts +1 -0
  25. package/dist/esm/src/serviceManager.js +9 -9
  26. package/dist/esm/src/types.d.ts +40 -0
  27. package/dist/esm/src/utils/BlockInstanceRunner.d.ts +2 -13
  28. package/dist/esm/src/utils/BlockInstanceRunner.js +91 -79
  29. package/dist/esm/src/utils/utils.d.ts +6 -2
  30. package/dist/esm/src/utils/utils.js +35 -2
  31. package/package.json +1 -1
  32. package/src/config/routes.ts +15 -0
  33. package/src/containerManager.ts +8 -15
  34. package/src/instanceManager.ts +218 -34
  35. package/src/operatorManager.ts +26 -31
  36. package/src/serviceManager.ts +11 -8
  37. package/src/types.ts +36 -0
  38. package/src/utils/BlockInstanceRunner.ts +119 -92
  39. package/src/utils/utils.ts +40 -3
@@ -56,6 +56,31 @@ export type ProcessInfo = {
56
56
  pid?: number | string | null;
57
57
  portType?: string;
58
58
  };
59
+ export interface Health {
60
+ cmd: string;
61
+ interval?: number;
62
+ timeout?: number;
63
+ retries?: number;
64
+ }
65
+ export type PortInfo = {
66
+ port: number;
67
+ type: 'tcp' | 'udp';
68
+ } | number | string;
69
+ export type LocalImageOptions<Credentials = AnyMap, Options = AnyMap> = {
70
+ image: string;
71
+ ports: {
72
+ [key: string]: PortInfo;
73
+ };
74
+ credentials?: Credentials;
75
+ options?: Options;
76
+ cmd?: string;
77
+ env?: AnyMap;
78
+ health?: Health;
79
+ singleton?: boolean;
80
+ mounts?: {
81
+ [key: string]: string;
82
+ };
83
+ };
59
84
  export type InstanceInfo = {
60
85
  systemId: string;
61
86
  instanceId: string;
@@ -73,6 +98,21 @@ export type InstanceInfo = {
73
98
  portType?: string;
74
99
  };
75
100
  export type ProxyRequestHandler = (req: StringBodyRequest, res: express.Response, info: ProxyRequestInfo) => void;
101
+ export interface OperatorInstancePort {
102
+ protocol: string;
103
+ port: number;
104
+ }
105
+ export interface OperatorInstanceInfo {
106
+ hostname: string;
107
+ ports: {
108
+ [portType: string]: OperatorInstancePort;
109
+ };
110
+ path?: string;
111
+ query?: string;
112
+ hash?: string;
113
+ options?: AnyMap;
114
+ credentials?: AnyMap;
115
+ }
76
116
  export interface OperatorInfo {
77
117
  host: string;
78
118
  port: string;
@@ -2,9 +2,7 @@
2
2
  * Copyright 2023 Kapeta Inc.
3
3
  * SPDX-License-Identifier: BUSL-1.1
4
4
  */
5
- import { DefinitionInfo } from '@kapeta/local-cluster-config';
6
- import { KapetaURI } from '@kapeta/nodejs-utils';
7
- import { AnyMap, BlockProcessParams, ProcessInfo, StringMap } from '../types';
5
+ import { AnyMap, ProcessInfo } from '../types';
8
6
  export declare function resolvePortType(portType: string): string;
9
7
  export declare class BlockInstanceRunner {
10
8
  private readonly _systemId;
@@ -20,16 +18,7 @@ export declare class BlockInstanceRunner {
20
18
  */
21
19
  private _startLocalProcess;
22
20
  private _startDockerProcess;
23
- /**
24
- *
25
- * @param blockInstance
26
- * @param blockUri
27
- * @param providerDefinition
28
- * @param {{[key:string]:string}} env
29
- * @return {Promise<ProcessDetails>}
30
- * @private
31
- */
32
- _startOperatorProcess(blockInstance: BlockProcessParams, blockUri: KapetaURI, providerDefinition: DefinitionInfo, env: StringMap): Promise<ProcessInfo>;
21
+ private _startOperatorProcess;
33
22
  private getDockerPortBindings;
34
23
  private ensureContainer;
35
24
  private _handleContainer;
@@ -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 dockerImage = spec?.local?.image;
292
- //We only want 1 operator per operator type - across all local systems
293
- const containerName = (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id);
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 = 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
- // For windows we need to default to root
328
- const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
329
- const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
330
- logs.addLog(`Creating new container for block: ${containerName}`);
331
- const out = await this.ensureContainer({
332
- Image: dockerImage,
333
- name: containerName,
334
- ExposedPorts,
335
- HealthCheck,
336
- HostConfig: {
337
- Binds: [
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
- PortBindings,
342
- Mounts,
343
- },
344
- Labels: {
345
- instance: blockInstance.id,
346
- [containerManager_1.COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
347
- [containerManager_1.COMPOSE_LABEL_SERVICE]: blockUri.id.replace(/[^a-z0-9]/gi, '_'),
348
- },
349
- Env: [
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
- const portTypes = spec.local.ports ? Object.keys(spec.local.ports) : [];
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
- function getBlockInstanceContainerName(systemId, instanceId) {
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;
@@ -148,4 +148,13 @@ router.get('/consumes/resource/:resourceType/:portType/:name', async (req, res)
148
148
  router.get('/consumes/:resourceName/:type', (req, res) => {
149
149
  res.send(serviceManager_1.serviceManager.getConsumerAddress(req.kapeta.systemId, req.kapeta.instanceId, req.params.resourceName, req.params.type, req.kapeta.environment));
150
150
  });
151
+ /**
152
+ * Used by services to information about a block operator
153
+ *
154
+ * If the remote service is not already running it will be started
155
+ */
156
+ router.get('/operator/:instanceId', async (req, res) => {
157
+ const operatorInfo = await instanceManager_1.instanceManager.getInstanceOperator(req.kapeta.systemId, req.params.instanceId, req.kapeta.environment);
158
+ res.send(operatorInfo);
159
+ });
151
160
  exports.default = router;
@@ -5,7 +5,7 @@
5
5
  /// <reference types="node" />
6
6
  import FSExtra from 'fs-extra';
7
7
  import Docker from 'dockerode';
8
- import { InstanceInfo, LogEntry } from './types';
8
+ import { Health, InstanceInfo, LogEntry } from './types';
9
9
  type StringMap = {
10
10
  [key: string]: string;
11
11
  };
@@ -26,12 +26,6 @@ export interface DockerMounts {
26
26
  }
27
27
  export type DockerContainerStatus = 'created' | 'running' | 'paused' | 'restarting' | 'removing' | 'exited' | 'dead';
28
28
  export type DockerContainerHealth = 'starting' | 'healthy' | 'unhealthy' | 'none';
29
- interface Health {
30
- cmd: string;
31
- interval?: number;
32
- timeout?: number;
33
- retries?: number;
34
- }
35
29
  export declare const CONTAINER_LABEL_PORT_PREFIX = "kapeta_port-";
36
30
  export declare const COMPOSE_LABEL_PROJECT = "com.docker.compose.project";
37
31
  export declare const COMPOSE_LABEL_SERVICE = "com.docker.compose.service";
@@ -50,7 +44,7 @@ declare class ContainerManager {
50
44
  isAlive(): boolean;
51
45
  getMountPoint(systemId: string, ref: string, mountName: string): string;
52
46
  createMounts(systemId: string, kind: string, mountOpts: StringMap | null | undefined): Promise<StringMap>;
53
- createVolumes(systemId: string, kind: string, mountOpts: StringMap | null | undefined): Promise<DockerMounts[]>;
47
+ createVolumes(systemId: string, serviceId: string, mountOpts: StringMap | null | undefined): Promise<DockerMounts[]>;
54
48
  ping(): Promise<void>;
55
49
  docker(): Docker;
56
50
  getContainerByName(containerName: string): Promise<ContainerInfo | undefined>;
@@ -168,12 +168,12 @@ class ContainerManager {
168
168
  }
169
169
  return mounts;
170
170
  }
171
- async createVolumes(systemId, kind, mountOpts) {
171
+ async createVolumes(systemId, serviceId, mountOpts) {
172
172
  const Mounts = [];
173
173
  if (mountOpts) {
174
174
  const mountOptList = Object.entries(mountOpts);
175
175
  for (const [mountName, containerPath] of mountOptList) {
176
- const volumeName = `${systemId}_${kind}_${mountName}`.replace(/[^a-z0-9]/gi, '_');
176
+ const volumeName = `${systemId}_${serviceId}_${mountName}`.replace(/[^a-z0-9]/gi, '_');
177
177
  Mounts.push({
178
178
  Target: containerPath,
179
179
  Source: volumeName,
@@ -182,7 +182,7 @@ class ContainerManager {
182
182
  Consistency: 'consistent',
183
183
  Labels: {
184
184
  [exports.COMPOSE_LABEL_PROJECT]: systemId.replace(/[^a-z0-9]/gi, '_'),
185
- [exports.COMPOSE_LABEL_SERVICE]: kind.replace(/[^a-z0-9]/gi, '_'),
185
+ [exports.COMPOSE_LABEL_SERVICE]: serviceId.replace(/[^a-z0-9]/gi, '_'),
186
186
  },
187
187
  });
188
188
  }
@@ -533,7 +533,7 @@ class ContainerManager {
533
533
  return new ContainerInfo(dockerContainer);
534
534
  }
535
535
  async getLogs(instance) {
536
- const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.systemId, instance.instanceId);
536
+ const containerName = await (0, utils_1.getBlockInstanceContainerName)(instance.systemId, instance.instanceId);
537
537
  const containerInfo = await this.getContainerByName(containerName);
538
538
  if (!containerInfo) {
539
539
  return [
@@ -548,7 +548,7 @@ class ContainerManager {
548
548
  return containerInfo.getLogs();
549
549
  }
550
550
  async stopLogListening(systemId, instanceId) {
551
- const containerName = (0, utils_1.getBlockInstanceContainerName)(systemId, instanceId);
551
+ const containerName = await (0, utils_1.getBlockInstanceContainerName)(systemId, instanceId);
552
552
  if (this.logStreams[containerName]) {
553
553
  if (this.logStreams[containerName]?.timer) {
554
554
  clearTimeout(this.logStreams[containerName].timer);
@@ -566,7 +566,7 @@ class ContainerManager {
566
566
  }
567
567
  }
568
568
  async ensureLogListening(systemId, instanceId, handler) {
569
- const containerName = (0, utils_1.getBlockInstanceContainerName)(systemId, instanceId);
569
+ const containerName = await (0, utils_1.getBlockInstanceContainerName)(systemId, instanceId);
570
570
  try {
571
571
  if (this.logStreams[containerName]?.stream) {
572
572
  // Already listening - will shut itself down
@@ -791,7 +791,7 @@ class ContainerInfo {
791
791
  if (!name.startsWith(exports.CONTAINER_LABEL_PORT_PREFIX)) {
792
792
  return;
793
793
  }
794
- const hostPort = name.substr(exports.CONTAINER_LABEL_PORT_PREFIX.length);
794
+ const hostPort = name.substring(exports.CONTAINER_LABEL_PORT_PREFIX.length);
795
795
  portTypes[hostPort] = portType;
796
796
  });
797
797
  lodash_1.default.forEach(inspectResult.HostConfig.PortBindings, (portBindings, containerPortSpec) => {
@@ -2,7 +2,7 @@
2
2
  * Copyright 2023 Kapeta Inc.
3
3
  * SPDX-License-Identifier: BUSL-1.1
4
4
  */
5
- import { InstanceInfo, LogEntry } from './types';
5
+ import { EnvironmentType, InstanceInfo, LogEntry, OperatorInstanceInfo } from './types';
6
6
  import { Task } from './taskManager';
7
7
  export declare class InstanceManager {
8
8
  private _interval;
@@ -24,10 +24,11 @@ export declare class InstanceManager {
24
24
  private getHealthUrl;
25
25
  markAsStopped(systemId: string, instanceId: string): Promise<void>;
26
26
  startAllForPlan(systemId: string): Promise<Task<InstanceInfo[]>>;
27
+ stopAllForPlan(systemId: string): Task<void>;
28
+ getInstanceOperator(systemId: string, instanceId: string, environment?: EnvironmentType): Promise<OperatorInstanceInfo>;
27
29
  stop(systemId: string, instanceId: string): Promise<void>;
28
30
  private stopInner;
29
- stopAllForPlan(systemId: string): Task<void>;
30
- start(systemId: string, instanceId: string): Promise<InstanceInfo | Task<InstanceInfo>>;
31
+ start(systemId: string, instanceId: string, checkForSingleton?: boolean): Promise<InstanceInfo | Task<InstanceInfo>>;
31
32
  /**
32
33
  * Stops an instance but does not remove it from the list of active instances
33
34
  *
@@ -42,5 +43,9 @@ export declare class InstanceManager {
42
43
  private checkInstances;
43
44
  private getExternalStatus;
44
45
  private requestInstanceStatus;
46
+ private isSingletonOperator;
47
+ private getKindForAssetRef;
48
+ private isUsingKind;
49
+ private getAllInstancesForKind;
45
50
  }
46
51
  export declare const instanceManager: InstanceManager;