@kapeta/local-cluster-service 0.40.4 → 0.40.6
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/CHANGELOG.md +14 -0
- package/dist/cjs/src/networkManager.d.ts +1 -1
- package/dist/cjs/src/networkManager.js +4 -6
- package/dist/cjs/src/operatorManager.d.ts +2 -2
- package/dist/cjs/src/operatorManager.js +18 -1
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +1 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.js +59 -15
- package/dist/esm/src/networkManager.d.ts +1 -1
- package/dist/esm/src/networkManager.js +4 -6
- package/dist/esm/src/operatorManager.d.ts +2 -2
- package/dist/esm/src/operatorManager.js +18 -1
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +1 -0
- package/dist/esm/src/utils/BlockInstanceRunner.js +59 -15
- package/package.json +2 -2
- package/src/networkManager.ts +4 -6
- package/src/operatorManager.ts +19 -2
- package/src/utils/BlockInstanceRunner.ts +78 -16
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.40.6](https://github.com/kapetacom/local-cluster-service/compare/v0.40.5...v0.40.6) (2024-04-11)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Fix wrong connection id structure ([4056bc5](https://github.com/kapetacom/local-cluster-service/commit/4056bc5c0d51aa15ff9be0b9ec3b9f9dbdfaec56))
|
7
|
+
|
8
|
+
## [0.40.5](https://github.com/kapetacom/local-cluster-service/compare/v0.40.4...v0.40.5) (2024-04-09)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Move most / big env vars to config file instead ([#137](https://github.com/kapetacom/local-cluster-service/issues/137)) ([21c5c50](https://github.com/kapetacom/local-cluster-service/commit/21c5c50341665c2919b9c1ed718b933a10a459fb))
|
14
|
+
|
1
15
|
## [0.40.4](https://github.com/kapetacom/local-cluster-service/compare/v0.40.3...v0.40.4) (2024-04-04)
|
2
16
|
|
3
17
|
|
@@ -8,7 +8,7 @@ declare class NetworkManager {
|
|
8
8
|
private _connections;
|
9
9
|
private _sources;
|
10
10
|
private _targets;
|
11
|
-
static toConnectionId(
|
11
|
+
static toConnectionId({ provider, consumer }: Connection): string;
|
12
12
|
constructor();
|
13
13
|
_ensureSystem(systemId: string): void;
|
14
14
|
_ensureConnection(systemId: string, connectionId: string): Traffic[];
|
@@ -14,13 +14,11 @@ class NetworkManager {
|
|
14
14
|
_connections;
|
15
15
|
_sources;
|
16
16
|
_targets;
|
17
|
-
static toConnectionId(
|
17
|
+
static toConnectionId({ provider, consumer }) {
|
18
18
|
return [
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
connection.consumer.resourceName,
|
23
|
-
].join('_');
|
19
|
+
[provider.blockId, provider.resourceName, 'PROVIDES'].join('__'),
|
20
|
+
[consumer.blockId, consumer.resourceName, 'CONSUMES'].join('__'),
|
21
|
+
].join('-');
|
24
22
|
}
|
25
23
|
constructor() {
|
26
24
|
this._connections = {};
|
@@ -22,7 +22,7 @@ declare class OperatorManager {
|
|
22
22
|
/**
|
23
23
|
* Get operator definition for resource type
|
24
24
|
*/
|
25
|
-
getOperator(fullName: string, version: string): Promise<Operator>;
|
25
|
+
getOperator(fullName: string, version: string): Promise<Operator | null>;
|
26
26
|
/**
|
27
27
|
* Get information about a specific consumed resource
|
28
28
|
*/
|
@@ -35,7 +35,7 @@ declare class OperatorManager {
|
|
35
35
|
* @param kind the full name - e.g. myhandle/rabbitmq
|
36
36
|
* @param version the version of the operator
|
37
37
|
*/
|
38
|
-
ensureOperator(systemId: string, kind: string, version: string): Promise<ContainerInfo>;
|
38
|
+
ensureOperator(systemId: string, kind: string, version: string): Promise<ContainerInfo | null>;
|
39
39
|
}
|
40
40
|
export declare const operatorManager: OperatorManager;
|
41
41
|
export {};
|
@@ -61,7 +61,8 @@ class OperatorManager {
|
|
61
61
|
throw new Error(`Unknown operator type: ${fullName}:${version}`);
|
62
62
|
}
|
63
63
|
if (!operator.definition.spec || !operator.definition.spec.local) {
|
64
|
-
|
64
|
+
console.warn(`Operator missing local definition: ${fullName}:${version}`);
|
65
|
+
return null;
|
65
66
|
}
|
66
67
|
return new Operator(operator);
|
67
68
|
}
|
@@ -95,6 +96,16 @@ class OperatorManager {
|
|
95
96
|
}
|
96
97
|
const kindUri = (0, nodejs_utils_1.parseKapetaUri)(blockResource.kind);
|
97
98
|
const operator = await this.getOperator(resourceType, kindUri.version);
|
99
|
+
if (!operator) {
|
100
|
+
return {
|
101
|
+
host: '',
|
102
|
+
port: 0,
|
103
|
+
type: '',
|
104
|
+
protocol: '',
|
105
|
+
options: {},
|
106
|
+
credentials: {},
|
107
|
+
};
|
108
|
+
}
|
98
109
|
const credentials = operator.getCredentials();
|
99
110
|
if (ensureContainer) {
|
100
111
|
await this.ensureOperator(systemId, resourceType, kindUri.version);
|
@@ -120,6 +131,9 @@ class OperatorManager {
|
|
120
131
|
}
|
121
132
|
async getOperatorPorts(systemId, kind, version) {
|
122
133
|
const operator = await this.getOperator(kind, version);
|
134
|
+
if (!operator) {
|
135
|
+
return {};
|
136
|
+
}
|
123
137
|
const operatorData = operator.getLocalData();
|
124
138
|
const portTypes = Object.keys(operatorData.ports);
|
125
139
|
portTypes.sort();
|
@@ -150,6 +164,9 @@ class OperatorManager {
|
|
150
164
|
const key = `${systemId}#${kind}:${version}`;
|
151
165
|
return await this.operatorLock.acquire(key, async () => {
|
152
166
|
const operator = await this.getOperator(kind, version);
|
167
|
+
if (!operator) {
|
168
|
+
return null;
|
169
|
+
}
|
153
170
|
const operatorData = operator.getLocalData();
|
154
171
|
const ports = await this.getOperatorPorts(systemId, kind, version);
|
155
172
|
const nameParts = [systemId, kind.toLowerCase(), version];
|
@@ -23,9 +23,12 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
23
23
|
const taskManager_1 = require("../taskManager");
|
24
24
|
const InternalConfigProvider_1 = require("./InternalConfigProvider");
|
25
25
|
const config_mapper_1 = require("@kapeta/config-mapper");
|
26
|
+
const crypto_1 = __importDefault(require("crypto"));
|
26
27
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
27
28
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
28
29
|
const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
|
30
|
+
// The maximum length of an environment variable - this is to avoid hitting the command line length limits
|
31
|
+
const MAX_ENV_LENGTH = 256;
|
29
32
|
/**
|
30
33
|
* Needed when running local docker containers as part of plan
|
31
34
|
* @type {string[]}
|
@@ -111,21 +114,28 @@ class BlockInstanceRunner {
|
|
111
114
|
const realBaseDir = await fs_extra_1.default.realpath(baseDir);
|
112
115
|
const internalConfigProvider = await (0, InternalConfigProvider_1.createInternalConfigProvider)(this._systemId, blockInstance.id, assetVersion);
|
113
116
|
// Resolve the environment variables
|
114
|
-
const
|
117
|
+
const variables = await (0, config_mapper_1.resolveKapetaVariables)(realBaseDir, internalConfigProvider);
|
115
118
|
// Write out the config templates if they exist
|
116
|
-
await (0, config_mapper_1.writeConfigTemplates)(
|
119
|
+
await (0, config_mapper_1.writeConfigTemplates)(variables, realBaseDir);
|
120
|
+
const env = await (0, config_mapper_1.getEnvironmentVariables)(variables);
|
121
|
+
// Gets the tmp path to write the config file
|
122
|
+
const configFilePath = (0, config_mapper_1.getConfigFilePath)(blockInstance.id);
|
123
|
+
// Write the config to a file - will be read by the SDKs
|
124
|
+
await (0, config_mapper_1.writeEnvConfigFile)(variables, configFilePath);
|
125
|
+
// Add the config file path to the environment variables
|
126
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = configFilePath;
|
117
127
|
let processInfo;
|
118
128
|
if (providerVersion.definition.kind === types_1.KIND_BLOCK_TYPE_OPERATOR) {
|
119
|
-
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion,
|
129
|
+
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
|
120
130
|
}
|
121
131
|
else {
|
122
132
|
//We need a port type to know how to connect to the block consistently
|
123
133
|
const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
|
124
134
|
if (blockUri.version === 'local') {
|
125
|
-
processInfo = await this._startLocalProcess(blockInstance, blockUri,
|
135
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
|
126
136
|
}
|
127
137
|
else {
|
128
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri,
|
138
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion);
|
129
139
|
}
|
130
140
|
if (portTypes.length > 0) {
|
131
141
|
processInfo.portType = portTypes[0];
|
@@ -200,6 +210,14 @@ class BlockInstanceRunner {
|
|
200
210
|
if (localContainer.healthcheck) {
|
201
211
|
HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
202
212
|
}
|
213
|
+
if (env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]) {
|
214
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
215
|
+
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
216
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
217
|
+
// We also provide the hash to detect changes to the config file
|
218
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
219
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
220
|
+
}
|
203
221
|
const Mounts = isDockerImage
|
204
222
|
? // For docker images we mount the local directory to the working directory
|
205
223
|
containerManager_1.containerManager.toDockerMounts({
|
@@ -208,6 +226,15 @@ class BlockInstanceRunner {
|
|
208
226
|
: // For dockerfiles we don't mount anything
|
209
227
|
[];
|
210
228
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
229
|
+
const Env = [
|
230
|
+
...customEnvs,
|
231
|
+
...DOCKER_ENV_VARS,
|
232
|
+
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
|
233
|
+
...Object.entries({
|
234
|
+
...env,
|
235
|
+
...addonEnv,
|
236
|
+
}).map(([key, value]) => `${key}=${value}`),
|
237
|
+
];
|
211
238
|
return this.ensureContainer({
|
212
239
|
...dockerOpts,
|
213
240
|
Image: dockerImage,
|
@@ -222,15 +249,7 @@ class BlockInstanceRunner {
|
|
222
249
|
HealthCheck,
|
223
250
|
ExposedPorts,
|
224
251
|
Cmd: startCmd ? startCmd.split(/\s+/g) : [],
|
225
|
-
Env
|
226
|
-
...customEnvs,
|
227
|
-
...DOCKER_ENV_VARS,
|
228
|
-
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
|
229
|
-
...Object.entries({
|
230
|
-
...env,
|
231
|
-
...addonEnv,
|
232
|
-
}).map(([key, value]) => `${key}=${value}`),
|
233
|
-
],
|
252
|
+
Env,
|
234
253
|
HostConfig: {
|
235
254
|
...customHostConfigs,
|
236
255
|
Binds: [
|
@@ -275,6 +294,15 @@ class BlockInstanceRunner {
|
|
275
294
|
// For windows we need to default to root
|
276
295
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
|
277
296
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
297
|
+
const Binds = [`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`];
|
298
|
+
if (env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]) {
|
299
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
300
|
+
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
301
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
302
|
+
// We also provide the hash to detect changes to the config file
|
303
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
304
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
305
|
+
}
|
278
306
|
return this.ensureContainer({
|
279
307
|
Image: dockerImage,
|
280
308
|
name: containerName,
|
@@ -293,7 +321,7 @@ class BlockInstanceRunner {
|
|
293
321
|
}).map(([key, value]) => `${key}=${value}`),
|
294
322
|
],
|
295
323
|
HostConfig: {
|
296
|
-
Binds
|
324
|
+
Binds,
|
297
325
|
PortBindings,
|
298
326
|
},
|
299
327
|
});
|
@@ -360,6 +388,14 @@ class BlockInstanceRunner {
|
|
360
388
|
`${(0, containerManager_1.toLocalBindVolume)(kapetaYmlPath)}:/kapeta.yml:ro`,
|
361
389
|
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`,
|
362
390
|
];
|
391
|
+
if (!local.singleton && env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]) {
|
392
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
393
|
+
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
394
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
395
|
+
// We also provide the hash to detect changes to the config file
|
396
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
397
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
398
|
+
}
|
363
399
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
364
400
|
console.log(`Ensuring container for operator block: ${containerName} [singleton: ${!!local.singleton}]`);
|
365
401
|
logs.addLog(`Ensuring container for operator block: ${containerName}`);
|
@@ -436,5 +472,13 @@ class BlockInstanceRunner {
|
|
436
472
|
pid: container.id,
|
437
473
|
};
|
438
474
|
}
|
475
|
+
async getFileHash(filePath) {
|
476
|
+
const content = await fs_extra_1.default.readFile(filePath);
|
477
|
+
const hash = crypto_1.default.createHash('md5');
|
478
|
+
//passing the data to be hashed
|
479
|
+
const data = hash.update(content);
|
480
|
+
//Creating the hash in the required format
|
481
|
+
return data.digest('hex');
|
482
|
+
}
|
439
483
|
}
|
440
484
|
exports.BlockInstanceRunner = BlockInstanceRunner;
|
@@ -8,7 +8,7 @@ declare class NetworkManager {
|
|
8
8
|
private _connections;
|
9
9
|
private _sources;
|
10
10
|
private _targets;
|
11
|
-
static toConnectionId(
|
11
|
+
static toConnectionId({ provider, consumer }: Connection): string;
|
12
12
|
constructor();
|
13
13
|
_ensureSystem(systemId: string): void;
|
14
14
|
_ensureConnection(systemId: string, connectionId: string): Traffic[];
|
@@ -14,13 +14,11 @@ class NetworkManager {
|
|
14
14
|
_connections;
|
15
15
|
_sources;
|
16
16
|
_targets;
|
17
|
-
static toConnectionId(
|
17
|
+
static toConnectionId({ provider, consumer }) {
|
18
18
|
return [
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
connection.consumer.resourceName,
|
23
|
-
].join('_');
|
19
|
+
[provider.blockId, provider.resourceName, 'PROVIDES'].join('__'),
|
20
|
+
[consumer.blockId, consumer.resourceName, 'CONSUMES'].join('__'),
|
21
|
+
].join('-');
|
24
22
|
}
|
25
23
|
constructor() {
|
26
24
|
this._connections = {};
|
@@ -22,7 +22,7 @@ declare class OperatorManager {
|
|
22
22
|
/**
|
23
23
|
* Get operator definition for resource type
|
24
24
|
*/
|
25
|
-
getOperator(fullName: string, version: string): Promise<Operator>;
|
25
|
+
getOperator(fullName: string, version: string): Promise<Operator | null>;
|
26
26
|
/**
|
27
27
|
* Get information about a specific consumed resource
|
28
28
|
*/
|
@@ -35,7 +35,7 @@ declare class OperatorManager {
|
|
35
35
|
* @param kind the full name - e.g. myhandle/rabbitmq
|
36
36
|
* @param version the version of the operator
|
37
37
|
*/
|
38
|
-
ensureOperator(systemId: string, kind: string, version: string): Promise<ContainerInfo>;
|
38
|
+
ensureOperator(systemId: string, kind: string, version: string): Promise<ContainerInfo | null>;
|
39
39
|
}
|
40
40
|
export declare const operatorManager: OperatorManager;
|
41
41
|
export {};
|
@@ -61,7 +61,8 @@ class OperatorManager {
|
|
61
61
|
throw new Error(`Unknown operator type: ${fullName}:${version}`);
|
62
62
|
}
|
63
63
|
if (!operator.definition.spec || !operator.definition.spec.local) {
|
64
|
-
|
64
|
+
console.warn(`Operator missing local definition: ${fullName}:${version}`);
|
65
|
+
return null;
|
65
66
|
}
|
66
67
|
return new Operator(operator);
|
67
68
|
}
|
@@ -95,6 +96,16 @@ class OperatorManager {
|
|
95
96
|
}
|
96
97
|
const kindUri = (0, nodejs_utils_1.parseKapetaUri)(blockResource.kind);
|
97
98
|
const operator = await this.getOperator(resourceType, kindUri.version);
|
99
|
+
if (!operator) {
|
100
|
+
return {
|
101
|
+
host: '',
|
102
|
+
port: 0,
|
103
|
+
type: '',
|
104
|
+
protocol: '',
|
105
|
+
options: {},
|
106
|
+
credentials: {},
|
107
|
+
};
|
108
|
+
}
|
98
109
|
const credentials = operator.getCredentials();
|
99
110
|
if (ensureContainer) {
|
100
111
|
await this.ensureOperator(systemId, resourceType, kindUri.version);
|
@@ -120,6 +131,9 @@ class OperatorManager {
|
|
120
131
|
}
|
121
132
|
async getOperatorPorts(systemId, kind, version) {
|
122
133
|
const operator = await this.getOperator(kind, version);
|
134
|
+
if (!operator) {
|
135
|
+
return {};
|
136
|
+
}
|
123
137
|
const operatorData = operator.getLocalData();
|
124
138
|
const portTypes = Object.keys(operatorData.ports);
|
125
139
|
portTypes.sort();
|
@@ -150,6 +164,9 @@ class OperatorManager {
|
|
150
164
|
const key = `${systemId}#${kind}:${version}`;
|
151
165
|
return await this.operatorLock.acquire(key, async () => {
|
152
166
|
const operator = await this.getOperator(kind, version);
|
167
|
+
if (!operator) {
|
168
|
+
return null;
|
169
|
+
}
|
153
170
|
const operatorData = operator.getLocalData();
|
154
171
|
const ports = await this.getOperatorPorts(systemId, kind, version);
|
155
172
|
const nameParts = [systemId, kind.toLowerCase(), version];
|
@@ -23,9 +23,12 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
23
23
|
const taskManager_1 = require("../taskManager");
|
24
24
|
const InternalConfigProvider_1 = require("./InternalConfigProvider");
|
25
25
|
const config_mapper_1 = require("@kapeta/config-mapper");
|
26
|
+
const crypto_1 = __importDefault(require("crypto"));
|
26
27
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
27
28
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
28
29
|
const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
|
30
|
+
// The maximum length of an environment variable - this is to avoid hitting the command line length limits
|
31
|
+
const MAX_ENV_LENGTH = 256;
|
29
32
|
/**
|
30
33
|
* Needed when running local docker containers as part of plan
|
31
34
|
* @type {string[]}
|
@@ -111,21 +114,28 @@ class BlockInstanceRunner {
|
|
111
114
|
const realBaseDir = await fs_extra_1.default.realpath(baseDir);
|
112
115
|
const internalConfigProvider = await (0, InternalConfigProvider_1.createInternalConfigProvider)(this._systemId, blockInstance.id, assetVersion);
|
113
116
|
// Resolve the environment variables
|
114
|
-
const
|
117
|
+
const variables = await (0, config_mapper_1.resolveKapetaVariables)(realBaseDir, internalConfigProvider);
|
115
118
|
// Write out the config templates if they exist
|
116
|
-
await (0, config_mapper_1.writeConfigTemplates)(
|
119
|
+
await (0, config_mapper_1.writeConfigTemplates)(variables, realBaseDir);
|
120
|
+
const env = await (0, config_mapper_1.getEnvironmentVariables)(variables);
|
121
|
+
// Gets the tmp path to write the config file
|
122
|
+
const configFilePath = (0, config_mapper_1.getConfigFilePath)(blockInstance.id);
|
123
|
+
// Write the config to a file - will be read by the SDKs
|
124
|
+
await (0, config_mapper_1.writeEnvConfigFile)(variables, configFilePath);
|
125
|
+
// Add the config file path to the environment variables
|
126
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = configFilePath;
|
117
127
|
let processInfo;
|
118
128
|
if (providerVersion.definition.kind === types_1.KIND_BLOCK_TYPE_OPERATOR) {
|
119
|
-
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion,
|
129
|
+
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
|
120
130
|
}
|
121
131
|
else {
|
122
132
|
//We need a port type to know how to connect to the block consistently
|
123
133
|
const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
|
124
134
|
if (blockUri.version === 'local') {
|
125
|
-
processInfo = await this._startLocalProcess(blockInstance, blockUri,
|
135
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
|
126
136
|
}
|
127
137
|
else {
|
128
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri,
|
138
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion);
|
129
139
|
}
|
130
140
|
if (portTypes.length > 0) {
|
131
141
|
processInfo.portType = portTypes[0];
|
@@ -200,6 +210,14 @@ class BlockInstanceRunner {
|
|
200
210
|
if (localContainer.healthcheck) {
|
201
211
|
HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
202
212
|
}
|
213
|
+
if (env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]) {
|
214
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
215
|
+
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
216
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
217
|
+
// We also provide the hash to detect changes to the config file
|
218
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
219
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
220
|
+
}
|
203
221
|
const Mounts = isDockerImage
|
204
222
|
? // For docker images we mount the local directory to the working directory
|
205
223
|
containerManager_1.containerManager.toDockerMounts({
|
@@ -208,6 +226,15 @@ class BlockInstanceRunner {
|
|
208
226
|
: // For dockerfiles we don't mount anything
|
209
227
|
[];
|
210
228
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
229
|
+
const Env = [
|
230
|
+
...customEnvs,
|
231
|
+
...DOCKER_ENV_VARS,
|
232
|
+
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
|
233
|
+
...Object.entries({
|
234
|
+
...env,
|
235
|
+
...addonEnv,
|
236
|
+
}).map(([key, value]) => `${key}=${value}`),
|
237
|
+
];
|
211
238
|
return this.ensureContainer({
|
212
239
|
...dockerOpts,
|
213
240
|
Image: dockerImage,
|
@@ -222,15 +249,7 @@ class BlockInstanceRunner {
|
|
222
249
|
HealthCheck,
|
223
250
|
ExposedPorts,
|
224
251
|
Cmd: startCmd ? startCmd.split(/\s+/g) : [],
|
225
|
-
Env
|
226
|
-
...customEnvs,
|
227
|
-
...DOCKER_ENV_VARS,
|
228
|
-
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService_1.clusterService.getClusterServicePort()}`,
|
229
|
-
...Object.entries({
|
230
|
-
...env,
|
231
|
-
...addonEnv,
|
232
|
-
}).map(([key, value]) => `${key}=${value}`),
|
233
|
-
],
|
252
|
+
Env,
|
234
253
|
HostConfig: {
|
235
254
|
...customHostConfigs,
|
236
255
|
Binds: [
|
@@ -275,6 +294,15 @@ class BlockInstanceRunner {
|
|
275
294
|
// For windows we need to default to root
|
276
295
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
|
277
296
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
297
|
+
const Binds = [`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`];
|
298
|
+
if (env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]) {
|
299
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
300
|
+
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
301
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
302
|
+
// We also provide the hash to detect changes to the config file
|
303
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
304
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
305
|
+
}
|
278
306
|
return this.ensureContainer({
|
279
307
|
Image: dockerImage,
|
280
308
|
name: containerName,
|
@@ -293,7 +321,7 @@ class BlockInstanceRunner {
|
|
293
321
|
}).map(([key, value]) => `${key}=${value}`),
|
294
322
|
],
|
295
323
|
HostConfig: {
|
296
|
-
Binds
|
324
|
+
Binds,
|
297
325
|
PortBindings,
|
298
326
|
},
|
299
327
|
});
|
@@ -360,6 +388,14 @@ class BlockInstanceRunner {
|
|
360
388
|
`${(0, containerManager_1.toLocalBindVolume)(kapetaYmlPath)}:/kapeta.yml:ro`,
|
361
389
|
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`,
|
362
390
|
];
|
391
|
+
if (!local.singleton && env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]) {
|
392
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
393
|
+
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
394
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
395
|
+
// We also provide the hash to detect changes to the config file
|
396
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
397
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
398
|
+
}
|
363
399
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
364
400
|
console.log(`Ensuring container for operator block: ${containerName} [singleton: ${!!local.singleton}]`);
|
365
401
|
logs.addLog(`Ensuring container for operator block: ${containerName}`);
|
@@ -436,5 +472,13 @@ class BlockInstanceRunner {
|
|
436
472
|
pid: container.id,
|
437
473
|
};
|
438
474
|
}
|
475
|
+
async getFileHash(filePath) {
|
476
|
+
const content = await fs_extra_1.default.readFile(filePath);
|
477
|
+
const hash = crypto_1.default.createHash('md5');
|
478
|
+
//passing the data to be hashed
|
479
|
+
const data = hash.update(content);
|
480
|
+
//Creating the hash in the required format
|
481
|
+
return data.digest('hex');
|
482
|
+
}
|
439
483
|
}
|
440
484
|
exports.BlockInstanceRunner = BlockInstanceRunner;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.40.
|
3
|
+
"version": "0.40.6",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -49,7 +49,7 @@
|
|
49
49
|
"homepage": "https://github.com/kapetacom/local-cluster-service#readme",
|
50
50
|
"dependencies": {
|
51
51
|
"@kapeta/codegen": "^1.3.0",
|
52
|
-
"@kapeta/config-mapper": "^1.
|
52
|
+
"@kapeta/config-mapper": "^1.2.0",
|
53
53
|
"@kapeta/local-cluster-config": "^0.4.1",
|
54
54
|
"@kapeta/nodejs-api-client": ">=0.2.0 <2",
|
55
55
|
"@kapeta/nodejs-process": "^1.2.0",
|
package/src/networkManager.ts
CHANGED
@@ -13,13 +13,11 @@ class NetworkManager {
|
|
13
13
|
private _sources: { [systemId: string]: { [instanceId: string]: Traffic[] } };
|
14
14
|
private _targets: { [systemId: string]: { [instanceId: string]: Traffic[] } };
|
15
15
|
|
16
|
-
static toConnectionId(
|
16
|
+
static toConnectionId({ provider, consumer }: Connection) {
|
17
17
|
return [
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
connection.consumer.resourceName,
|
22
|
-
].join('_');
|
18
|
+
[provider.blockId, provider.resourceName, 'PROVIDES'].join('__'),
|
19
|
+
[consumer.blockId, consumer.resourceName, 'CONSUMES'].join('__'),
|
20
|
+
].join('-');
|
23
21
|
}
|
24
22
|
|
25
23
|
constructor() {
|
package/src/operatorManager.ts
CHANGED
@@ -83,7 +83,8 @@ class OperatorManager {
|
|
83
83
|
}
|
84
84
|
|
85
85
|
if (!operator.definition.spec || !operator.definition.spec.local) {
|
86
|
-
|
86
|
+
console.warn(`Operator missing local definition: ${fullName}:${version}`);
|
87
|
+
return null;
|
87
88
|
}
|
88
89
|
|
89
90
|
return new Operator(operator);
|
@@ -138,6 +139,16 @@ class OperatorManager {
|
|
138
139
|
|
139
140
|
const kindUri = parseKapetaUri(blockResource.kind);
|
140
141
|
const operator = await this.getOperator(resourceType, kindUri.version);
|
142
|
+
if (!operator) {
|
143
|
+
return {
|
144
|
+
host: '',
|
145
|
+
port: 0,
|
146
|
+
type: '',
|
147
|
+
protocol: '',
|
148
|
+
options: {},
|
149
|
+
credentials: {},
|
150
|
+
};
|
151
|
+
}
|
141
152
|
const credentials = operator.getCredentials();
|
142
153
|
if (ensureContainer) {
|
143
154
|
await this.ensureOperator(systemId, resourceType, kindUri.version);
|
@@ -168,6 +179,9 @@ class OperatorManager {
|
|
168
179
|
|
169
180
|
async getOperatorPorts(systemId: string, kind: string, version: string) {
|
170
181
|
const operator = await this.getOperator(kind, version);
|
182
|
+
if (!operator) {
|
183
|
+
return {};
|
184
|
+
}
|
171
185
|
|
172
186
|
const operatorData = operator.getLocalData();
|
173
187
|
|
@@ -201,13 +215,16 @@ class OperatorManager {
|
|
201
215
|
* @param kind the full name - e.g. myhandle/rabbitmq
|
202
216
|
* @param version the version of the operator
|
203
217
|
*/
|
204
|
-
async ensureOperator(systemId: string, kind: string, version: string): Promise<ContainerInfo> {
|
218
|
+
async ensureOperator(systemId: string, kind: string, version: string): Promise<ContainerInfo | null> {
|
205
219
|
systemId = normalizeKapetaUri(systemId);
|
206
220
|
|
207
221
|
const key = `${systemId}#${kind}:${version}`;
|
208
222
|
|
209
223
|
return await this.operatorLock.acquire(key, async () => {
|
210
224
|
const operator = await this.getOperator(kind, version);
|
225
|
+
if (!operator) {
|
226
|
+
return null;
|
227
|
+
}
|
211
228
|
|
212
229
|
const operatorData = operator.getLocalData();
|
213
230
|
|
@@ -34,12 +34,24 @@ import Path from 'node:path';
|
|
34
34
|
import { taskManager } from '../taskManager';
|
35
35
|
import { LocalDevContainer, LocalInstance } from '@kapeta/schemas';
|
36
36
|
import { createInternalConfigProvider } from './InternalConfigProvider';
|
37
|
-
import {
|
37
|
+
import {
|
38
|
+
getConfigFilePath,
|
39
|
+
getEnvironmentVariables,
|
40
|
+
KAPETA_CONFIG_ENV_VAR,
|
41
|
+
KAPETA_ENV_CONFIG_FILE,
|
42
|
+
resolveKapetaVariables,
|
43
|
+
writeConfigTemplates,
|
44
|
+
writeEnvConfigFile,
|
45
|
+
} from '@kapeta/config-mapper';
|
46
|
+
import crypto from 'crypto';
|
38
47
|
|
39
48
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
40
49
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
41
50
|
const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
|
42
51
|
|
52
|
+
// The maximum length of an environment variable - this is to avoid hitting the command line length limits
|
53
|
+
const MAX_ENV_LENGTH = 256;
|
54
|
+
|
43
55
|
/**
|
44
56
|
* Needed when running local docker containers as part of plan
|
45
57
|
* @type {string[]}
|
@@ -145,23 +157,34 @@ export class BlockInstanceRunner {
|
|
145
157
|
);
|
146
158
|
|
147
159
|
// Resolve the environment variables
|
148
|
-
const
|
160
|
+
const variables = await resolveKapetaVariables(realBaseDir, internalConfigProvider);
|
149
161
|
|
150
162
|
// Write out the config templates if they exist
|
151
|
-
await writeConfigTemplates(
|
163
|
+
await writeConfigTemplates(variables, realBaseDir);
|
164
|
+
|
165
|
+
const env = await getEnvironmentVariables(variables);
|
166
|
+
|
167
|
+
// Gets the tmp path to write the config file
|
168
|
+
const configFilePath = getConfigFilePath(blockInstance.id);
|
169
|
+
|
170
|
+
// Write the config to a file - will be read by the SDKs
|
171
|
+
await writeEnvConfigFile(variables, configFilePath);
|
172
|
+
|
173
|
+
// Add the config file path to the environment variables
|
174
|
+
env[KAPETA_CONFIG_ENV_VAR] = configFilePath;
|
152
175
|
|
153
176
|
let processInfo: ProcessInfo;
|
154
177
|
|
155
178
|
if (providerVersion.definition.kind === KIND_BLOCK_TYPE_OPERATOR) {
|
156
|
-
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion,
|
179
|
+
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
|
157
180
|
} else {
|
158
181
|
//We need a port type to know how to connect to the block consistently
|
159
182
|
const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
|
160
183
|
|
161
184
|
if (blockUri.version === 'local') {
|
162
|
-
processInfo = await this._startLocalProcess(blockInstance, blockUri,
|
185
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
|
163
186
|
} else {
|
164
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri,
|
187
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion);
|
165
188
|
}
|
166
189
|
|
167
190
|
if (portTypes.length > 0) {
|
@@ -269,6 +292,15 @@ export class BlockInstanceRunner {
|
|
269
292
|
HealthCheck = containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
270
293
|
}
|
271
294
|
|
295
|
+
if (env[KAPETA_CONFIG_ENV_VAR]) {
|
296
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
297
|
+
const localConfig = `/${KAPETA_ENV_CONFIG_FILE}`;
|
298
|
+
Binds.push(`${toLocalBindVolume(env[KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
299
|
+
// We also provide the hash to detect changes to the config file
|
300
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[KAPETA_CONFIG_ENV_VAR]);
|
301
|
+
env[KAPETA_CONFIG_ENV_VAR] = localConfig;
|
302
|
+
}
|
303
|
+
|
272
304
|
const Mounts = isDockerImage
|
273
305
|
? // For docker images we mount the local directory to the working directory
|
274
306
|
containerManager.toDockerMounts({
|
@@ -279,6 +311,16 @@ export class BlockInstanceRunner {
|
|
279
311
|
|
280
312
|
const systemUri = parseKapetaUri(this._systemId);
|
281
313
|
|
314
|
+
const Env = [
|
315
|
+
...customEnvs,
|
316
|
+
...DOCKER_ENV_VARS,
|
317
|
+
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
|
318
|
+
...Object.entries({
|
319
|
+
...env,
|
320
|
+
...addonEnv,
|
321
|
+
}).map(([key, value]) => `${key}=${value}`),
|
322
|
+
];
|
323
|
+
|
282
324
|
return this.ensureContainer({
|
283
325
|
...dockerOpts,
|
284
326
|
Image: dockerImage,
|
@@ -293,15 +335,7 @@ export class BlockInstanceRunner {
|
|
293
335
|
HealthCheck,
|
294
336
|
ExposedPorts,
|
295
337
|
Cmd: startCmd ? startCmd.split(/\s+/g) : [],
|
296
|
-
Env
|
297
|
-
...customEnvs,
|
298
|
-
...DOCKER_ENV_VARS,
|
299
|
-
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
|
300
|
-
...Object.entries({
|
301
|
-
...env,
|
302
|
-
...addonEnv,
|
303
|
-
}).map(([key, value]) => `${key}=${value}`),
|
304
|
-
],
|
338
|
+
Env,
|
305
339
|
HostConfig: {
|
306
340
|
...customHostConfigs,
|
307
341
|
Binds: [
|
@@ -372,6 +406,16 @@ export class BlockInstanceRunner {
|
|
372
406
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
373
407
|
const systemUri = parseKapetaUri(this._systemId);
|
374
408
|
|
409
|
+
const Binds = [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`];
|
410
|
+
if (env[KAPETA_CONFIG_ENV_VAR]) {
|
411
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
412
|
+
const localConfig = `/${KAPETA_ENV_CONFIG_FILE}`;
|
413
|
+
Binds.push(`${toLocalBindVolume(env[KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
414
|
+
// We also provide the hash to detect changes to the config file
|
415
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[KAPETA_CONFIG_ENV_VAR]);
|
416
|
+
env[KAPETA_CONFIG_ENV_VAR] = localConfig;
|
417
|
+
}
|
418
|
+
|
375
419
|
return this.ensureContainer({
|
376
420
|
Image: dockerImage,
|
377
421
|
name: containerName,
|
@@ -390,7 +434,7 @@ export class BlockInstanceRunner {
|
|
390
434
|
}).map(([key, value]) => `${key}=${value}`),
|
391
435
|
],
|
392
436
|
HostConfig: {
|
393
|
-
Binds
|
437
|
+
Binds,
|
394
438
|
PortBindings,
|
395
439
|
},
|
396
440
|
});
|
@@ -486,6 +530,15 @@ export class BlockInstanceRunner {
|
|
486
530
|
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
487
531
|
];
|
488
532
|
|
533
|
+
if (!local.singleton && env[KAPETA_CONFIG_ENV_VAR]) {
|
534
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
535
|
+
const localConfig = `/${KAPETA_ENV_CONFIG_FILE}`;
|
536
|
+
Binds.push(`${toLocalBindVolume(env[KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
537
|
+
// We also provide the hash to detect changes to the config file
|
538
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[KAPETA_CONFIG_ENV_VAR]);
|
539
|
+
env[KAPETA_CONFIG_ENV_VAR] = localConfig;
|
540
|
+
}
|
541
|
+
|
489
542
|
const systemUri = parseKapetaUri(this._systemId);
|
490
543
|
|
491
544
|
console.log(
|
@@ -583,4 +636,13 @@ export class BlockInstanceRunner {
|
|
583
636
|
pid: container.id,
|
584
637
|
};
|
585
638
|
}
|
639
|
+
|
640
|
+
private async getFileHash(filePath: string) {
|
641
|
+
const content = await FSExtra.readFile(filePath);
|
642
|
+
const hash = crypto.createHash('md5');
|
643
|
+
//passing the data to be hashed
|
644
|
+
const data = hash.update(content);
|
645
|
+
//Creating the hash in the required format
|
646
|
+
return data.digest('hex');
|
647
|
+
}
|
586
648
|
}
|