@kapeta/local-cluster-service 0.6.0 → 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.
- package/.eslintrc.cjs +17 -0
- package/.github/workflows/main.yml +22 -22
- package/.prettierignore +4 -0
- package/.vscode/launch.json +2 -4
- package/CHANGELOG.md +14 -0
- package/definitions.d.ts +17 -35
- package/dist/cjs/index.d.ts +27 -0
- package/dist/cjs/index.js +126 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/src/assetManager.d.ts +31 -0
- package/dist/cjs/src/assetManager.js +153 -0
- package/dist/cjs/src/assets/routes.d.ts +3 -0
- package/dist/cjs/src/assets/routes.js +117 -0
- package/dist/cjs/src/clusterService.d.ts +40 -0
- package/dist/cjs/src/clusterService.js +114 -0
- package/dist/cjs/src/codeGeneratorManager.d.ts +8 -0
- package/dist/cjs/src/codeGeneratorManager.js +53 -0
- package/dist/cjs/src/config/routes.d.ts +3 -0
- package/dist/cjs/src/config/routes.js +126 -0
- package/dist/cjs/src/configManager.d.ts +36 -0
- package/dist/cjs/src/configManager.js +110 -0
- package/dist/cjs/src/containerManager.d.ts +89 -0
- package/dist/cjs/src/containerManager.js +365 -0
- package/dist/cjs/src/filesystem/routes.d.ts +3 -0
- package/dist/cjs/src/filesystem/routes.js +69 -0
- package/dist/cjs/src/filesystemManager.d.ts +15 -0
- package/dist/cjs/src/filesystemManager.js +87 -0
- package/dist/cjs/src/identities/routes.d.ts +3 -0
- package/dist/cjs/src/identities/routes.js +18 -0
- package/dist/cjs/src/instanceManager.d.ts +56 -0
- package/dist/cjs/src/instanceManager.js +424 -0
- package/dist/cjs/src/instances/routes.d.ts +3 -0
- package/dist/cjs/src/instances/routes.js +134 -0
- package/dist/cjs/src/middleware/cors.d.ts +2 -0
- package/dist/cjs/src/middleware/cors.js +10 -0
- package/dist/cjs/src/middleware/kapeta.d.ts +11 -0
- package/dist/cjs/src/middleware/kapeta.js +17 -0
- package/dist/cjs/src/middleware/stringBody.d.ts +5 -0
- package/dist/cjs/src/middleware/stringBody.js +14 -0
- package/dist/cjs/src/networkManager.d.ts +32 -0
- package/dist/cjs/src/networkManager.js +109 -0
- package/dist/cjs/src/operatorManager.d.ts +36 -0
- package/dist/cjs/src/operatorManager.js +165 -0
- package/dist/cjs/src/progressListener.d.ts +20 -0
- package/dist/cjs/src/progressListener.js +91 -0
- package/dist/cjs/src/providerManager.d.ts +9 -0
- package/dist/cjs/src/providerManager.js +51 -0
- package/dist/cjs/src/providers/routes.d.ts +3 -0
- package/dist/cjs/src/providers/routes.js +42 -0
- package/dist/cjs/src/proxy/routes.d.ts +3 -0
- package/dist/cjs/src/proxy/routes.js +111 -0
- package/dist/cjs/src/proxy/types/rest.d.ts +4 -0
- package/dist/cjs/src/proxy/types/rest.js +114 -0
- package/dist/cjs/src/proxy/types/web.d.ts +4 -0
- package/dist/cjs/src/proxy/types/web.js +53 -0
- package/dist/cjs/src/repositoryManager.d.ts +17 -0
- package/dist/cjs/src/repositoryManager.js +215 -0
- package/dist/cjs/src/serviceManager.d.ts +29 -0
- package/dist/cjs/src/serviceManager.js +99 -0
- package/dist/cjs/src/socketManager.d.ts +14 -0
- package/dist/cjs/src/socketManager.js +53 -0
- package/dist/cjs/src/storageService.d.ts +17 -0
- package/dist/cjs/src/storageService.js +74 -0
- package/dist/cjs/src/traffic/routes.d.ts +3 -0
- package/dist/cjs/src/traffic/routes.js +18 -0
- package/dist/cjs/src/types.d.ts +88 -0
- package/dist/cjs/src/types.js +2 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +29 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.js +468 -0
- package/dist/cjs/src/utils/LogData.d.ts +19 -0
- package/dist/cjs/src/utils/LogData.js +43 -0
- package/dist/cjs/src/utils/pathTemplateParser.d.ts +26 -0
- package/dist/cjs/src/utils/pathTemplateParser.js +121 -0
- package/dist/cjs/src/utils/utils.d.ts +1 -0
- package/dist/cjs/src/utils/utils.js +18 -0
- package/dist/cjs/start.d.ts +1 -0
- package/dist/cjs/start.js +12 -0
- package/dist/esm/index.d.ts +27 -0
- package/dist/esm/index.js +121 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/src/assetManager.d.ts +31 -0
- package/{src → dist/esm/src}/assetManager.js +22 -60
- package/dist/esm/src/assets/routes.d.ts +3 -0
- package/{src → dist/esm/src}/assets/routes.js +21 -36
- package/dist/esm/src/clusterService.d.ts +40 -0
- package/{src → dist/esm/src}/clusterService.js +14 -37
- package/dist/esm/src/codeGeneratorManager.d.ts +8 -0
- package/{src → dist/esm/src}/codeGeneratorManager.js +15 -24
- package/dist/esm/src/config/routes.d.ts +3 -0
- package/dist/esm/src/config/routes.js +121 -0
- package/dist/esm/src/configManager.d.ts +36 -0
- package/{src → dist/esm/src}/configManager.js +11 -40
- package/dist/esm/src/containerManager.d.ts +89 -0
- package/{src → dist/esm/src}/containerManager.js +81 -182
- package/dist/esm/src/filesystem/routes.d.ts +3 -0
- package/dist/esm/src/filesystem/routes.js +64 -0
- package/dist/esm/src/filesystemManager.d.ts +15 -0
- package/{src → dist/esm/src}/filesystemManager.js +20 -28
- package/dist/esm/src/identities/routes.d.ts +3 -0
- package/dist/esm/src/identities/routes.js +13 -0
- package/dist/esm/src/instanceManager.d.ts +56 -0
- package/{src → dist/esm/src}/instanceManager.js +94 -175
- package/dist/esm/src/instances/routes.d.ts +3 -0
- package/{src → dist/esm/src}/instances/routes.js +31 -70
- package/dist/esm/src/middleware/cors.d.ts +2 -0
- package/{src → dist/esm/src}/middleware/cors.js +2 -3
- package/dist/esm/src/middleware/kapeta.d.ts +11 -0
- package/{src → dist/esm/src}/middleware/kapeta.js +3 -7
- package/dist/esm/src/middleware/stringBody.d.ts +5 -0
- package/{src → dist/esm/src}/middleware/stringBody.js +2 -3
- package/dist/esm/src/networkManager.d.ts +32 -0
- package/{src → dist/esm/src}/networkManager.js +16 -33
- package/dist/esm/src/operatorManager.d.ts +36 -0
- package/{src → dist/esm/src}/operatorManager.js +35 -91
- package/dist/esm/src/progressListener.d.ts +20 -0
- package/dist/esm/src/progressListener.js +88 -0
- package/dist/esm/src/providerManager.d.ts +9 -0
- package/dist/esm/src/providerManager.js +45 -0
- package/dist/esm/src/providers/routes.d.ts +3 -0
- package/{src → dist/esm/src}/providers/routes.js +10 -16
- package/dist/esm/src/proxy/routes.d.ts +3 -0
- package/dist/esm/src/proxy/routes.js +106 -0
- package/dist/esm/src/proxy/types/rest.d.ts +4 -0
- package/dist/esm/src/proxy/types/rest.js +107 -0
- package/dist/esm/src/proxy/types/web.d.ts +4 -0
- package/{src → dist/esm/src}/proxy/types/web.js +13 -35
- package/dist/esm/src/repositoryManager.d.ts +17 -0
- package/dist/esm/src/repositoryManager.js +209 -0
- package/dist/esm/src/serviceManager.d.ts +29 -0
- package/{src → dist/esm/src}/serviceManager.js +12 -42
- package/dist/esm/src/socketManager.d.ts +14 -0
- package/{src → dist/esm/src}/socketManager.js +19 -23
- package/dist/esm/src/storageService.d.ts +17 -0
- package/{src → dist/esm/src}/storageService.js +8 -27
- package/dist/esm/src/traffic/routes.d.ts +3 -0
- package/{src → dist/esm/src}/traffic/routes.js +4 -9
- package/dist/esm/src/types.d.ts +88 -0
- package/dist/esm/src/types.js +1 -0
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +29 -0
- package/{src → dist/esm/src}/utils/BlockInstanceRunner.js +137 -256
- package/dist/esm/src/utils/LogData.d.ts +19 -0
- package/{src → dist/esm/src}/utils/LogData.js +11 -22
- package/dist/esm/src/utils/pathTemplateParser.d.ts +26 -0
- package/{src → dist/esm/src}/utils/pathTemplateParser.js +21 -40
- package/dist/esm/src/utils/utils.d.ts +1 -0
- package/dist/esm/src/utils/utils.js +11 -0
- package/dist/esm/start.d.ts +1 -0
- package/dist/esm/start.js +7 -0
- package/index.ts +147 -0
- package/package.json +106 -74
- package/src/assetManager.ts +191 -0
- package/src/assets/routes.ts +132 -0
- package/src/clusterService.ts +134 -0
- package/src/codeGeneratorManager.ts +57 -0
- package/src/config/routes.ts +159 -0
- package/src/configManager.ts +148 -0
- package/src/containerManager.ts +466 -0
- package/src/filesystem/routes.ts +74 -0
- package/src/filesystemManager.ts +93 -0
- package/src/identities/routes.ts +20 -0
- package/src/instanceManager.ts +503 -0
- package/src/instances/routes.ts +164 -0
- package/src/middleware/cors.ts +9 -0
- package/src/middleware/kapeta.ts +27 -0
- package/src/middleware/stringBody.ts +16 -0
- package/src/networkManager.ts +137 -0
- package/src/operatorManager.ts +221 -0
- package/src/progressListener.ts +102 -0
- package/src/{providerManager.js → providerManager.ts} +15 -31
- package/src/providers/routes.ts +46 -0
- package/src/proxy/routes.ts +148 -0
- package/src/proxy/types/{rest.js → rest.ts} +30 -30
- package/src/proxy/types/web.ts +60 -0
- package/src/{repositoryManager.js → repositoryManager.ts} +45 -73
- package/src/serviceManager.ts +120 -0
- package/src/socketManager.ts +57 -0
- package/src/storageService.ts +88 -0
- package/src/traffic/routes.ts +18 -0
- package/src/types.ts +97 -0
- package/src/utils/BlockInstanceRunner.ts +555 -0
- package/src/utils/LogData.ts +47 -0
- package/src/utils/pathTemplateParser.ts +138 -0
- package/src/utils/utils.ts +12 -0
- package/start.ts +8 -0
- package/tsconfig.json +13 -0
- package/index.js +0 -127
- package/src/config/routes.js +0 -160
- package/src/filesystem/routes.js +0 -74
- package/src/identities/routes.js +0 -19
- package/src/progressListener.js +0 -82
- package/src/proxy/routes.js +0 -126
- package/src/utils/utils.js +0 -13
- package/start.js +0 -7
@@ -1,41 +1,33 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
const {parseKapetaUri} = require("@kapeta/nodejs-utils");
|
10
|
-
|
1
|
+
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
2
|
+
import Path from 'path';
|
3
|
+
import md5 from 'md5';
|
4
|
+
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
5
|
+
import { serviceManager } from './serviceManager';
|
6
|
+
import { storageService } from './storageService';
|
7
|
+
import { containerManager } from './containerManager';
|
8
|
+
import FSExtra from 'fs-extra';
|
11
9
|
const KIND_OPERATOR = 'core/resource-type-operator';
|
12
|
-
|
13
10
|
class Operator {
|
11
|
+
_data;
|
14
12
|
constructor(data) {
|
15
13
|
this._data = data;
|
16
14
|
}
|
17
|
-
|
18
15
|
getData() {
|
19
16
|
return this._data;
|
20
17
|
}
|
21
|
-
|
22
18
|
getCredentials() {
|
23
19
|
return this._data.credentials;
|
24
20
|
}
|
25
21
|
}
|
26
|
-
|
27
22
|
class OperatorManager {
|
28
|
-
|
23
|
+
_mountDir;
|
29
24
|
constructor() {
|
30
25
|
this._mountDir = Path.join(storageService.getKapetaBasedir(), 'mounts');
|
31
|
-
|
32
|
-
mkdirp.sync(this._mountDir);
|
26
|
+
FSExtra.mkdirpSync(this._mountDir);
|
33
27
|
}
|
34
|
-
|
35
28
|
_getMountPoint(operatorType, mountName) {
|
36
29
|
return Path.join(this._mountDir, operatorType, mountName);
|
37
30
|
}
|
38
|
-
|
39
31
|
/**
|
40
32
|
* Get operator definition for resource type
|
41
33
|
*
|
@@ -45,89 +37,62 @@ class OperatorManager {
|
|
45
37
|
*/
|
46
38
|
getOperator(resourceType, version) {
|
47
39
|
const operators = ClusterConfiguration.getDefinitions(KIND_OPERATOR);
|
48
|
-
|
49
|
-
const operator = _.find(operators, (operator) => operator.definition &&
|
40
|
+
const operator = operators.find((operator) => operator.definition &&
|
50
41
|
operator.definition.metadata &&
|
51
42
|
operator.definition.metadata.name &&
|
52
43
|
operator.definition.metadata.name.toLowerCase() === resourceType.toLowerCase() &&
|
53
44
|
operator.version === version);
|
54
|
-
|
55
45
|
if (!operator) {
|
56
46
|
throw new Error(`Unknown resource type: ${resourceType}:${version}`);
|
57
47
|
}
|
58
|
-
|
59
|
-
if (!operator.definition.spec ||
|
60
|
-
!operator.definition.spec.local) {
|
48
|
+
if (!operator.definition.spec || !operator.definition.spec.local) {
|
61
49
|
throw new Error(`Operator missing local definition: ${resourceType}:${version}`);
|
62
50
|
}
|
63
|
-
|
64
51
|
return new Operator(operator.definition.spec.local);
|
65
52
|
}
|
66
|
-
|
67
53
|
/**
|
68
54
|
* Get information about a specific consumed resource
|
69
|
-
*
|
70
|
-
* @param {string} systemId
|
71
|
-
* @param {string} fromServiceId
|
72
|
-
* @param {string} resourceType
|
73
|
-
* @param {string} portType
|
74
|
-
* @param {string} name
|
75
|
-
* @returns {Promise<{host: string, port: (*|string), type: *, protocol: *, credentials: *}>}
|
76
55
|
*/
|
77
56
|
async getConsumerResourceInfo(systemId, fromServiceId, resourceType, portType, name, environment) {
|
78
|
-
|
79
57
|
const plans = ClusterConfiguration.getDefinitions('core/plan');
|
80
|
-
|
81
58
|
const planUri = parseKapetaUri(systemId);
|
82
|
-
const currentPlan = plans.find(plan => plan.definition.metadata.name === planUri.fullName && plan.version === planUri.version);
|
59
|
+
const currentPlan = plans.find((plan) => plan.definition.metadata.name === planUri.fullName && plan.version === planUri.version);
|
83
60
|
if (!currentPlan) {
|
84
61
|
throw new Error(`Unknown plan: ${systemId}`);
|
85
62
|
}
|
86
|
-
|
87
|
-
const currentInstance = currentPlan.definition.spec.blocks?.find(instance => instance.id === fromServiceId);
|
63
|
+
const currentInstance = currentPlan.definition.spec.blocks?.find((instance) => instance.id === fromServiceId);
|
88
64
|
if (!currentInstance) {
|
89
65
|
throw new Error(`Unknown instance: ${fromServiceId} in plan ${systemId}`);
|
90
66
|
}
|
91
|
-
|
92
67
|
const blockUri = parseKapetaUri(currentInstance.block.ref);
|
93
|
-
const blockDefinition = ClusterConfiguration.getDefinitions().find(definition =>
|
94
|
-
definition.version === blockUri.version &&
|
95
|
-
definition.definition.metadata.name === blockUri.fullName
|
96
|
-
);
|
97
|
-
|
68
|
+
const blockDefinition = ClusterConfiguration.getDefinitions().find((definition) => definition.version === blockUri.version && definition.definition.metadata.name === blockUri.fullName);
|
98
69
|
if (!blockDefinition) {
|
99
70
|
throw new Error(`Unknown block: ${currentInstance.block.ref} in plan ${systemId}`);
|
100
71
|
}
|
101
|
-
|
102
|
-
const blockResource = blockDefinition.definition.spec?.consumers?.find(resource => resource.metadata.name === name);
|
72
|
+
const blockResource = blockDefinition.definition.spec?.consumers?.find((resource) => resource.metadata.name === name);
|
103
73
|
if (!blockResource) {
|
104
74
|
throw new Error(`Unknown resource: ${name} in block ${currentInstance.block.ref} in plan ${systemId}`);
|
105
75
|
}
|
106
|
-
|
107
76
|
const kindUri = parseKapetaUri(blockResource.kind);
|
108
77
|
const operator = this.getOperator(resourceType, kindUri.version);
|
109
78
|
const credentials = operator.getCredentials();
|
110
79
|
const container = await this.ensureResource(systemId, resourceType, kindUri.version);
|
111
80
|
const portInfo = await container.getPort(portType);
|
112
|
-
|
113
81
|
if (!portInfo) {
|
114
82
|
throw new Error('Unknown resource port type : ' + resourceType + '#' + portType);
|
115
83
|
}
|
116
|
-
|
117
84
|
const dbName = name + '_' + fromServiceId.replace(/[^a-z0-9]/gi, '');
|
118
|
-
|
119
85
|
return {
|
120
86
|
host: environment === 'docker' ? 'host.docker.internal' : '127.0.0.1',
|
121
87
|
port: portInfo.hostPort,
|
122
88
|
type: portType,
|
123
89
|
protocol: portInfo.protocol,
|
124
90
|
options: {
|
125
|
-
dbName
|
91
|
+
dbName,
|
126
92
|
},
|
127
|
-
credentials
|
93
|
+
credentials,
|
128
94
|
};
|
129
95
|
}
|
130
|
-
|
131
96
|
/**
|
132
97
|
* Ensure we have a running operator of given type
|
133
98
|
*
|
@@ -138,78 +103,57 @@ class OperatorManager {
|
|
138
103
|
*/
|
139
104
|
async ensureResource(systemId, resourceType, version) {
|
140
105
|
const operator = this.getOperator(resourceType, version);
|
141
|
-
|
142
106
|
const operatorData = operator.getData();
|
143
|
-
|
144
107
|
const portTypes = Object.keys(operatorData.ports);
|
145
|
-
|
146
108
|
portTypes.sort();
|
147
|
-
|
148
109
|
const containerBaseName = 'kapeta-resource';
|
149
|
-
|
150
110
|
const nameParts = [resourceType.toLowerCase()];
|
151
|
-
|
152
111
|
const ports = {};
|
153
|
-
|
154
|
-
for(let i = 0 ; i < portTypes.length; i++) {
|
112
|
+
for (let i = 0; i < portTypes.length; i++) {
|
155
113
|
const portType = portTypes[i];
|
156
114
|
let containerPortInfo = operatorData.ports[portType];
|
157
115
|
const hostPort = await serviceManager.ensureServicePort(resourceType, portType);
|
158
|
-
|
159
|
-
|
160
|
-
typeof containerPortInfo === 'string') {
|
161
|
-
containerPortInfo = {port: containerPortInfo, type: 'tcp'};
|
116
|
+
if (typeof containerPortInfo === 'number' || typeof containerPortInfo === 'string') {
|
117
|
+
containerPortInfo = { port: containerPortInfo, type: 'tcp' };
|
162
118
|
}
|
163
|
-
|
164
119
|
if (!containerPortInfo.type) {
|
165
120
|
containerPortInfo.type = 'tcp';
|
166
121
|
}
|
167
|
-
|
168
122
|
const portId = containerPortInfo.port + '/' + containerPortInfo.type;
|
169
123
|
nameParts.push(portType + '-' + portId + '-' + hostPort);
|
170
|
-
|
171
124
|
ports[portId] = {
|
172
125
|
type: portType,
|
173
|
-
hostPort
|
126
|
+
hostPort,
|
174
127
|
};
|
175
128
|
}
|
176
|
-
|
177
129
|
const mounts = containerManager.createMounts(resourceType, operatorData.mounts);
|
178
|
-
|
179
130
|
const containerName = containerBaseName + '-' + md5(nameParts.join('_'));
|
180
131
|
let container = await containerManager.get(containerName);
|
181
|
-
|
182
132
|
const isRunning = container ? await container.isRunning() : false;
|
183
133
|
if (container && !isRunning) {
|
184
134
|
await container.start();
|
185
135
|
}
|
186
|
-
|
187
136
|
if (!container) {
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
health: operatorData.health,
|
196
|
-
env: operatorData.env,
|
197
|
-
cmd: operatorData.cmd
|
198
|
-
});
|
137
|
+
container = await containerManager.run(operatorData.image, containerName, {
|
138
|
+
mounts,
|
139
|
+
ports,
|
140
|
+
health: operatorData.health,
|
141
|
+
env: operatorData.env,
|
142
|
+
cmd: operatorData.cmd,
|
143
|
+
});
|
199
144
|
}
|
200
|
-
|
201
145
|
try {
|
202
146
|
if (operatorData.health) {
|
203
147
|
await containerManager.waitForHealthy(container.native);
|
204
|
-
}
|
148
|
+
}
|
149
|
+
else {
|
205
150
|
await containerManager.waitForReady(container.native);
|
206
151
|
}
|
207
|
-
}
|
152
|
+
}
|
153
|
+
catch (e) {
|
208
154
|
console.error(e.message);
|
209
155
|
}
|
210
|
-
|
211
156
|
return container;
|
212
157
|
}
|
213
158
|
}
|
214
|
-
|
215
|
-
module.exports = new OperatorManager();
|
159
|
+
export const operatorManager = new OperatorManager();
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
import { SocketManager } from './socketManager';
|
3
|
+
declare class ProgressListener {
|
4
|
+
private socketManager;
|
5
|
+
constructor(socketManager: SocketManager);
|
6
|
+
run(command: string, directory?: string): Promise<{
|
7
|
+
exit: number;
|
8
|
+
signal: NodeJS.Signals | null;
|
9
|
+
}>;
|
10
|
+
progress(label: string, callback: () => void | Promise<void>): Promise<void>;
|
11
|
+
check(message: string, ok: boolean | Promise<boolean> | (() => Promise<boolean>)): Promise<void>;
|
12
|
+
start(label: string): void;
|
13
|
+
showValue(label: string, value: any): void;
|
14
|
+
error(msg: string, ...args: any[]): void;
|
15
|
+
warn(msg: string, ...args: any[]): void;
|
16
|
+
info(msg: string, ...args: any[]): void;
|
17
|
+
debug(msg: string, ...args: any[]): void;
|
18
|
+
}
|
19
|
+
export declare const progressListener: ProgressListener;
|
20
|
+
export {};
|
@@ -0,0 +1,88 @@
|
|
1
|
+
import { spawn } from 'child_process';
|
2
|
+
import { socketManager } from './socketManager';
|
3
|
+
class ProgressListener {
|
4
|
+
socketManager;
|
5
|
+
constructor(socketManager) {
|
6
|
+
this.socketManager = socketManager;
|
7
|
+
}
|
8
|
+
run(command, directory) {
|
9
|
+
this.socketManager.emit(`install`, 'install:log', {
|
10
|
+
type: 'info',
|
11
|
+
message: `Running command "${command}"`,
|
12
|
+
});
|
13
|
+
return new Promise((resolve, reject) => {
|
14
|
+
const child = spawn(command, {
|
15
|
+
cwd: directory ? directory : process.cwd(),
|
16
|
+
detached: true,
|
17
|
+
shell: true,
|
18
|
+
});
|
19
|
+
child.stdout.on('data', (data) => {
|
20
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'info', message: data.toString() });
|
21
|
+
});
|
22
|
+
child.stderr.on('data', (data) => {
|
23
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'info', message: data.toString() });
|
24
|
+
});
|
25
|
+
child.on('exit', (exit, signal) => {
|
26
|
+
if (exit !== 0) {
|
27
|
+
this.socketManager.emit(`install`, 'install:log', {
|
28
|
+
type: 'info',
|
29
|
+
message: `"${command}" failed: "${exit}"`,
|
30
|
+
});
|
31
|
+
reject(new Error(`Command "${command}" exited with code ${exit}`));
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
this.socketManager.emit(`install`, 'install:log', {
|
35
|
+
type: 'info',
|
36
|
+
message: `Command OK: "${command}"`,
|
37
|
+
});
|
38
|
+
resolve({ exit, signal });
|
39
|
+
}
|
40
|
+
});
|
41
|
+
child.on('error', (err) => {
|
42
|
+
this.socketManager.emit(`install`, 'install:log', {
|
43
|
+
type: 'info',
|
44
|
+
message: `"${command}" failed: "${err.message}"`,
|
45
|
+
});
|
46
|
+
reject(err);
|
47
|
+
});
|
48
|
+
});
|
49
|
+
}
|
50
|
+
async progress(label, callback) {
|
51
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'info', message: `${label}: started` });
|
52
|
+
try {
|
53
|
+
const result = await callback();
|
54
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'info', message: `${label}: done` });
|
55
|
+
return result;
|
56
|
+
}
|
57
|
+
catch (e) {
|
58
|
+
this.socketManager.emit(`install`, 'install:log', {
|
59
|
+
type: 'info',
|
60
|
+
message: `${label}: failed. ${e.message}`,
|
61
|
+
});
|
62
|
+
throw e;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
async check(message, ok) {
|
66
|
+
const wasOk = await ok;
|
67
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'info', message: `${message}: ${wasOk}` });
|
68
|
+
}
|
69
|
+
start(label) {
|
70
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'info', message: label });
|
71
|
+
}
|
72
|
+
showValue(label, value) {
|
73
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'info', message: `${label}: ${value}` });
|
74
|
+
}
|
75
|
+
error(msg, ...args) {
|
76
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'error', message: msg });
|
77
|
+
}
|
78
|
+
warn(msg, ...args) {
|
79
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'warn', message: msg });
|
80
|
+
}
|
81
|
+
info(msg, ...args) {
|
82
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'info', message: msg });
|
83
|
+
}
|
84
|
+
debug(msg, ...args) {
|
85
|
+
this.socketManager.emit(`install`, 'install:log', { type: 'debug', message: msg });
|
86
|
+
}
|
87
|
+
}
|
88
|
+
export const progressListener = new ProgressListener(socketManager);
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
declare class ProviderManager {
|
3
|
+
private _webAssetCache;
|
4
|
+
constructor();
|
5
|
+
getWebProviders(): import("@kapeta/local-cluster-config").DefinitionInfo[];
|
6
|
+
getAsset(handle: string, name: string, version: string, sourceMap?: boolean): Promise<string | Buffer | null>;
|
7
|
+
}
|
8
|
+
export declare const providerManager: ProviderManager;
|
9
|
+
export {};
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import Path from 'path';
|
2
|
+
import FSExtra from 'fs-extra';
|
3
|
+
import { repositoryManager } from './repositoryManager';
|
4
|
+
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
5
|
+
class ProviderManager {
|
6
|
+
_webAssetCache;
|
7
|
+
constructor() {
|
8
|
+
this._webAssetCache = {};
|
9
|
+
}
|
10
|
+
getWebProviders() {
|
11
|
+
return ClusterConfiguration.getProviderDefinitions().filter((providerDefinition) => providerDefinition.hasWeb);
|
12
|
+
}
|
13
|
+
async getAsset(handle, name, version, sourceMap = false) {
|
14
|
+
const fullName = `${handle}/${name}`;
|
15
|
+
const id = `${handle}/${name}/${version}/web.js${sourceMap ? '.map' : ''}`;
|
16
|
+
if (this._webAssetCache[id] && (await FSExtra.pathExists(this._webAssetCache[id]))) {
|
17
|
+
return FSExtra.readFile(this._webAssetCache[id], 'utf8');
|
18
|
+
}
|
19
|
+
await repositoryManager.ensureAsset(handle, name, version);
|
20
|
+
const installedProvider = this.getWebProviders().find((providerDefinition) => {
|
21
|
+
return providerDefinition.definition.metadata.name === fullName && providerDefinition.version === version;
|
22
|
+
});
|
23
|
+
if (installedProvider) {
|
24
|
+
//Check locally installed providers
|
25
|
+
const path = Path.join(installedProvider.path, 'web', handle, `${name}.js${sourceMap ? '.map' : ''}`);
|
26
|
+
if (await FSExtra.pathExists(path)) {
|
27
|
+
this._webAssetCache[id] = path;
|
28
|
+
return FSExtra.readFile(path);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
return null;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
const providerDefinitions = ClusterConfiguration.getProviderDefinitions();
|
35
|
+
if (providerDefinitions.length > 0) {
|
36
|
+
console.log('## Loaded the following providers ##');
|
37
|
+
providerDefinitions.forEach((providerDefinition) => {
|
38
|
+
console.log(' - %s[%s:%s]', providerDefinition.definition.kind, providerDefinition.definition.metadata.name, providerDefinition.version);
|
39
|
+
console.log(' from %s', providerDefinition.path);
|
40
|
+
});
|
41
|
+
}
|
42
|
+
else {
|
43
|
+
console.log('## No providers found ##');
|
44
|
+
}
|
45
|
+
export const providerManager = new ProviderManager();
|
@@ -1,37 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
const router =
|
5
|
-
|
6
|
-
router.use('/', require('../middleware/cors'));
|
7
|
-
|
1
|
+
import Router from 'express-promise-router';
|
2
|
+
import { providerManager } from '../providerManager';
|
3
|
+
import { corsHandler } from '../middleware/cors';
|
4
|
+
const router = Router();
|
5
|
+
router.use('/', corsHandler);
|
8
6
|
router.get('/', async (req, res) => {
|
9
7
|
const result = await providerManager.getWebProviders();
|
10
|
-
|
11
8
|
res.send(result);
|
12
9
|
});
|
13
|
-
|
14
10
|
router.get('/asset/:handle/:name/:version/web.js', async (req, res) => {
|
15
11
|
const { handle, name, version } = req.params;
|
16
12
|
let result = await providerManager.getAsset(handle, name, version);
|
17
|
-
|
18
13
|
if (!result) {
|
19
14
|
res.status(404).send('');
|
20
|
-
}
|
15
|
+
}
|
16
|
+
else {
|
21
17
|
if (version !== 'local') {
|
22
18
|
res.setHeader('Cache-Control', 'max-age=31536000, immutable');
|
23
19
|
}
|
24
20
|
res.send(result.toString().replace(`${name}.js.map`, 'web.js.map'));
|
25
21
|
}
|
26
22
|
});
|
27
|
-
|
28
23
|
router.get('/asset/:handle/:name/:version/web.js.map', async (req, res) => {
|
29
24
|
const { handle, name, version } = req.params;
|
30
25
|
const result = await providerManager.getAsset(handle, name, version, true);
|
31
|
-
|
32
26
|
if (!result) {
|
33
27
|
res.status(404).send('');
|
34
|
-
}
|
28
|
+
}
|
29
|
+
else {
|
35
30
|
// Only cache successful requests
|
36
31
|
if (version !== 'local') {
|
37
32
|
res.setHeader('Cache-Control', 'max-age=31536000, immutable');
|
@@ -39,5 +34,4 @@ router.get('/asset/:handle/:name/:version/web.js.map', async (req, res) => {
|
|
39
34
|
res.send(result);
|
40
35
|
}
|
41
36
|
});
|
42
|
-
|
43
|
-
module.exports = router;
|
37
|
+
export default router;
|
@@ -0,0 +1,106 @@
|
|
1
|
+
import Router from 'express-promise-router';
|
2
|
+
import { proxyRestRequest } from './types/rest';
|
3
|
+
import { proxyWebRequest } from './types/web';
|
4
|
+
import { stringBody } from '../middleware/stringBody';
|
5
|
+
import { serviceManager } from '../serviceManager';
|
6
|
+
import { clusterService } from '../clusterService';
|
7
|
+
import { assetManager } from '../assetManager';
|
8
|
+
import _ from 'lodash';
|
9
|
+
const router = Router();
|
10
|
+
/**
|
11
|
+
* @var {{[key:string]:ProxyRequestHandler}}
|
12
|
+
*/
|
13
|
+
const TYPE_HANDLERS = {
|
14
|
+
rest: proxyRestRequest,
|
15
|
+
web: proxyWebRequest,
|
16
|
+
};
|
17
|
+
function getResource(resources, resourceName) {
|
18
|
+
return resources.find((resource) => {
|
19
|
+
return resource.metadata.name.toLowerCase() === resourceName.toLowerCase();
|
20
|
+
});
|
21
|
+
}
|
22
|
+
router.use('/:systemId/:consumerInstanceId/:consumerResourceName', stringBody);
|
23
|
+
router.all('/:systemId/:consumerInstanceId/:consumerResourceName/:type/*', async (req, res) => {
|
24
|
+
try {
|
25
|
+
const typeHandler = TYPE_HANDLERS[req.params.type.toLowerCase()];
|
26
|
+
if (!typeHandler) {
|
27
|
+
res.status(401).send({ error: 'Unknown connection type: ' + req.params.type });
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
const plan = await assetManager.getPlan(req.params.systemId);
|
31
|
+
// We can find the connection by the consumer information alone since
|
32
|
+
// only 1 provider can be connected to a consumer resource at a time
|
33
|
+
const connection = _.find(plan.spec.connections, (connection) => {
|
34
|
+
return (connection.consumer.blockId.toLowerCase() === req.params.consumerInstanceId.toLowerCase() &&
|
35
|
+
connection.consumer.resourceName.toLowerCase() === req.params.consumerResourceName.toLowerCase());
|
36
|
+
});
|
37
|
+
if (!connection) {
|
38
|
+
res.status(401).send({
|
39
|
+
error: `No connection found for consumer "${req.params.consumerInstanceId}::${req.params.consumerResourceName}"`,
|
40
|
+
});
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
const toBlockInstance = _.find(plan.spec.blocks, (blockInstance) => {
|
44
|
+
return blockInstance.id.toLowerCase() === connection.consumer.blockId.toLowerCase();
|
45
|
+
});
|
46
|
+
if (!toBlockInstance) {
|
47
|
+
res.status(401).send({ error: `Block instance not found "${req.params.consumerInstanceId}` });
|
48
|
+
return;
|
49
|
+
}
|
50
|
+
const toBlockAsset = await assetManager.getAsset(toBlockInstance.block.ref);
|
51
|
+
if (!toBlockAsset) {
|
52
|
+
res.status(401).send({ error: `Block asset not found "${toBlockInstance.block.ref}` });
|
53
|
+
return;
|
54
|
+
}
|
55
|
+
const consumerResource = getResource(toBlockAsset.data.spec.consumers, req.params.consumerResourceName);
|
56
|
+
if (!consumerResource) {
|
57
|
+
res.status(401).send({
|
58
|
+
error: `Block resource not found "${req.params.consumerInstanceId}::${req.params.consumerResourceName}`,
|
59
|
+
});
|
60
|
+
return;
|
61
|
+
}
|
62
|
+
const basePath = clusterService.getProxyPath(req.params.systemId, req.params.consumerInstanceId, req.params.consumerResourceName, req.params.type);
|
63
|
+
const fromBlockInstance = _.find(plan.spec.blocks, (blockInstance) => {
|
64
|
+
return blockInstance.id.toLowerCase() === connection.provider.blockId.toLowerCase();
|
65
|
+
});
|
66
|
+
if (!fromBlockInstance) {
|
67
|
+
res.status(401).send({ error: `Block instance not found "${connection.provider.blockId}` });
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
const fromBlockAsset = await assetManager.getAsset(fromBlockInstance.block.ref);
|
71
|
+
if (!fromBlockAsset) {
|
72
|
+
res.status(401).send({ error: `Block asset not found "${fromBlockInstance.block.ref}` });
|
73
|
+
return;
|
74
|
+
}
|
75
|
+
const providerResource = getResource(fromBlockAsset.data.spec.providers, connection.provider.resourceName);
|
76
|
+
if (!providerResource) {
|
77
|
+
res.status(401).send({
|
78
|
+
error: `Block resource not found "${connection.provider.blockId}::${connection.provider.resourceName}`,
|
79
|
+
});
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
//Get target address
|
83
|
+
let address = await serviceManager.getProviderAddress(req.params.systemId, connection.provider.blockId, req.params.type);
|
84
|
+
while (address.endsWith('/')) {
|
85
|
+
address = address.substring(0, address.length - 1);
|
86
|
+
}
|
87
|
+
/*
|
88
|
+
Get the path the consumer requested.
|
89
|
+
Note that this might not match the path the destination is expecting so we need to identify the method
|
90
|
+
that is being called and identify the destination path from the connection.
|
91
|
+
*/
|
92
|
+
const consumerPath = req.originalUrl.substring(basePath.length - 1);
|
93
|
+
typeHandler(req, res, {
|
94
|
+
consumerPath,
|
95
|
+
address,
|
96
|
+
consumerResource,
|
97
|
+
providerResource,
|
98
|
+
connection,
|
99
|
+
});
|
100
|
+
}
|
101
|
+
catch (err) {
|
102
|
+
console.warn('Failed to process proxy request', err);
|
103
|
+
res.status(400).send({ error: err.message });
|
104
|
+
}
|
105
|
+
});
|
106
|
+
export default router;
|