@kapeta/local-cluster-service 0.41.1 → 0.42.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/CHANGELOG.md +7 -0
- package/definitions.d.ts +4 -0
- package/dist/cjs/src/config/routes.js +16 -2
- package/dist/cjs/src/configManager.d.ts +7 -1
- package/dist/cjs/src/configManager.js +89 -3
- package/dist/cjs/src/instanceManager.js +1 -3
- package/dist/cjs/src/types.d.ts +0 -1
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +3 -2
- package/dist/cjs/src/utils/BlockInstanceRunner.js +29 -24
- package/dist/cjs/src/utils/InternalConfigProvider.d.ts +1 -1
- package/dist/cjs/src/utils/InternalConfigProvider.js +1 -3
- package/dist/esm/src/config/routes.js +16 -2
- package/dist/esm/src/configManager.d.ts +7 -1
- package/dist/esm/src/configManager.js +89 -3
- package/dist/esm/src/instanceManager.js +1 -3
- package/dist/esm/src/types.d.ts +0 -1
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +3 -2
- package/dist/esm/src/utils/BlockInstanceRunner.js +29 -24
- package/dist/esm/src/utils/InternalConfigProvider.d.ts +1 -1
- package/dist/esm/src/utils/InternalConfigProvider.js +1 -3
- package/package.json +2 -1
- package/src/config/routes.ts +28 -2
- package/src/configManager.ts +121 -8
- package/src/instanceManager.ts +1 -3
- package/src/types.ts +0 -1
- package/src/utils/BlockInstanceRunner.ts +48 -28
- package/src/utils/InternalConfigProvider.ts +2 -2
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# [0.42.0](https://github.com/kapetacom/local-cluster-service/compare/v0.41.1...v0.42.0) (2024-04-18)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* Add support for file config values ([#141](https://github.com/kapetacom/local-cluster-service/issues/141)) ([437eb75](https://github.com/kapetacom/local-cluster-service/commit/437eb75a1c5c94979cca4fedae6a2d1756f0043d))
|
7
|
+
|
1
8
|
## [0.41.1](https://github.com/kapetacom/local-cluster-service/compare/v0.41.0...v0.41.1) (2024-04-16)
|
2
9
|
|
3
10
|
|
package/definitions.d.ts
CHANGED
@@ -7,6 +7,10 @@ declare module 'recursive-watch' {
|
|
7
7
|
export default function watch(path: string, callback: (filename: string) => void): () => void;
|
8
8
|
}
|
9
9
|
|
10
|
+
declare module 'parse-data-uri' {
|
11
|
+
export default function parseDataUri(uri: string): { data: Buffer; mediaType: string };
|
12
|
+
}
|
13
|
+
|
10
14
|
declare module '@kapeta/nodejs-registry-utils' {
|
11
15
|
import { Dependency, Kind } from '@kapeta/schemas';
|
12
16
|
|
@@ -15,6 +15,8 @@ const instanceManager_1 = require("../instanceManager");
|
|
15
15
|
const cors_1 = require("../middleware/cors");
|
16
16
|
const kapeta_1 = require("../middleware/kapeta");
|
17
17
|
const stringBody_1 = require("../middleware/stringBody");
|
18
|
+
const assetManager_1 = require("../assetManager");
|
19
|
+
const definitionsManager_1 = require("../definitionsManager");
|
18
20
|
const router = (0, express_promise_router_1.default)();
|
19
21
|
router.use('/', cors_1.corsHandler);
|
20
22
|
router.use('/', kapeta_1.kapetaHeaders);
|
@@ -26,7 +28,7 @@ router.get('/instance', async (req, res) => {
|
|
26
28
|
try {
|
27
29
|
let config = {};
|
28
30
|
if (req.kapeta.instanceId) {
|
29
|
-
config = await configManager_1.configManager.getConfigForBlockInstance(req.kapeta.systemId, req.kapeta.instanceId);
|
31
|
+
config = await configManager_1.configManager.getConfigForBlockInstance(req.kapeta.systemId, req.kapeta.instanceId, req.kapeta?.environment === 'docker');
|
30
32
|
}
|
31
33
|
else {
|
32
34
|
config = configManager_1.configManager.getConfigForSystem(req.kapeta.systemId);
|
@@ -49,7 +51,19 @@ router.put('/instance', async (req, res) => {
|
|
49
51
|
config = {};
|
50
52
|
}
|
51
53
|
if (req.kapeta.instanceId) {
|
52
|
-
|
54
|
+
const blockInstance = await assetManager_1.assetManager.getBlockInstance(req.kapeta.systemId, req.kapeta.instanceId);
|
55
|
+
if (!blockInstance) {
|
56
|
+
throw new Error(`Block instance not found: ${req.kapeta.instanceId} in plan ${req.kapeta.systemId}`);
|
57
|
+
}
|
58
|
+
const blockDefinition = await definitionsManager_1.definitionsManager.getDefinition(blockInstance.block.ref);
|
59
|
+
if (!blockDefinition) {
|
60
|
+
throw new Error(`Block definition not found: ${blockInstance.block.ref}`);
|
61
|
+
}
|
62
|
+
let configEntityList = {};
|
63
|
+
if (blockDefinition.definition.spec.configuration) {
|
64
|
+
configEntityList = blockDefinition.definition.spec.configuration;
|
65
|
+
}
|
66
|
+
await configManager_1.configManager.setConfigForBlockInstance(req.kapeta.systemId, req.kapeta.instanceId, configEntityList, config);
|
53
67
|
//Restart the instance if it is running after config change
|
54
68
|
await instanceManager_1.instanceManager.prepareForRestart(req.kapeta.systemId, req.kapeta.instanceId);
|
55
69
|
}
|
@@ -2,6 +2,8 @@
|
|
2
2
|
* Copyright 2023 Kapeta Inc.
|
3
3
|
* SPDX-License-Identifier: BUSL-1.1
|
4
4
|
*/
|
5
|
+
import { EntityList } from '@kapeta/schemas';
|
6
|
+
import { StringMap } from './types';
|
5
7
|
export declare const SYSTEM_ID = "$plan";
|
6
8
|
type AnyMap = {
|
7
9
|
[key: string]: any;
|
@@ -16,8 +18,12 @@ declare class ConfigManager {
|
|
16
18
|
_forSystem(systemId: string): any;
|
17
19
|
setConfigForSystem(systemId: string, config: AnyMap): void;
|
18
20
|
getConfigForSystem(systemId: string): AnyMap;
|
19
|
-
getConfigForBlockInstance(systemId: string, instanceId: string): Promise<import("./types").AnyMap>;
|
21
|
+
getConfigForBlockInstance(systemId: string, instanceId: string, rewritePaths?: boolean): Promise<import("./types").AnyMap>;
|
22
|
+
rewriteFilePaths(configSchema: EntityList, config: AnyMap, toBaseDir?: string): StringMap;
|
20
23
|
setConfigForSection(systemId: string, sectionId: string, config: AnyMap): void;
|
24
|
+
getFilesBaseDir(): string;
|
25
|
+
private saveFile;
|
26
|
+
setConfigForBlockInstance(systemId: string, instanceId: string, configEntityList: EntityList, config: AnyMap): Promise<void>;
|
21
27
|
getConfigForSection(systemId: string, sectionId: string): any;
|
22
28
|
/**
|
23
29
|
* Try to identify the plan and instance in a plan automatically based on the block reference
|
@@ -3,12 +3,22 @@
|
|
3
3
|
* Copyright 2023 Kapeta Inc.
|
4
4
|
* SPDX-License-Identifier: BUSL-1.1
|
5
5
|
*/
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
8
|
+
};
|
6
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
7
10
|
exports.configManager = exports.SYSTEM_ID = void 0;
|
8
|
-
const storageService_1 = require("./storageService");
|
9
11
|
const assetManager_1 = require("./assetManager");
|
12
|
+
const schemas_1 = require("@kapeta/schemas");
|
13
|
+
const storageService_1 = require("./storageService");
|
10
14
|
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
11
15
|
const utils_1 = require("./utils/utils");
|
16
|
+
const parse_data_uri_1 = __importDefault(require("parse-data-uri"));
|
17
|
+
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
18
|
+
const path_1 = __importDefault(require("path"));
|
19
|
+
const node_uuid_1 = __importDefault(require("node-uuid"));
|
20
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
21
|
+
const lodash_1 = __importDefault(require("lodash"));
|
12
22
|
exports.SYSTEM_ID = '$plan';
|
13
23
|
class ConfigManager {
|
14
24
|
_config;
|
@@ -31,14 +41,49 @@ class ConfigManager {
|
|
31
41
|
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
32
42
|
return this._forSystem(systemId);
|
33
43
|
}
|
34
|
-
async getConfigForBlockInstance(systemId, instanceId) {
|
44
|
+
async getConfigForBlockInstance(systemId, instanceId, rewritePaths = false) {
|
35
45
|
const blockInstance = await assetManager_1.assetManager.getBlockInstance(systemId, instanceId);
|
36
46
|
const blockAsset = await assetManager_1.assetManager.getAsset(blockInstance.block.ref, true);
|
37
47
|
if (!blockAsset) {
|
38
48
|
throw new Error(`Block definition not found: ${blockInstance.block.ref}`);
|
39
49
|
}
|
40
50
|
const instanceConfig = this.getConfigForSection(systemId, instanceId);
|
41
|
-
|
51
|
+
const config = lodash_1.default.cloneDeep((0, utils_1.getResolvedConfiguration)(blockAsset.data.spec.configuration, instanceConfig, blockInstance.defaultConfiguration));
|
52
|
+
if (rewritePaths) {
|
53
|
+
this.rewriteFilePaths(blockAsset.data.spec.configuration, config);
|
54
|
+
}
|
55
|
+
return config;
|
56
|
+
}
|
57
|
+
rewriteFilePaths(configSchema, config, toBaseDir = '/files') {
|
58
|
+
const fileMap = {};
|
59
|
+
if (!configSchema || !configSchema.types) {
|
60
|
+
return fileMap;
|
61
|
+
}
|
62
|
+
const fromBaseDir = this.getFilesBaseDir();
|
63
|
+
for (const entity of configSchema.types) {
|
64
|
+
if (entity.type !== schemas_1.EntityType.Dto) {
|
65
|
+
continue;
|
66
|
+
}
|
67
|
+
if (!entity.properties || !config[entity.name]) {
|
68
|
+
continue;
|
69
|
+
}
|
70
|
+
const innerValue = config[entity.name];
|
71
|
+
for (const key in entity.properties) {
|
72
|
+
const prop = entity.properties[key];
|
73
|
+
if (prop.type !== 'file') {
|
74
|
+
continue;
|
75
|
+
}
|
76
|
+
const value = innerValue[key];
|
77
|
+
if (!value || !value.startsWith(fromBaseDir)) {
|
78
|
+
continue;
|
79
|
+
}
|
80
|
+
const src = value;
|
81
|
+
const dst = toBaseDir + '/' + value.substring(fromBaseDir.length + 1);
|
82
|
+
fileMap[src] = dst;
|
83
|
+
innerValue[key] = dst;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return fileMap;
|
42
87
|
}
|
43
88
|
setConfigForSection(systemId, sectionId, config) {
|
44
89
|
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
@@ -46,6 +91,47 @@ class ConfigManager {
|
|
46
91
|
systemConfig[sectionId] = config || {};
|
47
92
|
storageService_1.storageService.put('config', systemId, systemConfig);
|
48
93
|
}
|
94
|
+
getFilesBaseDir() {
|
95
|
+
return path_1.default.join(local_cluster_config_1.default.getKapetaBasedir(), 'files');
|
96
|
+
}
|
97
|
+
async saveFile(value) {
|
98
|
+
const filename = node_uuid_1.default.v4();
|
99
|
+
const basePath = this.getFilesBaseDir();
|
100
|
+
await fs_extra_1.default.mkdirp(basePath);
|
101
|
+
const filepath = path_1.default.join(basePath, filename);
|
102
|
+
await fs_extra_1.default.writeFile(filepath, value);
|
103
|
+
return filepath;
|
104
|
+
}
|
105
|
+
async setConfigForBlockInstance(systemId, instanceId, configEntityList, config) {
|
106
|
+
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
107
|
+
let systemConfig = this._forSystem(systemId);
|
108
|
+
let configValue = config || {};
|
109
|
+
if (configEntityList.types) {
|
110
|
+
for (let entity of configEntityList.types) {
|
111
|
+
if (entity.type !== schemas_1.EntityType.Dto) {
|
112
|
+
continue;
|
113
|
+
}
|
114
|
+
if (!configValue[entity.name] || !entity.properties) {
|
115
|
+
continue;
|
116
|
+
}
|
117
|
+
const innerValues = configValue[entity.name];
|
118
|
+
for (let key in innerValues) {
|
119
|
+
if (!entity.properties[key]) {
|
120
|
+
continue;
|
121
|
+
}
|
122
|
+
if (entity.properties[key].type === 'file' &&
|
123
|
+
typeof innerValues[key] === 'string' &&
|
124
|
+
innerValues[key].startsWith('data:')) {
|
125
|
+
// This was a file upload - save the file to disk and replace value with path
|
126
|
+
const data = (0, parse_data_uri_1.default)(innerValues[key]);
|
127
|
+
innerValues[key] = await this.saveFile(data.data);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
systemConfig[instanceId] = configValue;
|
133
|
+
storageService_1.storageService.put('config', systemId, systemConfig);
|
134
|
+
}
|
49
135
|
getConfigForSection(systemId, sectionId) {
|
50
136
|
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
51
137
|
const systemConfig = this._forSystem(systemId);
|
@@ -17,7 +17,6 @@ const socketManager_1 = require("./socketManager");
|
|
17
17
|
const serviceManager_1 = require("./serviceManager");
|
18
18
|
const assetManager_1 = require("./assetManager");
|
19
19
|
const containerManager_1 = require("./containerManager");
|
20
|
-
const configManager_1 = require("./configManager");
|
21
20
|
const types_1 = require("./types");
|
22
21
|
const utils_1 = require("./utils/utils");
|
23
22
|
const operatorManager_1 = require("./operatorManager");
|
@@ -501,12 +500,11 @@ class InstanceManager {
|
|
501
500
|
return existingInstance;
|
502
501
|
}
|
503
502
|
}
|
504
|
-
const resolvedConfig = await configManager_1.configManager.getConfigForBlockInstance(systemId, instanceId);
|
505
503
|
const task = taskManager_1.taskManager.add(`instance:start:${systemId}:${instanceId}`, async () => {
|
506
504
|
const runner = new BlockInstanceRunner_1.BlockInstanceRunner(systemId);
|
507
505
|
const startTime = Date.now();
|
508
506
|
try {
|
509
|
-
const processInfo = await runner.start(blockRef, instanceId
|
507
|
+
const processInfo = await runner.start(blockRef, instanceId);
|
510
508
|
instance.status = types_1.InstanceStatus.STARTING;
|
511
509
|
return this.saveInternalInstance({
|
512
510
|
...instance,
|
package/dist/cjs/src/types.d.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
* Copyright 2023 Kapeta Inc.
|
3
3
|
* SPDX-License-Identifier: BUSL-1.1
|
4
4
|
*/
|
5
|
-
import {
|
5
|
+
import { ProcessInfo } from '../types';
|
6
6
|
export declare function resolvePortType(portType: string): string;
|
7
7
|
export declare class BlockInstanceRunner {
|
8
8
|
private readonly _systemId;
|
@@ -11,12 +11,13 @@ export declare class BlockInstanceRunner {
|
|
11
11
|
* Start a block
|
12
12
|
*
|
13
13
|
*/
|
14
|
-
start(blockRef: string, instanceId: string
|
14
|
+
start(blockRef: string, instanceId: string): Promise<ProcessInfo>;
|
15
15
|
private _execute;
|
16
16
|
/**
|
17
17
|
* Starts local process
|
18
18
|
*/
|
19
19
|
private _startLocalProcess;
|
20
|
+
private prepareBinds;
|
20
21
|
private _startDockerProcess;
|
21
22
|
private _startOperatorProcess;
|
22
23
|
/**
|
@@ -24,6 +24,7 @@ const taskManager_1 = require("../taskManager");
|
|
24
24
|
const InternalConfigProvider_1 = require("./InternalConfigProvider");
|
25
25
|
const config_mapper_1 = require("@kapeta/config-mapper");
|
26
26
|
const crypto_1 = __importDefault(require("crypto"));
|
27
|
+
const configManager_1 = require("../configManager");
|
27
28
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
28
29
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
29
30
|
const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
|
@@ -89,11 +90,10 @@ class BlockInstanceRunner {
|
|
89
90
|
* Start a block
|
90
91
|
*
|
91
92
|
*/
|
92
|
-
async start(blockRef, instanceId
|
93
|
+
async start(blockRef, instanceId) {
|
93
94
|
return this._execute({
|
94
95
|
ref: blockRef,
|
95
96
|
id: instanceId,
|
96
|
-
configuration,
|
97
97
|
});
|
98
98
|
}
|
99
99
|
async _execute(blockInstance) {
|
@@ -112,7 +112,10 @@ class BlockInstanceRunner {
|
|
112
112
|
}
|
113
113
|
const baseDir = local_cluster_config_1.default.getRepositoryAssetPath(blockUri.handle, blockUri.name, blockUri.version);
|
114
114
|
const realBaseDir = await fs_extra_1.default.realpath(baseDir);
|
115
|
-
const
|
115
|
+
const config = await configManager_1.configManager.getConfigForBlockInstance(this._systemId, blockInstance.id);
|
116
|
+
const configSchema = (assetVersion.definition.spec.configuration ? assetVersion.definition.spec.configuration : {});
|
117
|
+
const fileMapping = configManager_1.configManager.rewriteFilePaths(configSchema, config);
|
118
|
+
const internalConfigProvider = await (0, InternalConfigProvider_1.createInternalConfigProvider)(this._systemId, blockInstance.id, assetVersion, config);
|
116
119
|
// Resolve the environment variables
|
117
120
|
const blockVariables = await (0, config_mapper_1.resolveKapetaVariables)(realBaseDir, internalConfigProvider);
|
118
121
|
const variables = await this.appendConnectedBlockOperatorEnv(internalConfigProvider, blockInstance, blockVariables);
|
@@ -133,10 +136,10 @@ class BlockInstanceRunner {
|
|
133
136
|
//We need a port type to know how to connect to the block consistently
|
134
137
|
const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
|
135
138
|
if (blockUri.version === 'local') {
|
136
|
-
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
|
139
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion, fileMapping);
|
137
140
|
}
|
138
141
|
else {
|
139
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion);
|
142
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion, fileMapping);
|
140
143
|
}
|
141
144
|
if (portTypes.length > 0) {
|
142
145
|
processInfo.portType = portTypes[0];
|
@@ -147,7 +150,7 @@ class BlockInstanceRunner {
|
|
147
150
|
/**
|
148
151
|
* Starts local process
|
149
152
|
*/
|
150
|
-
async _startLocalProcess(blockInstance, blockInfo, env, assetVersion) {
|
153
|
+
async _startLocalProcess(blockInstance, blockInfo, env, assetVersion, fileMapping) {
|
151
154
|
const baseDir = local_cluster_config_1.default.getRepositoryAssetPath(blockInfo.handle, blockInfo.name, blockInfo.version);
|
152
155
|
if (!fs_extra_1.default.existsSync(baseDir)) {
|
153
156
|
throw new Error(`Local block not registered correctly - expected symlink here: ${baseDir}.\n` +
|
@@ -211,14 +214,7 @@ class BlockInstanceRunner {
|
|
211
214
|
if (localContainer.healthcheck) {
|
212
215
|
HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
213
216
|
}
|
214
|
-
|
215
|
-
// If we have a config file, we need to bind it to the container and adjust the env var
|
216
|
-
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
217
|
-
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
218
|
-
// We also provide the hash to detect changes to the config file
|
219
|
-
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
220
|
-
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
221
|
-
}
|
217
|
+
await this.prepareBinds(env, Binds, fileMapping);
|
222
218
|
const Mounts = isDockerImage
|
223
219
|
? // For docker images we mount the local directory to the working directory
|
224
220
|
containerManager_1.containerManager.toDockerMounts({
|
@@ -271,7 +267,22 @@ class BlockInstanceRunner {
|
|
271
267
|
},
|
272
268
|
});
|
273
269
|
}
|
274
|
-
async
|
270
|
+
async prepareBinds(env, Binds, fileMapping) {
|
271
|
+
if (env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]) {
|
272
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
273
|
+
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
274
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
275
|
+
// We also provide the hash to detect changes to the config file
|
276
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
277
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
278
|
+
}
|
279
|
+
if (fileMapping) {
|
280
|
+
Object.entries(fileMapping).forEach(([src, dst]) => {
|
281
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(src)}:${dst}:ro`);
|
282
|
+
});
|
283
|
+
}
|
284
|
+
}
|
285
|
+
async _startDockerProcess(blockInstance, blockInfo, env, assetVersion, fileMapping) {
|
275
286
|
const { versionFile } = local_cluster_config_1.default.getRepositoryAssetInfoPath(blockInfo.handle, blockInfo.name, blockInfo.version);
|
276
287
|
const versionYml = versionFile;
|
277
288
|
if (!fs_extra_1.default.existsSync(versionYml)) {
|
@@ -296,14 +307,7 @@ class BlockInstanceRunner {
|
|
296
307
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
|
297
308
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
298
309
|
const Binds = [`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`];
|
299
|
-
|
300
|
-
// If we have a config file, we need to bind it to the container and adjust the env var
|
301
|
-
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
302
|
-
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
303
|
-
// We also provide the hash to detect changes to the config file
|
304
|
-
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
305
|
-
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
306
|
-
}
|
310
|
+
await this.prepareBinds(env, Binds, fileMapping);
|
307
311
|
return this.ensureContainer({
|
308
312
|
Image: dockerImage,
|
309
313
|
name: containerName,
|
@@ -486,7 +490,8 @@ class BlockInstanceRunner {
|
|
486
490
|
const plan = await internalConfigProvider.getPlan();
|
487
491
|
const connectedBlockIds = [
|
488
492
|
...new Set(plan.spec.connections
|
489
|
-
.filter((connection) => connection.provider.blockId == blockInstance.id ||
|
493
|
+
.filter((connection) => connection.provider.blockId == blockInstance.id ||
|
494
|
+
connection.consumer.blockId == blockInstance.id)
|
490
495
|
.flatMap((connection) => [connection.provider.blockId, connection.consumer.blockId])
|
491
496
|
.filter((blockId) => blockId !== blockInstance.id)),
|
492
497
|
];
|
@@ -35,4 +35,4 @@ export declare class InternalConfigProvider implements ConfigProvider {
|
|
35
35
|
getBlock(ref: any): Promise<Definition>;
|
36
36
|
getPlan(): Promise<Plan>;
|
37
37
|
}
|
38
|
-
export declare function createInternalConfigProvider(systemId: string, instanceId: string, info: DefinitionInfo): Promise<InternalConfigProvider>;
|
38
|
+
export declare function createInternalConfigProvider(systemId: string, instanceId: string, info: DefinitionInfo, config: AnyMap): Promise<InternalConfigProvider>;
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.createInternalConfigProvider = exports.InternalConfigProvider = void 0;
|
7
7
|
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
8
|
-
const configManager_1 = require("../configManager");
|
9
8
|
const lodash_1 = __importDefault(require("lodash"));
|
10
9
|
const serviceManager_1 = require("../serviceManager");
|
11
10
|
const operatorManager_1 = require("../operatorManager");
|
@@ -139,8 +138,7 @@ class InternalConfigProvider {
|
|
139
138
|
}
|
140
139
|
}
|
141
140
|
exports.InternalConfigProvider = InternalConfigProvider;
|
142
|
-
async function createInternalConfigProvider(systemId, instanceId, info) {
|
143
|
-
const config = await configManager_1.configManager.getConfigForBlockInstance(systemId, instanceId);
|
141
|
+
async function createInternalConfigProvider(systemId, instanceId, info, config) {
|
144
142
|
return new InternalConfigProvider(systemId, instanceId, info, config);
|
145
143
|
}
|
146
144
|
exports.createInternalConfigProvider = createInternalConfigProvider;
|
@@ -15,6 +15,8 @@ const instanceManager_1 = require("../instanceManager");
|
|
15
15
|
const cors_1 = require("../middleware/cors");
|
16
16
|
const kapeta_1 = require("../middleware/kapeta");
|
17
17
|
const stringBody_1 = require("../middleware/stringBody");
|
18
|
+
const assetManager_1 = require("../assetManager");
|
19
|
+
const definitionsManager_1 = require("../definitionsManager");
|
18
20
|
const router = (0, express_promise_router_1.default)();
|
19
21
|
router.use('/', cors_1.corsHandler);
|
20
22
|
router.use('/', kapeta_1.kapetaHeaders);
|
@@ -26,7 +28,7 @@ router.get('/instance', async (req, res) => {
|
|
26
28
|
try {
|
27
29
|
let config = {};
|
28
30
|
if (req.kapeta.instanceId) {
|
29
|
-
config = await configManager_1.configManager.getConfigForBlockInstance(req.kapeta.systemId, req.kapeta.instanceId);
|
31
|
+
config = await configManager_1.configManager.getConfigForBlockInstance(req.kapeta.systemId, req.kapeta.instanceId, req.kapeta?.environment === 'docker');
|
30
32
|
}
|
31
33
|
else {
|
32
34
|
config = configManager_1.configManager.getConfigForSystem(req.kapeta.systemId);
|
@@ -49,7 +51,19 @@ router.put('/instance', async (req, res) => {
|
|
49
51
|
config = {};
|
50
52
|
}
|
51
53
|
if (req.kapeta.instanceId) {
|
52
|
-
|
54
|
+
const blockInstance = await assetManager_1.assetManager.getBlockInstance(req.kapeta.systemId, req.kapeta.instanceId);
|
55
|
+
if (!blockInstance) {
|
56
|
+
throw new Error(`Block instance not found: ${req.kapeta.instanceId} in plan ${req.kapeta.systemId}`);
|
57
|
+
}
|
58
|
+
const blockDefinition = await definitionsManager_1.definitionsManager.getDefinition(blockInstance.block.ref);
|
59
|
+
if (!blockDefinition) {
|
60
|
+
throw new Error(`Block definition not found: ${blockInstance.block.ref}`);
|
61
|
+
}
|
62
|
+
let configEntityList = {};
|
63
|
+
if (blockDefinition.definition.spec.configuration) {
|
64
|
+
configEntityList = blockDefinition.definition.spec.configuration;
|
65
|
+
}
|
66
|
+
await configManager_1.configManager.setConfigForBlockInstance(req.kapeta.systemId, req.kapeta.instanceId, configEntityList, config);
|
53
67
|
//Restart the instance if it is running after config change
|
54
68
|
await instanceManager_1.instanceManager.prepareForRestart(req.kapeta.systemId, req.kapeta.instanceId);
|
55
69
|
}
|
@@ -2,6 +2,8 @@
|
|
2
2
|
* Copyright 2023 Kapeta Inc.
|
3
3
|
* SPDX-License-Identifier: BUSL-1.1
|
4
4
|
*/
|
5
|
+
import { EntityList } from '@kapeta/schemas';
|
6
|
+
import { StringMap } from './types';
|
5
7
|
export declare const SYSTEM_ID = "$plan";
|
6
8
|
type AnyMap = {
|
7
9
|
[key: string]: any;
|
@@ -16,8 +18,12 @@ declare class ConfigManager {
|
|
16
18
|
_forSystem(systemId: string): any;
|
17
19
|
setConfigForSystem(systemId: string, config: AnyMap): void;
|
18
20
|
getConfigForSystem(systemId: string): AnyMap;
|
19
|
-
getConfigForBlockInstance(systemId: string, instanceId: string): Promise<import("./types").AnyMap>;
|
21
|
+
getConfigForBlockInstance(systemId: string, instanceId: string, rewritePaths?: boolean): Promise<import("./types").AnyMap>;
|
22
|
+
rewriteFilePaths(configSchema: EntityList, config: AnyMap, toBaseDir?: string): StringMap;
|
20
23
|
setConfigForSection(systemId: string, sectionId: string, config: AnyMap): void;
|
24
|
+
getFilesBaseDir(): string;
|
25
|
+
private saveFile;
|
26
|
+
setConfigForBlockInstance(systemId: string, instanceId: string, configEntityList: EntityList, config: AnyMap): Promise<void>;
|
21
27
|
getConfigForSection(systemId: string, sectionId: string): any;
|
22
28
|
/**
|
23
29
|
* Try to identify the plan and instance in a plan automatically based on the block reference
|
@@ -3,12 +3,22 @@
|
|
3
3
|
* Copyright 2023 Kapeta Inc.
|
4
4
|
* SPDX-License-Identifier: BUSL-1.1
|
5
5
|
*/
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
8
|
+
};
|
6
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
7
10
|
exports.configManager = exports.SYSTEM_ID = void 0;
|
8
|
-
const storageService_1 = require("./storageService");
|
9
11
|
const assetManager_1 = require("./assetManager");
|
12
|
+
const schemas_1 = require("@kapeta/schemas");
|
13
|
+
const storageService_1 = require("./storageService");
|
10
14
|
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
11
15
|
const utils_1 = require("./utils/utils");
|
16
|
+
const parse_data_uri_1 = __importDefault(require("parse-data-uri"));
|
17
|
+
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
18
|
+
const path_1 = __importDefault(require("path"));
|
19
|
+
const node_uuid_1 = __importDefault(require("node-uuid"));
|
20
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
21
|
+
const lodash_1 = __importDefault(require("lodash"));
|
12
22
|
exports.SYSTEM_ID = '$plan';
|
13
23
|
class ConfigManager {
|
14
24
|
_config;
|
@@ -31,14 +41,49 @@ class ConfigManager {
|
|
31
41
|
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
32
42
|
return this._forSystem(systemId);
|
33
43
|
}
|
34
|
-
async getConfigForBlockInstance(systemId, instanceId) {
|
44
|
+
async getConfigForBlockInstance(systemId, instanceId, rewritePaths = false) {
|
35
45
|
const blockInstance = await assetManager_1.assetManager.getBlockInstance(systemId, instanceId);
|
36
46
|
const blockAsset = await assetManager_1.assetManager.getAsset(blockInstance.block.ref, true);
|
37
47
|
if (!blockAsset) {
|
38
48
|
throw new Error(`Block definition not found: ${blockInstance.block.ref}`);
|
39
49
|
}
|
40
50
|
const instanceConfig = this.getConfigForSection(systemId, instanceId);
|
41
|
-
|
51
|
+
const config = lodash_1.default.cloneDeep((0, utils_1.getResolvedConfiguration)(blockAsset.data.spec.configuration, instanceConfig, blockInstance.defaultConfiguration));
|
52
|
+
if (rewritePaths) {
|
53
|
+
this.rewriteFilePaths(blockAsset.data.spec.configuration, config);
|
54
|
+
}
|
55
|
+
return config;
|
56
|
+
}
|
57
|
+
rewriteFilePaths(configSchema, config, toBaseDir = '/files') {
|
58
|
+
const fileMap = {};
|
59
|
+
if (!configSchema || !configSchema.types) {
|
60
|
+
return fileMap;
|
61
|
+
}
|
62
|
+
const fromBaseDir = this.getFilesBaseDir();
|
63
|
+
for (const entity of configSchema.types) {
|
64
|
+
if (entity.type !== schemas_1.EntityType.Dto) {
|
65
|
+
continue;
|
66
|
+
}
|
67
|
+
if (!entity.properties || !config[entity.name]) {
|
68
|
+
continue;
|
69
|
+
}
|
70
|
+
const innerValue = config[entity.name];
|
71
|
+
for (const key in entity.properties) {
|
72
|
+
const prop = entity.properties[key];
|
73
|
+
if (prop.type !== 'file') {
|
74
|
+
continue;
|
75
|
+
}
|
76
|
+
const value = innerValue[key];
|
77
|
+
if (!value || !value.startsWith(fromBaseDir)) {
|
78
|
+
continue;
|
79
|
+
}
|
80
|
+
const src = value;
|
81
|
+
const dst = toBaseDir + '/' + value.substring(fromBaseDir.length + 1);
|
82
|
+
fileMap[src] = dst;
|
83
|
+
innerValue[key] = dst;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return fileMap;
|
42
87
|
}
|
43
88
|
setConfigForSection(systemId, sectionId, config) {
|
44
89
|
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
@@ -46,6 +91,47 @@ class ConfigManager {
|
|
46
91
|
systemConfig[sectionId] = config || {};
|
47
92
|
storageService_1.storageService.put('config', systemId, systemConfig);
|
48
93
|
}
|
94
|
+
getFilesBaseDir() {
|
95
|
+
return path_1.default.join(local_cluster_config_1.default.getKapetaBasedir(), 'files');
|
96
|
+
}
|
97
|
+
async saveFile(value) {
|
98
|
+
const filename = node_uuid_1.default.v4();
|
99
|
+
const basePath = this.getFilesBaseDir();
|
100
|
+
await fs_extra_1.default.mkdirp(basePath);
|
101
|
+
const filepath = path_1.default.join(basePath, filename);
|
102
|
+
await fs_extra_1.default.writeFile(filepath, value);
|
103
|
+
return filepath;
|
104
|
+
}
|
105
|
+
async setConfigForBlockInstance(systemId, instanceId, configEntityList, config) {
|
106
|
+
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
107
|
+
let systemConfig = this._forSystem(systemId);
|
108
|
+
let configValue = config || {};
|
109
|
+
if (configEntityList.types) {
|
110
|
+
for (let entity of configEntityList.types) {
|
111
|
+
if (entity.type !== schemas_1.EntityType.Dto) {
|
112
|
+
continue;
|
113
|
+
}
|
114
|
+
if (!configValue[entity.name] || !entity.properties) {
|
115
|
+
continue;
|
116
|
+
}
|
117
|
+
const innerValues = configValue[entity.name];
|
118
|
+
for (let key in innerValues) {
|
119
|
+
if (!entity.properties[key]) {
|
120
|
+
continue;
|
121
|
+
}
|
122
|
+
if (entity.properties[key].type === 'file' &&
|
123
|
+
typeof innerValues[key] === 'string' &&
|
124
|
+
innerValues[key].startsWith('data:')) {
|
125
|
+
// This was a file upload - save the file to disk and replace value with path
|
126
|
+
const data = (0, parse_data_uri_1.default)(innerValues[key]);
|
127
|
+
innerValues[key] = await this.saveFile(data.data);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
systemConfig[instanceId] = configValue;
|
133
|
+
storageService_1.storageService.put('config', systemId, systemConfig);
|
134
|
+
}
|
49
135
|
getConfigForSection(systemId, sectionId) {
|
50
136
|
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
51
137
|
const systemConfig = this._forSystem(systemId);
|
@@ -17,7 +17,6 @@ const socketManager_1 = require("./socketManager");
|
|
17
17
|
const serviceManager_1 = require("./serviceManager");
|
18
18
|
const assetManager_1 = require("./assetManager");
|
19
19
|
const containerManager_1 = require("./containerManager");
|
20
|
-
const configManager_1 = require("./configManager");
|
21
20
|
const types_1 = require("./types");
|
22
21
|
const utils_1 = require("./utils/utils");
|
23
22
|
const operatorManager_1 = require("./operatorManager");
|
@@ -501,12 +500,11 @@ class InstanceManager {
|
|
501
500
|
return existingInstance;
|
502
501
|
}
|
503
502
|
}
|
504
|
-
const resolvedConfig = await configManager_1.configManager.getConfigForBlockInstance(systemId, instanceId);
|
505
503
|
const task = taskManager_1.taskManager.add(`instance:start:${systemId}:${instanceId}`, async () => {
|
506
504
|
const runner = new BlockInstanceRunner_1.BlockInstanceRunner(systemId);
|
507
505
|
const startTime = Date.now();
|
508
506
|
try {
|
509
|
-
const processInfo = await runner.start(blockRef, instanceId
|
507
|
+
const processInfo = await runner.start(blockRef, instanceId);
|
510
508
|
instance.status = types_1.InstanceStatus.STARTING;
|
511
509
|
return this.saveInternalInstance({
|
512
510
|
...instance,
|
package/dist/esm/src/types.d.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
* Copyright 2023 Kapeta Inc.
|
3
3
|
* SPDX-License-Identifier: BUSL-1.1
|
4
4
|
*/
|
5
|
-
import {
|
5
|
+
import { ProcessInfo } from '../types';
|
6
6
|
export declare function resolvePortType(portType: string): string;
|
7
7
|
export declare class BlockInstanceRunner {
|
8
8
|
private readonly _systemId;
|
@@ -11,12 +11,13 @@ export declare class BlockInstanceRunner {
|
|
11
11
|
* Start a block
|
12
12
|
*
|
13
13
|
*/
|
14
|
-
start(blockRef: string, instanceId: string
|
14
|
+
start(blockRef: string, instanceId: string): Promise<ProcessInfo>;
|
15
15
|
private _execute;
|
16
16
|
/**
|
17
17
|
* Starts local process
|
18
18
|
*/
|
19
19
|
private _startLocalProcess;
|
20
|
+
private prepareBinds;
|
20
21
|
private _startDockerProcess;
|
21
22
|
private _startOperatorProcess;
|
22
23
|
/**
|
@@ -24,6 +24,7 @@ const taskManager_1 = require("../taskManager");
|
|
24
24
|
const InternalConfigProvider_1 = require("./InternalConfigProvider");
|
25
25
|
const config_mapper_1 = require("@kapeta/config-mapper");
|
26
26
|
const crypto_1 = __importDefault(require("crypto"));
|
27
|
+
const configManager_1 = require("../configManager");
|
27
28
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
28
29
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
29
30
|
const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
|
@@ -89,11 +90,10 @@ class BlockInstanceRunner {
|
|
89
90
|
* Start a block
|
90
91
|
*
|
91
92
|
*/
|
92
|
-
async start(blockRef, instanceId
|
93
|
+
async start(blockRef, instanceId) {
|
93
94
|
return this._execute({
|
94
95
|
ref: blockRef,
|
95
96
|
id: instanceId,
|
96
|
-
configuration,
|
97
97
|
});
|
98
98
|
}
|
99
99
|
async _execute(blockInstance) {
|
@@ -112,7 +112,10 @@ class BlockInstanceRunner {
|
|
112
112
|
}
|
113
113
|
const baseDir = local_cluster_config_1.default.getRepositoryAssetPath(blockUri.handle, blockUri.name, blockUri.version);
|
114
114
|
const realBaseDir = await fs_extra_1.default.realpath(baseDir);
|
115
|
-
const
|
115
|
+
const config = await configManager_1.configManager.getConfigForBlockInstance(this._systemId, blockInstance.id);
|
116
|
+
const configSchema = (assetVersion.definition.spec.configuration ? assetVersion.definition.spec.configuration : {});
|
117
|
+
const fileMapping = configManager_1.configManager.rewriteFilePaths(configSchema, config);
|
118
|
+
const internalConfigProvider = await (0, InternalConfigProvider_1.createInternalConfigProvider)(this._systemId, blockInstance.id, assetVersion, config);
|
116
119
|
// Resolve the environment variables
|
117
120
|
const blockVariables = await (0, config_mapper_1.resolveKapetaVariables)(realBaseDir, internalConfigProvider);
|
118
121
|
const variables = await this.appendConnectedBlockOperatorEnv(internalConfigProvider, blockInstance, blockVariables);
|
@@ -133,10 +136,10 @@ class BlockInstanceRunner {
|
|
133
136
|
//We need a port type to know how to connect to the block consistently
|
134
137
|
const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
|
135
138
|
if (blockUri.version === 'local') {
|
136
|
-
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
|
139
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion, fileMapping);
|
137
140
|
}
|
138
141
|
else {
|
139
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion);
|
142
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion, fileMapping);
|
140
143
|
}
|
141
144
|
if (portTypes.length > 0) {
|
142
145
|
processInfo.portType = portTypes[0];
|
@@ -147,7 +150,7 @@ class BlockInstanceRunner {
|
|
147
150
|
/**
|
148
151
|
* Starts local process
|
149
152
|
*/
|
150
|
-
async _startLocalProcess(blockInstance, blockInfo, env, assetVersion) {
|
153
|
+
async _startLocalProcess(blockInstance, blockInfo, env, assetVersion, fileMapping) {
|
151
154
|
const baseDir = local_cluster_config_1.default.getRepositoryAssetPath(blockInfo.handle, blockInfo.name, blockInfo.version);
|
152
155
|
if (!fs_extra_1.default.existsSync(baseDir)) {
|
153
156
|
throw new Error(`Local block not registered correctly - expected symlink here: ${baseDir}.\n` +
|
@@ -211,14 +214,7 @@ class BlockInstanceRunner {
|
|
211
214
|
if (localContainer.healthcheck) {
|
212
215
|
HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
213
216
|
}
|
214
|
-
|
215
|
-
// If we have a config file, we need to bind it to the container and adjust the env var
|
216
|
-
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
217
|
-
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
218
|
-
// We also provide the hash to detect changes to the config file
|
219
|
-
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
220
|
-
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
221
|
-
}
|
217
|
+
await this.prepareBinds(env, Binds, fileMapping);
|
222
218
|
const Mounts = isDockerImage
|
223
219
|
? // For docker images we mount the local directory to the working directory
|
224
220
|
containerManager_1.containerManager.toDockerMounts({
|
@@ -271,7 +267,22 @@ class BlockInstanceRunner {
|
|
271
267
|
},
|
272
268
|
});
|
273
269
|
}
|
274
|
-
async
|
270
|
+
async prepareBinds(env, Binds, fileMapping) {
|
271
|
+
if (env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]) {
|
272
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
273
|
+
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
274
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
275
|
+
// We also provide the hash to detect changes to the config file
|
276
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
277
|
+
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
278
|
+
}
|
279
|
+
if (fileMapping) {
|
280
|
+
Object.entries(fileMapping).forEach(([src, dst]) => {
|
281
|
+
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(src)}:${dst}:ro`);
|
282
|
+
});
|
283
|
+
}
|
284
|
+
}
|
285
|
+
async _startDockerProcess(blockInstance, blockInfo, env, assetVersion, fileMapping) {
|
275
286
|
const { versionFile } = local_cluster_config_1.default.getRepositoryAssetInfoPath(blockInfo.handle, blockInfo.name, blockInfo.version);
|
276
287
|
const versionYml = versionFile;
|
277
288
|
if (!fs_extra_1.default.existsSync(versionYml)) {
|
@@ -296,14 +307,7 @@ class BlockInstanceRunner {
|
|
296
307
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
|
297
308
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
298
309
|
const Binds = [`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`];
|
299
|
-
|
300
|
-
// If we have a config file, we need to bind it to the container and adjust the env var
|
301
|
-
const localConfig = `/${config_mapper_1.KAPETA_ENV_CONFIG_FILE}`;
|
302
|
-
Binds.push(`${(0, containerManager_1.toLocalBindVolume)(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
303
|
-
// We also provide the hash to detect changes to the config file
|
304
|
-
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[config_mapper_1.KAPETA_CONFIG_ENV_VAR]);
|
305
|
-
env[config_mapper_1.KAPETA_CONFIG_ENV_VAR] = localConfig;
|
306
|
-
}
|
310
|
+
await this.prepareBinds(env, Binds, fileMapping);
|
307
311
|
return this.ensureContainer({
|
308
312
|
Image: dockerImage,
|
309
313
|
name: containerName,
|
@@ -486,7 +490,8 @@ class BlockInstanceRunner {
|
|
486
490
|
const plan = await internalConfigProvider.getPlan();
|
487
491
|
const connectedBlockIds = [
|
488
492
|
...new Set(plan.spec.connections
|
489
|
-
.filter((connection) => connection.provider.blockId == blockInstance.id ||
|
493
|
+
.filter((connection) => connection.provider.blockId == blockInstance.id ||
|
494
|
+
connection.consumer.blockId == blockInstance.id)
|
490
495
|
.flatMap((connection) => [connection.provider.blockId, connection.consumer.blockId])
|
491
496
|
.filter((blockId) => blockId !== blockInstance.id)),
|
492
497
|
];
|
@@ -35,4 +35,4 @@ export declare class InternalConfigProvider implements ConfigProvider {
|
|
35
35
|
getBlock(ref: any): Promise<Definition>;
|
36
36
|
getPlan(): Promise<Plan>;
|
37
37
|
}
|
38
|
-
export declare function createInternalConfigProvider(systemId: string, instanceId: string, info: DefinitionInfo): Promise<InternalConfigProvider>;
|
38
|
+
export declare function createInternalConfigProvider(systemId: string, instanceId: string, info: DefinitionInfo, config: AnyMap): Promise<InternalConfigProvider>;
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.createInternalConfigProvider = exports.InternalConfigProvider = void 0;
|
7
7
|
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
8
|
-
const configManager_1 = require("../configManager");
|
9
8
|
const lodash_1 = __importDefault(require("lodash"));
|
10
9
|
const serviceManager_1 = require("../serviceManager");
|
11
10
|
const operatorManager_1 = require("../operatorManager");
|
@@ -139,8 +138,7 @@ class InternalConfigProvider {
|
|
139
138
|
}
|
140
139
|
}
|
141
140
|
exports.InternalConfigProvider = InternalConfigProvider;
|
142
|
-
async function createInternalConfigProvider(systemId, instanceId, info) {
|
143
|
-
const config = await configManager_1.configManager.getConfigForBlockInstance(systemId, instanceId);
|
141
|
+
async function createInternalConfigProvider(systemId, instanceId, info, config) {
|
144
142
|
return new InternalConfigProvider(systemId, instanceId, info, config);
|
145
143
|
}
|
146
144
|
exports.createInternalConfigProvider = createInternalConfigProvider;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.42.0",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -73,6 +73,7 @@
|
|
73
73
|
"md5": "2.2.1",
|
74
74
|
"node-cache": "^5.1.2",
|
75
75
|
"node-uuid": "^1.4.8",
|
76
|
+
"parse-data-uri": "^0.2.0",
|
76
77
|
"qs": "^6.11.2",
|
77
78
|
"request": "2.88.2",
|
78
79
|
"socket.io": "^4.5.2",
|
package/src/config/routes.ts
CHANGED
@@ -13,6 +13,9 @@ import { kapetaHeaders, KapetaRequest } from '../middleware/kapeta';
|
|
13
13
|
import { stringBody } from '../middleware/stringBody';
|
14
14
|
import { AnyMap, KapetaBodyRequest } from '../types';
|
15
15
|
import { Response } from 'express';
|
16
|
+
import { assetManager } from '../assetManager';
|
17
|
+
import { definitionsManager } from '../definitionsManager';
|
18
|
+
import { EntityList } from '@kapeta/schemas';
|
16
19
|
|
17
20
|
const router = Router();
|
18
21
|
|
@@ -27,7 +30,11 @@ router.get('/instance', async (req: KapetaBodyRequest, res: Response) => {
|
|
27
30
|
try {
|
28
31
|
let config: AnyMap = {};
|
29
32
|
if (req.kapeta!.instanceId) {
|
30
|
-
config = await configManager.getConfigForBlockInstance(
|
33
|
+
config = await configManager.getConfigForBlockInstance(
|
34
|
+
req.kapeta!.systemId,
|
35
|
+
req.kapeta!.instanceId,
|
36
|
+
req.kapeta?.environment === 'docker'
|
37
|
+
);
|
31
38
|
} else {
|
32
39
|
config = configManager.getConfigForSystem(req.kapeta!.systemId);
|
33
40
|
}
|
@@ -51,7 +58,26 @@ router.put('/instance', async (req: KapetaBodyRequest, res) => {
|
|
51
58
|
}
|
52
59
|
|
53
60
|
if (req.kapeta!.instanceId) {
|
54
|
-
|
61
|
+
const blockInstance = await assetManager.getBlockInstance(req.kapeta!.systemId, req.kapeta!.instanceId);
|
62
|
+
if (!blockInstance) {
|
63
|
+
throw new Error(`Block instance not found: ${req.kapeta!.instanceId} in plan ${req.kapeta!.systemId}`);
|
64
|
+
}
|
65
|
+
const blockDefinition = await definitionsManager.getDefinition(blockInstance.block.ref);
|
66
|
+
if (!blockDefinition) {
|
67
|
+
throw new Error(`Block definition not found: ${blockInstance.block.ref}`);
|
68
|
+
}
|
69
|
+
|
70
|
+
let configEntityList: EntityList = {};
|
71
|
+
if (blockDefinition.definition.spec.configuration) {
|
72
|
+
configEntityList = blockDefinition.definition.spec.configuration as EntityList;
|
73
|
+
}
|
74
|
+
|
75
|
+
await configManager.setConfigForBlockInstance(
|
76
|
+
req.kapeta!.systemId,
|
77
|
+
req.kapeta!.instanceId,
|
78
|
+
configEntityList,
|
79
|
+
config
|
80
|
+
);
|
55
81
|
//Restart the instance if it is running after config change
|
56
82
|
await instanceManager.prepareForRestart(req.kapeta!.systemId, req.kapeta!.instanceId);
|
57
83
|
} else {
|
package/src/configManager.ts
CHANGED
@@ -3,12 +3,18 @@
|
|
3
3
|
* SPDX-License-Identifier: BUSL-1.1
|
4
4
|
*/
|
5
5
|
|
6
|
-
import { EnrichedAsset } from './assetManager';
|
7
|
-
import { BlockInstance } from '@kapeta/schemas';
|
6
|
+
import { assetManager, EnrichedAsset } from './assetManager';
|
7
|
+
import { BlockInstance, EntityList, EntityType } from '@kapeta/schemas';
|
8
8
|
import { storageService } from './storageService';
|
9
|
-
import { assetManager } from './assetManager';
|
10
9
|
import { normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
|
11
10
|
import { getResolvedConfiguration } from './utils/utils';
|
11
|
+
import parseDataUri from 'parse-data-uri';
|
12
|
+
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
13
|
+
import Path from 'path';
|
14
|
+
import uuid from 'node-uuid';
|
15
|
+
import FS from 'fs-extra';
|
16
|
+
import { EnvironmentType, StringMap } from './types';
|
17
|
+
import _ from 'lodash';
|
12
18
|
|
13
19
|
export const SYSTEM_ID = '$plan';
|
14
20
|
type AnyMap = { [key: string]: any };
|
@@ -46,18 +52,68 @@ class ConfigManager {
|
|
46
52
|
return this._forSystem(systemId);
|
47
53
|
}
|
48
54
|
|
49
|
-
async getConfigForBlockInstance(systemId: string, instanceId: string) {
|
55
|
+
async getConfigForBlockInstance(systemId: string, instanceId: string, rewritePaths = false) {
|
50
56
|
const blockInstance = await assetManager.getBlockInstance(systemId, instanceId);
|
51
57
|
const blockAsset = await assetManager.getAsset(blockInstance.block.ref, true);
|
52
58
|
if (!blockAsset) {
|
53
59
|
throw new Error(`Block definition not found: ${blockInstance.block.ref}`);
|
54
60
|
}
|
55
61
|
const instanceConfig = this.getConfigForSection(systemId, instanceId);
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
62
|
+
const config = _.cloneDeep(
|
63
|
+
getResolvedConfiguration(
|
64
|
+
blockAsset.data.spec.configuration,
|
65
|
+
instanceConfig,
|
66
|
+
blockInstance.defaultConfiguration
|
67
|
+
)
|
60
68
|
);
|
69
|
+
|
70
|
+
if (rewritePaths) {
|
71
|
+
this.rewriteFilePaths(blockAsset.data.spec.configuration, config);
|
72
|
+
}
|
73
|
+
|
74
|
+
return config;
|
75
|
+
}
|
76
|
+
|
77
|
+
public rewriteFilePaths(configSchema: EntityList, config: AnyMap, toBaseDir: string = '/files') {
|
78
|
+
const fileMap: StringMap = {};
|
79
|
+
|
80
|
+
if (!configSchema || !configSchema.types) {
|
81
|
+
return fileMap;
|
82
|
+
}
|
83
|
+
|
84
|
+
const fromBaseDir = this.getFilesBaseDir();
|
85
|
+
|
86
|
+
for (const entity of configSchema.types) {
|
87
|
+
if (entity.type !== EntityType.Dto) {
|
88
|
+
continue;
|
89
|
+
}
|
90
|
+
|
91
|
+
if (!entity.properties || !config[entity.name]) {
|
92
|
+
continue;
|
93
|
+
}
|
94
|
+
|
95
|
+
const innerValue = config[entity.name];
|
96
|
+
|
97
|
+
for (const key in entity.properties) {
|
98
|
+
const prop = entity.properties[key];
|
99
|
+
if (prop.type !== 'file') {
|
100
|
+
continue;
|
101
|
+
}
|
102
|
+
|
103
|
+
const value = innerValue[key];
|
104
|
+
|
105
|
+
if (!value || !value.startsWith(fromBaseDir)) {
|
106
|
+
continue;
|
107
|
+
}
|
108
|
+
|
109
|
+
const src = value;
|
110
|
+
const dst = toBaseDir + '/' + value.substring(fromBaseDir.length + 1);
|
111
|
+
fileMap[src] = dst;
|
112
|
+
innerValue[key] = dst;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
return fileMap;
|
61
117
|
}
|
62
118
|
|
63
119
|
setConfigForSection(systemId: string, sectionId: string, config: AnyMap) {
|
@@ -68,6 +124,63 @@ class ConfigManager {
|
|
68
124
|
storageService.put('config', systemId, systemConfig);
|
69
125
|
}
|
70
126
|
|
127
|
+
public getFilesBaseDir() {
|
128
|
+
return Path.join(ClusterConfiguration.getKapetaBasedir(), 'files');
|
129
|
+
}
|
130
|
+
|
131
|
+
private async saveFile(value: Buffer) {
|
132
|
+
const filename = uuid.v4();
|
133
|
+
const basePath = this.getFilesBaseDir();
|
134
|
+
await FS.mkdirp(basePath);
|
135
|
+
const filepath = Path.join(basePath, filename);
|
136
|
+
await FS.writeFile(filepath, value);
|
137
|
+
return filepath;
|
138
|
+
}
|
139
|
+
|
140
|
+
async setConfigForBlockInstance(
|
141
|
+
systemId: string,
|
142
|
+
instanceId: string,
|
143
|
+
configEntityList: EntityList,
|
144
|
+
config: AnyMap
|
145
|
+
) {
|
146
|
+
systemId = normalizeKapetaUri(systemId);
|
147
|
+
let systemConfig = this._forSystem(systemId);
|
148
|
+
let configValue = config || {};
|
149
|
+
if (configEntityList.types) {
|
150
|
+
for (let entity of configEntityList.types) {
|
151
|
+
if (entity.type !== EntityType.Dto) {
|
152
|
+
continue;
|
153
|
+
}
|
154
|
+
|
155
|
+
if (!configValue[entity.name] || !entity.properties) {
|
156
|
+
continue;
|
157
|
+
}
|
158
|
+
|
159
|
+
const innerValues = configValue[entity.name];
|
160
|
+
|
161
|
+
for (let key in innerValues) {
|
162
|
+
if (!entity.properties[key]) {
|
163
|
+
continue;
|
164
|
+
}
|
165
|
+
|
166
|
+
if (
|
167
|
+
entity.properties[key].type === 'file' &&
|
168
|
+
typeof innerValues[key] === 'string' &&
|
169
|
+
innerValues[key].startsWith('data:')
|
170
|
+
) {
|
171
|
+
// This was a file upload - save the file to disk and replace value with path
|
172
|
+
const data = parseDataUri(innerValues[key]);
|
173
|
+
innerValues[key] = await this.saveFile(data.data);
|
174
|
+
}
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
systemConfig[instanceId] = configValue;
|
180
|
+
|
181
|
+
storageService.put('config', systemId, systemConfig);
|
182
|
+
}
|
183
|
+
|
71
184
|
getConfigForSection(systemId: string, sectionId: string) {
|
72
185
|
systemId = normalizeKapetaUri(systemId);
|
73
186
|
const systemConfig = this._forSystem(systemId);
|
package/src/instanceManager.ts
CHANGED
@@ -665,15 +665,13 @@ export class InstanceManager {
|
|
665
665
|
}
|
666
666
|
}
|
667
667
|
|
668
|
-
const resolvedConfig = await configManager.getConfigForBlockInstance(systemId, instanceId);
|
669
|
-
|
670
668
|
const task = taskManager.add(
|
671
669
|
`instance:start:${systemId}:${instanceId}`,
|
672
670
|
async () => {
|
673
671
|
const runner = new BlockInstanceRunner(systemId);
|
674
672
|
const startTime = Date.now();
|
675
673
|
try {
|
676
|
-
const processInfo = await runner.start(blockRef, instanceId
|
674
|
+
const processInfo = await runner.start(blockRef, instanceId);
|
677
675
|
|
678
676
|
instance.status = InstanceStatus.STARTING;
|
679
677
|
|
package/src/types.ts
CHANGED
@@ -5,8 +5,8 @@
|
|
5
5
|
|
6
6
|
import FSExtra from 'fs-extra';
|
7
7
|
import ClusterConfig, { DefinitionInfo } from '@kapeta/local-cluster-config';
|
8
|
-
import {
|
9
|
-
import { KapetaURI,
|
8
|
+
import { getBlockInstanceContainerName, getDockerHostIp, getOperatorInstancePorts, readYML } from './utils';
|
9
|
+
import { KapetaURI, normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
|
10
10
|
import { DEFAULT_PORT_TYPE, HTTP_PORT_TYPE, HTTP_PORTS, serviceManager } from '../serviceManager';
|
11
11
|
import {
|
12
12
|
COMPOSE_LABEL_PROJECT,
|
@@ -32,7 +32,7 @@ import Docker from 'dockerode';
|
|
32
32
|
import OS from 'node:os';
|
33
33
|
import Path from 'node:path';
|
34
34
|
import { taskManager } from '../taskManager';
|
35
|
-
import { LocalDevContainer, LocalInstance } from '@kapeta/schemas';
|
35
|
+
import { EntityList, EntityType, LocalDevContainer, LocalInstance } from '@kapeta/schemas';
|
36
36
|
import { createInternalConfigProvider, InternalConfigProvider } from './InternalConfigProvider';
|
37
37
|
import {
|
38
38
|
getConfigFilePath,
|
@@ -46,6 +46,8 @@ import {
|
|
46
46
|
writeEnvConfigFile,
|
47
47
|
} from '@kapeta/config-mapper';
|
48
48
|
import crypto from 'crypto';
|
49
|
+
import { configManager } from '../configManager';
|
50
|
+
import _ from 'lodash';
|
49
51
|
|
50
52
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
51
53
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
@@ -121,11 +123,10 @@ export class BlockInstanceRunner {
|
|
121
123
|
* Start a block
|
122
124
|
*
|
123
125
|
*/
|
124
|
-
async start(blockRef: string, instanceId: string
|
126
|
+
async start(blockRef: string, instanceId: string): Promise<ProcessInfo> {
|
125
127
|
return this._execute({
|
126
128
|
ref: blockRef,
|
127
129
|
id: instanceId,
|
128
|
-
configuration,
|
129
130
|
});
|
130
131
|
}
|
131
132
|
|
@@ -152,10 +153,18 @@ export class BlockInstanceRunner {
|
|
152
153
|
|
153
154
|
const baseDir = ClusterConfig.getRepositoryAssetPath(blockUri.handle, blockUri.name, blockUri.version);
|
154
155
|
const realBaseDir = await FSExtra.realpath(baseDir);
|
156
|
+
|
157
|
+
const config = await configManager.getConfigForBlockInstance(this._systemId, blockInstance.id);
|
158
|
+
const configSchema = (
|
159
|
+
assetVersion.definition.spec.configuration ? assetVersion.definition.spec.configuration : {}
|
160
|
+
) as EntityList;
|
161
|
+
const fileMapping = configManager.rewriteFilePaths(configSchema, config);
|
162
|
+
|
155
163
|
const internalConfigProvider = await createInternalConfigProvider(
|
156
164
|
this._systemId,
|
157
165
|
blockInstance.id,
|
158
|
-
assetVersion
|
166
|
+
assetVersion,
|
167
|
+
config
|
159
168
|
);
|
160
169
|
|
161
170
|
// Resolve the environment variables
|
@@ -189,9 +198,9 @@ export class BlockInstanceRunner {
|
|
189
198
|
const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
|
190
199
|
|
191
200
|
if (blockUri.version === 'local') {
|
192
|
-
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
|
201
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion, fileMapping);
|
193
202
|
} else {
|
194
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion);
|
203
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion, fileMapping);
|
195
204
|
}
|
196
205
|
|
197
206
|
if (portTypes.length > 0) {
|
@@ -209,7 +218,8 @@ export class BlockInstanceRunner {
|
|
209
218
|
blockInstance: BlockProcessParams,
|
210
219
|
blockInfo: KapetaURI,
|
211
220
|
env: StringMap,
|
212
|
-
assetVersion: DefinitionInfo
|
221
|
+
assetVersion: DefinitionInfo,
|
222
|
+
fileMapping: StringMap
|
213
223
|
): Promise<ProcessInfo> {
|
214
224
|
const baseDir = ClusterConfig.getRepositoryAssetPath(blockInfo.handle, blockInfo.name, blockInfo.version);
|
215
225
|
|
@@ -299,14 +309,7 @@ export class BlockInstanceRunner {
|
|
299
309
|
HealthCheck = containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
300
310
|
}
|
301
311
|
|
302
|
-
|
303
|
-
// If we have a config file, we need to bind it to the container and adjust the env var
|
304
|
-
const localConfig = `/${KAPETA_ENV_CONFIG_FILE}`;
|
305
|
-
Binds.push(`${toLocalBindVolume(env[KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
306
|
-
// We also provide the hash to detect changes to the config file
|
307
|
-
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[KAPETA_CONFIG_ENV_VAR]);
|
308
|
-
env[KAPETA_CONFIG_ENV_VAR] = localConfig;
|
309
|
-
}
|
312
|
+
await this.prepareBinds(env, Binds, fileMapping);
|
310
313
|
|
311
314
|
const Mounts = isDockerImage
|
312
315
|
? // For docker images we mount the local directory to the working directory
|
@@ -366,11 +369,29 @@ export class BlockInstanceRunner {
|
|
366
369
|
});
|
367
370
|
}
|
368
371
|
|
372
|
+
private async prepareBinds(env: StringMap, Binds: string[], fileMapping: StringMap) {
|
373
|
+
if (env[KAPETA_CONFIG_ENV_VAR]) {
|
374
|
+
// If we have a config file, we need to bind it to the container and adjust the env var
|
375
|
+
const localConfig = `/${KAPETA_ENV_CONFIG_FILE}`;
|
376
|
+
Binds.push(`${toLocalBindVolume(env[KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
377
|
+
// We also provide the hash to detect changes to the config file
|
378
|
+
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[KAPETA_CONFIG_ENV_VAR]);
|
379
|
+
env[KAPETA_CONFIG_ENV_VAR] = localConfig;
|
380
|
+
}
|
381
|
+
|
382
|
+
if (fileMapping) {
|
383
|
+
Object.entries(fileMapping).forEach(([src, dst]) => {
|
384
|
+
Binds.push(`${toLocalBindVolume(src)}:${dst}:ro`);
|
385
|
+
});
|
386
|
+
}
|
387
|
+
}
|
388
|
+
|
369
389
|
private async _startDockerProcess(
|
370
390
|
blockInstance: BlockProcessParams,
|
371
391
|
blockInfo: KapetaURI,
|
372
392
|
env: StringMap,
|
373
|
-
assetVersion: DefinitionInfo
|
393
|
+
assetVersion: DefinitionInfo,
|
394
|
+
fileMapping: StringMap
|
374
395
|
) {
|
375
396
|
const { versionFile } = ClusterConfig.getRepositoryAssetInfoPath(
|
376
397
|
blockInfo.handle,
|
@@ -414,14 +435,7 @@ export class BlockInstanceRunner {
|
|
414
435
|
const systemUri = parseKapetaUri(this._systemId);
|
415
436
|
|
416
437
|
const Binds = [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`];
|
417
|
-
|
418
|
-
// If we have a config file, we need to bind it to the container and adjust the env var
|
419
|
-
const localConfig = `/${KAPETA_ENV_CONFIG_FILE}`;
|
420
|
-
Binds.push(`${toLocalBindVolume(env[KAPETA_CONFIG_ENV_VAR])}:${localConfig}:ro`);
|
421
|
-
// We also provide the hash to detect changes to the config file
|
422
|
-
env['KAPETA_CONFIG_HASH'] = await this.getFileHash(env[KAPETA_CONFIG_ENV_VAR]);
|
423
|
-
env[KAPETA_CONFIG_ENV_VAR] = localConfig;
|
424
|
-
}
|
438
|
+
await this.prepareBinds(env, Binds, fileMapping);
|
425
439
|
|
426
440
|
return this.ensureContainer({
|
427
441
|
Image: dockerImage,
|
@@ -664,14 +678,20 @@ export class BlockInstanceRunner {
|
|
664
678
|
const connectedBlockIds = [
|
665
679
|
...new Set(
|
666
680
|
plan.spec.connections
|
667
|
-
.filter(
|
681
|
+
.filter(
|
682
|
+
(connection) =>
|
683
|
+
connection.provider.blockId == blockInstance.id ||
|
684
|
+
connection.consumer.blockId == blockInstance.id
|
685
|
+
)
|
668
686
|
.flatMap((connection) => [connection.provider.blockId, connection.consumer.blockId])
|
669
687
|
.filter((blockId) => blockId !== blockInstance.id)
|
670
688
|
),
|
671
689
|
];
|
672
690
|
|
673
691
|
for (const connectedBlockId of connectedBlockIds) {
|
674
|
-
const connectedBlockInstance = plan.spec.blocks.find(
|
692
|
+
const connectedBlockInstance = plan.spec.blocks.find(
|
693
|
+
(blockInstance) => blockInstance.id == connectedBlockId
|
694
|
+
);
|
675
695
|
if (!connectedBlockInstance) {
|
676
696
|
continue;
|
677
697
|
}
|
@@ -207,8 +207,8 @@ export class InternalConfigProvider implements ConfigProvider {
|
|
207
207
|
export async function createInternalConfigProvider(
|
208
208
|
systemId: string,
|
209
209
|
instanceId: string,
|
210
|
-
info: DefinitionInfo
|
210
|
+
info: DefinitionInfo,
|
211
|
+
config: AnyMap
|
211
212
|
): Promise<InternalConfigProvider> {
|
212
|
-
const config = await configManager.getConfigForBlockInstance(systemId, instanceId);
|
213
213
|
return new InternalConfigProvider(systemId, instanceId, info, config);
|
214
214
|
}
|