@kapeta/local-cluster-service 0.6.1 → 0.7.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 (192) hide show
  1. package/.eslintrc.cjs +17 -0
  2. package/.github/workflows/main.yml +22 -22
  3. package/.prettierignore +4 -0
  4. package/.vscode/launch.json +2 -4
  5. package/CHANGELOG.md +7 -0
  6. package/definitions.d.ts +17 -35
  7. package/dist/cjs/index.d.ts +27 -0
  8. package/dist/cjs/index.js +126 -0
  9. package/dist/cjs/package.json +1 -0
  10. package/dist/cjs/src/assetManager.d.ts +31 -0
  11. package/dist/cjs/src/assetManager.js +153 -0
  12. package/dist/cjs/src/assets/routes.d.ts +3 -0
  13. package/dist/cjs/src/assets/routes.js +117 -0
  14. package/dist/cjs/src/clusterService.d.ts +40 -0
  15. package/dist/cjs/src/clusterService.js +114 -0
  16. package/dist/cjs/src/codeGeneratorManager.d.ts +8 -0
  17. package/dist/cjs/src/codeGeneratorManager.js +53 -0
  18. package/dist/cjs/src/config/routes.d.ts +3 -0
  19. package/dist/cjs/src/config/routes.js +126 -0
  20. package/dist/cjs/src/configManager.d.ts +36 -0
  21. package/dist/cjs/src/configManager.js +110 -0
  22. package/dist/cjs/src/containerManager.d.ts +89 -0
  23. package/dist/cjs/src/containerManager.js +365 -0
  24. package/dist/cjs/src/filesystem/routes.d.ts +3 -0
  25. package/dist/cjs/src/filesystem/routes.js +69 -0
  26. package/dist/cjs/src/filesystemManager.d.ts +15 -0
  27. package/dist/cjs/src/filesystemManager.js +87 -0
  28. package/dist/cjs/src/identities/routes.d.ts +3 -0
  29. package/dist/cjs/src/identities/routes.js +18 -0
  30. package/dist/cjs/src/instanceManager.d.ts +56 -0
  31. package/dist/cjs/src/instanceManager.js +424 -0
  32. package/dist/cjs/src/instances/routes.d.ts +3 -0
  33. package/dist/cjs/src/instances/routes.js +134 -0
  34. package/dist/cjs/src/middleware/cors.d.ts +2 -0
  35. package/dist/cjs/src/middleware/cors.js +10 -0
  36. package/dist/cjs/src/middleware/kapeta.d.ts +11 -0
  37. package/dist/cjs/src/middleware/kapeta.js +17 -0
  38. package/dist/cjs/src/middleware/stringBody.d.ts +5 -0
  39. package/dist/cjs/src/middleware/stringBody.js +14 -0
  40. package/dist/cjs/src/networkManager.d.ts +32 -0
  41. package/dist/cjs/src/networkManager.js +109 -0
  42. package/dist/cjs/src/operatorManager.d.ts +36 -0
  43. package/dist/cjs/src/operatorManager.js +165 -0
  44. package/dist/cjs/src/progressListener.d.ts +20 -0
  45. package/dist/cjs/src/progressListener.js +91 -0
  46. package/dist/cjs/src/providerManager.d.ts +9 -0
  47. package/dist/cjs/src/providerManager.js +51 -0
  48. package/dist/cjs/src/providers/routes.d.ts +3 -0
  49. package/dist/cjs/src/providers/routes.js +42 -0
  50. package/dist/cjs/src/proxy/routes.d.ts +3 -0
  51. package/dist/cjs/src/proxy/routes.js +111 -0
  52. package/dist/cjs/src/proxy/types/rest.d.ts +4 -0
  53. package/dist/cjs/src/proxy/types/rest.js +114 -0
  54. package/dist/cjs/src/proxy/types/web.d.ts +4 -0
  55. package/dist/cjs/src/proxy/types/web.js +53 -0
  56. package/dist/cjs/src/repositoryManager.d.ts +17 -0
  57. package/dist/cjs/src/repositoryManager.js +215 -0
  58. package/dist/cjs/src/serviceManager.d.ts +29 -0
  59. package/dist/cjs/src/serviceManager.js +99 -0
  60. package/dist/cjs/src/socketManager.d.ts +14 -0
  61. package/dist/cjs/src/socketManager.js +53 -0
  62. package/dist/cjs/src/storageService.d.ts +17 -0
  63. package/dist/cjs/src/storageService.js +74 -0
  64. package/dist/cjs/src/traffic/routes.d.ts +3 -0
  65. package/dist/cjs/src/traffic/routes.js +18 -0
  66. package/dist/cjs/src/types.d.ts +88 -0
  67. package/dist/cjs/src/types.js +2 -0
  68. package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +29 -0
  69. package/dist/cjs/src/utils/BlockInstanceRunner.js +468 -0
  70. package/dist/cjs/src/utils/LogData.d.ts +19 -0
  71. package/dist/cjs/src/utils/LogData.js +43 -0
  72. package/dist/cjs/src/utils/pathTemplateParser.d.ts +26 -0
  73. package/dist/cjs/src/utils/pathTemplateParser.js +121 -0
  74. package/dist/cjs/src/utils/utils.d.ts +1 -0
  75. package/dist/cjs/src/utils/utils.js +18 -0
  76. package/dist/cjs/start.d.ts +1 -0
  77. package/dist/cjs/start.js +12 -0
  78. package/dist/esm/index.d.ts +27 -0
  79. package/dist/esm/index.js +121 -0
  80. package/dist/esm/package.json +1 -0
  81. package/dist/esm/src/assetManager.d.ts +31 -0
  82. package/{src → dist/esm/src}/assetManager.js +22 -60
  83. package/dist/esm/src/assets/routes.d.ts +3 -0
  84. package/{src → dist/esm/src}/assets/routes.js +21 -36
  85. package/dist/esm/src/clusterService.d.ts +40 -0
  86. package/{src → dist/esm/src}/clusterService.js +14 -37
  87. package/dist/esm/src/codeGeneratorManager.d.ts +8 -0
  88. package/{src → dist/esm/src}/codeGeneratorManager.js +15 -24
  89. package/dist/esm/src/config/routes.d.ts +3 -0
  90. package/{src → dist/esm/src}/config/routes.js +40 -89
  91. package/dist/esm/src/configManager.d.ts +36 -0
  92. package/{src → dist/esm/src}/configManager.js +11 -40
  93. package/dist/esm/src/containerManager.d.ts +89 -0
  94. package/{src → dist/esm/src}/containerManager.js +81 -182
  95. package/dist/esm/src/filesystem/routes.d.ts +3 -0
  96. package/dist/esm/src/filesystem/routes.js +64 -0
  97. package/dist/esm/src/filesystemManager.d.ts +15 -0
  98. package/{src → dist/esm/src}/filesystemManager.js +20 -28
  99. package/dist/esm/src/identities/routes.d.ts +3 -0
  100. package/dist/esm/src/identities/routes.js +13 -0
  101. package/dist/esm/src/instanceManager.d.ts +56 -0
  102. package/{src → dist/esm/src}/instanceManager.js +88 -179
  103. package/dist/esm/src/instances/routes.d.ts +3 -0
  104. package/{src → dist/esm/src}/instances/routes.js +31 -70
  105. package/dist/esm/src/middleware/cors.d.ts +2 -0
  106. package/{src → dist/esm/src}/middleware/cors.js +2 -3
  107. package/dist/esm/src/middleware/kapeta.d.ts +11 -0
  108. package/{src → dist/esm/src}/middleware/kapeta.js +3 -7
  109. package/dist/esm/src/middleware/stringBody.d.ts +5 -0
  110. package/{src → dist/esm/src}/middleware/stringBody.js +2 -3
  111. package/dist/esm/src/networkManager.d.ts +32 -0
  112. package/{src → dist/esm/src}/networkManager.js +16 -33
  113. package/dist/esm/src/operatorManager.d.ts +36 -0
  114. package/{src → dist/esm/src}/operatorManager.js +35 -91
  115. package/dist/esm/src/progressListener.d.ts +20 -0
  116. package/dist/esm/src/progressListener.js +88 -0
  117. package/dist/esm/src/providerManager.d.ts +9 -0
  118. package/dist/esm/src/providerManager.js +45 -0
  119. package/dist/esm/src/providers/routes.d.ts +3 -0
  120. package/{src → dist/esm/src}/providers/routes.js +10 -16
  121. package/dist/esm/src/proxy/routes.d.ts +3 -0
  122. package/dist/esm/src/proxy/routes.js +106 -0
  123. package/dist/esm/src/proxy/types/rest.d.ts +4 -0
  124. package/dist/esm/src/proxy/types/rest.js +107 -0
  125. package/dist/esm/src/proxy/types/web.d.ts +4 -0
  126. package/{src → dist/esm/src}/proxy/types/web.js +13 -35
  127. package/dist/esm/src/repositoryManager.d.ts +17 -0
  128. package/dist/esm/src/repositoryManager.js +209 -0
  129. package/dist/esm/src/serviceManager.d.ts +29 -0
  130. package/{src → dist/esm/src}/serviceManager.js +12 -42
  131. package/dist/esm/src/socketManager.d.ts +14 -0
  132. package/{src → dist/esm/src}/socketManager.js +19 -23
  133. package/dist/esm/src/storageService.d.ts +17 -0
  134. package/{src → dist/esm/src}/storageService.js +8 -27
  135. package/dist/esm/src/traffic/routes.d.ts +3 -0
  136. package/{src → dist/esm/src}/traffic/routes.js +4 -9
  137. package/dist/esm/src/types.d.ts +88 -0
  138. package/dist/esm/src/types.js +1 -0
  139. package/dist/esm/src/utils/BlockInstanceRunner.d.ts +29 -0
  140. package/{src → dist/esm/src}/utils/BlockInstanceRunner.js +137 -256
  141. package/dist/esm/src/utils/LogData.d.ts +19 -0
  142. package/{src → dist/esm/src}/utils/LogData.js +11 -22
  143. package/dist/esm/src/utils/pathTemplateParser.d.ts +26 -0
  144. package/{src → dist/esm/src}/utils/pathTemplateParser.js +21 -40
  145. package/dist/esm/src/utils/utils.d.ts +1 -0
  146. package/dist/esm/src/utils/utils.js +11 -0
  147. package/dist/esm/start.d.ts +1 -0
  148. package/dist/esm/start.js +7 -0
  149. package/index.ts +147 -0
  150. package/package.json +106 -74
  151. package/src/assetManager.ts +191 -0
  152. package/src/assets/routes.ts +132 -0
  153. package/src/clusterService.ts +134 -0
  154. package/src/codeGeneratorManager.ts +57 -0
  155. package/src/config/routes.ts +159 -0
  156. package/src/configManager.ts +148 -0
  157. package/src/containerManager.ts +466 -0
  158. package/src/filesystem/routes.ts +74 -0
  159. package/src/filesystemManager.ts +93 -0
  160. package/src/identities/routes.ts +20 -0
  161. package/src/instanceManager.ts +503 -0
  162. package/src/instances/routes.ts +164 -0
  163. package/src/middleware/cors.ts +9 -0
  164. package/src/middleware/kapeta.ts +27 -0
  165. package/src/middleware/stringBody.ts +16 -0
  166. package/src/networkManager.ts +137 -0
  167. package/src/operatorManager.ts +221 -0
  168. package/src/progressListener.ts +102 -0
  169. package/src/{providerManager.js → providerManager.ts} +15 -31
  170. package/src/providers/routes.ts +46 -0
  171. package/src/proxy/routes.ts +148 -0
  172. package/src/proxy/types/{rest.js → rest.ts} +30 -30
  173. package/src/proxy/types/web.ts +60 -0
  174. package/src/{repositoryManager.js → repositoryManager.ts} +45 -73
  175. package/src/serviceManager.ts +120 -0
  176. package/src/socketManager.ts +57 -0
  177. package/src/storageService.ts +88 -0
  178. package/src/traffic/routes.ts +18 -0
  179. package/src/types.ts +97 -0
  180. package/src/utils/BlockInstanceRunner.ts +555 -0
  181. package/src/utils/LogData.ts +47 -0
  182. package/src/utils/pathTemplateParser.ts +138 -0
  183. package/src/utils/utils.ts +12 -0
  184. package/start.ts +8 -0
  185. package/tsconfig.json +13 -0
  186. package/index.js +0 -127
  187. package/src/filesystem/routes.js +0 -74
  188. package/src/identities/routes.js +0 -19
  189. package/src/progressListener.js +0 -82
  190. package/src/proxy/routes.js +0 -126
  191. package/src/utils/utils.js +0 -13
  192. package/start.js +0 -7
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.storageService = void 0;
7
+ const lodash_1 = __importDefault(require("lodash"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const yaml_1 = __importDefault(require("yaml"));
11
+ const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
12
+ /**
13
+ * Class that handles reading and writing from local configuration file.
14
+ */
15
+ class StorageService {
16
+ _data;
17
+ constructor() {
18
+ this._data = this._readConfig();
19
+ }
20
+ getKapetaBasedir() {
21
+ return local_cluster_config_1.default.getKapetaBasedir();
22
+ }
23
+ _readConfig() {
24
+ return local_cluster_config_1.default.getClusterConfig();
25
+ }
26
+ _writeConfig() {
27
+ const configFile = local_cluster_config_1.default.getClusterConfigFile();
28
+ fs_extra_1.default.mkdirsSync(this.getKapetaBasedir());
29
+ fs_1.default.writeFileSync(configFile, yaml_1.default.stringify(this._data));
30
+ }
31
+ section(section, defaultValue) {
32
+ if (!defaultValue) {
33
+ defaultValue = {};
34
+ }
35
+ if (!this._data[section]) {
36
+ this._data[section] = defaultValue;
37
+ this._writeConfig();
38
+ }
39
+ return this._data[section];
40
+ }
41
+ put(section, property, value) {
42
+ if (!lodash_1.default.isString(property)) {
43
+ this._data[section] = property;
44
+ this._writeConfig();
45
+ return;
46
+ }
47
+ this.section(section)[property] = value;
48
+ this._writeConfig();
49
+ }
50
+ get(section, property) {
51
+ if (!property) {
52
+ return this.section(section);
53
+ }
54
+ return this.section(section)[property];
55
+ }
56
+ contains(section, property) {
57
+ if (!this._data[section]) {
58
+ return false;
59
+ }
60
+ return this._data[section].hasOwnProperty(property);
61
+ }
62
+ ensure(section, property, value) {
63
+ if (this.contains(section, property)) {
64
+ return this.get(section, property);
65
+ }
66
+ let out = value;
67
+ if (typeof value === 'function') {
68
+ out = value();
69
+ }
70
+ this.put(section, property, out);
71
+ return out;
72
+ }
73
+ }
74
+ exports.storageService = new StorageService();
@@ -0,0 +1,3 @@
1
+ /// <reference types="express" />
2
+ declare const router: import("express").Router;
3
+ export default router;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_promise_router_1 = __importDefault(require("express-promise-router"));
7
+ const networkManager_1 = require("../networkManager");
8
+ const router = (0, express_promise_router_1.default)();
9
+ router.get('/:systemId/target/:connectionId/', (req, res) => {
10
+ res.send(networkManager_1.networkManager.getTrafficForConnection(req.params.systemId, req.params.connectionId));
11
+ });
12
+ router.get('/:systemId/source/:blockInstanceId/', (req, res) => {
13
+ res.send(networkManager_1.networkManager.getTrafficForSource(req.params.systemId, req.params.blockInstanceId));
14
+ });
15
+ router.get('/:systemId/target/:blockInstanceId/', (req, res) => {
16
+ res.send(networkManager_1.networkManager.getTrafficForTarget(req.params.systemId, req.params.blockInstanceId));
17
+ });
18
+ exports.default = router;
@@ -0,0 +1,88 @@
1
+ /// <reference types="node" />
2
+ import EventEmitter from 'events';
3
+ import express from 'express';
4
+ import { Resource } from '@kapeta/schemas';
5
+ import { StringBodyRequest } from './middleware/stringBody';
6
+ import { KapetaRequest } from './middleware/kapeta';
7
+ export type StringMap = {
8
+ [key: string]: string;
9
+ };
10
+ export type AnyMap = {
11
+ [key: string]: any;
12
+ };
13
+ export type LogLevel = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'TRACE' | 'FATAL';
14
+ export type LogSource = 'stdout' | 'stderr';
15
+ export type EnvironmentType = 'docker' | 'process';
16
+ export interface LogEntry {
17
+ source: LogSource;
18
+ level: LogLevel;
19
+ message: string;
20
+ time: number;
21
+ }
22
+ export interface BlockProcessParams {
23
+ id: string;
24
+ ref: string;
25
+ configuration?: AnyMap;
26
+ }
27
+ export type ProcessType = 'docker' | 'local';
28
+ export interface ProcessDetails {
29
+ pid: number | string;
30
+ type: ProcessType;
31
+ portType?: string;
32
+ output: EventEmitter;
33
+ logs: () => LogEntry[];
34
+ stop: () => Promise<void> | void;
35
+ }
36
+ export interface ProcessInfo extends ProcessDetails {
37
+ id: string;
38
+ ref: string;
39
+ name: string;
40
+ }
41
+ export type InstanceInfo = {
42
+ systemId: string;
43
+ instanceId: string;
44
+ address?: string;
45
+ health?: string | null;
46
+ status: string;
47
+ pid?: number | string | null;
48
+ type: ProcessType;
49
+ portType?: string;
50
+ };
51
+ interface ResourceRef {
52
+ blockId: string;
53
+ resourceName: string;
54
+ }
55
+ export type ProxyRequestHandler = (req: StringBodyRequest, res: express.Response, info: ProxyRequestInfo) => void;
56
+ export interface Connection {
57
+ mapping: any;
58
+ provider: ResourceRef;
59
+ consumer: ResourceRef;
60
+ }
61
+ export interface OperatorInfo {
62
+ host: string;
63
+ port: string;
64
+ type: string;
65
+ protocol: string;
66
+ options: AnyMap;
67
+ credentials: AnyMap;
68
+ }
69
+ export interface ProxyRequestInfo {
70
+ address: string;
71
+ connection: Connection;
72
+ providerResource: Resource;
73
+ consumerResource: Resource;
74
+ consumerPath: string;
75
+ }
76
+ export interface SimpleResponse {
77
+ code: number;
78
+ headers: StringMap;
79
+ body: any;
80
+ }
81
+ export interface SimpleRequest {
82
+ method: string;
83
+ url: string;
84
+ headers: StringMap;
85
+ body: any;
86
+ }
87
+ export type KapetaBodyRequest = KapetaRequest & StringBodyRequest;
88
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,29 @@
1
+ import { DefinitionInfo } from '@kapeta/local-cluster-config';
2
+ import { KapetaURI } from '@kapeta/nodejs-utils';
3
+ import { AnyMap, BlockProcessParams, ProcessDetails, ProcessInfo, StringMap } from '../types';
4
+ export declare class BlockInstanceRunner {
5
+ private readonly _systemId;
6
+ constructor(planReference: string);
7
+ /**
8
+ * Start a block
9
+ *
10
+ */
11
+ start(blockRef: string, instanceId: string, configuration: AnyMap): Promise<ProcessInfo>;
12
+ private _execute;
13
+ /**
14
+ * Starts local process
15
+ */
16
+ private _startLocalProcess;
17
+ private _handleContainer;
18
+ private _startDockerProcess;
19
+ /**
20
+ *
21
+ * @param blockInstance
22
+ * @param blockUri
23
+ * @param providerDefinition
24
+ * @param {{[key:string]:string}} env
25
+ * @return {Promise<ProcessDetails>}
26
+ * @private
27
+ */
28
+ _startOperatorProcess(blockInstance: BlockProcessParams, blockUri: KapetaURI, providerDefinition: DefinitionInfo, env: StringMap): Promise<ProcessDetails>;
29
+ }
@@ -0,0 +1,468 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BlockInstanceRunner = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
9
+ const utils_1 = require("./utils");
10
+ const nodejs_utils_1 = require("@kapeta/nodejs-utils");
11
+ const serviceManager_1 = require("../serviceManager");
12
+ const containerManager_1 = require("../containerManager");
13
+ const LogData_1 = require("./LogData");
14
+ const events_1 = __importDefault(require("events"));
15
+ const md5_1 = __importDefault(require("md5"));
16
+ const clusterService_1 = require("../clusterService");
17
+ const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
18
+ const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
19
+ const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
20
+ const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
21
+ const KAPETA_LOCAL_CLUSTER_PORT = 'KAPETA_LOCAL_CLUSTER_PORT';
22
+ /**
23
+ * Needed when running local docker containers as part of plan
24
+ * @type {string[]}
25
+ */
26
+ const DOCKER_ENV_VARS = [
27
+ `KAPETA_LOCAL_SERVER=0.0.0.0`,
28
+ `KAPETA_LOCAL_CLUSTER_HOST=host.docker.internal`,
29
+ `KAPETA_ENVIRONMENT_TYPE=docker`,
30
+ ];
31
+ function getProvider(uri) {
32
+ return local_cluster_config_1.default.getProviderDefinitions().find((provider) => {
33
+ const ref = `${provider.definition.metadata.name}:${provider.version}`;
34
+ return (0, nodejs_utils_1.parseKapetaUri)(ref).id === uri.id;
35
+ });
36
+ }
37
+ function getProviderPorts(assetVersion) {
38
+ return (assetVersion.definition?.spec?.providers
39
+ ?.map((provider) => {
40
+ return provider.spec?.port?.type;
41
+ })
42
+ .filter((t) => !!t) ?? []);
43
+ }
44
+ class BlockInstanceRunner {
45
+ _systemId;
46
+ constructor(planReference) {
47
+ /**
48
+ *
49
+ * @type {string}
50
+ * @private
51
+ */
52
+ this._systemId = planReference ?? '';
53
+ }
54
+ /**
55
+ * Start a block
56
+ *
57
+ */
58
+ async start(blockRef, instanceId, configuration) {
59
+ return this._execute({
60
+ ref: blockRef,
61
+ id: instanceId,
62
+ configuration,
63
+ });
64
+ }
65
+ async _execute(blockInstance) {
66
+ const env = {};
67
+ if (this._systemId) {
68
+ env[KAPETA_SYSTEM_ID] = this._systemId;
69
+ }
70
+ if (blockInstance.ref) {
71
+ env[KAPETA_BLOCK_REF] = blockInstance.ref;
72
+ }
73
+ if (blockInstance.id) {
74
+ env[KAPETA_INSTANCE_ID] = blockInstance.id;
75
+ }
76
+ const blockUri = (0, nodejs_utils_1.parseKapetaUri)(blockInstance.ref);
77
+ if (!blockUri.version) {
78
+ blockUri.version = 'local';
79
+ }
80
+ const assetVersion = local_cluster_config_1.default.getDefinitions().find((definitions) => {
81
+ const ref = `${definitions.definition.metadata.name}:${definitions.version}`;
82
+ return (0, nodejs_utils_1.parseKapetaUri)(ref).id === blockUri.id;
83
+ });
84
+ if (!assetVersion) {
85
+ throw new Error(`Block definition not found: ${blockUri.id}`);
86
+ }
87
+ const kindUri = (0, nodejs_utils_1.parseKapetaUri)(assetVersion.definition.kind);
88
+ const providerVersion = getProvider(kindUri);
89
+ if (!providerVersion) {
90
+ throw new Error(`Kind not found: ${kindUri.id}`);
91
+ }
92
+ let processDetails;
93
+ if (providerVersion.definition.kind === KIND_BLOCK_TYPE_OPERATOR) {
94
+ processDetails = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
95
+ }
96
+ else {
97
+ //We need a port type to know how to connect to the block consistently
98
+ const portTypes = getProviderPorts(assetVersion);
99
+ if (blockUri.version === 'local') {
100
+ processDetails = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
101
+ }
102
+ else {
103
+ processDetails = await this._startDockerProcess(blockInstance, blockUri, env);
104
+ }
105
+ if (portTypes.length > 0) {
106
+ processDetails.portType = portTypes[0];
107
+ }
108
+ }
109
+ return {
110
+ name: blockUri.id,
111
+ ...blockInstance,
112
+ ...processDetails,
113
+ };
114
+ }
115
+ /**
116
+ * Starts local process
117
+ */
118
+ async _startLocalProcess(blockInstance, blockInfo, env, assetVersion) {
119
+ const baseDir = local_cluster_config_1.default.getRepositoryAssetPath(blockInfo.handle, blockInfo.name, blockInfo.version);
120
+ if (!node_fs_1.default.existsSync(baseDir)) {
121
+ throw new Error(`Local block not registered correctly - expected symlink here: ${baseDir}.\n` +
122
+ `Make sure you've run "blockctl registry link" in your local directory to connect it to Kapeta`);
123
+ }
124
+ if (!assetVersion.definition.spec?.target?.kind) {
125
+ throw new Error('Missing target kind in block definition');
126
+ }
127
+ const kindUri = (0, nodejs_utils_1.parseKapetaUri)(assetVersion.definition.spec?.target?.kind);
128
+ const targetVersion = getProvider(kindUri);
129
+ if (!targetVersion) {
130
+ throw new Error(`Target not found: ${kindUri.id}`);
131
+ }
132
+ const localContainer = targetVersion.definition.spec.local;
133
+ if (!localContainer) {
134
+ throw new Error(`Missing local container information from target: ${kindUri.id}`);
135
+ }
136
+ const dockerImage = localContainer.image;
137
+ if (!dockerImage) {
138
+ throw new Error(`Missing docker image information: ${JSON.stringify(localContainer)}`);
139
+ }
140
+ const containerName = `kapeta-block-instance-${blockInstance.id}`;
141
+ const logs = new LogData_1.LogData();
142
+ logs.addLog(`Starting block ${blockInstance.ref}`);
143
+ let container = (await containerManager_1.containerManager.getContainerByName(containerName)) ?? null;
144
+ console.log('Starting dev container', containerName);
145
+ if (container) {
146
+ console.log(`Container already exists. Deleting...`);
147
+ try {
148
+ await container.delete({
149
+ force: true,
150
+ });
151
+ }
152
+ catch (e) {
153
+ throw new Error('Failed to delete existing container: ' + e.message);
154
+ }
155
+ container = null;
156
+ }
157
+ logs.addLog(`Creating new container for block: ${containerName}`);
158
+ console.log('Creating new dev container', containerName, dockerImage);
159
+ await containerManager_1.containerManager.pull(dockerImage);
160
+ const startCmd = localContainer.handlers?.onCreate ? localContainer.handlers.onCreate : '';
161
+ const dockerOpts = localContainer.options ?? {};
162
+ const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
163
+ const workingDir = localContainer.workingDir ? localContainer.workingDir : '/workspace';
164
+ const ExposedPorts = {};
165
+ const addonEnv = {};
166
+ const PortBindings = {};
167
+ const portTypes = getProviderPorts(assetVersion);
168
+ let port = 80;
169
+ const promises = portTypes.map(async (portType) => {
170
+ const publicPort = await serviceManager_1.serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
171
+ const thisPort = port++; //TODO: Not sure how we should handle multiple ports or non-HTTP ports
172
+ const dockerPort = `${thisPort}/tcp`;
173
+ ExposedPorts[dockerPort] = {};
174
+ addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = '' + thisPort;
175
+ PortBindings[dockerPort] = [
176
+ {
177
+ HostIp: '127.0.0.1',
178
+ HostPort: `${publicPort}`,
179
+ },
180
+ ];
181
+ });
182
+ await Promise.all(promises);
183
+ let HealthCheck = undefined;
184
+ if (localContainer.healthcheck) {
185
+ HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
186
+ }
187
+ container = await containerManager_1.containerManager.startContainer({
188
+ Image: dockerImage,
189
+ name: containerName,
190
+ WorkingDir: workingDir,
191
+ Labels: {
192
+ instance: blockInstance.id,
193
+ },
194
+ HealthCheck,
195
+ ExposedPorts,
196
+ Cmd: startCmd ? startCmd.split(/\s+/g) : [],
197
+ Env: [
198
+ ...DOCKER_ENV_VARS,
199
+ `KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
200
+ ...Object.entries({
201
+ ...env,
202
+ ...addonEnv,
203
+ }).map(([key, value]) => `${key}=${value}`),
204
+ ],
205
+ HostConfig: {
206
+ Binds: [
207
+ `${local_cluster_config_1.default.getKapetaBasedir()}:${homeDir}/.kapeta`,
208
+ `${baseDir}:${workingDir}`, //We mount
209
+ ],
210
+ PortBindings,
211
+ },
212
+ ...dockerOpts,
213
+ });
214
+ try {
215
+ if (HealthCheck) {
216
+ await containerManager_1.containerManager.waitForHealthy(container);
217
+ }
218
+ else {
219
+ await containerManager_1.containerManager.waitForReady(container);
220
+ }
221
+ }
222
+ catch (e) {
223
+ logs.addLog(e.message, 'ERROR');
224
+ }
225
+ return this._handleContainer(container, logs);
226
+ }
227
+ async _handleContainer(container, logs, deleteOnExit = false) {
228
+ let localContainer = container;
229
+ const logStream = (await container.logs({
230
+ follow: true,
231
+ stdout: true,
232
+ stderr: true,
233
+ tail: LogData_1.LogData.MAX_LINES,
234
+ }));
235
+ const outputEvents = new events_1.default();
236
+ logStream.on('data', (data) => {
237
+ logs.addLog(data.toString());
238
+ outputEvents.emit('data', data);
239
+ });
240
+ logStream.on('error', (data) => {
241
+ logs.addLog(data.toString());
242
+ outputEvents.emit('data', data);
243
+ });
244
+ logStream.on('close', async () => {
245
+ const status = await container.status();
246
+ const data = status.data;
247
+ if (deleteOnExit) {
248
+ try {
249
+ await container.delete();
250
+ }
251
+ catch (e) { }
252
+ }
253
+ outputEvents.emit('exit', data?.State?.ExitCode ?? 0);
254
+ });
255
+ return {
256
+ type: 'docker',
257
+ pid: container.id,
258
+ output: outputEvents,
259
+ stop: async () => {
260
+ if (!localContainer) {
261
+ return;
262
+ }
263
+ try {
264
+ await localContainer.stop();
265
+ if (deleteOnExit) {
266
+ await localContainer.delete();
267
+ }
268
+ }
269
+ catch (e) { }
270
+ localContainer = null;
271
+ },
272
+ logs: () => {
273
+ return logs.getLogs();
274
+ },
275
+ };
276
+ }
277
+ async _startDockerProcess(blockInstance, blockInfo, env) {
278
+ const { versionFile } = local_cluster_config_1.default.getRepositoryAssetInfoPath(blockInfo.handle, blockInfo.name, blockInfo.version);
279
+ const versionYml = versionFile;
280
+ if (!node_fs_1.default.existsSync(versionYml)) {
281
+ throw new Error(`Did not find version info at the expected path: ${versionYml}`);
282
+ }
283
+ const versionInfo = (0, utils_1.readYML)(versionYml);
284
+ if (versionInfo?.artifact?.type !== 'docker') {
285
+ throw new Error(`Unsupported artifact type: ${versionInfo?.artifact?.type}`);
286
+ }
287
+ const dockerImage = versionInfo?.artifact?.details?.primary;
288
+ if (!dockerImage) {
289
+ throw new Error(`Missing docker image information: ${JSON.stringify(versionInfo?.artifact?.details)}`);
290
+ }
291
+ const containerName = `kapeta-block-instance-${blockInstance.id}`;
292
+ const logs = new LogData_1.LogData();
293
+ let container = await containerManager_1.containerManager.getContainerByName(containerName);
294
+ if (container) {
295
+ const containerData = container.data;
296
+ if (containerData.State === 'running') {
297
+ logs.addLog(`Found existing running container for block: ${containerName}`);
298
+ }
299
+ else {
300
+ logs.addLog(`Found existing container for block: ${containerName}. Starting now`);
301
+ await container.start();
302
+ }
303
+ }
304
+ else {
305
+ logs.addLog(`Creating new container for block: ${containerName}`);
306
+ container = await containerManager_1.containerManager.startContainer({
307
+ Image: dockerImage,
308
+ name: containerName,
309
+ Labels: {
310
+ instance: blockInstance.id,
311
+ },
312
+ Env: [
313
+ ...DOCKER_ENV_VARS,
314
+ `KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
315
+ ...Object.entries(env).map(([key, value]) => `${key}=${value}`),
316
+ ],
317
+ HostConfig: {
318
+ Binds: [`${local_cluster_config_1.default.getKapetaBasedir()}:${local_cluster_config_1.default.getKapetaBasedir()}`],
319
+ },
320
+ });
321
+ try {
322
+ await containerManager_1.containerManager.waitForReady(container);
323
+ }
324
+ catch (e) {
325
+ logs.addLog(e.message, 'ERROR');
326
+ }
327
+ }
328
+ return this._handleContainer(container, logs);
329
+ }
330
+ /**
331
+ *
332
+ * @param blockInstance
333
+ * @param blockUri
334
+ * @param providerDefinition
335
+ * @param {{[key:string]:string}} env
336
+ * @return {Promise<ProcessDetails>}
337
+ * @private
338
+ */
339
+ async _startOperatorProcess(blockInstance, blockUri, providerDefinition, env) {
340
+ const { assetFile } = local_cluster_config_1.default.getRepositoryAssetInfoPath(blockUri.handle, blockUri.name, blockUri.version);
341
+ const kapetaYmlPath = assetFile;
342
+ if (!node_fs_1.default.existsSync(kapetaYmlPath)) {
343
+ throw new Error(`Did not find kapeta.yml at the expected path: ${kapetaYmlPath}`);
344
+ }
345
+ const spec = providerDefinition.definition.spec;
346
+ const providerRef = `${providerDefinition.definition.metadata.name}:${providerDefinition.version}`;
347
+ if (!spec?.local?.image) {
348
+ throw new Error(`Provider did not have local image: ${providerRef}`);
349
+ }
350
+ const dockerImage = spec?.local?.image;
351
+ try {
352
+ await containerManager_1.containerManager.pull(dockerImage);
353
+ }
354
+ catch (e) {
355
+ console.warn('Failed to pull image. Continuing...', e);
356
+ }
357
+ const containerName = `kapeta-block-instance-${(0, md5_1.default)(blockInstance.id)}`;
358
+ const logs = new LogData_1.LogData();
359
+ let container = (await containerManager_1.containerManager.getContainerByName(containerName)) ?? null;
360
+ if (container) {
361
+ const containerData = container.data;
362
+ if (containerData.State === 'running') {
363
+ logs.addLog(`Found existing running container for block: ${containerName}`);
364
+ }
365
+ else {
366
+ if (containerData.State?.ExitCode > 0) {
367
+ logs.addLog(`Container exited with code: ${containerData.State.ExitCode}. Deleting...`);
368
+ try {
369
+ await container.delete();
370
+ }
371
+ catch (e) { }
372
+ container = null;
373
+ }
374
+ else {
375
+ logs.addLog(`Found existing container for block: ${containerName}. Starting now`);
376
+ try {
377
+ await container.start();
378
+ }
379
+ catch (e) {
380
+ console.warn('Failed to start container. Deleting...', e);
381
+ try {
382
+ await container.delete();
383
+ }
384
+ catch (e) { }
385
+ container = null;
386
+ }
387
+ }
388
+ }
389
+ }
390
+ if (!container) {
391
+ const ExposedPorts = {};
392
+ const addonEnv = {};
393
+ const PortBindings = {};
394
+ let HealthCheck = undefined;
395
+ let Mounts = [];
396
+ const promises = Object.entries(spec.local.ports).map(async ([portType, value]) => {
397
+ const dockerPort = `${value.port}/${value.type}`;
398
+ ExposedPorts[dockerPort] = {};
399
+ addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = value.port;
400
+ const publicPort = await serviceManager_1.serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
401
+ PortBindings[dockerPort] = [
402
+ {
403
+ HostIp: '127.0.0.1',
404
+ HostPort: `${publicPort}`,
405
+ },
406
+ ];
407
+ });
408
+ await Promise.all(promises);
409
+ if (spec.local?.env) {
410
+ Object.entries(spec.local.env).forEach(([key, value]) => {
411
+ addonEnv[key] = value;
412
+ });
413
+ }
414
+ if (spec.local?.mounts) {
415
+ const mounts = containerManager_1.containerManager.createMounts(blockUri.id, spec.local.mounts);
416
+ Mounts = containerManager_1.containerManager.toDockerMounts(mounts);
417
+ }
418
+ if (spec.local?.health) {
419
+ HealthCheck = containerManager_1.containerManager.toDockerHealth(spec.local?.health);
420
+ }
421
+ logs.addLog(`Creating new container for block: ${containerName}`);
422
+ container = await containerManager_1.containerManager.startContainer({
423
+ Image: dockerImage,
424
+ name: containerName,
425
+ ExposedPorts,
426
+ HealthCheck,
427
+ HostConfig: {
428
+ Binds: [
429
+ `${kapetaYmlPath}:/kapeta.yml:ro`,
430
+ `${local_cluster_config_1.default.getKapetaBasedir()}:${local_cluster_config_1.default.getKapetaBasedir()}`,
431
+ ],
432
+ PortBindings,
433
+ Mounts,
434
+ },
435
+ Labels: {
436
+ instance: blockInstance.id,
437
+ },
438
+ Env: [
439
+ `KAPETA_INSTANCE_NAME=${blockInstance.ref}`,
440
+ `KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
441
+ ...DOCKER_ENV_VARS,
442
+ ...Object.entries({
443
+ ...env,
444
+ ...addonEnv,
445
+ }).map(([key, value]) => `${key}=${value}`),
446
+ ],
447
+ });
448
+ try {
449
+ if (HealthCheck) {
450
+ await containerManager_1.containerManager.waitForHealthy(container);
451
+ }
452
+ else {
453
+ await containerManager_1.containerManager.waitForReady(container);
454
+ }
455
+ }
456
+ catch (e) {
457
+ logs.addLog(e.message, 'ERROR');
458
+ }
459
+ }
460
+ const out = await this._handleContainer(container, logs, true);
461
+ const portTypes = spec.local.ports ? Object.keys(spec.local.ports) : [];
462
+ if (portTypes.length > 0) {
463
+ out.portType = portTypes[0];
464
+ }
465
+ return out;
466
+ }
467
+ }
468
+ exports.BlockInstanceRunner = BlockInstanceRunner;