@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,164 @@
1
+ import Router from 'express-promise-router';
2
+ import { instanceManager } from '../instanceManager';
3
+ import { serviceManager } from '../serviceManager';
4
+ import { corsHandler } from '../middleware/cors';
5
+ import { NextFunction, Request, Response } from 'express';
6
+ import { kapetaHeaders, KapetaRequest } from '../middleware/kapeta';
7
+ import { stringBody } from '../middleware/stringBody';
8
+ import { EnvironmentType, KapetaBodyRequest } from '../types';
9
+
10
+ const router = Router();
11
+ router.use('/', corsHandler);
12
+ router.use('/', kapetaHeaders);
13
+ /**
14
+ * Get all instances
15
+ */
16
+ router.get('/', (req: Request, res: Response) => {
17
+ res.send(instanceManager.getInstances());
18
+ });
19
+
20
+ /**
21
+ * Get all instances
22
+ */
23
+ router.get('/:systemId/instances', (req: Request, res: Response) => {
24
+ res.send(instanceManager.getInstancesForPlan(req.params.systemId));
25
+ });
26
+
27
+ /**
28
+ * Start all instances in a plan
29
+ */
30
+ router.post('/:systemId/start', async (req: Request, res: Response) => {
31
+ const processes = await instanceManager.createProcessesForPlan(req.params.systemId);
32
+
33
+ res.status(202).send({
34
+ ok: true,
35
+ processes: processes.map((p) => {
36
+ return { pid: p.pid, type: p.type };
37
+ }),
38
+ });
39
+ });
40
+
41
+ /**
42
+ * Stop all instances in plan
43
+ */
44
+ router.post('/:systemId/stop', async (req: Request, res: Response) => {
45
+ await instanceManager.stopAllForPlan(req.params.systemId);
46
+
47
+ res.status(202).send({
48
+ ok: true,
49
+ });
50
+ });
51
+
52
+ /**
53
+ * Start single instance in a plan
54
+ */
55
+ router.post('/:systemId/:instanceId/start', async (req: Request, res: Response) => {
56
+ const process = await instanceManager.createProcess(req.params.systemId, req.params.instanceId);
57
+
58
+ res.status(202).send({
59
+ ok: true,
60
+ pid: process.pid,
61
+ type: process.type,
62
+ });
63
+ });
64
+
65
+ /**
66
+ * Stop single instance in a plan
67
+ */
68
+ router.post('/:systemId/:instanceId/stop', async (req: Request, res: Response) => {
69
+ await instanceManager.stopProcess(req.params.systemId, req.params.instanceId);
70
+
71
+ res.status(202).send({ ok: true });
72
+ });
73
+
74
+ /**
75
+ * Get logs for instance in a plan
76
+ */
77
+ router.get('/:systemId/:instanceId/logs', (req: Request, res: Response) => {
78
+ const processInfo = instanceManager.getProcessForInstance(req.params.systemId, req.params.instanceId);
79
+ if (!processInfo) {
80
+ res.status(404).send({ ok: false });
81
+ return;
82
+ }
83
+
84
+ res.status(202).send({
85
+ logs: processInfo.logs(),
86
+ });
87
+ });
88
+
89
+ /**
90
+ * Get public address for instance in a plan if available
91
+ */
92
+ router.get('/:systemId/:instanceId/address/public', (req: Request, res: Response) => {
93
+ const instance = instanceManager.getInstance(req.params.systemId, req.params.instanceId);
94
+ if (!instance) {
95
+ res.status(404).send({ ok: false });
96
+ return;
97
+ }
98
+
99
+ if (!instance.address) {
100
+ res.status(400).send({ error: `Instance does not have an address. Make sure it's running.` });
101
+ return;
102
+ }
103
+
104
+ res.status(200).send(instance.address);
105
+ });
106
+
107
+ /**
108
+ * Get public address for particular resource on instance in a plan if available
109
+ */
110
+ router.get(
111
+ '/:systemId/:instanceId/provider/:portType/:resourceName/address/public',
112
+ (req: KapetaRequest, res: Response) => {
113
+ res.send(
114
+ serviceManager.getConsumerAddress(
115
+ req.params.systemId,
116
+ req.params.instanceId,
117
+ req.params.resourceName,
118
+ req.params.portType,
119
+ req.kapeta?.environment
120
+ )
121
+ );
122
+ }
123
+ );
124
+
125
+ router.use('/', stringBody);
126
+ router.use('/', (req: KapetaBodyRequest, res: Response, next: NextFunction) => {
127
+ if (!req.kapeta!.blockRef) {
128
+ res.status(400).send({ error: 'Missing X-Kapeta-Block header.' });
129
+ return;
130
+ }
131
+ next();
132
+ });
133
+
134
+ /**
135
+ * Updates the full configuration for a given service.
136
+ */
137
+ router.put('/', async (req: KapetaBodyRequest, res: Response) => {
138
+ let instance = req.stringBody ? JSON.parse(req.stringBody) : null;
139
+ if (req.kapeta!.environment === 'docker') {
140
+ //A bit hacky but we want to avoid overwriting the docker PID with a process PID
141
+ const oldInstance = instanceManager.getInstance(req.kapeta!.systemId, req.kapeta!.instanceId);
142
+ if (oldInstance) {
143
+ instance.pid = oldInstance.pid;
144
+ }
145
+ instance.type = 'docker';
146
+ } else if (req.kapeta!.environment === 'process') {
147
+ instance.type = 'process';
148
+ }
149
+
150
+ await instanceManager.registerInstance(req.kapeta!.systemId, req.kapeta!.instanceId, instance);
151
+
152
+ res.status(202).send({ ok: true });
153
+ });
154
+
155
+ /**
156
+ * Delete instance
157
+ */
158
+ router.delete('/', async (req: KapetaRequest, res: Response) => {
159
+ await instanceManager.setInstanceAsStopped(req.kapeta!.systemId, req.kapeta!.instanceId);
160
+
161
+ res.status(202).send({ ok: true });
162
+ });
163
+
164
+ export default router;
@@ -0,0 +1,9 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+
3
+ export function corsHandler(req: Request, res: Response, next: NextFunction) {
4
+ res.set('Access-Control-Allow-Origin', req.headers.origin);
5
+ res.set('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, HEAD, PATCH');
6
+ res.set('Access-Control-Allow-Headers', '*');
7
+
8
+ next();
9
+ }
@@ -0,0 +1,27 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ import { EnvironmentType } from '../types';
3
+
4
+ export interface KapetaRequest extends Request {
5
+ kapeta?: {
6
+ blockRef: string;
7
+ instanceId: string;
8
+ systemId: string;
9
+ environment?: EnvironmentType;
10
+ };
11
+ }
12
+
13
+ export function kapetaHeaders(req: KapetaRequest, res: Response, next: NextFunction) {
14
+ let blockRef: string = req.headers['x-kapeta-block'] as string;
15
+ let systemId: string = req.headers['x-kapeta-system'] as string;
16
+ let instanceId: string = req.headers['x-kapeta-instance'] as string;
17
+ let environment: string = req.headers['x-kapeta-environment'] as string;
18
+
19
+ req.kapeta = {
20
+ blockRef,
21
+ instanceId,
22
+ systemId,
23
+ environment: environment ? (environment as EnvironmentType) : undefined,
24
+ };
25
+
26
+ next();
27
+ }
@@ -0,0 +1,16 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+
3
+ export type StringBodyRequest = Request<any> & {
4
+ stringBody?: string;
5
+ };
6
+
7
+ export function stringBody(req: StringBodyRequest, res: Response, next: NextFunction) {
8
+ // push the data to body
9
+ const body: Buffer[] = [];
10
+ req.on('data', (chunk) => {
11
+ body.push(chunk);
12
+ }).on('end', () => {
13
+ req.stringBody = Buffer.concat(body).toString();
14
+ next();
15
+ });
16
+ }
@@ -0,0 +1,137 @@
1
+ import uuid from 'node-uuid';
2
+ import { Connection, SimpleRequest, SimpleResponse } from './types';
3
+ import express from 'express';
4
+
5
+ class NetworkManager {
6
+ private _connections: { [systemId: string]: { [connectionId: string]: Traffic[] } };
7
+ private _sources: { [systemId: string]: { [instanceId: string]: Traffic[] } };
8
+ private _targets: { [systemId: string]: { [instanceId: string]: Traffic[] } };
9
+
10
+ static toConnectionId(connection: Connection) {
11
+ return [
12
+ connection.provider.blockId,
13
+ connection.provider.resourceName,
14
+ connection.consumer.blockId,
15
+ connection.consumer.resourceName,
16
+ ].join('_');
17
+ }
18
+
19
+ constructor() {
20
+ this._connections = {};
21
+ this._sources = {};
22
+ this._targets = {};
23
+ }
24
+
25
+ _ensureSystem(systemId: string) {
26
+ if (!this._connections[systemId]) {
27
+ this._connections[systemId] = {};
28
+ }
29
+
30
+ if (!this._sources[systemId]) {
31
+ this._sources[systemId] = {};
32
+ }
33
+
34
+ if (!this._targets[systemId]) {
35
+ this._targets[systemId] = {};
36
+ }
37
+ }
38
+
39
+ _ensureConnection(systemId: string, connectionId: string) {
40
+ this._ensureSystem(systemId);
41
+
42
+ if (!this._connections[systemId][connectionId]) {
43
+ this._connections[systemId][connectionId] = [];
44
+ }
45
+
46
+ return this._connections[systemId][connectionId];
47
+ }
48
+
49
+ _ensureSource(systemId: string, sourceBlockInstanceId: string) {
50
+ this._ensureSystem(systemId);
51
+
52
+ if (!this._sources[systemId][sourceBlockInstanceId]) {
53
+ this._sources[systemId][sourceBlockInstanceId] = [];
54
+ }
55
+
56
+ return this._sources[systemId][sourceBlockInstanceId];
57
+ }
58
+
59
+ _ensureTarget(systemId: string, targetBlockInstanceId: string) {
60
+ this._ensureSystem(systemId);
61
+
62
+ if (!this._targets[systemId][targetBlockInstanceId]) {
63
+ this._targets[systemId][targetBlockInstanceId] = [];
64
+ }
65
+
66
+ return this._targets[systemId][targetBlockInstanceId];
67
+ }
68
+
69
+ addRequest(
70
+ systemId: string,
71
+ connection: Connection,
72
+ request: SimpleRequest,
73
+ consumerMethodId?: string,
74
+ providerMethodId?: string
75
+ ) {
76
+ const traffic = new Traffic(connection, request, consumerMethodId, providerMethodId);
77
+
78
+ this._ensureConnection(systemId, traffic.connectionId).push(traffic);
79
+ this._ensureSource(systemId, connection.provider.blockId).push(traffic);
80
+ this._ensureTarget(systemId, connection.consumer.blockId).push(traffic);
81
+
82
+ return traffic;
83
+ }
84
+
85
+ getTrafficForConnection(systemId: string, connectionId: string) {
86
+ return this._ensureConnection(systemId, connectionId);
87
+ }
88
+
89
+ getTrafficForSource(systemId: string, blockInstanceId: string) {
90
+ return this._ensureSource(systemId, blockInstanceId);
91
+ }
92
+
93
+ getTrafficForTarget(systemId: string, blockInstanceId: string) {
94
+ return this._ensureTarget(systemId, blockInstanceId);
95
+ }
96
+ }
97
+
98
+ class Traffic {
99
+ public readonly id: string;
100
+ public readonly connectionId: string;
101
+ public readonly consumerMethodId: string | undefined;
102
+ public readonly providerMethodId: string | undefined;
103
+ public readonly created: number;
104
+ public readonly request: SimpleRequest;
105
+ public ended: null | number;
106
+ public error: null | string;
107
+ public response: SimpleResponse | null;
108
+
109
+ constructor(connection: Connection, request: SimpleRequest, consumerMethodId?: string, providerMethodId?: string) {
110
+ this.id = uuid.v4();
111
+ this.connectionId = NetworkManager.toConnectionId(connection);
112
+ this.consumerMethodId = consumerMethodId;
113
+ this.providerMethodId = providerMethodId;
114
+ this.request = request;
115
+ this.response = null;
116
+ this.error = null;
117
+ this.ended = null;
118
+ this.created = new Date().getTime();
119
+ }
120
+
121
+ asError(err: any) {
122
+ this.ended = new Date().getTime();
123
+ this.response = {
124
+ code: 0,
125
+ headers: {},
126
+ body: null,
127
+ };
128
+ this.error = err + '';
129
+ }
130
+
131
+ withResponse(response: SimpleResponse) {
132
+ this.ended = new Date().getTime();
133
+ this.response = response;
134
+ }
135
+ }
136
+
137
+ export const networkManager = new NetworkManager();
@@ -0,0 +1,221 @@
1
+ import ClusterConfiguration, { DefinitionInfo } from '@kapeta/local-cluster-config';
2
+ import _ from 'lodash';
3
+ import Path from 'path';
4
+ import md5 from 'md5';
5
+ import { parseKapetaUri } from '@kapeta/nodejs-utils';
6
+ import { serviceManager } from './serviceManager';
7
+ import { storageService } from './storageService';
8
+ import { ContainerInfo, containerManager } from './containerManager';
9
+ import FSExtra from 'fs-extra';
10
+ import { AnyMap, EnvironmentType, OperatorInfo } from './types';
11
+ import { BlockInstance, BlockResource, Resource } from '@kapeta/schemas';
12
+
13
+ const KIND_OPERATOR = 'core/resource-type-operator';
14
+
15
+ class Operator {
16
+ private _data: any;
17
+ constructor(data: any) {
18
+ this._data = data;
19
+ }
20
+
21
+ getData() {
22
+ return this._data;
23
+ }
24
+
25
+ getCredentials() {
26
+ return this._data.credentials;
27
+ }
28
+ }
29
+
30
+ class OperatorManager {
31
+ private _mountDir: string;
32
+
33
+ constructor() {
34
+ this._mountDir = Path.join(storageService.getKapetaBasedir(), 'mounts');
35
+
36
+ FSExtra.mkdirpSync(this._mountDir);
37
+ }
38
+
39
+ _getMountPoint(operatorType: string, mountName: string) {
40
+ return Path.join(this._mountDir, operatorType, mountName);
41
+ }
42
+
43
+ /**
44
+ * Get operator definition for resource type
45
+ *
46
+ * @param {string} resourceType
47
+ * @param {string} version
48
+ * @return {Operator}
49
+ */
50
+ getOperator(resourceType: string, version: string) {
51
+ const operators = ClusterConfiguration.getDefinitions(KIND_OPERATOR);
52
+
53
+ const operator: DefinitionInfo | undefined = operators.find(
54
+ (operator) =>
55
+ operator.definition &&
56
+ operator.definition.metadata &&
57
+ operator.definition.metadata.name &&
58
+ operator.definition.metadata.name.toLowerCase() === resourceType.toLowerCase() &&
59
+ operator.version === version
60
+ );
61
+
62
+ if (!operator) {
63
+ throw new Error(`Unknown resource type: ${resourceType}:${version}`);
64
+ }
65
+
66
+ if (!operator.definition.spec || !operator.definition.spec.local) {
67
+ throw new Error(`Operator missing local definition: ${resourceType}:${version}`);
68
+ }
69
+
70
+ return new Operator(operator.definition.spec.local);
71
+ }
72
+
73
+ /**
74
+ * Get information about a specific consumed resource
75
+ */
76
+ async getConsumerResourceInfo(
77
+ systemId: string,
78
+ fromServiceId: string,
79
+ resourceType: string,
80
+ portType: string,
81
+ name: string,
82
+ environment?: EnvironmentType
83
+ ): Promise<OperatorInfo> {
84
+ const plans = ClusterConfiguration.getDefinitions('core/plan');
85
+
86
+ const planUri = parseKapetaUri(systemId);
87
+ const currentPlan = plans.find(
88
+ (plan) => plan.definition.metadata.name === planUri.fullName && plan.version === planUri.version
89
+ );
90
+ if (!currentPlan) {
91
+ throw new Error(`Unknown plan: ${systemId}`);
92
+ }
93
+
94
+ const currentInstance = currentPlan.definition.spec.blocks?.find(
95
+ (instance: BlockInstance) => instance.id === fromServiceId
96
+ );
97
+ if (!currentInstance) {
98
+ throw new Error(`Unknown instance: ${fromServiceId} in plan ${systemId}`);
99
+ }
100
+
101
+ const blockUri = parseKapetaUri(currentInstance.block.ref);
102
+ const blockDefinition = ClusterConfiguration.getDefinitions().find(
103
+ (definition) =>
104
+ definition.version === blockUri.version && definition.definition.metadata.name === blockUri.fullName
105
+ );
106
+
107
+ if (!blockDefinition) {
108
+ throw new Error(`Unknown block: ${currentInstance.block.ref} in plan ${systemId}`);
109
+ }
110
+
111
+ const blockResource = blockDefinition.definition.spec?.consumers?.find(
112
+ (resource: Resource) => resource.metadata.name === name
113
+ );
114
+ if (!blockResource) {
115
+ throw new Error(`Unknown resource: ${name} in block ${currentInstance.block.ref} in plan ${systemId}`);
116
+ }
117
+
118
+ const kindUri = parseKapetaUri(blockResource.kind);
119
+ const operator = this.getOperator(resourceType, kindUri.version);
120
+ const credentials = operator.getCredentials();
121
+ const container = await this.ensureResource(systemId, resourceType, kindUri.version);
122
+ const portInfo = await container.getPort(portType);
123
+
124
+ if (!portInfo) {
125
+ throw new Error('Unknown resource port type : ' + resourceType + '#' + portType);
126
+ }
127
+
128
+ const dbName = name + '_' + fromServiceId.replace(/[^a-z0-9]/gi, '');
129
+
130
+ return {
131
+ host: environment === 'docker' ? 'host.docker.internal' : '127.0.0.1',
132
+ port: portInfo.hostPort,
133
+ type: portType,
134
+ protocol: portInfo.protocol,
135
+ options: {
136
+ dbName,
137
+ },
138
+ credentials,
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Ensure we have a running operator of given type
144
+ *
145
+ * @param {string} systemId
146
+ * @param {string} resourceType
147
+ * @param {string} version
148
+ * @return {Promise<ContainerInfo>}
149
+ */
150
+ async ensureResource(systemId: string, resourceType: string, version: string): Promise<ContainerInfo> {
151
+ const operator = this.getOperator(resourceType, version);
152
+
153
+ const operatorData = operator.getData();
154
+
155
+ const portTypes = Object.keys(operatorData.ports);
156
+
157
+ portTypes.sort();
158
+
159
+ const containerBaseName = 'kapeta-resource';
160
+
161
+ const nameParts = [resourceType.toLowerCase()];
162
+
163
+ const ports: AnyMap = {};
164
+
165
+ for (let i = 0; i < portTypes.length; i++) {
166
+ const portType = portTypes[i];
167
+ let containerPortInfo = operatorData.ports[portType];
168
+ const hostPort = await serviceManager.ensureServicePort(resourceType, portType);
169
+
170
+ if (typeof containerPortInfo === 'number' || typeof containerPortInfo === 'string') {
171
+ containerPortInfo = { port: containerPortInfo, type: 'tcp' };
172
+ }
173
+
174
+ if (!containerPortInfo.type) {
175
+ containerPortInfo.type = 'tcp';
176
+ }
177
+
178
+ const portId = containerPortInfo.port + '/' + containerPortInfo.type;
179
+ nameParts.push(portType + '-' + portId + '-' + hostPort);
180
+
181
+ ports[portId] = {
182
+ type: portType,
183
+ hostPort,
184
+ };
185
+ }
186
+
187
+ const mounts = containerManager.createMounts(resourceType, operatorData.mounts);
188
+
189
+ const containerName = containerBaseName + '-' + md5(nameParts.join('_'));
190
+ let container = await containerManager.get(containerName);
191
+
192
+ const isRunning = container ? await container.isRunning() : false;
193
+ if (container && !isRunning) {
194
+ await container.start();
195
+ }
196
+
197
+ if (!container) {
198
+ container = await containerManager.run(operatorData.image, containerName, {
199
+ mounts,
200
+ ports,
201
+ health: operatorData.health,
202
+ env: operatorData.env,
203
+ cmd: operatorData.cmd,
204
+ });
205
+ }
206
+
207
+ try {
208
+ if (operatorData.health) {
209
+ await containerManager.waitForHealthy(container.native);
210
+ } else {
211
+ await containerManager.waitForReady(container.native);
212
+ }
213
+ } catch (e: any) {
214
+ console.error(e.message);
215
+ }
216
+
217
+ return container;
218
+ }
219
+ }
220
+
221
+ export const operatorManager = new OperatorManager();
@@ -0,0 +1,102 @@
1
+ import { spawn } from 'child_process';
2
+ import { SocketManager, socketManager } from './socketManager';
3
+ class ProgressListener {
4
+ private socketManager: SocketManager;
5
+
6
+ constructor(socketManager: SocketManager) {
7
+ this.socketManager = socketManager;
8
+ }
9
+
10
+ run(command: string, directory?: string): Promise<{ exit: number; signal: NodeJS.Signals | null }> {
11
+ this.socketManager.emit(`install`, 'install:log', {
12
+ type: 'info',
13
+ message: `Running command "${command}"`,
14
+ });
15
+
16
+ return new Promise((resolve, reject) => {
17
+ const child = spawn(command, {
18
+ cwd: directory ? directory : process.cwd(),
19
+ detached: true,
20
+ shell: true,
21
+ });
22
+
23
+ child.stdout.on('data', (data) => {
24
+ this.socketManager.emit(`install`, 'install:log', { type: 'info', message: data.toString() });
25
+ });
26
+
27
+ child.stderr.on('data', (data) => {
28
+ this.socketManager.emit(`install`, 'install:log', { type: 'info', message: data.toString() });
29
+ });
30
+
31
+ child.on('exit', (exit, signal) => {
32
+ if (exit !== 0) {
33
+ this.socketManager.emit(`install`, 'install:log', {
34
+ type: 'info',
35
+ message: `"${command}" failed: "${exit}"`,
36
+ });
37
+ reject(new Error(`Command "${command}" exited with code ${exit}`));
38
+ } else {
39
+ this.socketManager.emit(`install`, 'install:log', {
40
+ type: 'info',
41
+ message: `Command OK: "${command}"`,
42
+ });
43
+ resolve({ exit, signal });
44
+ }
45
+ });
46
+
47
+ child.on('error', (err) => {
48
+ this.socketManager.emit(`install`, 'install:log', {
49
+ type: 'info',
50
+ message: `"${command}" failed: "${err.message}"`,
51
+ });
52
+ reject(err);
53
+ });
54
+ });
55
+ }
56
+
57
+ async progress(label: string, callback: () => void | Promise<void>) {
58
+ this.socketManager.emit(`install`, 'install:log', { type: 'info', message: `${label}: started` });
59
+ try {
60
+ const result = await callback();
61
+ this.socketManager.emit(`install`, 'install:log', { type: 'info', message: `${label}: done` });
62
+ return result;
63
+ } catch (e: any) {
64
+ this.socketManager.emit(`install`, 'install:log', {
65
+ type: 'info',
66
+ message: `${label}: failed. ${e.message}`,
67
+ });
68
+ throw e;
69
+ }
70
+ }
71
+
72
+ async check(message: string, ok: boolean | Promise<boolean> | (() => Promise<boolean>)) {
73
+ const wasOk = await ok;
74
+ this.socketManager.emit(`install`, 'install:log', { type: 'info', message: `${message}: ${wasOk}` });
75
+ }
76
+
77
+ start(label: string) {
78
+ this.socketManager.emit(`install`, 'install:log', { type: 'info', message: label });
79
+ }
80
+
81
+ showValue(label: string, value: any) {
82
+ this.socketManager.emit(`install`, 'install:log', { type: 'info', message: `${label}: ${value}` });
83
+ }
84
+
85
+ error(msg: string, ...args: any[]) {
86
+ this.socketManager.emit(`install`, 'install:log', { type: 'error', message: msg });
87
+ }
88
+
89
+ warn(msg: string, ...args: any[]) {
90
+ this.socketManager.emit(`install`, 'install:log', { type: 'warn', message: msg });
91
+ }
92
+
93
+ info(msg: string, ...args: any[]) {
94
+ this.socketManager.emit(`install`, 'install:log', { type: 'info', message: msg });
95
+ }
96
+
97
+ debug(msg: string, ...args: any[]) {
98
+ this.socketManager.emit(`install`, 'install:log', { type: 'debug', message: msg });
99
+ }
100
+ }
101
+
102
+ export const progressListener = new ProgressListener(socketManager);