@kapeta/local-cluster-service 0.11.1 → 0.12.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 (40) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/definitions.d.ts +7 -0
  3. package/dist/cjs/src/config/routes.js +1 -1
  4. package/dist/cjs/src/containerManager.d.ts +2 -1
  5. package/dist/cjs/src/containerManager.js +125 -21
  6. package/dist/cjs/src/definitionsManager.d.ts +1 -0
  7. package/dist/cjs/src/definitionsManager.js +7 -4
  8. package/dist/cjs/src/instanceManager.d.ts +8 -1
  9. package/dist/cjs/src/instanceManager.js +48 -19
  10. package/dist/cjs/src/operatorManager.d.ts +2 -0
  11. package/dist/cjs/src/operatorManager.js +69 -67
  12. package/dist/cjs/src/socketManager.d.ts +1 -0
  13. package/dist/cjs/src/socketManager.js +3 -0
  14. package/dist/cjs/src/types.d.ts +1 -0
  15. package/dist/cjs/src/utils/BlockInstanceRunner.js +2 -2
  16. package/dist/esm/src/config/routes.js +1 -1
  17. package/dist/esm/src/containerManager.d.ts +2 -1
  18. package/dist/esm/src/containerManager.js +126 -22
  19. package/dist/esm/src/definitionsManager.d.ts +1 -0
  20. package/dist/esm/src/definitionsManager.js +8 -5
  21. package/dist/esm/src/instanceManager.d.ts +8 -1
  22. package/dist/esm/src/instanceManager.js +48 -19
  23. package/dist/esm/src/operatorManager.d.ts +2 -0
  24. package/dist/esm/src/operatorManager.js +67 -65
  25. package/dist/esm/src/socketManager.d.ts +1 -0
  26. package/dist/esm/src/socketManager.js +3 -0
  27. package/dist/esm/src/types.d.ts +1 -0
  28. package/dist/esm/src/utils/BlockInstanceRunner.js +2 -2
  29. package/dist/esm/src/utils/utils.js +1 -1
  30. package/package.json +1 -1
  31. package/src/config/routes.ts +1 -1
  32. package/src/containerManager.ts +178 -43
  33. package/src/definitionsManager.ts +9 -5
  34. package/src/instanceManager.ts +70 -40
  35. package/src/instances/routes.ts +1 -1
  36. package/src/operatorManager.ts +72 -70
  37. package/src/socketManager.ts +4 -0
  38. package/src/types.ts +1 -1
  39. package/src/utils/BlockInstanceRunner.ts +12 -22
  40. package/src/utils/utils.ts +2 -2
@@ -11,9 +11,9 @@ import { BlockInstance, Resource } from '@kapeta/schemas';
11
11
  import { definitionsManager } from './definitionsManager';
12
12
  import { getBindHost, normalizeKapetaUri } from './utils/utils';
13
13
  import _ from 'lodash';
14
- import { Container } from 'node-docker-api/lib/container';
14
+ import AsyncLock from 'async-lock';
15
15
 
16
- const KIND_OPERATOR = 'core/resource-type-operator';
16
+ export const KIND_OPERATOR = 'core/resource-type-operator';
17
17
 
18
18
  class Operator {
19
19
  private _data: any;
@@ -33,6 +33,8 @@ class Operator {
33
33
  class OperatorManager {
34
34
  private _mountDir: string;
35
35
 
36
+ private operatorLock: AsyncLock = new AsyncLock();
37
+
36
38
  constructor() {
37
39
  this._mountDir = Path.join(storageService.getKapetaBasedir(), 'mounts');
38
40
 
@@ -154,98 +156,98 @@ class OperatorManager {
154
156
  * @return {Promise<ContainerInfo>}
155
157
  */
156
158
  async ensureResource(systemId: string, resourceType: string, version: string): Promise<ContainerInfo> {
157
- const operator = this.getOperator(resourceType, version);
159
+ systemId = normalizeKapetaUri(systemId);
160
+ const key = `${systemId}#${resourceType}:${version}`;
161
+ return await this.operatorLock.acquire(key, async () => {
162
+ const operator = this.getOperator(resourceType, version);
158
163
 
159
- const operatorData = operator.getData();
164
+ const operatorData = operator.getData();
160
165
 
161
- const portTypes = Object.keys(operatorData.ports);
166
+ const portTypes = Object.keys(operatorData.ports);
162
167
 
163
- portTypes.sort();
168
+ portTypes.sort();
164
169
 
165
- const ports: AnyMap = {};
170
+ const ports: AnyMap = {};
166
171
 
167
- for (let i = 0; i < portTypes.length; i++) {
168
- const portType = portTypes[i];
169
- let containerPortInfo = operatorData.ports[portType];
170
- const hostPort = await serviceManager.ensureServicePort(systemId, resourceType, portType);
172
+ for (let i = 0; i < portTypes.length; i++) {
173
+ const portType = portTypes[i];
174
+ let containerPortInfo = operatorData.ports[portType];
175
+ const hostPort = await serviceManager.ensureServicePort(systemId, resourceType, portType);
171
176
 
172
- if (typeof containerPortInfo === 'number' || typeof containerPortInfo === 'string') {
173
- containerPortInfo = { port: containerPortInfo, type: 'tcp' };
174
- }
177
+ if (typeof containerPortInfo === 'number' || typeof containerPortInfo === 'string') {
178
+ containerPortInfo = { port: containerPortInfo, type: 'tcp' };
179
+ }
175
180
 
176
- if (!containerPortInfo.type) {
177
- containerPortInfo.type = 'tcp';
178
- }
181
+ if (!containerPortInfo.type) {
182
+ containerPortInfo.type = 'tcp';
183
+ }
179
184
 
180
- const portId = containerPortInfo.port + '/' + containerPortInfo.type;
185
+ const portId = containerPortInfo.port + '/' + containerPortInfo.type;
181
186
 
182
- ports[portId] = {
183
- type: portType,
184
- hostPort,
185
- };
186
- }
187
+ ports[portId] = {
188
+ type: portType,
189
+ hostPort,
190
+ };
191
+ }
187
192
 
188
- const mounts = await containerManager.createMounts(systemId, resourceType, operatorData.mounts);
193
+ const mounts = await containerManager.createMounts(systemId, resourceType, operatorData.mounts);
189
194
 
190
- const nameParts = [
191
- systemId,
192
- resourceType.toLowerCase(),
193
- version
194
- ];
195
+ const nameParts = [systemId, resourceType.toLowerCase(), version];
195
196
 
196
- const containerName = `kapeta-resource-${md5(nameParts.join('_'))}`;
197
+ const containerName = `kapeta-resource-${md5(nameParts.join('_'))}`;
197
198
 
198
- const PortBindings: { [key: string]: any } = {};
199
- const Env: string[] = [];
199
+ const PortBindings: { [key: string]: any } = {};
200
+ const Env: string[] = [];
200
201
 
201
- const Labels: StringMap = {
202
- kapeta: 'true',
203
- };
202
+ const Labels: StringMap = {
203
+ kapeta: 'true',
204
+ };
204
205
 
205
- const bindHost = getBindHost();
206
+ const bindHost = getBindHost();
206
207
 
207
- const ExposedPorts: { [key: string]: any } = {};
208
+ const ExposedPorts: { [key: string]: any } = {};
208
209
 
209
- _.forEach(ports, (portInfo: any, containerPort) => {
210
- ExposedPorts['' + containerPort] = {};
211
- PortBindings['' + containerPort] = [
212
- {
213
- HostPort: '' + portInfo.hostPort,
214
- HostIp: bindHost,
215
- },
216
- ];
210
+ _.forEach(ports, (portInfo: any, containerPort) => {
211
+ ExposedPorts['' + containerPort] = {};
212
+ PortBindings['' + containerPort] = [
213
+ {
214
+ HostPort: '' + portInfo.hostPort,
215
+ HostIp: bindHost,
216
+ },
217
+ ];
217
218
 
218
- Labels[CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
219
- });
219
+ Labels[CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
220
+ });
220
221
 
221
- const Mounts = containerManager.toDockerMounts(mounts);
222
+ const Mounts = containerManager.toDockerMounts(mounts);
222
223
 
223
- _.forEach(operatorData.env, (value, name) => {
224
- Env.push(name + '=' + value);
225
- });
224
+ _.forEach(operatorData.env, (value, name) => {
225
+ Env.push(name + '=' + value);
226
+ });
226
227
 
227
- let HealthCheck = undefined;
228
+ let HealthCheck = undefined;
228
229
 
229
- if (operatorData.health) {
230
- HealthCheck = containerManager.toDockerHealth(operatorData.health);
231
- }
230
+ if (operatorData.health) {
231
+ HealthCheck = containerManager.toDockerHealth(operatorData.health);
232
+ }
232
233
 
233
- const container = await containerManager.ensureContainer({
234
- name: containerName,
235
- Image: operatorData.image,
236
- Hostname: containerName + '.kapeta',
237
- Labels,
238
- Cmd: operatorData.cmd,
239
- ExposedPorts,
240
- Env,
241
- HealthCheck,
242
- HostConfig: {
243
- PortBindings,
244
- Mounts,
245
- },
246
- });
234
+ const container = await containerManager.ensureContainer({
235
+ name: containerName,
236
+ Image: operatorData.image,
237
+ Hostname: containerName + '.kapeta',
238
+ Labels,
239
+ Cmd: operatorData.cmd,
240
+ ExposedPorts,
241
+ Env,
242
+ HealthCheck,
243
+ HostConfig: {
244
+ PortBindings,
245
+ Mounts,
246
+ },
247
+ });
247
248
 
248
- return new ContainerInfo(container);
249
+ return new ContainerInfo(container);
250
+ });
249
251
  }
250
252
  }
251
253
 
@@ -31,6 +31,10 @@ export class SocketManager {
31
31
  this.io.to(context).emit(type, { context, payload });
32
32
  }
33
33
 
34
+ emitGlobal(type: string, payload: any) {
35
+ this.io.emit(type, { payload });
36
+ }
37
+
34
38
  _bindIO() {
35
39
  this.io.on('connection', (socket) => this._handleSocketCreated(socket));
36
40
  }
package/src/types.ts CHANGED
@@ -64,6 +64,7 @@ export type InstanceInfo = {
64
64
  type: InstanceType;
65
65
  owner: InstanceOwner;
66
66
  status: InstanceStatus;
67
+ errorMessage?: string;
67
68
  desiredStatus: DesiredInstanceStatus;
68
69
  address?: string;
69
70
 
@@ -71,7 +72,6 @@ export type InstanceInfo = {
71
72
  health?: string | null;
72
73
  pid?: number | string | null;
73
74
  portType?: string;
74
-
75
75
  };
76
76
 
77
77
  interface ResourceRef {
@@ -175,11 +175,7 @@ export class BlockInstanceRunner {
175
175
  const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
176
176
  const workingDir = localContainer.workingDir ? localContainer.workingDir : '/workspace';
177
177
 
178
- const {
179
- PortBindings,
180
- ExposedPorts,
181
- addonEnv
182
- } = await this.getDockerPortBindings(blockInstance, assetVersion);
178
+ const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion);
183
179
 
184
180
  let HealthCheck = undefined;
185
181
  if (localContainer.healthcheck) {
@@ -215,7 +211,12 @@ export class BlockInstanceRunner {
215
211
  });
216
212
  }
217
213
 
218
- private async _startDockerProcess(blockInstance: BlockProcessParams, blockInfo: KapetaURI, env: StringMap, assetVersion: DefinitionInfo) {
214
+ private async _startDockerProcess(
215
+ blockInstance: BlockProcessParams,
216
+ blockInfo: KapetaURI,
217
+ env: StringMap,
218
+ assetVersion: DefinitionInfo
219
+ ) {
219
220
  const { versionFile } = ClusterConfig.getRepositoryAssetInfoPath(
220
221
  blockInfo.handle,
221
222
  blockInfo.name,
@@ -237,11 +238,7 @@ export class BlockInstanceRunner {
237
238
  throw new Error(`Missing docker image information: ${JSON.stringify(versionInfo?.artifact?.details)}`);
238
239
  }
239
240
 
240
- const {
241
- PortBindings,
242
- ExposedPorts,
243
- addonEnv
244
- } = await this.getDockerPortBindings(blockInstance, assetVersion);
241
+ const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion);
245
242
 
246
243
  const containerName = getBlockInstanceContainerName(this._systemId, blockInstance.id);
247
244
 
@@ -260,9 +257,8 @@ export class BlockInstanceRunner {
260
257
  `KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
261
258
  ...Object.entries({
262
259
  ...env,
263
- ...addonEnv
260
+ ...addonEnv,
264
261
  }).map(([key, value]) => `${key}=${value}`),
265
-
266
262
  ],
267
263
  HostConfig: {
268
264
  Binds: [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`],
@@ -388,7 +384,6 @@ export class BlockInstanceRunner {
388
384
  return out;
389
385
  }
390
386
 
391
-
392
387
  private async getDockerPortBindings(blockInstance: BlockProcessParams, assetVersion: DefinitionInfo) {
393
388
  const bindHost = getBindHost();
394
389
  const ExposedPorts: AnyMap = {};
@@ -412,10 +407,9 @@ export class BlockInstanceRunner {
412
407
  ];
413
408
  });
414
409
 
415
-
416
410
  await Promise.all(promises);
417
411
 
418
- return {PortBindings,ExposedPorts, addonEnv};
412
+ return { PortBindings, ExposedPorts, addonEnv };
419
413
  }
420
414
 
421
415
  private async ensureContainer(opts: any) {
@@ -424,16 +418,12 @@ export class BlockInstanceRunner {
424
418
  await containerManager.waitForReady(container);
425
419
 
426
420
  return this._handleContainer(container);
427
-
428
421
  }
429
422
 
430
- private async _handleContainer(
431
- container: Container
432
- ): Promise<ProcessInfo> {
433
-
423
+ private async _handleContainer(container: Container): Promise<ProcessInfo> {
434
424
  return {
435
425
  type: InstanceType.DOCKER,
436
- pid: container.id
426
+ pid: container.id,
437
427
  };
438
428
  }
439
429
  }
@@ -1,9 +1,9 @@
1
1
  import FS from 'node:fs';
2
2
  import YAML from 'yaml';
3
3
  import { parseKapetaUri } from '@kapeta/nodejs-utils';
4
- import md5 from "md5";
4
+ import md5 from 'md5';
5
5
 
6
- export function getBlockInstanceContainerName(systemId:string, instanceId: string) {
6
+ export function getBlockInstanceContainerName(systemId: string, instanceId: string) {
7
7
  return `kapeta-block-instance-${md5(systemId + instanceId)}`;
8
8
  }
9
9