@kapeta/local-cluster-service 0.0.0-96f91ef

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 (274) hide show
  1. package/.eslintrc.cjs +25 -0
  2. package/.github/workflows/check-license.yml +17 -0
  3. package/.github/workflows/main.yml +26 -0
  4. package/.prettierignore +4 -0
  5. package/.vscode/launch.json +19 -0
  6. package/CHANGELOG.md +920 -0
  7. package/LICENSE +38 -0
  8. package/README.md +36 -0
  9. package/definitions.d.ts +35 -0
  10. package/dist/cjs/index.d.ts +34 -0
  11. package/dist/cjs/index.js +263 -0
  12. package/dist/cjs/package.json +1 -0
  13. package/dist/cjs/src/RepositoryWatcher.d.ts +30 -0
  14. package/dist/cjs/src/RepositoryWatcher.js +332 -0
  15. package/dist/cjs/src/ai/aiClient.d.ts +20 -0
  16. package/dist/cjs/src/ai/aiClient.js +74 -0
  17. package/dist/cjs/src/ai/routes.d.ts +7 -0
  18. package/dist/cjs/src/ai/routes.js +37 -0
  19. package/dist/cjs/src/ai/transform.d.ts +11 -0
  20. package/dist/cjs/src/ai/transform.js +239 -0
  21. package/dist/cjs/src/ai/types.d.ts +40 -0
  22. package/dist/cjs/src/ai/types.js +2 -0
  23. package/dist/cjs/src/api.d.ts +7 -0
  24. package/dist/cjs/src/api.js +29 -0
  25. package/dist/cjs/src/assetManager.d.ts +41 -0
  26. package/dist/cjs/src/assetManager.js +274 -0
  27. package/dist/cjs/src/assets/routes.d.ts +7 -0
  28. package/dist/cjs/src/assets/routes.js +165 -0
  29. package/dist/cjs/src/attachments/routes.d.ts +7 -0
  30. package/dist/cjs/src/attachments/routes.js +72 -0
  31. package/dist/cjs/src/authManager.d.ts +16 -0
  32. package/dist/cjs/src/authManager.js +64 -0
  33. package/dist/cjs/src/cacheManager.d.ts +20 -0
  34. package/dist/cjs/src/cacheManager.js +51 -0
  35. package/dist/cjs/src/clusterService.d.ts +44 -0
  36. package/dist/cjs/src/clusterService.js +120 -0
  37. package/dist/cjs/src/codeGeneratorManager.d.ts +14 -0
  38. package/dist/cjs/src/codeGeneratorManager.js +93 -0
  39. package/dist/cjs/src/config/routes.d.ts +7 -0
  40. package/dist/cjs/src/config/routes.js +160 -0
  41. package/dist/cjs/src/configManager.d.ts +42 -0
  42. package/dist/cjs/src/configManager.js +136 -0
  43. package/dist/cjs/src/containerManager.d.ts +148 -0
  44. package/dist/cjs/src/containerManager.js +958 -0
  45. package/dist/cjs/src/definitionsManager.d.ts +20 -0
  46. package/dist/cjs/src/definitionsManager.js +171 -0
  47. package/dist/cjs/src/filesystem/routes.d.ts +7 -0
  48. package/dist/cjs/src/filesystem/routes.js +105 -0
  49. package/dist/cjs/src/filesystemManager.d.ts +27 -0
  50. package/dist/cjs/src/filesystemManager.js +118 -0
  51. package/dist/cjs/src/identities/routes.d.ts +7 -0
  52. package/dist/cjs/src/identities/routes.js +37 -0
  53. package/dist/cjs/src/instanceManager.d.ts +69 -0
  54. package/dist/cjs/src/instanceManager.js +910 -0
  55. package/dist/cjs/src/instances/routes.d.ts +7 -0
  56. package/dist/cjs/src/instances/routes.js +179 -0
  57. package/dist/cjs/src/middleware/cors.d.ts +6 -0
  58. package/dist/cjs/src/middleware/cors.js +14 -0
  59. package/dist/cjs/src/middleware/kapeta.d.ts +15 -0
  60. package/dist/cjs/src/middleware/kapeta.js +28 -0
  61. package/dist/cjs/src/middleware/stringBody.d.ts +9 -0
  62. package/dist/cjs/src/middleware/stringBody.js +18 -0
  63. package/dist/cjs/src/networkManager.d.ts +37 -0
  64. package/dist/cjs/src/networkManager.js +119 -0
  65. package/dist/cjs/src/operatorManager.d.ts +41 -0
  66. package/dist/cjs/src/operatorManager.js +211 -0
  67. package/dist/cjs/src/progressListener.d.ts +31 -0
  68. package/dist/cjs/src/progressListener.js +133 -0
  69. package/dist/cjs/src/providerManager.d.ts +11 -0
  70. package/dist/cjs/src/providerManager.js +84 -0
  71. package/dist/cjs/src/providers/routes.d.ts +7 -0
  72. package/dist/cjs/src/providers/routes.js +46 -0
  73. package/dist/cjs/src/proxy/routes.d.ts +7 -0
  74. package/dist/cjs/src/proxy/routes.js +115 -0
  75. package/dist/cjs/src/proxy/types/rest.d.ts +10 -0
  76. package/dist/cjs/src/proxy/types/rest.js +123 -0
  77. package/dist/cjs/src/proxy/types/web.d.ts +8 -0
  78. package/dist/cjs/src/proxy/types/web.js +61 -0
  79. package/dist/cjs/src/repositoryManager.d.ts +35 -0
  80. package/dist/cjs/src/repositoryManager.js +247 -0
  81. package/dist/cjs/src/serviceManager.d.ts +36 -0
  82. package/dist/cjs/src/serviceManager.js +106 -0
  83. package/dist/cjs/src/socketManager.d.ts +32 -0
  84. package/dist/cjs/src/socketManager.js +125 -0
  85. package/dist/cjs/src/storageService.d.ts +21 -0
  86. package/dist/cjs/src/storageService.js +81 -0
  87. package/dist/cjs/src/taskManager.d.ts +70 -0
  88. package/dist/cjs/src/taskManager.js +181 -0
  89. package/dist/cjs/src/tasks/routes.d.ts +7 -0
  90. package/dist/cjs/src/tasks/routes.js +39 -0
  91. package/dist/cjs/src/traffic/routes.d.ts +7 -0
  92. package/dist/cjs/src/traffic/routes.js +22 -0
  93. package/dist/cjs/src/types.d.ts +99 -0
  94. package/dist/cjs/src/types.js +39 -0
  95. package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +28 -0
  96. package/dist/cjs/src/utils/BlockInstanceRunner.js +432 -0
  97. package/dist/cjs/src/utils/DefaultProviderInstaller.d.ts +15 -0
  98. package/dist/cjs/src/utils/DefaultProviderInstaller.js +136 -0
  99. package/dist/cjs/src/utils/InternalConfigProvider.d.ts +38 -0
  100. package/dist/cjs/src/utils/InternalConfigProvider.js +146 -0
  101. package/dist/cjs/src/utils/LogData.d.ts +23 -0
  102. package/dist/cjs/src/utils/LogData.js +46 -0
  103. package/dist/cjs/src/utils/commandLineUtils.d.ts +8 -0
  104. package/dist/cjs/src/utils/commandLineUtils.js +39 -0
  105. package/dist/cjs/src/utils/pathTemplateParser.d.ts +30 -0
  106. package/dist/cjs/src/utils/pathTemplateParser.js +135 -0
  107. package/dist/cjs/src/utils/utils.d.ts +40 -0
  108. package/dist/cjs/src/utils/utils.js +148 -0
  109. package/dist/cjs/start.d.ts +5 -0
  110. package/dist/cjs/start.js +17 -0
  111. package/dist/cjs/test/proxy/types/rest.test.d.ts +5 -0
  112. package/dist/cjs/test/proxy/types/rest.test.js +48 -0
  113. package/dist/cjs/test/utils/pathTemplateParser.test.d.ts +5 -0
  114. package/dist/cjs/test/utils/pathTemplateParser.test.js +27 -0
  115. package/dist/esm/index.d.ts +34 -0
  116. package/dist/esm/index.js +263 -0
  117. package/dist/esm/package.json +1 -0
  118. package/dist/esm/src/RepositoryWatcher.d.ts +30 -0
  119. package/dist/esm/src/RepositoryWatcher.js +332 -0
  120. package/dist/esm/src/ai/aiClient.d.ts +20 -0
  121. package/dist/esm/src/ai/aiClient.js +74 -0
  122. package/dist/esm/src/ai/routes.d.ts +7 -0
  123. package/dist/esm/src/ai/routes.js +37 -0
  124. package/dist/esm/src/ai/transform.d.ts +11 -0
  125. package/dist/esm/src/ai/transform.js +239 -0
  126. package/dist/esm/src/ai/types.d.ts +40 -0
  127. package/dist/esm/src/ai/types.js +2 -0
  128. package/dist/esm/src/api.d.ts +7 -0
  129. package/dist/esm/src/api.js +29 -0
  130. package/dist/esm/src/assetManager.d.ts +41 -0
  131. package/dist/esm/src/assetManager.js +274 -0
  132. package/dist/esm/src/assets/routes.d.ts +7 -0
  133. package/dist/esm/src/assets/routes.js +165 -0
  134. package/dist/esm/src/attachments/routes.d.ts +7 -0
  135. package/dist/esm/src/attachments/routes.js +72 -0
  136. package/dist/esm/src/authManager.d.ts +16 -0
  137. package/dist/esm/src/authManager.js +64 -0
  138. package/dist/esm/src/cacheManager.d.ts +20 -0
  139. package/dist/esm/src/cacheManager.js +51 -0
  140. package/dist/esm/src/clusterService.d.ts +44 -0
  141. package/dist/esm/src/clusterService.js +120 -0
  142. package/dist/esm/src/codeGeneratorManager.d.ts +14 -0
  143. package/dist/esm/src/codeGeneratorManager.js +93 -0
  144. package/dist/esm/src/config/routes.d.ts +7 -0
  145. package/dist/esm/src/config/routes.js +160 -0
  146. package/dist/esm/src/configManager.d.ts +42 -0
  147. package/dist/esm/src/configManager.js +136 -0
  148. package/dist/esm/src/containerManager.d.ts +148 -0
  149. package/dist/esm/src/containerManager.js +958 -0
  150. package/dist/esm/src/definitionsManager.d.ts +20 -0
  151. package/dist/esm/src/definitionsManager.js +171 -0
  152. package/dist/esm/src/filesystem/routes.d.ts +7 -0
  153. package/dist/esm/src/filesystem/routes.js +105 -0
  154. package/dist/esm/src/filesystemManager.d.ts +27 -0
  155. package/dist/esm/src/filesystemManager.js +118 -0
  156. package/dist/esm/src/identities/routes.d.ts +7 -0
  157. package/dist/esm/src/identities/routes.js +37 -0
  158. package/dist/esm/src/instanceManager.d.ts +69 -0
  159. package/dist/esm/src/instanceManager.js +910 -0
  160. package/dist/esm/src/instances/routes.d.ts +7 -0
  161. package/dist/esm/src/instances/routes.js +179 -0
  162. package/dist/esm/src/middleware/cors.d.ts +6 -0
  163. package/dist/esm/src/middleware/cors.js +14 -0
  164. package/dist/esm/src/middleware/kapeta.d.ts +15 -0
  165. package/dist/esm/src/middleware/kapeta.js +28 -0
  166. package/dist/esm/src/middleware/stringBody.d.ts +9 -0
  167. package/dist/esm/src/middleware/stringBody.js +18 -0
  168. package/dist/esm/src/networkManager.d.ts +37 -0
  169. package/dist/esm/src/networkManager.js +119 -0
  170. package/dist/esm/src/operatorManager.d.ts +41 -0
  171. package/dist/esm/src/operatorManager.js +211 -0
  172. package/dist/esm/src/progressListener.d.ts +31 -0
  173. package/dist/esm/src/progressListener.js +133 -0
  174. package/dist/esm/src/providerManager.d.ts +11 -0
  175. package/dist/esm/src/providerManager.js +84 -0
  176. package/dist/esm/src/providers/routes.d.ts +7 -0
  177. package/dist/esm/src/providers/routes.js +46 -0
  178. package/dist/esm/src/proxy/routes.d.ts +7 -0
  179. package/dist/esm/src/proxy/routes.js +115 -0
  180. package/dist/esm/src/proxy/types/rest.d.ts +10 -0
  181. package/dist/esm/src/proxy/types/rest.js +123 -0
  182. package/dist/esm/src/proxy/types/web.d.ts +8 -0
  183. package/dist/esm/src/proxy/types/web.js +61 -0
  184. package/dist/esm/src/repositoryManager.d.ts +35 -0
  185. package/dist/esm/src/repositoryManager.js +247 -0
  186. package/dist/esm/src/serviceManager.d.ts +36 -0
  187. package/dist/esm/src/serviceManager.js +106 -0
  188. package/dist/esm/src/socketManager.d.ts +32 -0
  189. package/dist/esm/src/socketManager.js +125 -0
  190. package/dist/esm/src/storageService.d.ts +21 -0
  191. package/dist/esm/src/storageService.js +81 -0
  192. package/dist/esm/src/taskManager.d.ts +70 -0
  193. package/dist/esm/src/taskManager.js +181 -0
  194. package/dist/esm/src/tasks/routes.d.ts +7 -0
  195. package/dist/esm/src/tasks/routes.js +39 -0
  196. package/dist/esm/src/traffic/routes.d.ts +7 -0
  197. package/dist/esm/src/traffic/routes.js +22 -0
  198. package/dist/esm/src/types.d.ts +99 -0
  199. package/dist/esm/src/types.js +39 -0
  200. package/dist/esm/src/utils/BlockInstanceRunner.d.ts +28 -0
  201. package/dist/esm/src/utils/BlockInstanceRunner.js +432 -0
  202. package/dist/esm/src/utils/DefaultProviderInstaller.d.ts +15 -0
  203. package/dist/esm/src/utils/DefaultProviderInstaller.js +136 -0
  204. package/dist/esm/src/utils/InternalConfigProvider.d.ts +38 -0
  205. package/dist/esm/src/utils/InternalConfigProvider.js +146 -0
  206. package/dist/esm/src/utils/LogData.d.ts +23 -0
  207. package/dist/esm/src/utils/LogData.js +46 -0
  208. package/dist/esm/src/utils/commandLineUtils.d.ts +8 -0
  209. package/dist/esm/src/utils/commandLineUtils.js +39 -0
  210. package/dist/esm/src/utils/pathTemplateParser.d.ts +30 -0
  211. package/dist/esm/src/utils/pathTemplateParser.js +135 -0
  212. package/dist/esm/src/utils/utils.d.ts +40 -0
  213. package/dist/esm/src/utils/utils.js +148 -0
  214. package/dist/esm/start.d.ts +5 -0
  215. package/dist/esm/start.js +17 -0
  216. package/dist/esm/test/proxy/types/rest.test.d.ts +5 -0
  217. package/dist/esm/test/proxy/types/rest.test.js +48 -0
  218. package/dist/esm/test/utils/pathTemplateParser.test.d.ts +5 -0
  219. package/dist/esm/test/utils/pathTemplateParser.test.js +27 -0
  220. package/index.ts +280 -0
  221. package/jest.config.js +8 -0
  222. package/package.json +134 -0
  223. package/src/RepositoryWatcher.ts +363 -0
  224. package/src/ai/aiClient.ts +93 -0
  225. package/src/ai/routes.ts +39 -0
  226. package/src/ai/transform.ts +275 -0
  227. package/src/ai/types.ts +45 -0
  228. package/src/api.ts +32 -0
  229. package/src/assetManager.ts +355 -0
  230. package/src/assets/routes.ts +183 -0
  231. package/src/attachments/routes.ts +79 -0
  232. package/src/authManager.ts +67 -0
  233. package/src/cacheManager.ts +59 -0
  234. package/src/clusterService.ts +142 -0
  235. package/src/codeGeneratorManager.ts +109 -0
  236. package/src/config/routes.ts +201 -0
  237. package/src/configManager.ts +180 -0
  238. package/src/containerManager.ts +1178 -0
  239. package/src/definitionsManager.ts +212 -0
  240. package/src/filesystem/routes.ts +123 -0
  241. package/src/filesystemManager.ts +133 -0
  242. package/src/identities/routes.ts +38 -0
  243. package/src/instanceManager.ts +1160 -0
  244. package/src/instances/routes.ts +203 -0
  245. package/src/middleware/cors.ts +14 -0
  246. package/src/middleware/kapeta.ts +41 -0
  247. package/src/middleware/stringBody.ts +21 -0
  248. package/src/networkManager.ts +148 -0
  249. package/src/operatorManager.ts +294 -0
  250. package/src/progressListener.ts +151 -0
  251. package/src/providerManager.ts +97 -0
  252. package/src/providers/routes.ts +51 -0
  253. package/src/proxy/routes.ts +153 -0
  254. package/src/proxy/types/rest.ts +172 -0
  255. package/src/proxy/types/web.ts +70 -0
  256. package/src/repositoryManager.ts +291 -0
  257. package/src/serviceManager.ts +133 -0
  258. package/src/socketManager.ts +138 -0
  259. package/src/storageService.ts +97 -0
  260. package/src/taskManager.ts +247 -0
  261. package/src/tasks/routes.ts +43 -0
  262. package/src/traffic/routes.ts +23 -0
  263. package/src/types.ts +112 -0
  264. package/src/utils/BlockInstanceRunner.ts +577 -0
  265. package/src/utils/DefaultProviderInstaller.ts +150 -0
  266. package/src/utils/InternalConfigProvider.ts +214 -0
  267. package/src/utils/LogData.ts +50 -0
  268. package/src/utils/commandLineUtils.ts +45 -0
  269. package/src/utils/pathTemplateParser.ts +157 -0
  270. package/src/utils/utils.ts +155 -0
  271. package/start.ts +14 -0
  272. package/test/proxy/types/rest.test.ts +54 -0
  273. package/test/utils/pathTemplateParser.test.ts +29 -0
  274. package/tsconfig.json +15 -0
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+
6
+ import { DefinitionInfo } from '@kapeta/local-cluster-config';
7
+ import Path from 'path';
8
+ import md5 from 'md5';
9
+ import { serviceManager } from './serviceManager';
10
+ import { storageService } from './storageService';
11
+ import {
12
+ COMPOSE_LABEL_PROJECT,
13
+ COMPOSE_LABEL_SERVICE,
14
+ CONTAINER_LABEL_PORT_PREFIX,
15
+ ContainerInfo,
16
+ containerManager,
17
+ } from './containerManager';
18
+ import FSExtra from 'fs-extra';
19
+ import { AnyMap, EnvironmentType, KIND_BLOCK_TYPE_OPERATOR, KIND_RESOURCE_OPERATOR, StringMap } from './types';
20
+ import { BlockInstance, LocalInstance, Resource } from '@kapeta/schemas';
21
+ import { definitionsManager } from './definitionsManager';
22
+ import { getDockerHostIp, getRemoteHostForEnvironment, toPortInfo } from './utils/utils';
23
+ import { parseKapetaUri, normalizeKapetaUri } from '@kapeta/nodejs-utils';
24
+ import _ from 'lodash';
25
+ import AsyncLock from 'async-lock';
26
+ import { taskManager } from './taskManager';
27
+ import { ResourceInfo } from '@kapeta/sdk-config';
28
+
29
+ const KIND_PLAN = 'core/plan';
30
+
31
+ class Operator {
32
+ private readonly _data: DefinitionInfo;
33
+
34
+ constructor(data: DefinitionInfo) {
35
+ this._data = data;
36
+ }
37
+
38
+ getLocalData(): LocalInstance {
39
+ return this._data.definition.spec.local;
40
+ }
41
+
42
+ getDefinitionInfo() {
43
+ return this._data;
44
+ }
45
+
46
+ getCredentials() {
47
+ return this._data.definition.spec.local.credentials;
48
+ }
49
+ }
50
+
51
+ class OperatorManager {
52
+ private _mountDir: string;
53
+
54
+ private operatorLock: AsyncLock = new AsyncLock();
55
+
56
+ constructor() {
57
+ this._mountDir = Path.join(storageService.getKapetaBasedir(), 'mounts');
58
+
59
+ FSExtra.mkdirpSync(this._mountDir);
60
+ }
61
+
62
+ _getMountPoint(operatorType: string, mountName: string) {
63
+ return Path.join(this._mountDir, operatorType, mountName);
64
+ }
65
+
66
+ /**
67
+ * Get operator definition for resource type
68
+ */
69
+ async getOperator(fullName: string, version: string) {
70
+ const operators = await definitionsManager.getDefinitions([KIND_RESOURCE_OPERATOR, KIND_BLOCK_TYPE_OPERATOR]);
71
+
72
+ const operator: DefinitionInfo | undefined = operators.find(
73
+ (operator) =>
74
+ operator.definition &&
75
+ operator.definition.metadata &&
76
+ operator.definition.metadata.name &&
77
+ operator.definition.metadata.name.toLowerCase() === fullName.toLowerCase() &&
78
+ operator.version === version
79
+ );
80
+
81
+ if (!operator) {
82
+ throw new Error(`Unknown operator type: ${fullName}:${version}`);
83
+ }
84
+
85
+ if (!operator.definition.spec || !operator.definition.spec.local) {
86
+ throw new Error(`Operator missing local definition: ${fullName}:${version}`);
87
+ }
88
+
89
+ return new Operator(operator);
90
+ }
91
+
92
+ /**
93
+ * Get information about a specific consumed resource
94
+ */
95
+ async getConsumerResourceInfo(
96
+ systemId: string,
97
+ fromServiceId: string,
98
+ resourceType: string,
99
+ portType: string,
100
+ name: string,
101
+ environment?: EnvironmentType,
102
+ ensureContainer: boolean = true
103
+ ): Promise<ResourceInfo<any, any>> {
104
+ systemId = normalizeKapetaUri(systemId);
105
+ const plans = await definitionsManager.getDefinitions(KIND_PLAN);
106
+
107
+ const planUri = parseKapetaUri(systemId);
108
+ const currentPlan = plans.find(
109
+ (plan) => plan.definition.metadata.name === planUri.fullName && plan.version === planUri.version
110
+ );
111
+ if (!currentPlan) {
112
+ throw new Error(`Unknown plan: ${systemId}`);
113
+ }
114
+
115
+ const currentInstance = currentPlan.definition.spec.blocks?.find(
116
+ (instance: BlockInstance) => instance.id === fromServiceId
117
+ );
118
+ if (!currentInstance) {
119
+ throw new Error(`Unknown instance: ${fromServiceId} in plan ${systemId}`);
120
+ }
121
+
122
+ const blockDefinition = await definitionsManager.getDefinition(currentInstance.block.ref);
123
+
124
+ if (!blockDefinition) {
125
+ throw new Error(`Unknown block: ${currentInstance.block.ref} in plan ${systemId}`);
126
+ }
127
+
128
+ const blockResource = blockDefinition.definition.spec?.consumers?.find((resource: Resource) => {
129
+ if (resource.metadata.name !== name) {
130
+ return false;
131
+ }
132
+ return parseKapetaUri(resource.kind).fullName === resourceType;
133
+ });
134
+
135
+ if (!blockResource) {
136
+ throw new Error(`Unknown resource: ${name} in block ${currentInstance.block.ref} in plan ${systemId}`);
137
+ }
138
+
139
+ const kindUri = parseKapetaUri(blockResource.kind);
140
+ const operator = await this.getOperator(resourceType, kindUri.version);
141
+ const credentials = operator.getCredentials();
142
+ if (ensureContainer) {
143
+ await this.ensureOperator(systemId, resourceType, kindUri.version);
144
+ }
145
+
146
+ const hostPort = await serviceManager.ensureServicePort(systemId, resourceType, portType);
147
+
148
+ if (!hostPort) {
149
+ throw new Error('Unknown resource port type : ' + resourceType + '#' + portType);
150
+ }
151
+
152
+ const dbName = name + '_' + fromServiceId.replace(/[^a-z0-9]/gi, '');
153
+ const safeName = dbName.replace('_', '-');
154
+
155
+ return {
156
+ host: getRemoteHostForEnvironment(environment),
157
+ port: hostPort,
158
+ type: portType,
159
+ protocol: 'tcp',
160
+ options: {
161
+ // expose as fullName since that is not operator specific, but unique
162
+ fullName: safeName,
163
+ dbName,
164
+ },
165
+ credentials,
166
+ };
167
+ }
168
+
169
+ async getOperatorPorts(systemId: string, kind: string, version: string) {
170
+ const operator = await this.getOperator(kind, version);
171
+
172
+ const operatorData = operator.getLocalData();
173
+
174
+ const portTypes = Object.keys(operatorData.ports);
175
+
176
+ portTypes.sort();
177
+
178
+ const ports: AnyMap = {};
179
+
180
+ for (let i = 0; i < portTypes.length; i++) {
181
+ const portType = portTypes[i];
182
+ let containerPortInfo = operatorData.ports[portType];
183
+ const hostPort = await serviceManager.ensureServicePort(systemId, kind, portType);
184
+ const portInfo = toPortInfo(containerPortInfo);
185
+ const portId = portInfo.port + '/' + portInfo.type;
186
+
187
+ ports[portId] = {
188
+ type: portType,
189
+ hostPort,
190
+ protocol: portInfo.type,
191
+ };
192
+ }
193
+
194
+ return ports;
195
+ }
196
+
197
+ /**
198
+ * Ensure we have a running operator of given type
199
+ *
200
+ * @param systemId the plan ref
201
+ * @param kind the full name - e.g. myhandle/rabbitmq
202
+ * @param version the version of the operator
203
+ */
204
+ async ensureOperator(systemId: string, kind: string, version: string): Promise<ContainerInfo> {
205
+ systemId = normalizeKapetaUri(systemId);
206
+
207
+ const key = `${systemId}#${kind}:${version}`;
208
+
209
+ return await this.operatorLock.acquire(key, async () => {
210
+ const operator = await this.getOperator(kind, version);
211
+
212
+ const operatorData = operator.getLocalData();
213
+
214
+ const ports = await this.getOperatorPorts(systemId, kind, version);
215
+
216
+ const nameParts = [systemId, kind.toLowerCase(), version];
217
+
218
+ const containerName = `kapeta-resource-${md5(nameParts.join('_'))}`;
219
+
220
+ const PortBindings: { [key: string]: any } = {};
221
+ const Env: string[] = [];
222
+
223
+ const systemUri = parseKapetaUri(systemId);
224
+
225
+ const Labels: StringMap = {
226
+ kapeta: 'true',
227
+ [COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
228
+ [COMPOSE_LABEL_SERVICE]: [kind, version].join('_').replace(/[^a-z0-9]/gi, '_'),
229
+ };
230
+
231
+ const operatorMetadata = operator.getDefinitionInfo().definition.metadata;
232
+
233
+ const hostIp = getDockerHostIp();
234
+
235
+ const ExposedPorts: { [key: string]: any } = {};
236
+
237
+ _.forEach(ports, (portInfo: any, containerPort) => {
238
+ ExposedPorts['' + containerPort] = {};
239
+ PortBindings['' + containerPort] = [
240
+ {
241
+ HostPort: '' + portInfo.hostPort,
242
+ HostIp: hostIp,
243
+ },
244
+ ];
245
+
246
+ Labels[CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
247
+ });
248
+
249
+ const Mounts = await containerManager.createVolumes(systemId, kind, operatorData.mounts);
250
+
251
+ _.forEach(operatorData.env, (value, name) => {
252
+ Env.push(name + '=' + value);
253
+ });
254
+
255
+ const task = taskManager.add(
256
+ `operator:ensure:${key}`,
257
+ async () => {
258
+ let HealthCheck = undefined;
259
+
260
+ if (operatorData.health) {
261
+ HealthCheck = containerManager.toDockerHealth(operatorData.health);
262
+ }
263
+
264
+ const container = await containerManager.ensureContainer({
265
+ name: containerName,
266
+ Image: operatorData.image,
267
+ Hostname: containerName + '.kapeta',
268
+ Labels,
269
+ Cmd: operatorData.cmd,
270
+ ExposedPorts,
271
+ Env,
272
+ HealthCheck,
273
+ HostConfig: {
274
+ PortBindings,
275
+ Mounts,
276
+ },
277
+ });
278
+
279
+ await containerManager.waitForReady(container);
280
+
281
+ return new ContainerInfo(container);
282
+ },
283
+ {
284
+ name: `Ensuring ${operatorMetadata.title ?? operatorMetadata.name}`,
285
+ systemId,
286
+ }
287
+ );
288
+
289
+ return task.wait();
290
+ });
291
+ }
292
+ }
293
+
294
+ export const operatorManager = new OperatorManager();
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+
6
+ import { spawn } from '@kapeta/nodejs-process';
7
+ import { socketManager } from './socketManager';
8
+ import { LogEntry } from './types';
9
+ import { format } from 'node:util';
10
+ import { Task } from './taskManager';
11
+
12
+ export class ProgressListener {
13
+ private readonly systemId: string | undefined;
14
+ private readonly instanceId: string | undefined;
15
+
16
+ constructor(systemId?: string, instanceId?: string) {
17
+ this.systemId = systemId;
18
+ this.instanceId = instanceId;
19
+ }
20
+
21
+ protected emitLog(payload: Omit<LogEntry, 'time' | 'source'>) {
22
+ const logEntry: LogEntry = {
23
+ ...payload,
24
+ source: 'stdout',
25
+ time: Date.now(),
26
+ };
27
+ if (this.systemId && this.instanceId) {
28
+ socketManager.emitInstanceLog(this.systemId, this.instanceId, logEntry);
29
+ return;
30
+ }
31
+
32
+ if (this.systemId) {
33
+ socketManager.emitSystemLog(this.systemId, logEntry);
34
+ return;
35
+ }
36
+
37
+ socketManager.emitGlobalLog(logEntry);
38
+ }
39
+
40
+ run(command: string, directory?: string): Promise<{ exit: number; signal: NodeJS.Signals | null; output: string }> {
41
+ this.info(`Running command "${command}"`);
42
+
43
+ return new Promise(async (resolve, reject) => {
44
+ try {
45
+ const chunks: Buffer[] = [];
46
+ const child = spawn(command, [], {
47
+ cwd: directory ? directory : process.cwd(),
48
+ shell: true,
49
+ });
50
+
51
+ child.onData((data) => {
52
+ this.emitLog({
53
+ level: data.type === 'stdout' ? 'INFO' : 'WARN',
54
+ message: data.line,
55
+ });
56
+ });
57
+
58
+ if (child.process.stdout) {
59
+ child.process.stdout.on('data', (data) => {
60
+ chunks.push(data);
61
+ });
62
+ }
63
+
64
+ child.process.on('exit', (exit, signal) => {
65
+ if (exit !== 0) {
66
+ this.warn(`Command "${command}" failed: ${exit}`);
67
+ reject(new Error(`Command "${command}" exited with code ${exit}`));
68
+ } else {
69
+ this.info(`Command OK: "${command}"`);
70
+ resolve({ exit, signal, output: Buffer.concat(chunks).toString() });
71
+ }
72
+ });
73
+
74
+ child.process.on('error', (err) => {
75
+ this.warn(`"${command}" failed: "${err.message}"`);
76
+ reject(err);
77
+ });
78
+
79
+ await child.wait();
80
+ } catch (e) {
81
+ reject(e);
82
+ }
83
+ });
84
+ }
85
+
86
+ async progress(label: string, callback: () => void | Promise<void>) {
87
+ this.info(`${label}: started`);
88
+ try {
89
+ const result = await callback();
90
+ this.info(`${label}: done`);
91
+ return result;
92
+ } catch (e: any) {
93
+ this.warn(`${label}: failed. ${e.message}`);
94
+ throw e;
95
+ }
96
+ }
97
+
98
+ async check(message: string, ok: boolean | Promise<boolean> | (() => Promise<boolean>)) {
99
+ const wasOk = await ok;
100
+ this.info(`${message}: ${wasOk}`);
101
+ }
102
+
103
+ start(label: string) {
104
+ this.info(label);
105
+ }
106
+
107
+ showValue(label: string, value: any) {
108
+ this.info(`${label}: ${value}`);
109
+ }
110
+
111
+ error(msg: string, ...args: any[]) {
112
+ this.emitLog({
113
+ message: format(msg, args),
114
+ level: 'ERROR',
115
+ });
116
+ }
117
+
118
+ warn(msg: string, ...args: any[]) {
119
+ this.emitLog({
120
+ message: format(msg, args),
121
+ level: 'WARN',
122
+ });
123
+ }
124
+
125
+ info(msg: string, ...args: any[]) {
126
+ this.emitLog({
127
+ message: format(msg, args),
128
+ level: 'INFO',
129
+ });
130
+ }
131
+
132
+ debug(msg: string, ...args: any[]) {
133
+ this.emitLog({
134
+ message: format(msg, args),
135
+ level: 'DEBUG',
136
+ });
137
+ }
138
+ }
139
+
140
+ export class TaskProgressListener extends ProgressListener {
141
+ private readonly task: Task;
142
+
143
+ constructor(task: Task) {
144
+ super();
145
+ this.task = task;
146
+ }
147
+
148
+ protected emitLog(payload: Omit<LogEntry, 'time' | 'source'>) {
149
+ this.task.addLog(payload.message, payload.level);
150
+ }
151
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+
6
+ import Path from 'path';
7
+ import FSExtra from 'fs-extra';
8
+ import { definitionsManager } from './definitionsManager';
9
+ import { cacheManager } from './cacheManager';
10
+ import request from 'request';
11
+ import { DefinitionInfo } from '@kapeta/local-cluster-config';
12
+
13
+ const PROVIDER_FILE_BASE = 'https://providers.kapeta.com/files';
14
+
15
+ class ProviderManager {
16
+ async getWebProviders(): Promise<DefinitionInfo[]> {
17
+ const providers = await definitionsManager.getProviderDefinitions();
18
+ return providers.filter((providerDefinition) => providerDefinition.hasWeb);
19
+ }
20
+
21
+ async getProviderWebJS(handle: string, name: string, version: string, sourceMap: boolean = false) {
22
+ const fullName = `${handle}/${name}`;
23
+ const id = `${handle}/${name}/${version}/web.js${sourceMap ? '.map' : ''}`;
24
+
25
+ const cacheKey = `provider:web:${id}`;
26
+
27
+ const file = cacheManager.get<string>(cacheKey);
28
+ if (file && (await FSExtra.pathExists(file))) {
29
+ return FSExtra.readFile(file, 'utf8');
30
+ }
31
+
32
+ const providers = await this.getWebProviders();
33
+ const installedProvider = providers.find((providerDefinition) => {
34
+ return providerDefinition.definition.metadata.name === fullName && providerDefinition.version === version;
35
+ });
36
+
37
+ if (installedProvider) {
38
+ //Check locally installed providers
39
+ const path = Path.join(installedProvider.path, 'web', handle, `${name}.js${sourceMap ? '.map' : ''}`);
40
+ if (await FSExtra.pathExists(path)) {
41
+ cacheManager.set(cacheKey, path, 24 * 60 * 60 * 1000);
42
+ return FSExtra.readFile(path);
43
+ }
44
+ }
45
+
46
+ if (version === 'local') {
47
+ return null;
48
+ }
49
+
50
+ const url = `${PROVIDER_FILE_BASE}/${id}`;
51
+ return new Promise((resolve, reject) => {
52
+ console.log('Loading provider from %s', url);
53
+ request.get(url, (error, response, body) => {
54
+ if (error) {
55
+ reject(error);
56
+ return;
57
+ }
58
+ if (response.statusCode === 404) {
59
+ resolve(null);
60
+ return;
61
+ }
62
+
63
+ if (response.statusCode !== 200) {
64
+ reject(new Error(`Failed to load provider from ${url}: ${body}`));
65
+ return;
66
+ }
67
+
68
+ resolve(body);
69
+ });
70
+ });
71
+ }
72
+ }
73
+
74
+ definitionsManager
75
+ .getProviderDefinitions()
76
+ .then((providerDefinitions) => {
77
+ if (providerDefinitions.length > 0) {
78
+ console.log('## Loaded the following providers ##');
79
+ providerDefinitions.forEach((providerDefinition) => {
80
+ console.log(
81
+ ' - %s[%s:%s]',
82
+ providerDefinition.definition.kind,
83
+ providerDefinition.definition.metadata.name,
84
+ providerDefinition.version
85
+ );
86
+ console.log(' from %s', providerDefinition.path);
87
+ });
88
+ console.log('##');
89
+ } else {
90
+ console.log('## No providers found ##');
91
+ }
92
+ })
93
+ .catch((e) => {
94
+ console.error('Failed to load providers', e);
95
+ });
96
+
97
+ export const providerManager = new ProviderManager();
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+
6
+ import Router from 'express-promise-router';
7
+ import { providerManager } from '../providerManager';
8
+
9
+ import { corsHandler } from '../middleware/cors';
10
+ import { Request, Response } from 'express';
11
+
12
+ const router = Router();
13
+
14
+ router.use('/', corsHandler);
15
+
16
+ router.get('/', async (req: Request, res: Response) => {
17
+ const result = await providerManager.getWebProviders();
18
+
19
+ res.send(result);
20
+ });
21
+
22
+ router.get('/asset/:handle/:name/:version/web.js', async (req: Request, res: Response) => {
23
+ const { handle, name, version } = req.params;
24
+ let result = await providerManager.getProviderWebJS(handle, name, version);
25
+
26
+ if (!result) {
27
+ res.status(404).send('');
28
+ } else {
29
+ if (version !== 'local') {
30
+ res.setHeader('Cache-Control', 'max-age=31536000, immutable');
31
+ }
32
+ res.send(result.toString().replace(`${name}.js.map`, 'web.js.map'));
33
+ }
34
+ });
35
+
36
+ router.get('/asset/:handle/:name/:version/web.js.map', async (req: Request, res: Response) => {
37
+ const { handle, name, version } = req.params;
38
+ const result = await providerManager.getProviderWebJS(handle, name, version, true);
39
+
40
+ if (!result) {
41
+ res.status(404).send('');
42
+ } else {
43
+ // Only cache successful requests
44
+ if (version !== 'local') {
45
+ res.setHeader('Cache-Control', 'max-age=31536000, immutable');
46
+ }
47
+ res.send(result);
48
+ }
49
+ });
50
+
51
+ export default router;