@kapeta/local-cluster-service 0.36.0 → 0.37.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.
@@ -1,15 +1,19 @@
1
1
  {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
2
  "version": "0.2.0",
6
3
  "configurations": [
7
4
  {
8
5
  "type": "node",
9
6
  "request": "launch",
10
- "name": "Launch Program",
7
+ "name": "Debug Node.js (npm run dev)",
8
+ "runtimeExecutable": "npm",
9
+ "runtimeArgs": ["run-script", "dev"],
10
+ "restart": true,
11
+ "console": "integratedTerminal",
12
+ "internalConsoleOptions": "neverOpen",
11
13
  "skipFiles": ["<node_internals>/**"],
12
- "program": "${workspaceFolder}/start.js"
14
+ "env": {
15
+ "NODE_ENV": "development"
16
+ }
13
17
  }
14
18
  ]
15
19
  }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ # [0.37.0](https://github.com/kapetacom/local-cluster-service/compare/v0.36.1...v0.37.0) (2024-02-23)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Self review ([50bd377](https://github.com/kapetacom/local-cluster-service/commit/50bd377c41f132fd3f61afb1fc74b823bf60729f))
7
+ * Start debugger as "npm run dev" ([44b745a](https://github.com/kapetacom/local-cluster-service/commit/44b745af75e333056f7b187680f43c786461eb1d))
8
+
9
+
10
+ ### Features
11
+
12
+ * Add block-type-executabla ([7426433](https://github.com/kapetacom/local-cluster-service/commit/742643358022c0eb3b6065a42abba00e27dfc2e8))
13
+ * Do not attempt to start instances of kind 'core/block-type-executable' ([9239eaf](https://github.com/kapetacom/local-cluster-service/commit/9239eafc117c98fa215b67e2dd99f5d8f18c2881))
14
+
15
+ ## [0.36.1](https://github.com/kapetacom/local-cluster-service/compare/v0.36.0...v0.36.1) (2024-02-07)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * Ensure consistent naming for containers ([#124](https://github.com/kapetacom/local-cluster-service/issues/124)) ([f6041e7](https://github.com/kapetacom/local-cluster-service/commit/f6041e781797aa76a44dc9fb1f9f37c6d926a079))
21
+
1
22
  # [0.36.0](https://github.com/kapetacom/local-cluster-service/compare/v0.35.0...v0.36.0) (2024-02-06)
2
23
 
3
24
 
@@ -18,6 +18,7 @@ const repositoryManager_1 = require("./repositoryManager");
18
18
  const nodejs_registry_utils_1 = require("@kapeta/nodejs-registry-utils");
19
19
  const definitionsManager_1 = require("./definitionsManager");
20
20
  const taskManager_1 = require("./taskManager");
21
+ const types_1 = require("./types");
21
22
  const cacheManager_1 = require("./cacheManager");
22
23
  const node_uuid_1 = __importDefault(require("node-uuid"));
23
24
  const node_os_1 = __importDefault(require("node:os"));
@@ -75,8 +76,9 @@ class AssetManager {
75
76
  async getAssets(assetKinds) {
76
77
  if (!assetKinds) {
77
78
  const blockTypeProviders = await definitionsManager_1.definitionsManager.getDefinitions([
78
- 'core/block-type',
79
- 'core/block-type-operator',
79
+ types_1.KIND_BLOCK_TYPE,
80
+ types_1.KIND_BLOCK_TYPE_OPERATOR,
81
+ types_1.KIND_BLOCK_TYPE_EXECUTABLE,
80
82
  ]);
81
83
  assetKinds = blockTypeProviders.map((p) => {
82
84
  return `${p.definition.metadata.name}:${p.version}`;
@@ -45,7 +45,23 @@ export declare class InstanceManager {
45
45
  private requestInstanceStatus;
46
46
  private isSingletonOperator;
47
47
  private getKindForAssetRef;
48
+ /**
49
+ * Get the kind of an asset. Use the maxDepth parameter to specify how deep to look for the
50
+ * kind. For example, if maxDepth is 2, the method will look for the kind of the asset and then
51
+ * the kind of the kind.
52
+ * @param assetRef The asset reference
53
+ * @param maxDepth The maximum depth to look for the kind
54
+ * @returns The kind of the asset or null if not found
55
+ */
56
+ private getDeepKindForAssetRef;
48
57
  private isUsingKind;
49
58
  private getAllInstancesForKind;
59
+ /**
60
+ * Get the ids for all block instances except the ones of the specified kind
61
+ * @param systemId The plan reference id
62
+ * @param kind The kind to exclude. Can be a string or an array of strings
63
+ * @returns An array of block instance ids
64
+ */
65
+ private getAllInstancesExceptKind;
50
66
  }
51
67
  export declare const instanceManager: InstanceManager;
@@ -230,11 +230,12 @@ class InstanceManager {
230
230
  throw new Error(`No blocks found in plan: ${systemId}`);
231
231
  }
232
232
  return taskManager_1.taskManager.add(`plan:start:${systemId}`, async () => {
233
- let promises = [];
234
- let errors = [];
235
- for (let blockInstance of Object.values(plan.spec.blocks)) {
233
+ const promises = [];
234
+ const errors = [];
235
+ const instanceIds = await this.getAllInstancesExceptKind(systemId, types_1.KIND_BLOCK_TYPE_EXECUTABLE);
236
+ for (const instanceId of instanceIds) {
236
237
  try {
237
- promises.push(this.start(systemId, blockInstance.id).then((taskOrInstance) => {
238
+ promises.push(this.start(systemId, instanceId).then((taskOrInstance) => {
238
239
  if (taskOrInstance instanceof taskManager_1.Task) {
239
240
  return taskOrInstance.wait();
240
241
  }
@@ -449,7 +450,7 @@ class InstanceManager {
449
450
  // Definition not found
450
451
  return Promise.resolve();
451
452
  }
452
- if (operatorManager_1.KIND_RESOURCE_OPERATOR.toLowerCase() !== asset.definition.kind.toLowerCase()) {
453
+ if (types_1.KIND_RESOURCE_OPERATOR.toLowerCase() !== asset.definition.kind.toLowerCase()) {
453
454
  // Not an operator
454
455
  return Promise.resolve();
455
456
  }
@@ -776,7 +777,7 @@ class InstanceManager {
776
777
  if (!provider) {
777
778
  return false;
778
779
  }
779
- if ((0, nodejs_utils_1.parseKapetaUri)(provider.kind).fullName === operatorManager_1.KIND_BLOCK_OPERATOR) {
780
+ if ((0, nodejs_utils_1.parseKapetaUri)(provider.kind).fullName === types_1.KIND_BLOCK_TYPE_OPERATOR) {
780
781
  const localConfig = provider.data.spec.local;
781
782
  return localConfig.singleton ?? false;
782
783
  }
@@ -789,6 +790,36 @@ class InstanceManager {
789
790
  }
790
791
  return block.data.kind;
791
792
  }
793
+ /**
794
+ * Get the kind of an asset. Use the maxDepth parameter to specify how deep to look for the
795
+ * kind. For example, if maxDepth is 2, the method will look for the kind of the asset and then
796
+ * the kind of the kind.
797
+ * @param assetRef The asset reference
798
+ * @param maxDepth The maximum depth to look for the kind
799
+ * @returns The kind of the asset or null if not found
800
+ */
801
+ async getDeepKindForAssetRef(assetRef, maxDepth) {
802
+ if (maxDepth <= 0) {
803
+ return null;
804
+ }
805
+ try {
806
+ const asset = await assetManager_1.assetManager.getAsset(assetRef);
807
+ if (!asset || !asset.data.kind) {
808
+ return null;
809
+ }
810
+ if (maxDepth === 1) {
811
+ return asset.data.kind;
812
+ }
813
+ else {
814
+ // Recurse with the kind of the current block and one less depth
815
+ return await this.getDeepKindForAssetRef(asset.data.kind, maxDepth - 1);
816
+ }
817
+ }
818
+ catch (error) {
819
+ console.error('Error fetching kind for assetRef:', assetRef, error);
820
+ return null;
821
+ }
822
+ }
792
823
  async isUsingKind(ref, kind) {
793
824
  const assetKind = await this.getKindForAssetRef(ref);
794
825
  if (!assetKind) {
@@ -809,6 +840,32 @@ class InstanceManager {
809
840
  }
810
841
  return out;
811
842
  }
843
+ /**
844
+ * Get the ids for all block instances except the ones of the specified kind
845
+ * @param systemId The plan reference id
846
+ * @param kind The kind to exclude. Can be a string or an array of strings
847
+ * @returns An array of block instance ids
848
+ */
849
+ async getAllInstancesExceptKind(systemId, kind) {
850
+ const plan = await assetManager_1.assetManager.getPlan(systemId);
851
+ if (!plan?.spec?.blocks) {
852
+ return [];
853
+ }
854
+ const out = [];
855
+ const excludedKinds = kind instanceof Array ? kind : [kind];
856
+ for (const block of plan.spec.blocks) {
857
+ const blockKindOfKind = await this.getDeepKindForAssetRef(block.block.ref, 2);
858
+ if (!blockKindOfKind) {
859
+ continue;
860
+ }
861
+ const shouldIncludeBlock = excludedKinds.some((excludedKind) => excludedKind === (0, nodejs_utils_1.parseKapetaUri)(blockKindOfKind).fullName) ===
862
+ false;
863
+ if (shouldIncludeBlock) {
864
+ out.push(block.id);
865
+ }
866
+ }
867
+ return out;
868
+ }
812
869
  }
813
870
  exports.InstanceManager = InstanceManager;
814
871
  exports.instanceManager = new InstanceManager();
@@ -5,8 +5,6 @@
5
5
  import { DefinitionInfo } from '@kapeta/local-cluster-config';
6
6
  import { ContainerInfo } from './containerManager';
7
7
  import { EnvironmentType, LocalImageOptions, OperatorInfo } from './types';
8
- export declare const KIND_RESOURCE_OPERATOR = "core/resource-type-operator";
9
- export declare const KIND_BLOCK_OPERATOR = "core/block-type-operator";
10
8
  declare class Operator {
11
9
  private readonly _data;
12
10
  constructor(data: DefinitionInfo);
@@ -7,21 +7,20 @@ 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.operatorManager = exports.KIND_BLOCK_OPERATOR = exports.KIND_RESOURCE_OPERATOR = void 0;
10
+ exports.operatorManager = void 0;
11
11
  const path_1 = __importDefault(require("path"));
12
12
  const md5_1 = __importDefault(require("md5"));
13
13
  const serviceManager_1 = require("./serviceManager");
14
14
  const storageService_1 = require("./storageService");
15
15
  const containerManager_1 = require("./containerManager");
16
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
17
+ const types_1 = require("./types");
17
18
  const definitionsManager_1 = require("./definitionsManager");
18
19
  const utils_1 = require("./utils/utils");
19
20
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
20
21
  const lodash_1 = __importDefault(require("lodash"));
21
22
  const async_lock_1 = __importDefault(require("async-lock"));
22
23
  const taskManager_1 = require("./taskManager");
23
- exports.KIND_RESOURCE_OPERATOR = 'core/resource-type-operator';
24
- exports.KIND_BLOCK_OPERATOR = 'core/block-type-operator';
25
24
  const KIND_PLAN = 'core/plan';
26
25
  class Operator {
27
26
  _data;
@@ -52,7 +51,7 @@ class OperatorManager {
52
51
  * Get operator definition for resource type
53
52
  */
54
53
  async getOperator(fullName, version) {
55
- const operators = await definitionsManager_1.definitionsManager.getDefinitions([exports.KIND_RESOURCE_OPERATOR, exports.KIND_BLOCK_OPERATOR]);
54
+ const operators = await definitionsManager_1.definitionsManager.getDefinitions([types_1.KIND_RESOURCE_OPERATOR, types_1.KIND_BLOCK_TYPE_OPERATOR]);
56
55
  const operator = operators.find((operator) => operator.definition &&
57
56
  operator.definition.metadata &&
58
57
  operator.definition.metadata.name &&
@@ -6,6 +6,10 @@ import express from 'express';
6
6
  import { Connection, Resource } from '@kapeta/schemas';
7
7
  import { StringBodyRequest } from './middleware/stringBody';
8
8
  import { KapetaRequest } from './middleware/kapeta';
9
+ export declare const KIND_RESOURCE_OPERATOR = "core/resource-type-operator";
10
+ export declare const KIND_BLOCK_TYPE = "core/block-type";
11
+ export declare const KIND_BLOCK_TYPE_OPERATOR = "core/block-type-operator";
12
+ export declare const KIND_BLOCK_TYPE_EXECUTABLE = "core/block-type-executable";
9
13
  export type StringMap = {
10
14
  [key: string]: string;
11
15
  };
@@ -4,7 +4,11 @@
4
4
  * SPDX-License-Identifier: BUSL-1.1
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.DesiredInstanceStatus = exports.InstanceStatus = exports.InstanceOwner = exports.InstanceType = void 0;
7
+ exports.DesiredInstanceStatus = exports.InstanceStatus = exports.InstanceOwner = exports.InstanceType = exports.KIND_BLOCK_TYPE_EXECUTABLE = exports.KIND_BLOCK_TYPE_OPERATOR = exports.KIND_BLOCK_TYPE = exports.KIND_RESOURCE_OPERATOR = void 0;
8
+ exports.KIND_RESOURCE_OPERATOR = 'core/resource-type-operator';
9
+ exports.KIND_BLOCK_TYPE = 'core/block-type';
10
+ exports.KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
11
+ exports.KIND_BLOCK_TYPE_EXECUTABLE = 'core/block-type-executable';
8
12
  var InstanceType;
9
13
  (function (InstanceType) {
10
14
  InstanceType["DOCKER"] = "docker";
@@ -19,7 +19,10 @@ export declare class BlockInstanceRunner {
19
19
  private _startLocalProcess;
20
20
  private _startDockerProcess;
21
21
  private _startOperatorProcess;
22
- private getDockerPortBindings;
22
+ /**
23
+ * Get the port bindings for a non-operator block
24
+ */
25
+ private getServiceBlockPortBindings;
23
26
  private ensureContainer;
24
27
  private _handleContainer;
25
28
  }
@@ -20,7 +20,6 @@ const types_1 = require("../types");
20
20
  const definitionsManager_1 = require("../definitionsManager");
21
21
  const node_os_1 = __importDefault(require("node:os"));
22
22
  const taskManager_1 = require("../taskManager");
23
- const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
24
23
  const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
25
24
  const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
26
25
  const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
@@ -41,16 +40,23 @@ async function getProvider(uri) {
41
40
  });
42
41
  }
43
42
  function resolvePortType(portType) {
44
- if (serviceManager_1.HTTP_PORTS.includes(portType)) {
43
+ if (portType && serviceManager_1.HTTP_PORTS.includes(portType.toLowerCase())) {
45
44
  return serviceManager_1.HTTP_PORT_TYPE;
46
45
  }
47
46
  return portType;
48
47
  }
49
48
  exports.resolvePortType = resolvePortType;
50
- function getProviderPorts(assetVersion, providerVersion) {
49
+ /**
50
+ * Get the port types for a non-operator block instance
51
+ */
52
+ function getServiceProviderPorts(assetVersion, providerVersion) {
51
53
  const out = assetVersion.definition?.spec?.providers
54
+ ?.filter((provider) => {
55
+ // We only support HTTP provider ports for now. Need to figure out how to handle other types
56
+ return serviceManager_1.HTTP_PORTS.includes(provider.spec?.port?.type?.toLowerCase());
57
+ })
52
58
  ?.map((provider) => {
53
- return resolvePortType(provider.spec?.port?.type);
59
+ return resolvePortType(provider.spec?.port?.type?.toLowerCase());
54
60
  })
55
61
  .filter((t) => !!t) ?? [];
56
62
  if (out.length === 0) {
@@ -108,12 +114,12 @@ class BlockInstanceRunner {
108
114
  throw new Error(`Kind not found: ${kindUri.id}`);
109
115
  }
110
116
  let processInfo;
111
- if (providerVersion.definition.kind === KIND_BLOCK_TYPE_OPERATOR) {
117
+ if (providerVersion.definition.kind === types_1.KIND_BLOCK_TYPE_OPERATOR) {
112
118
  processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
113
119
  }
114
120
  else {
115
121
  //We need a port type to know how to connect to the block consistently
116
- const portTypes = getProviderPorts(assetVersion, providerVersion);
122
+ const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
117
123
  if (blockUri.version === 'local') {
118
124
  processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
119
125
  }
@@ -169,7 +175,7 @@ class BlockInstanceRunner {
169
175
  delete localContainer.HostConfig;
170
176
  delete localContainer.Labels;
171
177
  delete localContainer.Env;
172
- const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion, providerVersion);
178
+ const { PortBindings, ExposedPorts, addonEnv } = await this.getServiceBlockPortBindings(blockInstance, assetVersion, providerVersion);
173
179
  let HealthCheck = undefined;
174
180
  if (localContainer.healthcheck) {
175
181
  HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
@@ -241,7 +247,7 @@ class BlockInstanceRunner {
241
247
  if (!providerVersion) {
242
248
  throw new Error(`Block type not found: ${kindUri.id}`);
243
249
  }
244
- const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion, providerVersion);
250
+ const { PortBindings, ExposedPorts, addonEnv } = await this.getServiceBlockPortBindings(blockInstance, assetVersion, providerVersion);
245
251
  const containerName = await (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id, kindUri.id);
246
252
  // For windows we need to default to root
247
253
  const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
@@ -374,12 +380,15 @@ class BlockInstanceRunner {
374
380
  });
375
381
  return task.wait();
376
382
  }
377
- async getDockerPortBindings(blockInstance, assetVersion, providerVersion) {
383
+ /**
384
+ * Get the port bindings for a non-operator block
385
+ */
386
+ async getServiceBlockPortBindings(blockInstance, assetVersion, providerVersion) {
378
387
  const bindHost = (0, utils_1.getBindHost)();
379
388
  const ExposedPorts = {};
380
389
  const addonEnv = {};
381
390
  const PortBindings = {};
382
- const portTypes = getProviderPorts(assetVersion, providerVersion);
391
+ const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
383
392
  let port = 80;
384
393
  const promises = portTypes.map(async (portType) => {
385
394
  const publicPort = await serviceManager_1.serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
@@ -12,10 +12,10 @@ 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
+ const types_1 = require("../types");
15
16
  const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
16
17
  const definitionsManager_1 = require("../definitionsManager");
17
18
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
18
- const operatorManager_1 = require("../operatorManager");
19
19
  const assetManager_1 = require("../assetManager");
20
20
  async function getBlockInstanceContainerName(systemId, instanceId, blockType) {
21
21
  if (!blockType) {
@@ -33,11 +33,11 @@ async function getBlockInstanceContainerName(systemId, instanceId, blockType) {
33
33
  if (!typeDefinition) {
34
34
  throw new Error(`Block type ${blockType} not found`);
35
35
  }
36
- if ((0, nodejs_utils_1.parseKapetaUri)(typeDefinition.definition.kind).fullName === operatorManager_1.KIND_BLOCK_OPERATOR &&
36
+ if ((0, nodejs_utils_1.parseKapetaUri)(typeDefinition.definition.kind).fullName === types_1.KIND_BLOCK_TYPE_OPERATOR &&
37
37
  typeDefinition.definition.spec?.local?.singleton) {
38
- return `kapeta-instance-operator-${(0, md5_1.default)(systemId + blockType)}`;
38
+ return `kapeta-instance-operator-${(0, md5_1.default)((0, nodejs_utils_1.normalizeKapetaUri)(systemId) + (0, nodejs_utils_1.normalizeKapetaUri)(blockType))}`;
39
39
  }
40
- return `kapeta-block-instance-${(0, md5_1.default)(systemId + instanceId)}`;
40
+ return `kapeta-block-instance-${(0, md5_1.default)((0, nodejs_utils_1.normalizeKapetaUri)(systemId) + instanceId)}`;
41
41
  }
42
42
  exports.getBlockInstanceContainerName = getBlockInstanceContainerName;
43
43
  function toPortInfo(port) {
@@ -18,6 +18,7 @@ const repositoryManager_1 = require("./repositoryManager");
18
18
  const nodejs_registry_utils_1 = require("@kapeta/nodejs-registry-utils");
19
19
  const definitionsManager_1 = require("./definitionsManager");
20
20
  const taskManager_1 = require("./taskManager");
21
+ const types_1 = require("./types");
21
22
  const cacheManager_1 = require("./cacheManager");
22
23
  const node_uuid_1 = __importDefault(require("node-uuid"));
23
24
  const node_os_1 = __importDefault(require("node:os"));
@@ -75,8 +76,9 @@ class AssetManager {
75
76
  async getAssets(assetKinds) {
76
77
  if (!assetKinds) {
77
78
  const blockTypeProviders = await definitionsManager_1.definitionsManager.getDefinitions([
78
- 'core/block-type',
79
- 'core/block-type-operator',
79
+ types_1.KIND_BLOCK_TYPE,
80
+ types_1.KIND_BLOCK_TYPE_OPERATOR,
81
+ types_1.KIND_BLOCK_TYPE_EXECUTABLE,
80
82
  ]);
81
83
  assetKinds = blockTypeProviders.map((p) => {
82
84
  return `${p.definition.metadata.name}:${p.version}`;
@@ -45,7 +45,23 @@ export declare class InstanceManager {
45
45
  private requestInstanceStatus;
46
46
  private isSingletonOperator;
47
47
  private getKindForAssetRef;
48
+ /**
49
+ * Get the kind of an asset. Use the maxDepth parameter to specify how deep to look for the
50
+ * kind. For example, if maxDepth is 2, the method will look for the kind of the asset and then
51
+ * the kind of the kind.
52
+ * @param assetRef The asset reference
53
+ * @param maxDepth The maximum depth to look for the kind
54
+ * @returns The kind of the asset or null if not found
55
+ */
56
+ private getDeepKindForAssetRef;
48
57
  private isUsingKind;
49
58
  private getAllInstancesForKind;
59
+ /**
60
+ * Get the ids for all block instances except the ones of the specified kind
61
+ * @param systemId The plan reference id
62
+ * @param kind The kind to exclude. Can be a string or an array of strings
63
+ * @returns An array of block instance ids
64
+ */
65
+ private getAllInstancesExceptKind;
50
66
  }
51
67
  export declare const instanceManager: InstanceManager;
@@ -230,11 +230,12 @@ class InstanceManager {
230
230
  throw new Error(`No blocks found in plan: ${systemId}`);
231
231
  }
232
232
  return taskManager_1.taskManager.add(`plan:start:${systemId}`, async () => {
233
- let promises = [];
234
- let errors = [];
235
- for (let blockInstance of Object.values(plan.spec.blocks)) {
233
+ const promises = [];
234
+ const errors = [];
235
+ const instanceIds = await this.getAllInstancesExceptKind(systemId, types_1.KIND_BLOCK_TYPE_EXECUTABLE);
236
+ for (const instanceId of instanceIds) {
236
237
  try {
237
- promises.push(this.start(systemId, blockInstance.id).then((taskOrInstance) => {
238
+ promises.push(this.start(systemId, instanceId).then((taskOrInstance) => {
238
239
  if (taskOrInstance instanceof taskManager_1.Task) {
239
240
  return taskOrInstance.wait();
240
241
  }
@@ -449,7 +450,7 @@ class InstanceManager {
449
450
  // Definition not found
450
451
  return Promise.resolve();
451
452
  }
452
- if (operatorManager_1.KIND_RESOURCE_OPERATOR.toLowerCase() !== asset.definition.kind.toLowerCase()) {
453
+ if (types_1.KIND_RESOURCE_OPERATOR.toLowerCase() !== asset.definition.kind.toLowerCase()) {
453
454
  // Not an operator
454
455
  return Promise.resolve();
455
456
  }
@@ -776,7 +777,7 @@ class InstanceManager {
776
777
  if (!provider) {
777
778
  return false;
778
779
  }
779
- if ((0, nodejs_utils_1.parseKapetaUri)(provider.kind).fullName === operatorManager_1.KIND_BLOCK_OPERATOR) {
780
+ if ((0, nodejs_utils_1.parseKapetaUri)(provider.kind).fullName === types_1.KIND_BLOCK_TYPE_OPERATOR) {
780
781
  const localConfig = provider.data.spec.local;
781
782
  return localConfig.singleton ?? false;
782
783
  }
@@ -789,6 +790,36 @@ class InstanceManager {
789
790
  }
790
791
  return block.data.kind;
791
792
  }
793
+ /**
794
+ * Get the kind of an asset. Use the maxDepth parameter to specify how deep to look for the
795
+ * kind. For example, if maxDepth is 2, the method will look for the kind of the asset and then
796
+ * the kind of the kind.
797
+ * @param assetRef The asset reference
798
+ * @param maxDepth The maximum depth to look for the kind
799
+ * @returns The kind of the asset or null if not found
800
+ */
801
+ async getDeepKindForAssetRef(assetRef, maxDepth) {
802
+ if (maxDepth <= 0) {
803
+ return null;
804
+ }
805
+ try {
806
+ const asset = await assetManager_1.assetManager.getAsset(assetRef);
807
+ if (!asset || !asset.data.kind) {
808
+ return null;
809
+ }
810
+ if (maxDepth === 1) {
811
+ return asset.data.kind;
812
+ }
813
+ else {
814
+ // Recurse with the kind of the current block and one less depth
815
+ return await this.getDeepKindForAssetRef(asset.data.kind, maxDepth - 1);
816
+ }
817
+ }
818
+ catch (error) {
819
+ console.error('Error fetching kind for assetRef:', assetRef, error);
820
+ return null;
821
+ }
822
+ }
792
823
  async isUsingKind(ref, kind) {
793
824
  const assetKind = await this.getKindForAssetRef(ref);
794
825
  if (!assetKind) {
@@ -809,6 +840,32 @@ class InstanceManager {
809
840
  }
810
841
  return out;
811
842
  }
843
+ /**
844
+ * Get the ids for all block instances except the ones of the specified kind
845
+ * @param systemId The plan reference id
846
+ * @param kind The kind to exclude. Can be a string or an array of strings
847
+ * @returns An array of block instance ids
848
+ */
849
+ async getAllInstancesExceptKind(systemId, kind) {
850
+ const plan = await assetManager_1.assetManager.getPlan(systemId);
851
+ if (!plan?.spec?.blocks) {
852
+ return [];
853
+ }
854
+ const out = [];
855
+ const excludedKinds = kind instanceof Array ? kind : [kind];
856
+ for (const block of plan.spec.blocks) {
857
+ const blockKindOfKind = await this.getDeepKindForAssetRef(block.block.ref, 2);
858
+ if (!blockKindOfKind) {
859
+ continue;
860
+ }
861
+ const shouldIncludeBlock = excludedKinds.some((excludedKind) => excludedKind === (0, nodejs_utils_1.parseKapetaUri)(blockKindOfKind).fullName) ===
862
+ false;
863
+ if (shouldIncludeBlock) {
864
+ out.push(block.id);
865
+ }
866
+ }
867
+ return out;
868
+ }
812
869
  }
813
870
  exports.InstanceManager = InstanceManager;
814
871
  exports.instanceManager = new InstanceManager();
@@ -5,8 +5,6 @@
5
5
  import { DefinitionInfo } from '@kapeta/local-cluster-config';
6
6
  import { ContainerInfo } from './containerManager';
7
7
  import { EnvironmentType, LocalImageOptions, OperatorInfo } from './types';
8
- export declare const KIND_RESOURCE_OPERATOR = "core/resource-type-operator";
9
- export declare const KIND_BLOCK_OPERATOR = "core/block-type-operator";
10
8
  declare class Operator {
11
9
  private readonly _data;
12
10
  constructor(data: DefinitionInfo);
@@ -7,21 +7,20 @@ 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.operatorManager = exports.KIND_BLOCK_OPERATOR = exports.KIND_RESOURCE_OPERATOR = void 0;
10
+ exports.operatorManager = void 0;
11
11
  const path_1 = __importDefault(require("path"));
12
12
  const md5_1 = __importDefault(require("md5"));
13
13
  const serviceManager_1 = require("./serviceManager");
14
14
  const storageService_1 = require("./storageService");
15
15
  const containerManager_1 = require("./containerManager");
16
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
17
+ const types_1 = require("./types");
17
18
  const definitionsManager_1 = require("./definitionsManager");
18
19
  const utils_1 = require("./utils/utils");
19
20
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
20
21
  const lodash_1 = __importDefault(require("lodash"));
21
22
  const async_lock_1 = __importDefault(require("async-lock"));
22
23
  const taskManager_1 = require("./taskManager");
23
- exports.KIND_RESOURCE_OPERATOR = 'core/resource-type-operator';
24
- exports.KIND_BLOCK_OPERATOR = 'core/block-type-operator';
25
24
  const KIND_PLAN = 'core/plan';
26
25
  class Operator {
27
26
  _data;
@@ -52,7 +51,7 @@ class OperatorManager {
52
51
  * Get operator definition for resource type
53
52
  */
54
53
  async getOperator(fullName, version) {
55
- const operators = await definitionsManager_1.definitionsManager.getDefinitions([exports.KIND_RESOURCE_OPERATOR, exports.KIND_BLOCK_OPERATOR]);
54
+ const operators = await definitionsManager_1.definitionsManager.getDefinitions([types_1.KIND_RESOURCE_OPERATOR, types_1.KIND_BLOCK_TYPE_OPERATOR]);
56
55
  const operator = operators.find((operator) => operator.definition &&
57
56
  operator.definition.metadata &&
58
57
  operator.definition.metadata.name &&
@@ -6,6 +6,10 @@ import express from 'express';
6
6
  import { Connection, Resource } from '@kapeta/schemas';
7
7
  import { StringBodyRequest } from './middleware/stringBody';
8
8
  import { KapetaRequest } from './middleware/kapeta';
9
+ export declare const KIND_RESOURCE_OPERATOR = "core/resource-type-operator";
10
+ export declare const KIND_BLOCK_TYPE = "core/block-type";
11
+ export declare const KIND_BLOCK_TYPE_OPERATOR = "core/block-type-operator";
12
+ export declare const KIND_BLOCK_TYPE_EXECUTABLE = "core/block-type-executable";
9
13
  export type StringMap = {
10
14
  [key: string]: string;
11
15
  };
@@ -4,7 +4,11 @@
4
4
  * SPDX-License-Identifier: BUSL-1.1
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.DesiredInstanceStatus = exports.InstanceStatus = exports.InstanceOwner = exports.InstanceType = void 0;
7
+ exports.DesiredInstanceStatus = exports.InstanceStatus = exports.InstanceOwner = exports.InstanceType = exports.KIND_BLOCK_TYPE_EXECUTABLE = exports.KIND_BLOCK_TYPE_OPERATOR = exports.KIND_BLOCK_TYPE = exports.KIND_RESOURCE_OPERATOR = void 0;
8
+ exports.KIND_RESOURCE_OPERATOR = 'core/resource-type-operator';
9
+ exports.KIND_BLOCK_TYPE = 'core/block-type';
10
+ exports.KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
11
+ exports.KIND_BLOCK_TYPE_EXECUTABLE = 'core/block-type-executable';
8
12
  var InstanceType;
9
13
  (function (InstanceType) {
10
14
  InstanceType["DOCKER"] = "docker";
@@ -19,7 +19,10 @@ export declare class BlockInstanceRunner {
19
19
  private _startLocalProcess;
20
20
  private _startDockerProcess;
21
21
  private _startOperatorProcess;
22
- private getDockerPortBindings;
22
+ /**
23
+ * Get the port bindings for a non-operator block
24
+ */
25
+ private getServiceBlockPortBindings;
23
26
  private ensureContainer;
24
27
  private _handleContainer;
25
28
  }
@@ -20,7 +20,6 @@ const types_1 = require("../types");
20
20
  const definitionsManager_1 = require("../definitionsManager");
21
21
  const node_os_1 = __importDefault(require("node:os"));
22
22
  const taskManager_1 = require("../taskManager");
23
- const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
24
23
  const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
25
24
  const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
26
25
  const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
@@ -41,16 +40,23 @@ async function getProvider(uri) {
41
40
  });
42
41
  }
43
42
  function resolvePortType(portType) {
44
- if (serviceManager_1.HTTP_PORTS.includes(portType)) {
43
+ if (portType && serviceManager_1.HTTP_PORTS.includes(portType.toLowerCase())) {
45
44
  return serviceManager_1.HTTP_PORT_TYPE;
46
45
  }
47
46
  return portType;
48
47
  }
49
48
  exports.resolvePortType = resolvePortType;
50
- function getProviderPorts(assetVersion, providerVersion) {
49
+ /**
50
+ * Get the port types for a non-operator block instance
51
+ */
52
+ function getServiceProviderPorts(assetVersion, providerVersion) {
51
53
  const out = assetVersion.definition?.spec?.providers
54
+ ?.filter((provider) => {
55
+ // We only support HTTP provider ports for now. Need to figure out how to handle other types
56
+ return serviceManager_1.HTTP_PORTS.includes(provider.spec?.port?.type?.toLowerCase());
57
+ })
52
58
  ?.map((provider) => {
53
- return resolvePortType(provider.spec?.port?.type);
59
+ return resolvePortType(provider.spec?.port?.type?.toLowerCase());
54
60
  })
55
61
  .filter((t) => !!t) ?? [];
56
62
  if (out.length === 0) {
@@ -108,12 +114,12 @@ class BlockInstanceRunner {
108
114
  throw new Error(`Kind not found: ${kindUri.id}`);
109
115
  }
110
116
  let processInfo;
111
- if (providerVersion.definition.kind === KIND_BLOCK_TYPE_OPERATOR) {
117
+ if (providerVersion.definition.kind === types_1.KIND_BLOCK_TYPE_OPERATOR) {
112
118
  processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
113
119
  }
114
120
  else {
115
121
  //We need a port type to know how to connect to the block consistently
116
- const portTypes = getProviderPorts(assetVersion, providerVersion);
122
+ const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
117
123
  if (blockUri.version === 'local') {
118
124
  processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
119
125
  }
@@ -169,7 +175,7 @@ class BlockInstanceRunner {
169
175
  delete localContainer.HostConfig;
170
176
  delete localContainer.Labels;
171
177
  delete localContainer.Env;
172
- const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion, providerVersion);
178
+ const { PortBindings, ExposedPorts, addonEnv } = await this.getServiceBlockPortBindings(blockInstance, assetVersion, providerVersion);
173
179
  let HealthCheck = undefined;
174
180
  if (localContainer.healthcheck) {
175
181
  HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
@@ -241,7 +247,7 @@ class BlockInstanceRunner {
241
247
  if (!providerVersion) {
242
248
  throw new Error(`Block type not found: ${kindUri.id}`);
243
249
  }
244
- const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion, providerVersion);
250
+ const { PortBindings, ExposedPorts, addonEnv } = await this.getServiceBlockPortBindings(blockInstance, assetVersion, providerVersion);
245
251
  const containerName = await (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id, kindUri.id);
246
252
  // For windows we need to default to root
247
253
  const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
@@ -374,12 +380,15 @@ class BlockInstanceRunner {
374
380
  });
375
381
  return task.wait();
376
382
  }
377
- async getDockerPortBindings(blockInstance, assetVersion, providerVersion) {
383
+ /**
384
+ * Get the port bindings for a non-operator block
385
+ */
386
+ async getServiceBlockPortBindings(blockInstance, assetVersion, providerVersion) {
378
387
  const bindHost = (0, utils_1.getBindHost)();
379
388
  const ExposedPorts = {};
380
389
  const addonEnv = {};
381
390
  const PortBindings = {};
382
- const portTypes = getProviderPorts(assetVersion, providerVersion);
391
+ const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
383
392
  let port = 80;
384
393
  const promises = portTypes.map(async (portType) => {
385
394
  const publicPort = await serviceManager_1.serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
@@ -12,10 +12,10 @@ 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
+ const types_1 = require("../types");
15
16
  const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
16
17
  const definitionsManager_1 = require("../definitionsManager");
17
18
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
18
- const operatorManager_1 = require("../operatorManager");
19
19
  const assetManager_1 = require("../assetManager");
20
20
  async function getBlockInstanceContainerName(systemId, instanceId, blockType) {
21
21
  if (!blockType) {
@@ -33,11 +33,11 @@ async function getBlockInstanceContainerName(systemId, instanceId, blockType) {
33
33
  if (!typeDefinition) {
34
34
  throw new Error(`Block type ${blockType} not found`);
35
35
  }
36
- if ((0, nodejs_utils_1.parseKapetaUri)(typeDefinition.definition.kind).fullName === operatorManager_1.KIND_BLOCK_OPERATOR &&
36
+ if ((0, nodejs_utils_1.parseKapetaUri)(typeDefinition.definition.kind).fullName === types_1.KIND_BLOCK_TYPE_OPERATOR &&
37
37
  typeDefinition.definition.spec?.local?.singleton) {
38
- return `kapeta-instance-operator-${(0, md5_1.default)(systemId + blockType)}`;
38
+ return `kapeta-instance-operator-${(0, md5_1.default)((0, nodejs_utils_1.normalizeKapetaUri)(systemId) + (0, nodejs_utils_1.normalizeKapetaUri)(blockType))}`;
39
39
  }
40
- return `kapeta-block-instance-${(0, md5_1.default)(systemId + instanceId)}`;
40
+ return `kapeta-block-instance-${(0, md5_1.default)((0, nodejs_utils_1.normalizeKapetaUri)(systemId) + instanceId)}`;
41
41
  }
42
42
  exports.getBlockInstanceContainerName = getBlockInstanceContainerName;
43
43
  function toPortInfo(port) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -49,7 +49,7 @@
49
49
  "dependencies": {
50
50
  "@kapeta/codegen": "^1.2.1",
51
51
  "@kapeta/kaplang-core": "^1.9.3",
52
- "@kapeta/local-cluster-config": ">= 0.3.2 <2",
52
+ "@kapeta/local-cluster-config": "^0.4.0",
53
53
  "@kapeta/nodejs-api-client": ">=0.1.3 <2",
54
54
  "@kapeta/nodejs-process": "<2",
55
55
  "@kapeta/nodejs-registry-utils": ">=0.9.4 <2",
@@ -85,8 +85,8 @@
85
85
  "yaml": "^1.6.0"
86
86
  },
87
87
  "devDependencies": {
88
- "@kapeta/eslint-config": "^0.6.1",
89
- "@kapeta/prettier-config": "^0.6.0",
88
+ "@kapeta/eslint-config": "^0.7.0",
89
+ "@kapeta/prettier-config": "^0.6.2",
90
90
  "@tsconfig/node18": "^18.2.0",
91
91
  "@types/async-lock": "^1.4.0",
92
92
  "@types/express": "^4.17.17",
@@ -15,7 +15,7 @@ import { BlockDefinition, BlockInstance, Plan } from '@kapeta/schemas';
15
15
  import { Actions } from '@kapeta/nodejs-registry-utils';
16
16
  import { definitionsManager } from './definitionsManager';
17
17
  import { taskManager } from './taskManager';
18
- import { SourceOfChange } from './types';
18
+ import { KIND_BLOCK_TYPE_EXECUTABLE, KIND_BLOCK_TYPE_OPERATOR, KIND_BLOCK_TYPE, SourceOfChange } from './types';
19
19
  import { cacheManager } from './cacheManager';
20
20
  import uuid from 'node-uuid';
21
21
  import os from 'node:os';
@@ -94,8 +94,9 @@ class AssetManager {
94
94
  async getAssets(assetKinds?: string[]): Promise<EnrichedAsset[]> {
95
95
  if (!assetKinds) {
96
96
  const blockTypeProviders = await definitionsManager.getDefinitions([
97
- 'core/block-type',
98
- 'core/block-type-operator',
97
+ KIND_BLOCK_TYPE,
98
+ KIND_BLOCK_TYPE_OPERATOR,
99
+ KIND_BLOCK_TYPE_EXECUTABLE,
99
100
  ]);
100
101
  assetKinds = blockTypeProviders.map((p) => {
101
102
  return `${p.definition.metadata.name}:${p.version}`;
@@ -25,6 +25,9 @@ import {
25
25
  InstanceOwner,
26
26
  InstanceStatus,
27
27
  InstanceType,
28
+ KIND_BLOCK_TYPE_EXECUTABLE,
29
+ KIND_BLOCK_TYPE_OPERATOR,
30
+ KIND_RESOURCE_OPERATOR,
28
31
  LocalImageOptions,
29
32
  LogEntry,
30
33
  OperatorInstanceInfo,
@@ -32,7 +35,7 @@ import {
32
35
  } from './types';
33
36
  import { BlockDefinitionSpec, BlockInstance, Plan } from '@kapeta/schemas';
34
37
  import { getBlockInstanceContainerName, getResolvedConfiguration } from './utils/utils';
35
- import { KIND_BLOCK_OPERATOR, KIND_RESOURCE_OPERATOR, operatorManager } from './operatorManager';
38
+ import { operatorManager } from './operatorManager';
36
39
  import { normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
37
40
  import { definitionsManager } from './definitionsManager';
38
41
  import { Task, taskManager } from './taskManager';
@@ -313,12 +316,13 @@ export class InstanceManager {
313
316
  return taskManager.add(
314
317
  `plan:start:${systemId}`,
315
318
  async () => {
316
- let promises: Promise<InstanceInfo>[] = [];
317
- let errors = [];
318
- for (let blockInstance of Object.values(plan.spec.blocks as BlockInstance[])) {
319
+ const promises: Promise<InstanceInfo>[] = [];
320
+ const errors = [];
321
+ const instanceIds = await this.getAllInstancesExceptKind(systemId, KIND_BLOCK_TYPE_EXECUTABLE);
322
+ for (const instanceId of instanceIds) {
319
323
  try {
320
324
  promises.push(
321
- this.start(systemId, blockInstance.id).then((taskOrInstance) => {
325
+ this.start(systemId, instanceId).then((taskOrInstance) => {
322
326
  if (taskOrInstance instanceof Task) {
323
327
  return taskOrInstance.wait();
324
328
  }
@@ -1008,7 +1012,7 @@ export class InstanceManager {
1008
1012
  return false;
1009
1013
  }
1010
1014
 
1011
- if (parseKapetaUri(provider.kind).fullName === KIND_BLOCK_OPERATOR) {
1015
+ if (parseKapetaUri(provider.kind).fullName === KIND_BLOCK_TYPE_OPERATOR) {
1012
1016
  const localConfig = provider.data.spec.local as LocalImageOptions;
1013
1017
  return localConfig.singleton ?? false;
1014
1018
  }
@@ -1025,6 +1029,37 @@ export class InstanceManager {
1025
1029
  return block.data.kind;
1026
1030
  }
1027
1031
 
1032
+ /**
1033
+ * Get the kind of an asset. Use the maxDepth parameter to specify how deep to look for the
1034
+ * kind. For example, if maxDepth is 2, the method will look for the kind of the asset and then
1035
+ * the kind of the kind.
1036
+ * @param assetRef The asset reference
1037
+ * @param maxDepth The maximum depth to look for the kind
1038
+ * @returns The kind of the asset or null if not found
1039
+ */
1040
+ private async getDeepKindForAssetRef(assetRef: string, maxDepth: number): Promise<string | null> {
1041
+ if (maxDepth <= 0) {
1042
+ return null;
1043
+ }
1044
+
1045
+ try {
1046
+ const asset = await assetManager.getAsset(assetRef);
1047
+ if (!asset || !asset.data.kind) {
1048
+ return null;
1049
+ }
1050
+
1051
+ if (maxDepth === 1) {
1052
+ return asset.data.kind;
1053
+ } else {
1054
+ // Recurse with the kind of the current block and one less depth
1055
+ return await this.getDeepKindForAssetRef(asset.data.kind, maxDepth - 1);
1056
+ }
1057
+ } catch (error) {
1058
+ console.error('Error fetching kind for assetRef:', assetRef, error);
1059
+ return null;
1060
+ }
1061
+ }
1062
+
1028
1063
  private async isUsingKind(ref: string, kind: string): Promise<boolean> {
1029
1064
  const assetKind = await this.getKindForAssetRef(ref);
1030
1065
  if (!assetKind) {
@@ -1048,6 +1083,36 @@ export class InstanceManager {
1048
1083
 
1049
1084
  return out;
1050
1085
  }
1086
+
1087
+ /**
1088
+ * Get the ids for all block instances except the ones of the specified kind
1089
+ * @param systemId The plan reference id
1090
+ * @param kind The kind to exclude. Can be a string or an array of strings
1091
+ * @returns An array of block instance ids
1092
+ */
1093
+ private async getAllInstancesExceptKind(systemId: string, kind: string | string[]): Promise<string[]> {
1094
+ const plan = await assetManager.getPlan(systemId);
1095
+ if (!plan?.spec?.blocks) {
1096
+ return [];
1097
+ }
1098
+ const out: string[] = [];
1099
+ const excludedKinds = kind instanceof Array ? kind : [kind];
1100
+ for (const block of plan.spec.blocks) {
1101
+ const blockKindOfKind = await this.getDeepKindForAssetRef(block.block.ref, 2);
1102
+ if (!blockKindOfKind) {
1103
+ continue;
1104
+ }
1105
+
1106
+ const shouldIncludeBlock =
1107
+ excludedKinds.some((excludedKind) => excludedKind === parseKapetaUri(blockKindOfKind).fullName) ===
1108
+ false;
1109
+ if (shouldIncludeBlock) {
1110
+ out.push(block.id);
1111
+ }
1112
+ }
1113
+
1114
+ return out;
1115
+ }
1051
1116
  }
1052
1117
 
1053
1118
  export const instanceManager = new InstanceManager();
@@ -16,7 +16,15 @@ import {
16
16
  containerManager,
17
17
  } from './containerManager';
18
18
  import FSExtra from 'fs-extra';
19
- import { AnyMap, EnvironmentType, LocalImageOptions, OperatorInfo, StringMap } from './types';
19
+ import {
20
+ AnyMap,
21
+ EnvironmentType,
22
+ KIND_BLOCK_TYPE_OPERATOR,
23
+ KIND_RESOURCE_OPERATOR,
24
+ LocalImageOptions,
25
+ OperatorInfo,
26
+ StringMap,
27
+ } from './types';
20
28
  import { BlockInstance, Resource } from '@kapeta/schemas';
21
29
  import { definitionsManager } from './definitionsManager';
22
30
  import { getBindHost, toPortInfo } from './utils/utils';
@@ -25,8 +33,6 @@ import _ from 'lodash';
25
33
  import AsyncLock from 'async-lock';
26
34
  import { taskManager } from './taskManager';
27
35
 
28
- export const KIND_RESOURCE_OPERATOR = 'core/resource-type-operator';
29
- export const KIND_BLOCK_OPERATOR = 'core/block-type-operator';
30
36
  const KIND_PLAN = 'core/plan';
31
37
 
32
38
  class Operator {
@@ -68,7 +74,7 @@ class OperatorManager {
68
74
  * Get operator definition for resource type
69
75
  */
70
76
  async getOperator(fullName: string, version: string) {
71
- const operators = await definitionsManager.getDefinitions([KIND_RESOURCE_OPERATOR, KIND_BLOCK_OPERATOR]);
77
+ const operators = await definitionsManager.getDefinitions([KIND_RESOURCE_OPERATOR, KIND_BLOCK_TYPE_OPERATOR]);
72
78
 
73
79
  const operator: DefinitionInfo | undefined = operators.find(
74
80
  (operator) =>
package/src/types.ts CHANGED
@@ -8,6 +8,11 @@ import { Connection, Resource } from '@kapeta/schemas';
8
8
  import { StringBodyRequest } from './middleware/stringBody';
9
9
  import { KapetaRequest } from './middleware/kapeta';
10
10
 
11
+ export const KIND_RESOURCE_OPERATOR = 'core/resource-type-operator';
12
+ export const KIND_BLOCK_TYPE = 'core/block-type';
13
+ export const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
14
+ export const KIND_BLOCK_TYPE_EXECUTABLE = 'core/block-type-executable';
15
+
11
16
  export type StringMap = { [key: string]: string };
12
17
  export type AnyMap = { [key: string]: any };
13
18
  export type SourceOfChange = 'user' | 'filesystem';
@@ -18,13 +18,20 @@ import {
18
18
  } from '../containerManager';
19
19
  import { LogData } from './LogData';
20
20
  import { clusterService } from '../clusterService';
21
- import { AnyMap, BlockProcessParams, InstanceType, LocalImageOptions, ProcessInfo, StringMap } from '../types';
21
+ import {
22
+ AnyMap,
23
+ BlockProcessParams,
24
+ InstanceType,
25
+ KIND_BLOCK_TYPE_OPERATOR,
26
+ LocalImageOptions,
27
+ ProcessInfo,
28
+ StringMap,
29
+ } from '../types';
22
30
  import { definitionsManager } from '../definitionsManager';
23
31
  import Docker from 'dockerode';
24
32
  import OS from 'node:os';
25
33
  import { taskManager } from '../taskManager';
26
34
 
27
- const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
28
35
  const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
29
36
  const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
30
37
  const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
@@ -48,17 +55,24 @@ async function getProvider(uri: KapetaURI) {
48
55
  }
49
56
 
50
57
  export function resolvePortType(portType: string) {
51
- if (HTTP_PORTS.includes(portType)) {
58
+ if (portType && HTTP_PORTS.includes(portType.toLowerCase())) {
52
59
  return HTTP_PORT_TYPE;
53
60
  }
54
61
  return portType;
55
62
  }
56
63
 
57
- function getProviderPorts(assetVersion: DefinitionInfo, providerVersion: DefinitionInfo): string[] {
64
+ /**
65
+ * Get the port types for a non-operator block instance
66
+ */
67
+ function getServiceProviderPorts(assetVersion: DefinitionInfo, providerVersion: DefinitionInfo): string[] {
58
68
  const out =
59
69
  assetVersion.definition?.spec?.providers
70
+ ?.filter((provider: any) => {
71
+ // We only support HTTP provider ports for now. Need to figure out how to handle other types
72
+ return HTTP_PORTS.includes(provider.spec?.port?.type?.toLowerCase());
73
+ })
60
74
  ?.map((provider: any) => {
61
- return resolvePortType(provider.spec?.port?.type);
75
+ return resolvePortType(provider.spec?.port?.type?.toLowerCase());
62
76
  })
63
77
  .filter((t: any) => !!t) ?? [];
64
78
 
@@ -137,7 +151,7 @@ export class BlockInstanceRunner {
137
151
  processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
138
152
  } else {
139
153
  //We need a port type to know how to connect to the block consistently
140
- const portTypes = getProviderPorts(assetVersion, providerVersion);
154
+ const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
141
155
 
142
156
  if (blockUri.version === 'local') {
143
157
  processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
@@ -217,7 +231,7 @@ export class BlockInstanceRunner {
217
231
  delete localContainer.Labels;
218
232
  delete localContainer.Env;
219
233
 
220
- const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(
234
+ const { PortBindings, ExposedPorts, addonEnv } = await this.getServiceBlockPortBindings(
221
235
  blockInstance,
222
236
  assetVersion,
223
237
  providerVersion
@@ -317,7 +331,7 @@ export class BlockInstanceRunner {
317
331
  throw new Error(`Block type not found: ${kindUri.id}`);
318
332
  }
319
333
 
320
- const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(
334
+ const { PortBindings, ExposedPorts, addonEnv } = await this.getServiceBlockPortBindings(
321
335
  blockInstance,
322
336
  assetVersion,
323
337
  providerVersion
@@ -497,7 +511,10 @@ export class BlockInstanceRunner {
497
511
  return task.wait();
498
512
  }
499
513
 
500
- private async getDockerPortBindings(
514
+ /**
515
+ * Get the port bindings for a non-operator block
516
+ */
517
+ private async getServiceBlockPortBindings(
501
518
  blockInstance: BlockProcessParams,
502
519
  assetVersion: DefinitionInfo,
503
520
  providerVersion: DefinitionInfo
@@ -507,7 +524,7 @@ export class BlockInstanceRunner {
507
524
  const addonEnv: StringMap = {};
508
525
  const PortBindings: AnyMap = {};
509
526
 
510
- const portTypes = getProviderPorts(assetVersion, providerVersion);
527
+ const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
511
528
  let port = 80;
512
529
  const promises = portTypes.map(async (portType) => {
513
530
  const publicPort = await serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
@@ -8,11 +8,10 @@ import YAML from 'yaml';
8
8
  import md5 from 'md5';
9
9
  import { EntityList } from '@kapeta/schemas';
10
10
  import _ from 'lodash';
11
- import { AnyMap, PortInfo } from '../types';
11
+ import { AnyMap, KIND_BLOCK_TYPE_OPERATOR, PortInfo } from '../types';
12
12
  import ClusterConfiguration from '@kapeta/local-cluster-config';
13
13
  import { definitionsManager } from '../definitionsManager';
14
- import { parseKapetaUri } from '@kapeta/nodejs-utils';
15
- import { KIND_BLOCK_OPERATOR } from '../operatorManager';
14
+ import { normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
16
15
  import { assetManager } from '../assetManager';
17
16
 
18
17
  export async function getBlockInstanceContainerName(systemId: string, instanceId: string, blockType?: string) {
@@ -32,13 +31,13 @@ export async function getBlockInstanceContainerName(systemId: string, instanceId
32
31
  throw new Error(`Block type ${blockType} not found`);
33
32
  }
34
33
  if (
35
- parseKapetaUri(typeDefinition.definition.kind).fullName === KIND_BLOCK_OPERATOR &&
34
+ parseKapetaUri(typeDefinition.definition.kind).fullName === KIND_BLOCK_TYPE_OPERATOR &&
36
35
  typeDefinition.definition.spec?.local?.singleton
37
36
  ) {
38
- return `kapeta-instance-operator-${md5(systemId + blockType)}`;
37
+ return `kapeta-instance-operator-${md5(normalizeKapetaUri(systemId) + normalizeKapetaUri(blockType))}`;
39
38
  }
40
39
 
41
- return `kapeta-block-instance-${md5(systemId + instanceId)}`;
40
+ return `kapeta-block-instance-${md5(normalizeKapetaUri(systemId) + instanceId)}`;
42
41
  }
43
42
 
44
43
  export function toPortInfo(port: PortInfo) {