@kapeta/local-cluster-service 0.38.0 → 0.39.1
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/index.js +4 -1
- package/dist/cjs/src/config/routes.js +2 -2
- package/dist/cjs/src/containerManager.js +5 -3
- package/dist/cjs/src/instanceManager.d.ts +4 -2
- package/dist/cjs/src/instanceManager.js +60 -28
- package/dist/cjs/src/operatorManager.d.ts +4 -2
- package/dist/cjs/src/operatorManager.js +32 -23
- package/dist/cjs/src/serviceManager.d.ts +0 -1
- package/dist/cjs/src/serviceManager.js +2 -8
- package/dist/cjs/src/types.d.ts +1 -29
- package/dist/cjs/src/types.js +2 -1
- package/dist/cjs/src/utils/BlockInstanceRunner.js +30 -30
- package/dist/cjs/src/utils/InternalConfigProvider.d.ts +38 -0
- package/dist/cjs/src/utils/InternalConfigProvider.js +146 -0
- package/dist/cjs/src/utils/utils.d.ts +25 -3
- package/dist/cjs/src/utils/utils.js +46 -7
- package/dist/esm/index.js +4 -1
- package/dist/esm/src/config/routes.js +2 -2
- package/dist/esm/src/containerManager.js +5 -3
- package/dist/esm/src/instanceManager.d.ts +4 -2
- package/dist/esm/src/instanceManager.js +60 -28
- package/dist/esm/src/operatorManager.d.ts +4 -2
- package/dist/esm/src/operatorManager.js +32 -23
- package/dist/esm/src/serviceManager.d.ts +0 -1
- package/dist/esm/src/serviceManager.js +2 -8
- package/dist/esm/src/types.d.ts +1 -29
- package/dist/esm/src/types.js +2 -1
- package/dist/esm/src/utils/BlockInstanceRunner.js +30 -30
- package/dist/esm/src/utils/InternalConfigProvider.d.ts +38 -0
- package/dist/esm/src/utils/InternalConfigProvider.js +146 -0
- package/dist/esm/src/utils/utils.d.ts +25 -3
- package/dist/esm/src/utils/utils.js +46 -7
- package/index.ts +5 -2
- package/package.json +6 -6
- package/src/config/routes.ts +4 -2
- package/src/containerManager.ts +6 -4
- package/src/instanceManager.ts +74 -38
- package/src/operatorManager.ts +46 -37
- package/src/serviceManager.ts +3 -11
- package/src/types.ts +2 -31
- package/src/utils/BlockInstanceRunner.ts +48 -38
- package/src/utils/InternalConfigProvider.ts +214 -0
- package/src/utils/utils.ts +51 -8
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.39.1](https://github.com/kapetacom/local-cluster-service/compare/v0.39.0...v0.39.1) (2024-02-27)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* remove dep on ui-web-plan-editor ([#128](https://github.com/kapetacom/local-cluster-service/issues/128)) ([48ee136](https://github.com/kapetacom/local-cluster-service/commit/48ee13629040b19c7eb716f33955c5bce280f069))
|
7
|
+
|
8
|
+
# [0.39.0](https://github.com/kapetacom/local-cluster-service/compare/v0.38.0...v0.39.0) (2024-02-26)
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* Add support for dotenv and config templates ([#127](https://github.com/kapetacom/local-cluster-service/issues/127)) ([5e78610](https://github.com/kapetacom/local-cluster-service/commit/5e786106f1d6ca69fcd79cde351cc37908c2b4b2))
|
14
|
+
|
1
15
|
# [0.38.0](https://github.com/kapetacom/local-cluster-service/compare/v0.37.0...v0.38.0) (2024-02-24)
|
2
16
|
|
3
17
|
|
package/dist/cjs/index.js
CHANGED
@@ -210,7 +210,10 @@ exports.default = {
|
|
210
210
|
}
|
211
211
|
reject(err);
|
212
212
|
});
|
213
|
-
|
213
|
+
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
214
|
+
// TODO: This might pose a security risk - so we should authenticate all requests using a
|
215
|
+
// shared secret/nonce that we pass around.
|
216
|
+
const bindHost = (0, utils_1.isLinux)() ? '0.0.0.0' : host;
|
214
217
|
currentServer.listen(port, bindHost, async () => {
|
215
218
|
try {
|
216
219
|
const ensureCLITask = await (0, commandLineUtils_1.ensureCLI)();
|
@@ -136,7 +136,7 @@ router.get('/provides/:type', async (req, res) => {
|
|
136
136
|
* assign port numbers to it etc.
|
137
137
|
*/
|
138
138
|
router.get('/consumes/resource/:resourceType/:portType/:name', async (req, res) => {
|
139
|
-
const operatorInfo = await operatorManager_1.operatorManager.getConsumerResourceInfo(req.kapeta.systemId, req.kapeta.instanceId, req.params.resourceType, req.params.portType, req.params.name, req.kapeta.environment);
|
139
|
+
const operatorInfo = await operatorManager_1.operatorManager.getConsumerResourceInfo(req.kapeta.systemId, req.kapeta.instanceId, req.params.resourceType, req.params.portType, req.params.name, req.kapeta.environment, req.query.ensure !== 'false');
|
140
140
|
res.send(operatorInfo);
|
141
141
|
});
|
142
142
|
/**
|
@@ -154,7 +154,7 @@ router.get('/consumes/:resourceName/:type', (req, res) => {
|
|
154
154
|
* If the remote service is not already running it will be started
|
155
155
|
*/
|
156
156
|
router.get('/operator/:instanceId', async (req, res) => {
|
157
|
-
const operatorInfo = await instanceManager_1.instanceManager.getInstanceOperator(req.kapeta.systemId, req.params.instanceId, req.kapeta.environment);
|
157
|
+
const operatorInfo = await instanceManager_1.instanceManager.getInstanceOperator(req.kapeta.systemId, req.params.instanceId, req.kapeta.environment, req.query.ensure !== 'false');
|
158
158
|
res.send(operatorInfo);
|
159
159
|
});
|
160
160
|
exports.default = router;
|
@@ -19,6 +19,7 @@ const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-co
|
|
19
19
|
const node_uuid_1 = __importDefault(require("node-uuid"));
|
20
20
|
const md5_1 = __importDefault(require("md5"));
|
21
21
|
const utils_1 = require("./utils/utils");
|
22
|
+
const types_1 = require("./types");
|
22
23
|
const nodejs_api_client_1 = require("@kapeta/nodejs-api-client");
|
23
24
|
const taskManager_1 = require("./taskManager");
|
24
25
|
const node_events_1 = require("node:events");
|
@@ -508,7 +509,8 @@ class ContainerManager {
|
|
508
509
|
const newName = 'deleting-' + node_uuid_1.default.v4();
|
509
510
|
// Rename the container first to avoid name conflicts if people start the same container
|
510
511
|
await container.rename({ name: newName });
|
511
|
-
|
512
|
+
const newContainer = this.docker().getContainer(newName);
|
513
|
+
await newContainer.remove({ force: !!opts?.force });
|
512
514
|
}
|
513
515
|
/**
|
514
516
|
*
|
@@ -925,11 +927,11 @@ function getExtraHosts(dockerVersion) {
|
|
925
927
|
const [major, minor] = dockerVersion.split('.');
|
926
928
|
if (parseInt(major) >= 20 && parseInt(minor) >= 10) {
|
927
929
|
// Docker 20.10+ on Linux supports adding host.docker.internal to point to host-gateway
|
928
|
-
return [
|
930
|
+
return [`${types_1.DOCKER_HOST_INTERNAL}:host-gateway`];
|
929
931
|
}
|
930
932
|
// Docker versions lower than 20.10 needs an actual IP address. We use the default network bridge which
|
931
933
|
// is always 172.17.0.1
|
932
|
-
return [
|
934
|
+
return [`${types_1.DOCKER_HOST_INTERNAL}:172.17.0.1`];
|
933
935
|
}
|
934
936
|
return undefined;
|
935
937
|
}
|
@@ -2,8 +2,9 @@
|
|
2
2
|
* Copyright 2023 Kapeta Inc.
|
3
3
|
* SPDX-License-Identifier: BUSL-1.1
|
4
4
|
*/
|
5
|
-
import { EnvironmentType, InstanceInfo, LogEntry
|
5
|
+
import { EnvironmentType, InstanceInfo, LogEntry } from './types';
|
6
6
|
import { Task } from './taskManager';
|
7
|
+
import { InstanceOperator } from '@kapeta/sdk-config';
|
7
8
|
export declare class InstanceManager {
|
8
9
|
private _interval;
|
9
10
|
private readonly _instances;
|
@@ -14,6 +15,7 @@ export declare class InstanceManager {
|
|
14
15
|
getInstancesForPlan(systemId: string): Promise<InstanceInfo[]>;
|
15
16
|
getInstance(systemId: string, instanceId: string): InstanceInfo | undefined;
|
16
17
|
private exclusive;
|
18
|
+
private isLocked;
|
17
19
|
getLogs(systemId: string, instanceId: string): Promise<LogEntry[]>;
|
18
20
|
saveInternalInstance(instance: InstanceInfo): Promise<InstanceInfo>;
|
19
21
|
/**
|
@@ -25,7 +27,7 @@ export declare class InstanceManager {
|
|
25
27
|
markAsStopped(systemId: string, instanceId: string): Promise<void>;
|
26
28
|
startAllForPlan(systemId: string): Promise<Task<InstanceInfo[]>>;
|
27
29
|
stopAllForPlan(systemId: string): Task<void>;
|
28
|
-
getInstanceOperator(systemId: string, instanceId: string, environment?: EnvironmentType): Promise<
|
30
|
+
getInstanceOperator(systemId: string, instanceId: string, environment?: EnvironmentType, ensureContainer?: boolean): Promise<InstanceOperator<any, any>>;
|
29
31
|
stop(systemId: string, instanceId: string): Promise<void>;
|
30
32
|
private stopInner;
|
31
33
|
start(systemId: string, instanceId: string, checkForSingleton?: boolean): Promise<InstanceInfo | Task<InstanceInfo>>;
|
@@ -79,6 +79,9 @@ class InstanceManager {
|
|
79
79
|
//console.log(`Releasing lock for ${key}`, this.instanceLocks.isBusy(key));
|
80
80
|
return result;
|
81
81
|
}
|
82
|
+
isLocked(systemId, instanceId) {
|
83
|
+
return this.instanceLocks.isBusy(`${systemId}/${instanceId}`);
|
84
|
+
}
|
82
85
|
async getLogs(systemId, instanceId) {
|
83
86
|
const instance = this.getInstance(systemId, instanceId);
|
84
87
|
if (!instance) {
|
@@ -268,7 +271,7 @@ class InstanceManager {
|
|
268
271
|
name: `Stopping plan ${systemId}`,
|
269
272
|
});
|
270
273
|
}
|
271
|
-
async getInstanceOperator(systemId, instanceId, environment) {
|
274
|
+
async getInstanceOperator(systemId, instanceId, environment, ensureContainer = true) {
|
272
275
|
const blockInstance = await assetManager_1.assetManager.getBlockInstance(systemId, instanceId);
|
273
276
|
if (!blockInstance) {
|
274
277
|
throw new Error(`Instance not found: ${systemId}/${instanceId}`);
|
@@ -279,30 +282,48 @@ class InstanceManager {
|
|
279
282
|
throw new Error(`Block not found: ${blockRef}`);
|
280
283
|
}
|
281
284
|
const operatorDefinition = await definitionsManager_1.definitionsManager.getDefinition(block.kind);
|
282
|
-
if (!operatorDefinition
|
285
|
+
if (!operatorDefinition) {
|
286
|
+
throw new Error(`Operator not found: ${block.kind}`);
|
287
|
+
}
|
288
|
+
if (operatorDefinition.definition.kind !== types_1.KIND_BLOCK_TYPE_OPERATOR) {
|
289
|
+
throw new Error(`Block is not an operator: ${blockRef}`);
|
290
|
+
}
|
291
|
+
if (!operatorDefinition.definition.spec.local) {
|
283
292
|
throw new Error(`Operator block has no local definition: ${blockRef}`);
|
284
293
|
}
|
285
294
|
const localConfig = operatorDefinition.definition.spec.local;
|
286
|
-
|
287
|
-
if (
|
288
|
-
instance = await
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
295
|
+
const ports = {};
|
296
|
+
if (ensureContainer) {
|
297
|
+
let instance = await this.start(systemId, instanceId);
|
298
|
+
if (instance instanceof taskManager_1.Task) {
|
299
|
+
instance = await instance.wait();
|
300
|
+
}
|
301
|
+
const container = await containerManager_1.containerManager.get(instance.pid);
|
302
|
+
if (!container) {
|
303
|
+
throw new Error(`Container not found: ${instance.pid}`);
|
304
|
+
}
|
305
|
+
const portInfo = await container.getPorts();
|
306
|
+
if (!portInfo) {
|
307
|
+
throw new Error(`No ports found for instance: ${instanceId}`);
|
308
|
+
}
|
309
|
+
Object.entries(portInfo).forEach(([key, value]) => {
|
310
|
+
ports[key] = {
|
311
|
+
protocol: value.protocol,
|
312
|
+
port: parseInt(value.hostPort),
|
313
|
+
};
|
314
|
+
});
|
293
315
|
}
|
294
|
-
|
295
|
-
|
296
|
-
|
316
|
+
else {
|
317
|
+
// If we're not ensuring the container is running we just get the ports from the local config
|
318
|
+
const instancePorts = await (0, utils_1.getOperatorInstancePorts)(systemId, instanceId, localConfig);
|
319
|
+
instancePorts.forEach((port) => {
|
320
|
+
ports[port.portType] = {
|
321
|
+
protocol: port.protocol,
|
322
|
+
port: port.hostPort,
|
323
|
+
};
|
324
|
+
});
|
297
325
|
}
|
298
|
-
const hostname =
|
299
|
-
const ports = {};
|
300
|
-
Object.entries(portInfo).forEach(([key, value]) => {
|
301
|
-
ports[key] = {
|
302
|
-
protocol: value.protocol,
|
303
|
-
port: parseInt(value.hostPort),
|
304
|
-
};
|
305
|
-
});
|
326
|
+
const hostname = (0, utils_1.getRemoteHostForEnvironment)(environment);
|
306
327
|
return {
|
307
328
|
hostname,
|
308
329
|
ports,
|
@@ -347,6 +368,7 @@ class InstanceManager {
|
|
347
368
|
if (changeDesired && instance.desiredStatus !== types_1.DesiredInstanceStatus.EXTERNAL) {
|
348
369
|
instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
|
349
370
|
}
|
371
|
+
const wasFailed = instance.status === types_1.InstanceStatus.FAILED;
|
350
372
|
instance.status = types_1.InstanceStatus.STOPPING;
|
351
373
|
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
352
374
|
console.log('Stopping instance: %s::%s [desired: %s] [intentional: %s]', systemId, instanceId, instance.desiredStatus, changeDesired);
|
@@ -357,7 +379,12 @@ class InstanceManager {
|
|
357
379
|
const container = await containerManager_1.containerManager.getContainerByName(containerName);
|
358
380
|
if (container) {
|
359
381
|
try {
|
360
|
-
|
382
|
+
if (wasFailed) {
|
383
|
+
await container.remove();
|
384
|
+
}
|
385
|
+
else {
|
386
|
+
await container.stop();
|
387
|
+
}
|
361
388
|
instance.status = types_1.InstanceStatus.STOPPED;
|
362
389
|
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
363
390
|
this.save();
|
@@ -413,7 +440,7 @@ class InstanceManager {
|
|
413
440
|
existingInstance = undefined;
|
414
441
|
}
|
415
442
|
}
|
416
|
-
if (existingInstance
|
443
|
+
if (existingInstance && existingInstance.pid) {
|
417
444
|
if (existingInstance.status === types_1.InstanceStatus.READY) {
|
418
445
|
// Instance is already running
|
419
446
|
return existingInstance;
|
@@ -474,8 +501,7 @@ class InstanceManager {
|
|
474
501
|
return existingInstance;
|
475
502
|
}
|
476
503
|
}
|
477
|
-
const
|
478
|
-
const resolvedConfig = (0, utils_1.getResolvedConfiguration)(blockSpec.configuration, instanceConfig, blockInstance.defaultConfiguration);
|
504
|
+
const resolvedConfig = await configManager_1.configManager.getConfigForBlockInstance(systemId, instanceId);
|
479
505
|
const task = taskManager_1.taskManager.add(`instance:start:${systemId}:${instanceId}`, async () => {
|
480
506
|
const runner = new BlockInstanceRunner_1.BlockInstanceRunner(systemId);
|
481
507
|
const startTime = Date.now();
|
@@ -708,14 +734,20 @@ class InstanceManager {
|
|
708
734
|
return types_1.InstanceStatus.READY;
|
709
735
|
}
|
710
736
|
if (statusType === 'created') {
|
711
|
-
if (state.ExitCode !== 0) {
|
712
|
-
// Failed during creation
|
713
|
-
|
737
|
+
if (state.ExitCode !== undefined && state.ExitCode !== 0) {
|
738
|
+
// Failed during creation. Exit code is not always reliable though
|
739
|
+
if (state.Error) {
|
740
|
+
return types_1.InstanceStatus.FAILED;
|
741
|
+
}
|
742
|
+
else {
|
743
|
+
return types_1.InstanceStatus.STOPPED;
|
744
|
+
}
|
714
745
|
}
|
715
746
|
return types_1.InstanceStatus.STARTING;
|
716
747
|
}
|
717
748
|
if (statusType === 'exited' || statusType === 'dead') {
|
718
|
-
if (state.
|
749
|
+
if (!state.Error) {
|
750
|
+
// Exit code is not always reliable - if there is no error we assume it's stopped
|
719
751
|
return types_1.InstanceStatus.STOPPED;
|
720
752
|
}
|
721
753
|
return types_1.InstanceStatus.FAILED;
|
@@ -4,8 +4,9 @@
|
|
4
4
|
*/
|
5
5
|
import { DefinitionInfo } from '@kapeta/local-cluster-config';
|
6
6
|
import { ContainerInfo } from './containerManager';
|
7
|
-
import {
|
7
|
+
import { AnyMap, EnvironmentType } from './types';
|
8
8
|
import { LocalInstance } from '@kapeta/schemas';
|
9
|
+
import { ResourceInfo } from '@kapeta/sdk-config';
|
9
10
|
declare class Operator {
|
10
11
|
private readonly _data;
|
11
12
|
constructor(data: DefinitionInfo);
|
@@ -25,7 +26,8 @@ declare class OperatorManager {
|
|
25
26
|
/**
|
26
27
|
* Get information about a specific consumed resource
|
27
28
|
*/
|
28
|
-
getConsumerResourceInfo(systemId: string, fromServiceId: string, resourceType: string, portType: string, name: string, environment?: EnvironmentType): Promise<
|
29
|
+
getConsumerResourceInfo(systemId: string, fromServiceId: string, resourceType: string, portType: string, name: string, environment?: EnvironmentType, ensureContainer?: boolean): Promise<ResourceInfo<any, any>>;
|
30
|
+
getOperatorPorts(systemId: string, kind: string, version: string): Promise<AnyMap>;
|
29
31
|
/**
|
30
32
|
* Ensure we have a running operator of given type
|
31
33
|
*
|
@@ -68,7 +68,7 @@ class OperatorManager {
|
|
68
68
|
/**
|
69
69
|
* Get information about a specific consumed resource
|
70
70
|
*/
|
71
|
-
async getConsumerResourceInfo(systemId, fromServiceId, resourceType, portType, name, environment) {
|
71
|
+
async getConsumerResourceInfo(systemId, fromServiceId, resourceType, portType, name, environment, ensureContainer = true) {
|
72
72
|
systemId = (0, nodejs_utils_1.normalizeKapetaUri)(systemId);
|
73
73
|
const plans = await definitionsManager_1.definitionsManager.getDefinitions(KIND_PLAN);
|
74
74
|
const planUri = (0, nodejs_utils_1.parseKapetaUri)(systemId);
|
@@ -96,18 +96,20 @@ class OperatorManager {
|
|
96
96
|
const kindUri = (0, nodejs_utils_1.parseKapetaUri)(blockResource.kind);
|
97
97
|
const operator = await this.getOperator(resourceType, kindUri.version);
|
98
98
|
const credentials = operator.getCredentials();
|
99
|
-
|
100
|
-
|
101
|
-
|
99
|
+
if (ensureContainer) {
|
100
|
+
await this.ensureOperator(systemId, resourceType, kindUri.version);
|
101
|
+
}
|
102
|
+
const hostPort = await serviceManager_1.serviceManager.ensureServicePort(systemId, resourceType, portType);
|
103
|
+
if (!hostPort) {
|
102
104
|
throw new Error('Unknown resource port type : ' + resourceType + '#' + portType);
|
103
105
|
}
|
104
106
|
const dbName = name + '_' + fromServiceId.replace(/[^a-z0-9]/gi, '');
|
105
107
|
const safeName = dbName.replace('_', '-');
|
106
108
|
return {
|
107
|
-
host:
|
108
|
-
port:
|
109
|
+
host: (0, utils_1.getRemoteHostForEnvironment)(environment),
|
110
|
+
port: hostPort,
|
109
111
|
type: portType,
|
110
|
-
protocol:
|
112
|
+
protocol: 'tcp',
|
111
113
|
options: {
|
112
114
|
// expose as fullName since that is not operator specific, but unique
|
113
115
|
fullName: safeName,
|
@@ -116,6 +118,26 @@ class OperatorManager {
|
|
116
118
|
credentials,
|
117
119
|
};
|
118
120
|
}
|
121
|
+
async getOperatorPorts(systemId, kind, version) {
|
122
|
+
const operator = await this.getOperator(kind, version);
|
123
|
+
const operatorData = operator.getLocalData();
|
124
|
+
const portTypes = Object.keys(operatorData.ports);
|
125
|
+
portTypes.sort();
|
126
|
+
const ports = {};
|
127
|
+
for (let i = 0; i < portTypes.length; i++) {
|
128
|
+
const portType = portTypes[i];
|
129
|
+
let containerPortInfo = operatorData.ports[portType];
|
130
|
+
const hostPort = await serviceManager_1.serviceManager.ensureServicePort(systemId, kind, portType);
|
131
|
+
const portInfo = (0, utils_1.toPortInfo)(containerPortInfo);
|
132
|
+
const portId = portInfo.port + '/' + portInfo.type;
|
133
|
+
ports[portId] = {
|
134
|
+
type: portType,
|
135
|
+
hostPort,
|
136
|
+
protocol: portInfo.type,
|
137
|
+
};
|
138
|
+
}
|
139
|
+
return ports;
|
140
|
+
}
|
119
141
|
/**
|
120
142
|
* Ensure we have a running operator of given type
|
121
143
|
*
|
@@ -129,20 +151,7 @@ class OperatorManager {
|
|
129
151
|
return await this.operatorLock.acquire(key, async () => {
|
130
152
|
const operator = await this.getOperator(kind, version);
|
131
153
|
const operatorData = operator.getLocalData();
|
132
|
-
const
|
133
|
-
portTypes.sort();
|
134
|
-
const ports = {};
|
135
|
-
for (let i = 0; i < portTypes.length; i++) {
|
136
|
-
const portType = portTypes[i];
|
137
|
-
let containerPortInfo = operatorData.ports[portType];
|
138
|
-
const hostPort = await serviceManager_1.serviceManager.ensureServicePort(systemId, kind, portType);
|
139
|
-
const portInfo = (0, utils_1.toPortInfo)(containerPortInfo);
|
140
|
-
const portId = portInfo.port + '/' + portInfo.type;
|
141
|
-
ports[portId] = {
|
142
|
-
type: portType,
|
143
|
-
hostPort,
|
144
|
-
};
|
145
|
-
}
|
154
|
+
const ports = await this.getOperatorPorts(systemId, kind, version);
|
146
155
|
const nameParts = [systemId, kind.toLowerCase(), version];
|
147
156
|
const containerName = `kapeta-resource-${(0, md5_1.default)(nameParts.join('_'))}`;
|
148
157
|
const PortBindings = {};
|
@@ -154,14 +163,14 @@ class OperatorManager {
|
|
154
163
|
[containerManager_1.COMPOSE_LABEL_SERVICE]: [kind, version].join('_').replace(/[^a-z0-9]/gi, '_'),
|
155
164
|
};
|
156
165
|
const operatorMetadata = operator.getDefinitionInfo().definition.metadata;
|
157
|
-
const
|
166
|
+
const hostIp = (0, utils_1.getDockerHostIp)();
|
158
167
|
const ExposedPorts = {};
|
159
168
|
lodash_1.default.forEach(ports, (portInfo, containerPort) => {
|
160
169
|
ExposedPorts['' + containerPort] = {};
|
161
170
|
PortBindings['' + containerPort] = [
|
162
171
|
{
|
163
172
|
HostPort: '' + portInfo.hostPort,
|
164
|
-
HostIp:
|
173
|
+
HostIp: hostIp,
|
165
174
|
},
|
166
175
|
];
|
167
176
|
Labels[containerManager_1.CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
|
@@ -9,7 +9,6 @@ export declare const HTTP_PORTS: string[];
|
|
9
9
|
declare class ServiceManager {
|
10
10
|
private _systems;
|
11
11
|
constructor();
|
12
|
-
getLocalHost(environmentType?: EnvironmentType): string;
|
13
12
|
_forLocal(port: string | number, path?: string, environmentType?: EnvironmentType): string;
|
14
13
|
_ensureSystem(systemId: string): any;
|
15
14
|
_ensureService(systemId: string, serviceId: string): any;
|
@@ -13,6 +13,7 @@ const clusterService_1 = require("./clusterService");
|
|
13
13
|
const storageService_1 = require("./storageService");
|
14
14
|
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
15
15
|
const BlockInstanceRunner_1 = require("./utils/BlockInstanceRunner");
|
16
|
+
const utils_1 = require("./utils/utils");
|
16
17
|
exports.HTTP_PORT_TYPE = 'http';
|
17
18
|
exports.DEFAULT_PORT_TYPE = exports.HTTP_PORT_TYPE;
|
18
19
|
exports.HTTP_PORTS = [exports.HTTP_PORT_TYPE, 'web', 'rest'];
|
@@ -31,18 +32,11 @@ class ServiceManager {
|
|
31
32
|
});
|
32
33
|
});
|
33
34
|
}
|
34
|
-
getLocalHost(environmentType) {
|
35
|
-
if (environmentType === 'docker') {
|
36
|
-
//We're inside a docker container, so we can use this special host name to access the host machine
|
37
|
-
return 'host.docker.internal';
|
38
|
-
}
|
39
|
-
return clusterService_1.clusterService.getClusterServiceHost();
|
40
|
-
}
|
41
35
|
_forLocal(port, path, environmentType) {
|
42
36
|
if (!path) {
|
43
37
|
path = '';
|
44
38
|
}
|
45
|
-
const hostname =
|
39
|
+
const hostname = (0, utils_1.getRemoteHostForEnvironment)(environmentType);
|
46
40
|
if (path.startsWith('/')) {
|
47
41
|
path = path.substring(1);
|
48
42
|
}
|
package/dist/cjs/src/types.d.ts
CHANGED
@@ -21,6 +21,7 @@ export type WatchEventName = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir
|
|
21
21
|
export type LogLevel = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'TRACE' | 'FATAL';
|
22
22
|
export type LogSource = 'stdout' | 'stderr';
|
23
23
|
export type EnvironmentType = 'docker' | 'process';
|
24
|
+
export declare const DOCKER_HOST_INTERNAL = "host.docker.internal";
|
24
25
|
export interface LogEntry {
|
25
26
|
source: LogSource;
|
26
27
|
level: LogLevel;
|
@@ -60,12 +61,6 @@ export type ProcessInfo = {
|
|
60
61
|
pid?: number | string | null;
|
61
62
|
portType?: string;
|
62
63
|
};
|
63
|
-
export interface Health {
|
64
|
-
cmd: string;
|
65
|
-
interval?: number;
|
66
|
-
timeout?: number;
|
67
|
-
retries?: number;
|
68
|
-
}
|
69
64
|
export type InstanceInfo = {
|
70
65
|
systemId: string;
|
71
66
|
instanceId: string;
|
@@ -83,29 +78,6 @@ export type InstanceInfo = {
|
|
83
78
|
portType?: string;
|
84
79
|
};
|
85
80
|
export type ProxyRequestHandler = (req: StringBodyRequest, res: express.Response, info: ProxyRequestInfo) => void;
|
86
|
-
export interface OperatorInstancePort {
|
87
|
-
protocol: string;
|
88
|
-
port: number;
|
89
|
-
}
|
90
|
-
export interface OperatorInstanceInfo {
|
91
|
-
hostname: string;
|
92
|
-
ports: {
|
93
|
-
[portType: string]: OperatorInstancePort;
|
94
|
-
};
|
95
|
-
path?: string;
|
96
|
-
query?: string;
|
97
|
-
hash?: string;
|
98
|
-
options?: AnyMap;
|
99
|
-
credentials?: AnyMap;
|
100
|
-
}
|
101
|
-
export interface OperatorInfo {
|
102
|
-
host: string;
|
103
|
-
port: string;
|
104
|
-
type: string;
|
105
|
-
protocol: string;
|
106
|
-
options: AnyMap;
|
107
|
-
credentials: AnyMap;
|
108
|
-
}
|
109
81
|
export interface ProxyRequestInfo {
|
110
82
|
address: string;
|
111
83
|
connection: Connection;
|
package/dist/cjs/src/types.js
CHANGED
@@ -4,11 +4,12 @@
|
|
4
4
|
* SPDX-License-Identifier: BUSL-1.1
|
5
5
|
*/
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
7
|
-
exports.DesiredInstanceStatus = exports.InstanceStatus = exports.InstanceOwner = exports.InstanceType = exports.KIND_BLOCK_TYPE_EXECUTABLE = exports.KIND_BLOCK_TYPE_OPERATOR = exports.KIND_BLOCK_TYPE = exports.KIND_RESOURCE_OPERATOR = void 0;
|
7
|
+
exports.DesiredInstanceStatus = exports.InstanceStatus = exports.InstanceOwner = exports.InstanceType = exports.DOCKER_HOST_INTERNAL = exports.KIND_BLOCK_TYPE_EXECUTABLE = exports.KIND_BLOCK_TYPE_OPERATOR = exports.KIND_BLOCK_TYPE = exports.KIND_RESOURCE_OPERATOR = void 0;
|
8
8
|
exports.KIND_RESOURCE_OPERATOR = 'core/resource-type-operator';
|
9
9
|
exports.KIND_BLOCK_TYPE = 'core/block-type';
|
10
10
|
exports.KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
|
11
11
|
exports.KIND_BLOCK_TYPE_EXECUTABLE = 'core/block-type-executable';
|
12
|
+
exports.DOCKER_HOST_INTERNAL = 'host.docker.internal';
|
12
13
|
var InstanceType;
|
13
14
|
(function (InstanceType) {
|
14
15
|
InstanceType["DOCKER"] = "docker";
|
@@ -21,6 +21,8 @@ const definitionsManager_1 = require("../definitionsManager");
|
|
21
21
|
const node_os_1 = __importDefault(require("node:os"));
|
22
22
|
const node_path_1 = __importDefault(require("node:path"));
|
23
23
|
const taskManager_1 = require("../taskManager");
|
24
|
+
const InternalConfigProvider_1 = require("./InternalConfigProvider");
|
25
|
+
const config_mapper_1 = require("@kapeta/config-mapper");
|
24
26
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
25
27
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
26
28
|
const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
|
@@ -30,7 +32,7 @@ const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
|
|
30
32
|
*/
|
31
33
|
const DOCKER_ENV_VARS = [
|
32
34
|
`KAPETA_LOCAL_SERVER=0.0.0.0`,
|
33
|
-
`KAPETA_LOCAL_CLUSTER_HOST
|
35
|
+
`KAPETA_LOCAL_CLUSTER_HOST=${types_1.DOCKER_HOST_INTERNAL}`,
|
34
36
|
`KAPETA_ENVIRONMENT_TYPE=docker`,
|
35
37
|
];
|
36
38
|
async function getProvider(uri) {
|
@@ -91,16 +93,6 @@ class BlockInstanceRunner {
|
|
91
93
|
});
|
92
94
|
}
|
93
95
|
async _execute(blockInstance) {
|
94
|
-
const env = {};
|
95
|
-
if (this._systemId) {
|
96
|
-
env[KAPETA_SYSTEM_ID] = this._systemId;
|
97
|
-
}
|
98
|
-
if (blockInstance.ref) {
|
99
|
-
env[KAPETA_BLOCK_REF] = blockInstance.ref;
|
100
|
-
}
|
101
|
-
if (blockInstance.id) {
|
102
|
-
env[KAPETA_INSTANCE_ID] = blockInstance.id;
|
103
|
-
}
|
104
96
|
const blockUri = (0, nodejs_utils_1.parseKapetaUri)(blockInstance.ref);
|
105
97
|
if (!blockUri.version) {
|
106
98
|
blockUri.version = 'local';
|
@@ -114,18 +106,25 @@ class BlockInstanceRunner {
|
|
114
106
|
if (!providerVersion) {
|
115
107
|
throw new Error(`Kind not found: ${kindUri.id}`);
|
116
108
|
}
|
109
|
+
const baseDir = local_cluster_config_1.default.getRepositoryAssetPath(blockUri.handle, blockUri.name, blockUri.version);
|
110
|
+
const realBaseDir = await fs_extra_1.default.realpath(baseDir);
|
111
|
+
const internalConfigProvider = await (0, InternalConfigProvider_1.createInternalConfigProvider)(this._systemId, blockInstance.id, assetVersion);
|
112
|
+
// Resolve the environment variables
|
113
|
+
const envVars = await (0, config_mapper_1.resolveKapetaVariables)(realBaseDir, internalConfigProvider);
|
114
|
+
// Write out the config templates if they exist
|
115
|
+
await (0, config_mapper_1.writeConfigTemplates)(envVars, realBaseDir);
|
117
116
|
let processInfo;
|
118
117
|
if (providerVersion.definition.kind === types_1.KIND_BLOCK_TYPE_OPERATOR) {
|
119
|
-
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion,
|
118
|
+
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, envVars);
|
120
119
|
}
|
121
120
|
else {
|
122
121
|
//We need a port type to know how to connect to the block consistently
|
123
122
|
const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
|
124
123
|
if (blockUri.version === 'local') {
|
125
|
-
processInfo = await this._startLocalProcess(blockInstance, blockUri,
|
124
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, envVars, assetVersion);
|
126
125
|
}
|
127
126
|
else {
|
128
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri,
|
127
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, envVars, assetVersion);
|
129
128
|
}
|
130
129
|
if (portTypes.length > 0) {
|
131
130
|
processInfo.portType = portTypes[0];
|
@@ -193,9 +192,13 @@ class BlockInstanceRunner {
|
|
193
192
|
if (localContainer.healthcheck) {
|
194
193
|
HealthCheck = containerManager_1.containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
195
194
|
}
|
196
|
-
const Mounts =
|
197
|
-
|
198
|
-
|
195
|
+
const Mounts = isDockerImage
|
196
|
+
? // For docker images we mount the local directory to the working directory
|
197
|
+
containerManager_1.containerManager.toDockerMounts({
|
198
|
+
[workingDir]: (0, containerManager_1.toLocalBindVolume)(realLocalPath),
|
199
|
+
})
|
200
|
+
: // For dockerfiles we don't mount anything
|
201
|
+
[];
|
199
202
|
const systemUri = (0, nodejs_utils_1.parseKapetaUri)(this._systemId);
|
200
203
|
return this.ensureContainer({
|
201
204
|
...dockerOpts,
|
@@ -310,29 +313,26 @@ class BlockInstanceRunner {
|
|
310
313
|
const containerName = await (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id, providerRef);
|
311
314
|
const task = taskManager_1.taskManager.add(`container:start:${containerName}`, async () => {
|
312
315
|
const logs = new LogData_1.LogData();
|
313
|
-
const
|
316
|
+
const hostIp = (0, utils_1.getDockerHostIp)();
|
314
317
|
const ExposedPorts = {};
|
315
318
|
const addonEnv = {};
|
316
319
|
const PortBindings = {};
|
317
320
|
let HealthCheck = undefined;
|
318
321
|
let Mounts = [];
|
319
|
-
const
|
322
|
+
const instancePorts = await (0, utils_1.getOperatorInstancePorts)(this._systemId, operatorId, local);
|
320
323
|
const labels = {};
|
321
|
-
|
322
|
-
const
|
323
|
-
const dockerPort = `${portInfo.port}/${portInfo.type}`;
|
324
|
+
instancePorts.forEach((portInfo) => {
|
325
|
+
const dockerPort = `${portInfo.port}/${portInfo.protocol}`;
|
324
326
|
ExposedPorts[dockerPort] = {};
|
325
|
-
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = `${portInfo.port}`;
|
326
|
-
const publicPort = await serviceManager_1.serviceManager.ensureServicePort(this._systemId, operatorId, portType);
|
327
|
+
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portInfo.portType.toUpperCase()}`] = `${portInfo.port}`;
|
327
328
|
PortBindings[dockerPort] = [
|
328
329
|
{
|
329
|
-
HostIp:
|
330
|
-
HostPort: `${
|
330
|
+
HostIp: hostIp,
|
331
|
+
HostPort: `${portInfo.hostPort}`,
|
331
332
|
},
|
332
333
|
];
|
333
|
-
labels[containerManager_1.CONTAINER_LABEL_PORT_PREFIX +
|
334
|
+
labels[containerManager_1.CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.portType;
|
334
335
|
});
|
335
|
-
await Promise.all(promises);
|
336
336
|
if (local.env) {
|
337
337
|
Object.entries(local.env).forEach(([key, value]) => {
|
338
338
|
addonEnv[key] = value;
|
@@ -396,7 +396,7 @@ class BlockInstanceRunner {
|
|
396
396
|
* Get the port bindings for a non-operator block
|
397
397
|
*/
|
398
398
|
async getServiceBlockPortBindings(blockInstance, assetVersion, providerVersion) {
|
399
|
-
const
|
399
|
+
const hostIp = (0, utils_1.getDockerHostIp)();
|
400
400
|
const ExposedPorts = {};
|
401
401
|
const addonEnv = {};
|
402
402
|
const PortBindings = {};
|
@@ -410,7 +410,7 @@ class BlockInstanceRunner {
|
|
410
410
|
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = '' + thisPort;
|
411
411
|
PortBindings[dockerPort] = [
|
412
412
|
{
|
413
|
-
HostIp:
|
413
|
+
HostIp: hostIp,
|
414
414
|
HostPort: `${publicPort}`,
|
415
415
|
},
|
416
416
|
];
|