@kapeta/local-cluster-service 0.37.0 → 0.39.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 +14 -0
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/src/assetManager.d.ts +2 -1
- package/dist/cjs/src/assetManager.js +3 -2
- package/dist/cjs/src/config/routes.js +2 -2
- package/dist/cjs/src/containerManager.d.ts +6 -3
- package/dist/cjs/src/containerManager.js +101 -21
- package/dist/cjs/src/instanceManager.d.ts +4 -2
- package/dist/cjs/src/instanceManager.js +71 -32
- package/dist/cjs/src/operatorManager.d.ts +6 -3
- package/dist/cjs/src/operatorManager.js +32 -23
- package/dist/cjs/src/progressListener.d.ts +8 -1
- package/dist/cjs/src/progressListener.js +12 -1
- package/dist/cjs/src/repositoryManager.js +3 -2
- package/dist/cjs/src/serviceManager.d.ts +0 -1
- package/dist/cjs/src/serviceManager.js +2 -8
- package/dist/cjs/src/taskManager.d.ts +2 -0
- package/dist/cjs/src/taskManager.js +9 -0
- package/dist/cjs/src/types.d.ts +1 -48
- package/dist/cjs/src/types.js +2 -1
- package/dist/cjs/src/utils/BlockInstanceRunner.js +45 -33
- package/dist/cjs/src/utils/InternalConfigProvider.d.ts +38 -0
- package/dist/cjs/src/utils/InternalConfigProvider.js +146 -0
- package/dist/cjs/src/utils/commandLineUtils.d.ts +2 -1
- package/dist/cjs/src/utils/commandLineUtils.js +7 -1
- package/dist/cjs/src/utils/utils.d.ts +26 -4
- package/dist/cjs/src/utils/utils.js +48 -8
- package/dist/esm/index.js +4 -1
- package/dist/esm/src/assetManager.d.ts +2 -1
- package/dist/esm/src/assetManager.js +3 -2
- package/dist/esm/src/config/routes.js +2 -2
- package/dist/esm/src/containerManager.d.ts +6 -3
- package/dist/esm/src/containerManager.js +101 -21
- package/dist/esm/src/instanceManager.d.ts +4 -2
- package/dist/esm/src/instanceManager.js +71 -32
- package/dist/esm/src/operatorManager.d.ts +6 -3
- package/dist/esm/src/operatorManager.js +32 -23
- package/dist/esm/src/progressListener.d.ts +8 -1
- package/dist/esm/src/progressListener.js +12 -1
- package/dist/esm/src/repositoryManager.js +3 -2
- package/dist/esm/src/serviceManager.d.ts +0 -1
- package/dist/esm/src/serviceManager.js +2 -8
- package/dist/esm/src/taskManager.d.ts +2 -0
- package/dist/esm/src/taskManager.js +9 -0
- package/dist/esm/src/types.d.ts +1 -48
- package/dist/esm/src/types.js +2 -1
- package/dist/esm/src/utils/BlockInstanceRunner.js +45 -33
- package/dist/esm/src/utils/InternalConfigProvider.d.ts +38 -0
- package/dist/esm/src/utils/InternalConfigProvider.js +146 -0
- package/dist/esm/src/utils/commandLineUtils.d.ts +2 -1
- package/dist/esm/src/utils/commandLineUtils.js +7 -1
- package/dist/esm/src/utils/utils.d.ts +26 -4
- package/dist/esm/src/utils/utils.js +48 -8
- package/index.ts +5 -2
- package/package.json +16 -14
- package/src/assetManager.ts +5 -4
- package/src/config/routes.ts +4 -2
- package/src/containerManager.ts +115 -26
- package/src/instanceManager.ts +86 -44
- package/src/operatorManager.ts +48 -40
- package/src/progressListener.ts +15 -1
- package/src/repositoryManager.ts +5 -3
- package/src/serviceManager.ts +3 -11
- package/src/taskManager.ts +11 -0
- package/src/types.ts +2 -50
- package/src/utils/BlockInstanceRunner.ts +60 -44
- package/src/utils/InternalConfigProvider.ts +214 -0
- package/src/utils/commandLineUtils.ts +10 -2
- package/src/utils/utils.ts +53 -10
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
import FSExtra from 'fs-extra';
|
7
7
|
import ClusterConfig, { DefinitionInfo } from '@kapeta/local-cluster-config';
|
8
|
-
import {
|
8
|
+
import { getDockerHostIp, getBlockInstanceContainerName, getOperatorInstancePorts, readYML, toPortInfo } from './utils';
|
9
9
|
import { KapetaURI, parseKapetaUri, normalizeKapetaUri } from '@kapeta/nodejs-utils';
|
10
10
|
import { DEFAULT_PORT_TYPE, HTTP_PORT_TYPE, HTTP_PORTS, serviceManager } from '../serviceManager';
|
11
11
|
import {
|
@@ -21,16 +21,20 @@ import { clusterService } from '../clusterService';
|
|
21
21
|
import {
|
22
22
|
AnyMap,
|
23
23
|
BlockProcessParams,
|
24
|
+
DOCKER_HOST_INTERNAL,
|
24
25
|
InstanceType,
|
25
26
|
KIND_BLOCK_TYPE_OPERATOR,
|
26
|
-
LocalImageOptions,
|
27
27
|
ProcessInfo,
|
28
28
|
StringMap,
|
29
29
|
} from '../types';
|
30
30
|
import { definitionsManager } from '../definitionsManager';
|
31
31
|
import Docker from 'dockerode';
|
32
32
|
import OS from 'node:os';
|
33
|
+
import Path from 'node:path';
|
33
34
|
import { taskManager } from '../taskManager';
|
35
|
+
import { LocalDevContainer, LocalInstance } from '@kapeta/schemas';
|
36
|
+
import { createInternalConfigProvider } from './InternalConfigProvider';
|
37
|
+
import { resolveKapetaVariables, writeConfigTemplates } from '@kapeta/config-mapper';
|
34
38
|
|
35
39
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
36
40
|
const KAPETA_BLOCK_REF = 'KAPETA_BLOCK_REF';
|
@@ -42,7 +46,7 @@ const KAPETA_INSTANCE_ID = 'KAPETA_INSTANCE_ID';
|
|
42
46
|
*/
|
43
47
|
const DOCKER_ENV_VARS = [
|
44
48
|
`KAPETA_LOCAL_SERVER=0.0.0.0`,
|
45
|
-
`KAPETA_LOCAL_CLUSTER_HOST
|
49
|
+
`KAPETA_LOCAL_CLUSTER_HOST=${DOCKER_HOST_INTERNAL}`,
|
46
50
|
`KAPETA_ENVIRONMENT_TYPE=docker`,
|
47
51
|
];
|
48
52
|
|
@@ -111,20 +115,6 @@ export class BlockInstanceRunner {
|
|
111
115
|
}
|
112
116
|
|
113
117
|
private async _execute(blockInstance: BlockProcessParams): Promise<ProcessInfo> {
|
114
|
-
const env: StringMap = {};
|
115
|
-
|
116
|
-
if (this._systemId) {
|
117
|
-
env[KAPETA_SYSTEM_ID] = this._systemId;
|
118
|
-
}
|
119
|
-
|
120
|
-
if (blockInstance.ref) {
|
121
|
-
env[KAPETA_BLOCK_REF] = blockInstance.ref;
|
122
|
-
}
|
123
|
-
|
124
|
-
if (blockInstance.id) {
|
125
|
-
env[KAPETA_INSTANCE_ID] = blockInstance.id;
|
126
|
-
}
|
127
|
-
|
128
118
|
const blockUri = parseKapetaUri(blockInstance.ref);
|
129
119
|
|
130
120
|
if (!blockUri.version) {
|
@@ -145,18 +135,32 @@ export class BlockInstanceRunner {
|
|
145
135
|
throw new Error(`Kind not found: ${kindUri.id}`);
|
146
136
|
}
|
147
137
|
|
138
|
+
const baseDir = ClusterConfig.getRepositoryAssetPath(blockUri.handle, blockUri.name, blockUri.version);
|
139
|
+
const realBaseDir = await FSExtra.realpath(baseDir);
|
140
|
+
const internalConfigProvider = await createInternalConfigProvider(
|
141
|
+
this._systemId,
|
142
|
+
blockInstance.id,
|
143
|
+
assetVersion
|
144
|
+
);
|
145
|
+
|
146
|
+
// Resolve the environment variables
|
147
|
+
const envVars = await resolveKapetaVariables(realBaseDir, internalConfigProvider);
|
148
|
+
|
149
|
+
// Write out the config templates if they exist
|
150
|
+
await writeConfigTemplates(envVars, realBaseDir);
|
151
|
+
|
148
152
|
let processInfo: ProcessInfo;
|
149
153
|
|
150
154
|
if (providerVersion.definition.kind === KIND_BLOCK_TYPE_OPERATOR) {
|
151
|
-
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion,
|
155
|
+
processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, envVars);
|
152
156
|
} else {
|
153
157
|
//We need a port type to know how to connect to the block consistently
|
154
158
|
const portTypes = getServiceProviderPorts(assetVersion, providerVersion);
|
155
159
|
|
156
160
|
if (blockUri.version === 'local') {
|
157
|
-
processInfo = await this._startLocalProcess(blockInstance, blockUri,
|
161
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, envVars, assetVersion);
|
158
162
|
} else {
|
159
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri,
|
163
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, envVars, assetVersion);
|
160
164
|
}
|
161
165
|
|
162
166
|
if (portTypes.length > 0) {
|
@@ -189,6 +193,8 @@ export class BlockInstanceRunner {
|
|
189
193
|
throw new Error('Missing target kind in block definition');
|
190
194
|
}
|
191
195
|
|
196
|
+
const realLocalPath = await FSExtra.realpath(baseDir);
|
197
|
+
|
192
198
|
const kindUri = parseKapetaUri(assetVersion.definition.kind);
|
193
199
|
|
194
200
|
const providerVersion = await getProvider(kindUri);
|
@@ -205,17 +211,29 @@ export class BlockInstanceRunner {
|
|
205
211
|
throw new Error(`Target not found: ${targetKindUri.id}`);
|
206
212
|
}
|
207
213
|
|
208
|
-
const localContainer = targetVersion.definition.spec.local;
|
214
|
+
const localContainer = targetVersion.definition.spec.local as LocalDevContainer;
|
209
215
|
|
210
216
|
if (!localContainer) {
|
211
217
|
throw new Error(`Missing local container information from target: ${targetKindUri.id}`);
|
212
218
|
}
|
213
219
|
|
214
|
-
|
215
|
-
|
220
|
+
let dockerImage = localContainer.image;
|
221
|
+
const isDockerImage = !localContainer.type || localContainer.type.toLowerCase() === 'docker';
|
222
|
+
const isDockerFile = Boolean(localContainer.type && localContainer.type.toLowerCase() === 'dockerfile');
|
223
|
+
if (isDockerImage && !dockerImage) {
|
216
224
|
throw new Error(`Missing docker image information: ${JSON.stringify(localContainer)}`);
|
217
225
|
}
|
218
226
|
|
227
|
+
if (isDockerFile) {
|
228
|
+
dockerImage = blockInfo.fullName + ':local';
|
229
|
+
const dockerFile = Path.join(realLocalPath, localContainer.file ?? 'Dockerfile');
|
230
|
+
if (!FSExtra.existsSync(dockerFile)) {
|
231
|
+
throw new Error(`Dockerfile not found at: ${dockerFile}`);
|
232
|
+
}
|
233
|
+
const task = containerManager.buildDockerImage(dockerFile, blockInfo.fullName + ':local');
|
234
|
+
await task.wait();
|
235
|
+
}
|
236
|
+
|
219
237
|
const containerName = await getBlockInstanceContainerName(this._systemId, blockInstance.id, targetKindUri.id);
|
220
238
|
const startCmd = localContainer.handlers?.onCreate ? localContainer.handlers.onCreate : '';
|
221
239
|
const dockerOpts = localContainer.options ?? {};
|
@@ -242,11 +260,13 @@ export class BlockInstanceRunner {
|
|
242
260
|
HealthCheck = containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
243
261
|
}
|
244
262
|
|
245
|
-
const
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
263
|
+
const Mounts = isDockerImage
|
264
|
+
? // For docker images we mount the local directory to the working directory
|
265
|
+
containerManager.toDockerMounts({
|
266
|
+
[workingDir]: toLocalBindVolume(realLocalPath),
|
267
|
+
})
|
268
|
+
: // For dockerfiles we don't mount anything
|
269
|
+
[];
|
250
270
|
|
251
271
|
const systemUri = parseKapetaUri(this._systemId);
|
252
272
|
|
@@ -391,7 +411,7 @@ export class BlockInstanceRunner {
|
|
391
411
|
throw new Error(`Provider did not have local image: ${providerRef}`);
|
392
412
|
}
|
393
413
|
|
394
|
-
const local = spec.local as
|
414
|
+
const local = spec.local as LocalInstance;
|
395
415
|
|
396
416
|
const dockerImage = local.image;
|
397
417
|
const operatorUri = local.singleton ? parseKapetaUri(providerRef) : blockUri;
|
@@ -409,34 +429,30 @@ export class BlockInstanceRunner {
|
|
409
429
|
`container:start:${containerName}`,
|
410
430
|
async () => {
|
411
431
|
const logs = new LogData();
|
412
|
-
|
413
|
-
const bindHost = getBindHost();
|
432
|
+
const hostIp = getDockerHostIp();
|
414
433
|
|
415
434
|
const ExposedPorts: AnyMap = {};
|
416
435
|
const addonEnv: StringMap = {};
|
417
436
|
const PortBindings: AnyMap = {};
|
418
437
|
let HealthCheck = undefined;
|
419
438
|
let Mounts: DockerMounts[] = [];
|
420
|
-
const
|
439
|
+
const instancePorts = await getOperatorInstancePorts(this._systemId, operatorId, local);
|
421
440
|
const labels: { [key: string]: string } = {};
|
422
|
-
|
423
|
-
const
|
424
|
-
const dockerPort = `${portInfo.port}/${portInfo.type}`;
|
441
|
+
instancePorts.forEach((portInfo) => {
|
442
|
+
const dockerPort = `${portInfo.port}/${portInfo.protocol}`;
|
425
443
|
ExposedPorts[dockerPort] = {};
|
426
|
-
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = `${portInfo.port}`;
|
427
|
-
|
444
|
+
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portInfo.portType.toUpperCase()}`] = `${portInfo.port}`;
|
445
|
+
|
428
446
|
PortBindings[dockerPort] = [
|
429
447
|
{
|
430
|
-
HostIp:
|
431
|
-
HostPort: `${
|
448
|
+
HostIp: hostIp,
|
449
|
+
HostPort: `${portInfo.hostPort}`,
|
432
450
|
},
|
433
451
|
];
|
434
452
|
|
435
|
-
labels[CONTAINER_LABEL_PORT_PREFIX +
|
453
|
+
labels[CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.portType;
|
436
454
|
});
|
437
455
|
|
438
|
-
await Promise.all(promises);
|
439
|
-
|
440
456
|
if (local.env) {
|
441
457
|
Object.entries(local.env).forEach(([key, value]) => {
|
442
458
|
addonEnv[key] = value as string;
|
@@ -519,7 +535,7 @@ export class BlockInstanceRunner {
|
|
519
535
|
assetVersion: DefinitionInfo,
|
520
536
|
providerVersion: DefinitionInfo
|
521
537
|
) {
|
522
|
-
const
|
538
|
+
const hostIp = getDockerHostIp();
|
523
539
|
const ExposedPorts: AnyMap = {};
|
524
540
|
const addonEnv: StringMap = {};
|
525
541
|
const PortBindings: AnyMap = {};
|
@@ -535,7 +551,7 @@ export class BlockInstanceRunner {
|
|
535
551
|
|
536
552
|
PortBindings[dockerPort] = [
|
537
553
|
{
|
538
|
-
HostIp:
|
554
|
+
HostIp: hostIp,
|
539
555
|
HostPort: `${publicPort}`,
|
540
556
|
},
|
541
557
|
];
|
@@ -0,0 +1,214 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2023 Kapeta Inc.
|
3
|
+
* SPDX-License-Identifier: BUSL-1.1
|
4
|
+
*/
|
5
|
+
import {
|
6
|
+
BlockInstanceDetails,
|
7
|
+
ConfigProvider,
|
8
|
+
DefaultCredentials,
|
9
|
+
DefaultResourceOptions,
|
10
|
+
InstanceOperator,
|
11
|
+
ResourceInfo,
|
12
|
+
} from '@kapeta/sdk-config';
|
13
|
+
import { Definition, DefinitionInfo } from '@kapeta/local-cluster-config';
|
14
|
+
import { normalizeKapetaUri } from '@kapeta/nodejs-utils';
|
15
|
+
import { BlockDefinition, Plan } from '@kapeta/schemas';
|
16
|
+
import { configManager } from '../configManager';
|
17
|
+
import { AnyMap, EnvironmentType } from '../types';
|
18
|
+
import _ from 'lodash';
|
19
|
+
import { serviceManager } from '../serviceManager';
|
20
|
+
import { operatorManager } from '../operatorManager';
|
21
|
+
import { instanceManager } from '../instanceManager';
|
22
|
+
import { definitionsManager } from '../definitionsManager';
|
23
|
+
import { getBindAddressForEnvironment } from './utils';
|
24
|
+
|
25
|
+
/**
|
26
|
+
* A configuration provider that does the same as the LocalConfigProvider
|
27
|
+
* but without calling the API of the local cluster service (since it's running in the same process)
|
28
|
+
*/
|
29
|
+
export class InternalConfigProvider implements ConfigProvider {
|
30
|
+
private readonly info: DefinitionInfo;
|
31
|
+
private readonly systemId: string;
|
32
|
+
private readonly instanceId: string;
|
33
|
+
private readonly config: AnyMap;
|
34
|
+
private readonly environment: EnvironmentType;
|
35
|
+
|
36
|
+
constructor(
|
37
|
+
systemId: string,
|
38
|
+
instanceId: string,
|
39
|
+
info: DefinitionInfo,
|
40
|
+
config: AnyMap,
|
41
|
+
environment: EnvironmentType = 'docker'
|
42
|
+
) {
|
43
|
+
this.info = info;
|
44
|
+
this.systemId = normalizeKapetaUri(systemId);
|
45
|
+
this.instanceId = instanceId;
|
46
|
+
this.config = config;
|
47
|
+
this.environment = environment;
|
48
|
+
}
|
49
|
+
|
50
|
+
getBlockDefinition() {
|
51
|
+
return this.info.definition;
|
52
|
+
}
|
53
|
+
getBlockReference(): string {
|
54
|
+
return normalizeKapetaUri(this.info.definition.metadata.name + ':' + this.info.version);
|
55
|
+
}
|
56
|
+
getSystemId(): string {
|
57
|
+
return this.systemId;
|
58
|
+
}
|
59
|
+
getInstanceId(): string {
|
60
|
+
return this.instanceId;
|
61
|
+
}
|
62
|
+
getServerPort(portType?: string | undefined): Promise<string> {
|
63
|
+
return serviceManager.ensureServicePort(this.systemId, this.instanceId, portType);
|
64
|
+
}
|
65
|
+
async getServiceAddress(serviceName: string, portType: string): Promise<string | null> {
|
66
|
+
return serviceManager.getConsumerAddress(
|
67
|
+
this.systemId,
|
68
|
+
this.instanceId,
|
69
|
+
serviceName,
|
70
|
+
portType,
|
71
|
+
this.environment
|
72
|
+
);
|
73
|
+
}
|
74
|
+
getResourceInfo<Options = DefaultResourceOptions, Credentials = DefaultCredentials>(
|
75
|
+
resourceType: string,
|
76
|
+
portType: string,
|
77
|
+
resourceName: string
|
78
|
+
): Promise<ResourceInfo<Options, Credentials> | null> {
|
79
|
+
return operatorManager.getConsumerResourceInfo(
|
80
|
+
this.systemId,
|
81
|
+
this.instanceId,
|
82
|
+
resourceType,
|
83
|
+
portType,
|
84
|
+
resourceName,
|
85
|
+
this.environment,
|
86
|
+
false
|
87
|
+
);
|
88
|
+
}
|
89
|
+
async getInstanceHost(instanceId: string): Promise<string | null> {
|
90
|
+
const instance = instanceManager.getInstance(this.systemId, instanceId);
|
91
|
+
return instance?.address ?? null;
|
92
|
+
}
|
93
|
+
async getServerHost(): Promise<string> {
|
94
|
+
return getBindAddressForEnvironment(this.environment);
|
95
|
+
}
|
96
|
+
getProviderId(): string {
|
97
|
+
return 'internal';
|
98
|
+
}
|
99
|
+
getOrDefault<T = any>(path: string, defaultValue: T): T {
|
100
|
+
return this.get(path) ?? defaultValue;
|
101
|
+
}
|
102
|
+
get<T = any>(path: string): T | undefined {
|
103
|
+
return _.get(this.config, path);
|
104
|
+
}
|
105
|
+
|
106
|
+
getInstanceOperator<Options = any, Credentials extends DefaultCredentials = DefaultCredentials>(
|
107
|
+
instanceId: string
|
108
|
+
): Promise<InstanceOperator<Options, Credentials> | null> {
|
109
|
+
return instanceManager.getInstanceOperator(this.systemId, instanceId, this.environment, false);
|
110
|
+
}
|
111
|
+
|
112
|
+
public async getInstanceForConsumer<BlockType = BlockDefinition>(
|
113
|
+
resourceName: string
|
114
|
+
): Promise<BlockInstanceDetails<BlockType> | null> {
|
115
|
+
const plan = await this.getPlan();
|
116
|
+
if (!plan) {
|
117
|
+
throw new Error('Could not find plan');
|
118
|
+
}
|
119
|
+
const instanceId = this.getInstanceId();
|
120
|
+
const connection = plan.spec.connections.find(
|
121
|
+
(connection) =>
|
122
|
+
connection.consumer.blockId === instanceId && connection.consumer.resourceName === resourceName
|
123
|
+
);
|
124
|
+
|
125
|
+
if (!connection) {
|
126
|
+
throw new Error(`Could not find connection for consumer ${resourceName}`);
|
127
|
+
}
|
128
|
+
|
129
|
+
const instance = plan.spec.blocks.find((b) => b.id === connection.provider.blockId);
|
130
|
+
|
131
|
+
if (!instance) {
|
132
|
+
throw new Error(`Could not find instance ${connection.provider.blockId} in plan`);
|
133
|
+
}
|
134
|
+
|
135
|
+
const block = await this.getBlock(instance.block.ref);
|
136
|
+
|
137
|
+
if (!block) {
|
138
|
+
throw new Error(`Could not find block ${instance.block.ref} in plan`);
|
139
|
+
}
|
140
|
+
|
141
|
+
return {
|
142
|
+
instanceId: connection.provider.blockId,
|
143
|
+
connections: [connection],
|
144
|
+
block: block as BlockType,
|
145
|
+
};
|
146
|
+
}
|
147
|
+
|
148
|
+
public async getInstancesForProvider<BlockType = BlockDefinition>(
|
149
|
+
resourceName: string
|
150
|
+
): Promise<BlockInstanceDetails<BlockType>[]> {
|
151
|
+
const plan = await this.getPlan();
|
152
|
+
if (!plan) {
|
153
|
+
throw new Error('Could not find plan');
|
154
|
+
}
|
155
|
+
const instanceId = this.getInstanceId();
|
156
|
+
|
157
|
+
const blockDetails: { [key: string]: BlockInstanceDetails<BlockType> } = {};
|
158
|
+
const connections = plan.spec.connections.filter(
|
159
|
+
(connection) =>
|
160
|
+
connection.provider.blockId === instanceId && connection.provider.resourceName === resourceName
|
161
|
+
);
|
162
|
+
|
163
|
+
for (const connection of connections) {
|
164
|
+
const blockInstanceId = connection.consumer.blockId;
|
165
|
+
if (blockDetails[blockInstanceId]) {
|
166
|
+
blockDetails[blockInstanceId].connections.push(connection);
|
167
|
+
continue;
|
168
|
+
}
|
169
|
+
|
170
|
+
const instance = plan.spec.blocks.find((b) => b.id === blockInstanceId);
|
171
|
+
if (!instance) {
|
172
|
+
throw new Error(`Could not find instance ${blockInstanceId} in plan`);
|
173
|
+
}
|
174
|
+
|
175
|
+
const block = await this.getBlock(instance.block.ref);
|
176
|
+
if (!block) {
|
177
|
+
throw new Error(`Could not find block ${instance.block.ref} in plan`);
|
178
|
+
}
|
179
|
+
|
180
|
+
blockDetails[blockInstanceId] = {
|
181
|
+
instanceId: blockInstanceId,
|
182
|
+
connections: [connection],
|
183
|
+
block: block as BlockType,
|
184
|
+
};
|
185
|
+
}
|
186
|
+
|
187
|
+
return Object.values(blockDetails);
|
188
|
+
}
|
189
|
+
|
190
|
+
async getBlock(ref: any): Promise<Definition> {
|
191
|
+
const definition = await definitionsManager.getDefinition(ref);
|
192
|
+
if (!definition) {
|
193
|
+
throw new Error(`Could not find definition for ${ref}`);
|
194
|
+
}
|
195
|
+
return definition.definition;
|
196
|
+
}
|
197
|
+
|
198
|
+
async getPlan(): Promise<Plan> {
|
199
|
+
const definition = await definitionsManager.getDefinition(this.systemId);
|
200
|
+
if (!definition) {
|
201
|
+
throw new Error(`Could not find plan ${this.systemId}`);
|
202
|
+
}
|
203
|
+
return definition.definition as Plan;
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
export async function createInternalConfigProvider(
|
208
|
+
systemId: string,
|
209
|
+
instanceId: string,
|
210
|
+
info: DefinitionInfo
|
211
|
+
): Promise<InternalConfigProvider> {
|
212
|
+
const config = await configManager.getConfigForBlockInstance(systemId, instanceId);
|
213
|
+
return new InternalConfigProvider(systemId, instanceId, info, config);
|
214
|
+
}
|
@@ -4,7 +4,7 @@
|
|
4
4
|
*/
|
5
5
|
|
6
6
|
import { spawn, hasApp } from '@kapeta/nodejs-process';
|
7
|
-
import { taskManager } from '../taskManager';
|
7
|
+
import { Task, taskManager } from '../taskManager';
|
8
8
|
|
9
9
|
export async function hasCLI() {
|
10
10
|
return hasApp('kap');
|
@@ -17,11 +17,19 @@ export async function ensureCLI() {
|
|
17
17
|
|
18
18
|
return taskManager.add(
|
19
19
|
`cli:install`,
|
20
|
-
() => {
|
20
|
+
(task: Task) => {
|
21
21
|
const process = spawn('npm', ['install', '-g', '@kapeta/kap'], {
|
22
22
|
shell: true,
|
23
23
|
});
|
24
24
|
|
25
|
+
process.process.stdout?.on('data', (data: any) => {
|
26
|
+
task.addLog(data.toString(), 'INFO');
|
27
|
+
});
|
28
|
+
|
29
|
+
process.process.stderr?.on('data', (data: any) => {
|
30
|
+
task.addLog(data.toString(), 'ERROR');
|
31
|
+
});
|
32
|
+
|
25
33
|
return process.wait();
|
26
34
|
},
|
27
35
|
{
|
package/src/utils/utils.ts
CHANGED
@@ -6,13 +6,15 @@
|
|
6
6
|
import FS from 'node:fs';
|
7
7
|
import YAML from 'yaml';
|
8
8
|
import md5 from 'md5';
|
9
|
-
import { EntityList } from '@kapeta/schemas';
|
9
|
+
import { EntityList, LocalInstance, LocalInstancePort, LocalInstancePortType } from '@kapeta/schemas';
|
10
10
|
import _ from 'lodash';
|
11
|
-
import { AnyMap,
|
11
|
+
import { AnyMap, DOCKER_HOST_INTERNAL, EnvironmentType, KIND_BLOCK_TYPE_OPERATOR } from '../types';
|
12
12
|
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
13
13
|
import { definitionsManager } from '../definitionsManager';
|
14
14
|
import { normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
|
15
15
|
import { assetManager } from '../assetManager';
|
16
|
+
import { serviceManager } from '../serviceManager';
|
17
|
+
import { clusterService } from '../clusterService';
|
16
18
|
|
17
19
|
export async function getBlockInstanceContainerName(systemId: string, instanceId: string, blockType?: string) {
|
18
20
|
if (!blockType) {
|
@@ -40,18 +42,65 @@ export async function getBlockInstanceContainerName(systemId: string, instanceId
|
|
40
42
|
return `kapeta-block-instance-${md5(normalizeKapetaUri(systemId) + instanceId)}`;
|
41
43
|
}
|
42
44
|
|
43
|
-
export function toPortInfo(port:
|
45
|
+
export function toPortInfo(port: LocalInstancePort) {
|
44
46
|
if (typeof port === 'number' || typeof port === 'string') {
|
45
47
|
return { port: parseInt(`${port}`), type: 'tcp' };
|
46
48
|
}
|
47
49
|
|
48
50
|
if (!port.type) {
|
49
|
-
port.type =
|
51
|
+
port.type = LocalInstancePortType.TCP;
|
50
52
|
}
|
51
53
|
|
52
54
|
return port;
|
53
55
|
}
|
54
56
|
|
57
|
+
export async function getOperatorInstancePorts(systemId: string, operatorId: string, local: LocalInstance) {
|
58
|
+
const localPorts = local.ports ?? {};
|
59
|
+
|
60
|
+
const promises = Object.entries(localPorts).map(async ([portType, value]) => {
|
61
|
+
const portInfo = toPortInfo(value);
|
62
|
+
const hostPort = await serviceManager.ensureServicePort(systemId, operatorId, portType);
|
63
|
+
return {
|
64
|
+
portType,
|
65
|
+
port: portInfo.port,
|
66
|
+
hostPort,
|
67
|
+
protocol: portInfo.type,
|
68
|
+
};
|
69
|
+
});
|
70
|
+
return await Promise.all(promises);
|
71
|
+
}
|
72
|
+
|
73
|
+
/**
|
74
|
+
* Gets the hostname where all services are available - including the cluster service.
|
75
|
+
*
|
76
|
+
* For docker this is the internal docker host - otherwise it's the local machine
|
77
|
+
* Assumed to be the same address as the cluster service outside docker.
|
78
|
+
*/
|
79
|
+
export function getRemoteHostForEnvironment(environment: EnvironmentType | undefined): string {
|
80
|
+
return environment === 'docker' ? DOCKER_HOST_INTERNAL : clusterService.getClusterServiceHost();
|
81
|
+
}
|
82
|
+
|
83
|
+
/**
|
84
|
+
* Get the bind address for the given environment.
|
85
|
+
*
|
86
|
+
* Outside of docker we bind to 127.0.0.1 - inside we bind to everything (0.0.0.0)
|
87
|
+
*/
|
88
|
+
export function getBindAddressForEnvironment(
|
89
|
+
environment: EnvironmentType | undefined,
|
90
|
+
preferredHost = '127.0.0.1'
|
91
|
+
): string {
|
92
|
+
return environment === 'docker' ? '0.0.0.0' : preferredHost;
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Get the docker host IP address for port binding.
|
97
|
+
*/
|
98
|
+
export function getDockerHostIp(preferredHost = '127.0.0.1') {
|
99
|
+
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
100
|
+
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
101
|
+
return isLinux() ? '0.0.0.0' : preferredHost;
|
102
|
+
}
|
103
|
+
|
55
104
|
export function getRemoteUrl(id: string, defautValue: string) {
|
56
105
|
const remoteConfig = ClusterConfiguration.getClusterConfig().remote;
|
57
106
|
return remoteConfig?.[id] ?? defautValue;
|
@@ -79,12 +128,6 @@ export function isLinux() {
|
|
79
128
|
return !isWindows() && !isMac();
|
80
129
|
}
|
81
130
|
|
82
|
-
export function getBindHost(preferredHost = '127.0.0.1') {
|
83
|
-
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
84
|
-
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
85
|
-
return isLinux() ? '0.0.0.0' : preferredHost;
|
86
|
-
}
|
87
|
-
|
88
131
|
export function getResolvedConfiguration(entities?: EntityList, config?: AnyMap, globalConfiguration?: AnyMap): AnyMap {
|
89
132
|
if (!entities || !globalConfiguration) {
|
90
133
|
return config || {};
|