@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.
Files changed (44) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/index.js +4 -1
  3. package/dist/cjs/src/config/routes.js +2 -2
  4. package/dist/cjs/src/containerManager.js +5 -3
  5. package/dist/cjs/src/instanceManager.d.ts +4 -2
  6. package/dist/cjs/src/instanceManager.js +60 -28
  7. package/dist/cjs/src/operatorManager.d.ts +4 -2
  8. package/dist/cjs/src/operatorManager.js +32 -23
  9. package/dist/cjs/src/serviceManager.d.ts +0 -1
  10. package/dist/cjs/src/serviceManager.js +2 -8
  11. package/dist/cjs/src/types.d.ts +1 -29
  12. package/dist/cjs/src/types.js +2 -1
  13. package/dist/cjs/src/utils/BlockInstanceRunner.js +30 -30
  14. package/dist/cjs/src/utils/InternalConfigProvider.d.ts +38 -0
  15. package/dist/cjs/src/utils/InternalConfigProvider.js +146 -0
  16. package/dist/cjs/src/utils/utils.d.ts +25 -3
  17. package/dist/cjs/src/utils/utils.js +46 -7
  18. package/dist/esm/index.js +4 -1
  19. package/dist/esm/src/config/routes.js +2 -2
  20. package/dist/esm/src/containerManager.js +5 -3
  21. package/dist/esm/src/instanceManager.d.ts +4 -2
  22. package/dist/esm/src/instanceManager.js +60 -28
  23. package/dist/esm/src/operatorManager.d.ts +4 -2
  24. package/dist/esm/src/operatorManager.js +32 -23
  25. package/dist/esm/src/serviceManager.d.ts +0 -1
  26. package/dist/esm/src/serviceManager.js +2 -8
  27. package/dist/esm/src/types.d.ts +1 -29
  28. package/dist/esm/src/types.js +2 -1
  29. package/dist/esm/src/utils/BlockInstanceRunner.js +30 -30
  30. package/dist/esm/src/utils/InternalConfigProvider.d.ts +38 -0
  31. package/dist/esm/src/utils/InternalConfigProvider.js +146 -0
  32. package/dist/esm/src/utils/utils.d.ts +25 -3
  33. package/dist/esm/src/utils/utils.js +46 -7
  34. package/index.ts +5 -2
  35. package/package.json +6 -6
  36. package/src/config/routes.ts +4 -2
  37. package/src/containerManager.ts +6 -4
  38. package/src/instanceManager.ts +74 -38
  39. package/src/operatorManager.ts +46 -37
  40. package/src/serviceManager.ts +3 -11
  41. package/src/types.ts +2 -31
  42. package/src/utils/BlockInstanceRunner.ts +48 -38
  43. package/src/utils/InternalConfigProvider.ts +214 -0
  44. 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
- const bindHost = (0, utils_1.getBindHost)(host);
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
- await container.remove({ force: !!opts?.force });
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 ['host.docker.internal:host-gateway'];
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 ['host.docker.internal:172.17.0.1'];
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, OperatorInstanceInfo } from './types';
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<OperatorInstanceInfo>;
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?.definition.spec.local) {
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
- let instance = await this.start(systemId, instanceId);
287
- if (instance instanceof taskManager_1.Task) {
288
- instance = await instance.wait();
289
- }
290
- const container = await containerManager_1.containerManager.get(instance.pid);
291
- if (!container) {
292
- throw new Error(`Container not found: ${instance.pid}`);
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
- const portInfo = await container.getPorts();
295
- if (!portInfo) {
296
- throw new Error(`No ports found for instance: ${instanceId}`);
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 = serviceManager_1.serviceManager.getLocalHost(environment);
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
- await container.stop();
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?.pid) {
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 instanceConfig = await configManager_1.configManager.getConfigForSection(systemId, instanceId);
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
- return types_1.InstanceStatus.FAILED;
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.ExitCode === 0) {
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 { EnvironmentType, OperatorInfo } from './types';
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<OperatorInfo>;
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
- const container = await this.ensureOperator(systemId, resourceType, kindUri.version);
100
- const portInfo = await container.getPort(portType);
101
- if (!portInfo) {
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: environment === 'docker' ? 'host.docker.internal' : '127.0.0.1',
108
- port: portInfo.hostPort,
109
+ host: (0, utils_1.getRemoteHostForEnvironment)(environment),
110
+ port: hostPort,
109
111
  type: portType,
110
- protocol: portInfo.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 portTypes = Object.keys(operatorData.ports);
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 bindHost = (0, utils_1.getBindHost)();
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: bindHost,
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 = this.getLocalHost(environmentType);
39
+ const hostname = (0, utils_1.getRemoteHostForEnvironment)(environmentType);
46
40
  if (path.startsWith('/')) {
47
41
  path = path.substring(1);
48
42
  }
@@ -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;
@@ -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=host.docker.internal`,
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, env);
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, env, assetVersion);
124
+ processInfo = await this._startLocalProcess(blockInstance, blockUri, envVars, assetVersion);
126
125
  }
127
126
  else {
128
- processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion);
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 = containerManager_1.containerManager.toDockerMounts({
197
- [workingDir]: (0, containerManager_1.toLocalBindVolume)(realLocalPath),
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 bindHost = (0, utils_1.getBindHost)();
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 localPorts = local.ports ?? {};
322
+ const instancePorts = await (0, utils_1.getOperatorInstancePorts)(this._systemId, operatorId, local);
320
323
  const labels = {};
321
- const promises = Object.entries(localPorts).map(async ([portType, value]) => {
322
- const portInfo = (0, utils_1.toPortInfo)(value);
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: bindHost,
330
- HostPort: `${publicPort}`,
330
+ HostIp: hostIp,
331
+ HostPort: `${portInfo.hostPort}`,
331
332
  },
332
333
  ];
333
- labels[containerManager_1.CONTAINER_LABEL_PORT_PREFIX + publicPort] = portType;
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 bindHost = (0, utils_1.getBindHost)();
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: bindHost,
413
+ HostIp: hostIp,
414
414
  HostPort: `${publicPort}`,
415
415
  },
416
416
  ];