@kapeta/local-cluster-service 0.8.2 → 0.9.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/definitions.d.ts +1 -1
  3. package/dist/cjs/index.js +3 -3
  4. package/dist/cjs/src/assetManager.js +7 -4
  5. package/dist/cjs/src/attachments/routes.js +4 -4
  6. package/dist/cjs/src/clusterService.js +2 -0
  7. package/dist/cjs/src/codeGeneratorManager.js +3 -3
  8. package/dist/cjs/src/config/routes.js +1 -1
  9. package/dist/cjs/src/configManager.js +13 -1
  10. package/dist/cjs/src/containerManager.d.ts +22 -2
  11. package/dist/cjs/src/containerManager.js +42 -15
  12. package/dist/cjs/src/definitionsManager.d.ts +11 -0
  13. package/dist/cjs/src/definitionsManager.js +44 -0
  14. package/dist/cjs/src/filesystemManager.js +0 -2
  15. package/dist/cjs/src/instanceManager.d.ts +23 -47
  16. package/dist/cjs/src/instanceManager.js +416 -235
  17. package/dist/cjs/src/instances/routes.js +23 -14
  18. package/dist/cjs/src/middleware/kapeta.js +7 -0
  19. package/dist/cjs/src/networkManager.js +6 -0
  20. package/dist/cjs/src/operatorManager.js +8 -4
  21. package/dist/cjs/src/providerManager.js +3 -3
  22. package/dist/cjs/src/repositoryManager.js +7 -3
  23. package/dist/cjs/src/serviceManager.js +5 -0
  24. package/dist/cjs/src/types.d.ts +39 -13
  25. package/dist/cjs/src/types.js +28 -0
  26. package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +3 -3
  27. package/dist/cjs/src/utils/BlockInstanceRunner.js +28 -29
  28. package/dist/cjs/src/utils/utils.d.ts +2 -0
  29. package/dist/cjs/src/utils/utils.js +18 -2
  30. package/dist/esm/index.js +4 -4
  31. package/dist/esm/src/assetManager.js +7 -4
  32. package/dist/esm/src/attachments/routes.js +5 -5
  33. package/dist/esm/src/clusterService.js +2 -0
  34. package/dist/esm/src/codeGeneratorManager.js +3 -3
  35. package/dist/esm/src/config/routes.js +1 -1
  36. package/dist/esm/src/configManager.js +13 -1
  37. package/dist/esm/src/containerManager.d.ts +22 -2
  38. package/dist/esm/src/containerManager.js +41 -14
  39. package/dist/esm/src/definitionsManager.d.ts +11 -0
  40. package/dist/esm/src/definitionsManager.js +38 -0
  41. package/dist/esm/src/filesystemManager.js +0 -2
  42. package/dist/esm/src/instanceManager.d.ts +23 -47
  43. package/dist/esm/src/instanceManager.js +416 -236
  44. package/dist/esm/src/instances/routes.js +23 -14
  45. package/dist/esm/src/middleware/kapeta.js +7 -0
  46. package/dist/esm/src/networkManager.js +6 -0
  47. package/dist/esm/src/operatorManager.js +8 -4
  48. package/dist/esm/src/providerManager.js +3 -3
  49. package/dist/esm/src/repositoryManager.js +7 -3
  50. package/dist/esm/src/serviceManager.js +5 -0
  51. package/dist/esm/src/types.d.ts +39 -13
  52. package/dist/esm/src/types.js +27 -1
  53. package/dist/esm/src/utils/BlockInstanceRunner.d.ts +3 -3
  54. package/dist/esm/src/utils/BlockInstanceRunner.js +29 -30
  55. package/dist/esm/src/utils/utils.d.ts +2 -0
  56. package/dist/esm/src/utils/utils.js +15 -1
  57. package/index.ts +10 -8
  58. package/package.json +2 -1
  59. package/src/assetManager.ts +7 -4
  60. package/src/attachments/routes.ts +8 -8
  61. package/src/clusterService.ts +3 -0
  62. package/src/codeGeneratorManager.ts +3 -2
  63. package/src/config/routes.ts +1 -1
  64. package/src/configManager.ts +13 -1
  65. package/src/containerManager.ts +63 -16
  66. package/src/definitionsManager.ts +54 -0
  67. package/src/filesystemManager.ts +0 -2
  68. package/src/identities/routes.ts +2 -3
  69. package/src/instanceManager.ts +495 -266
  70. package/src/instances/routes.ts +23 -17
  71. package/src/middleware/kapeta.ts +10 -0
  72. package/src/networkManager.ts +6 -0
  73. package/src/operatorManager.ts +11 -6
  74. package/src/providerManager.ts +3 -2
  75. package/src/repositoryManager.ts +14 -10
  76. package/src/serviceManager.ts +6 -0
  77. package/src/storageService.ts +1 -1
  78. package/src/types.ts +44 -14
  79. package/src/utils/BlockInstanceRunner.ts +34 -34
  80. package/src/utils/utils.ts +20 -2
@@ -5,7 +5,7 @@ import { corsHandler } from '../middleware/cors';
5
5
  import { NextFunction, Request, Response } from 'express';
6
6
  import { kapetaHeaders, KapetaRequest } from '../middleware/kapeta';
7
7
  import { stringBody } from '../middleware/stringBody';
8
- import { EnvironmentType, KapetaBodyRequest } from '../types';
8
+ import { DesiredInstanceStatus, InstanceInfo, InstanceOwner, InstanceType, KapetaBodyRequest } from '../types';
9
9
 
10
10
  const router = Router();
11
11
  router.use('/', corsHandler);
@@ -28,11 +28,11 @@ router.get('/:systemId/instances', (req: Request, res: Response) => {
28
28
  * Start all instances in a plan
29
29
  */
30
30
  router.post('/:systemId/start', async (req: Request, res: Response) => {
31
- const processes = await instanceManager.createProcessesForPlan(req.params.systemId);
31
+ const instances = await instanceManager.startAllForPlan(req.params.systemId);
32
32
 
33
33
  res.status(202).send({
34
34
  ok: true,
35
- processes: processes.map((p) => {
35
+ processes: instances.map((p) => {
36
36
  return { pid: p.pid, type: p.type };
37
37
  }),
38
38
  });
@@ -53,7 +53,7 @@ router.post('/:systemId/stop', async (req: Request, res: Response) => {
53
53
  * Start single instance in a plan
54
54
  */
55
55
  router.post('/:systemId/:instanceId/start', async (req: Request, res: Response) => {
56
- const process = await instanceManager.createProcess(req.params.systemId, req.params.instanceId);
56
+ const process = await instanceManager.start(req.params.systemId, req.params.instanceId);
57
57
 
58
58
  res.status(202).send({
59
59
  ok: true,
@@ -66,7 +66,7 @@ router.post('/:systemId/:instanceId/start', async (req: Request, res: Response)
66
66
  * Stop single instance in a plan
67
67
  */
68
68
  router.post('/:systemId/:instanceId/stop', async (req: Request, res: Response) => {
69
- await instanceManager.stopProcess(req.params.systemId, req.params.instanceId);
69
+ await instanceManager.stop(req.params.systemId, req.params.instanceId);
70
70
 
71
71
  res.status(202).send({ ok: true });
72
72
  });
@@ -75,14 +75,14 @@ router.post('/:systemId/:instanceId/stop', async (req: Request, res: Response) =
75
75
  * Get logs for instance in a plan
76
76
  */
77
77
  router.get('/:systemId/:instanceId/logs', (req: Request, res: Response) => {
78
- const processInfo = instanceManager.getProcessForInstance(req.params.systemId, req.params.instanceId);
79
- if (!processInfo) {
78
+ const instanceInfo = instanceManager.getInstance(req.params.systemId, req.params.instanceId);
79
+ if (!instanceInfo) {
80
80
  res.status(404).send({ ok: false });
81
81
  return;
82
82
  }
83
83
 
84
84
  res.status(202).send({
85
- logs: processInfo.logs(),
85
+ logs: instanceInfo.internal?.logs() ?? [],
86
86
  });
87
87
  });
88
88
 
@@ -132,31 +132,37 @@ router.use('/', (req: KapetaBodyRequest, res: Response, next: NextFunction) => {
132
132
  });
133
133
 
134
134
  /**
135
- * Updates the full configuration for a given service.
135
+ * Updates the full configuration for a given instance.
136
136
  */
137
137
  router.put('/', async (req: KapetaBodyRequest, res: Response) => {
138
- let instance = req.stringBody ? JSON.parse(req.stringBody) : null;
138
+ let instance: InstanceInfo = req.stringBody ? JSON.parse(req.stringBody) : null;
139
139
  if (req.kapeta!.environment === 'docker') {
140
140
  //A bit hacky but we want to avoid overwriting the docker PID with a process PID
141
141
  const oldInstance = instanceManager.getInstance(req.kapeta!.systemId, req.kapeta!.instanceId);
142
142
  if (oldInstance) {
143
143
  instance.pid = oldInstance.pid;
144
144
  }
145
- instance.type = 'docker';
146
- } else if (req.kapeta!.environment === 'process') {
147
- instance.type = 'process';
145
+ instance.type = InstanceType.DOCKER;
146
+ } else {
147
+ // Coming from user starting the instance outside of kapeta
148
+ instance.type = InstanceType.LOCAL;
149
+ instance.owner = InstanceOwner.EXTERNAL;
150
+ instance.desiredStatus = DesiredInstanceStatus.EXTERNAL;
148
151
  }
149
152
 
150
- await instanceManager.registerInstance(req.kapeta!.systemId, req.kapeta!.instanceId, instance);
151
-
152
- res.status(202).send({ ok: true });
153
+ try {
154
+ await instanceManager.registerInstanceFromSDK(req.kapeta!.systemId, req.kapeta!.instanceId, instance);
155
+ res.status(202).send({ ok: true });
156
+ } catch (e: any) {
157
+ res.status(400).send({ error: e.message });
158
+ }
153
159
  });
154
160
 
155
161
  /**
156
162
  * Delete instance
157
163
  */
158
164
  router.delete('/', async (req: KapetaRequest, res: Response) => {
159
- await instanceManager.setInstanceAsStopped(req.kapeta!.systemId, req.kapeta!.instanceId);
165
+ await instanceManager.markAsStopped(req.kapeta!.systemId, req.kapeta!.instanceId);
160
166
 
161
167
  res.status(202).send({ ok: true });
162
168
  });
@@ -1,5 +1,7 @@
1
1
  import { NextFunction, Request, Response } from 'express';
2
2
  import { EnvironmentType } from '../types';
3
+ import { parseKapetaUri } from '@kapeta/nodejs-utils';
4
+ import { normalizeKapetaUri } from '../utils/utils';
3
5
 
4
6
  export interface KapetaRequest extends Request {
5
7
  kapeta?: {
@@ -16,6 +18,14 @@ export function kapetaHeaders(req: KapetaRequest, res: Response, next: NextFunct
16
18
  let instanceId: string = req.headers['x-kapeta-instance'] as string;
17
19
  let environment: string = req.headers['x-kapeta-environment'] as string;
18
20
 
21
+ if (blockRef) {
22
+ blockRef = normalizeKapetaUri(blockRef);
23
+ }
24
+
25
+ if (systemId) {
26
+ systemId = normalizeKapetaUri(systemId);
27
+ }
28
+
19
29
  req.kapeta = {
20
30
  blockRef,
21
31
  instanceId,
@@ -1,6 +1,7 @@
1
1
  import uuid from 'node-uuid';
2
2
  import { Connection, SimpleRequest, SimpleResponse } from './types';
3
3
  import express from 'express';
4
+ import { normalizeKapetaUri } from './utils/utils';
4
5
 
5
6
  class NetworkManager {
6
7
  private _connections: { [systemId: string]: { [connectionId: string]: Traffic[] } };
@@ -23,6 +24,7 @@ class NetworkManager {
23
24
  }
24
25
 
25
26
  _ensureSystem(systemId: string) {
27
+ systemId = normalizeKapetaUri(systemId);
26
28
  if (!this._connections[systemId]) {
27
29
  this._connections[systemId] = {};
28
30
  }
@@ -37,6 +39,7 @@ class NetworkManager {
37
39
  }
38
40
 
39
41
  _ensureConnection(systemId: string, connectionId: string) {
42
+ systemId = normalizeKapetaUri(systemId);
40
43
  this._ensureSystem(systemId);
41
44
 
42
45
  if (!this._connections[systemId][connectionId]) {
@@ -47,6 +50,7 @@ class NetworkManager {
47
50
  }
48
51
 
49
52
  _ensureSource(systemId: string, sourceBlockInstanceId: string) {
53
+ systemId = normalizeKapetaUri(systemId);
50
54
  this._ensureSystem(systemId);
51
55
 
52
56
  if (!this._sources[systemId][sourceBlockInstanceId]) {
@@ -57,6 +61,7 @@ class NetworkManager {
57
61
  }
58
62
 
59
63
  _ensureTarget(systemId: string, targetBlockInstanceId: string) {
64
+ systemId = normalizeKapetaUri(systemId);
60
65
  this._ensureSystem(systemId);
61
66
 
62
67
  if (!this._targets[systemId][targetBlockInstanceId]) {
@@ -73,6 +78,7 @@ class NetworkManager {
73
78
  consumerMethodId?: string,
74
79
  providerMethodId?: string
75
80
  ) {
81
+ systemId = normalizeKapetaUri(systemId);
76
82
  const traffic = new Traffic(connection, request, consumerMethodId, providerMethodId);
77
83
 
78
84
  this._ensureConnection(systemId, traffic.connectionId).push(traffic);
@@ -8,6 +8,8 @@ import { ContainerInfo, containerManager } from './containerManager';
8
8
  import FSExtra from 'fs-extra';
9
9
  import { AnyMap, EnvironmentType, OperatorInfo } from './types';
10
10
  import { BlockInstance, Resource } from '@kapeta/schemas';
11
+ import { definitionsManager } from './definitionsManager';
12
+ import { normalizeKapetaUri } from './utils/utils';
11
13
 
12
14
  const KIND_OPERATOR = 'core/resource-type-operator';
13
15
 
@@ -47,7 +49,7 @@ class OperatorManager {
47
49
  * @return {Operator}
48
50
  */
49
51
  getOperator(resourceType: string, version: string) {
50
- const operators = ClusterConfiguration.getDefinitions(KIND_OPERATOR);
52
+ const operators = definitionsManager.getDefinitions(KIND_OPERATOR);
51
53
 
52
54
  const operator: DefinitionInfo | undefined = operators.find(
53
55
  (operator) =>
@@ -80,7 +82,8 @@ class OperatorManager {
80
82
  name: string,
81
83
  environment?: EnvironmentType
82
84
  ): Promise<OperatorInfo> {
83
- const plans = ClusterConfiguration.getDefinitions('core/plan');
85
+ systemId = normalizeKapetaUri(systemId);
86
+ const plans = definitionsManager.getDefinitions('core/plan');
84
87
 
85
88
  const planUri = parseKapetaUri(systemId);
86
89
  const currentPlan = plans.find(
@@ -98,10 +101,12 @@ class OperatorManager {
98
101
  }
99
102
 
100
103
  const blockUri = parseKapetaUri(currentInstance.block.ref);
101
- const blockDefinition = ClusterConfiguration.getDefinitions().find(
102
- (definition) =>
103
- definition.version === blockUri.version && definition.definition.metadata.name === blockUri.fullName
104
- );
104
+ const blockDefinition = definitionsManager
105
+ .getDefinitions()
106
+ .find(
107
+ (definition) =>
108
+ definition.version === blockUri.version && definition.definition.metadata.name === blockUri.fullName
109
+ );
105
110
 
106
111
  if (!blockDefinition) {
107
112
  throw new Error(`Unknown block: ${currentInstance.block.ref} in plan ${systemId}`);
@@ -3,6 +3,7 @@ import FSExtra from 'fs-extra';
3
3
  import { repositoryManager } from './repositoryManager';
4
4
  import ClusterConfiguration from '@kapeta/local-cluster-config';
5
5
  import { StringMap } from './types';
6
+ import { definitionsManager } from './definitionsManager';
6
7
 
7
8
  class ProviderManager {
8
9
  private _webAssetCache: StringMap;
@@ -11,7 +12,7 @@ class ProviderManager {
11
12
  }
12
13
 
13
14
  getWebProviders() {
14
- return ClusterConfiguration.getProviderDefinitions().filter((providerDefinition) => providerDefinition.hasWeb);
15
+ return definitionsManager.getProviderDefinitions().filter((providerDefinition) => providerDefinition.hasWeb);
15
16
  }
16
17
 
17
18
  async getAsset(handle: string, name: string, version: string, sourceMap: boolean = false) {
@@ -42,7 +43,7 @@ class ProviderManager {
42
43
  }
43
44
  }
44
45
 
45
- const providerDefinitions = ClusterConfiguration.getProviderDefinitions();
46
+ const providerDefinitions = definitionsManager.getProviderDefinitions();
46
47
 
47
48
  if (providerDefinitions.length > 0) {
48
49
  console.log('## Loaded the following providers ##');
@@ -9,6 +9,7 @@ import { socketManager } from './socketManager';
9
9
  import { progressListener } from './progressListener';
10
10
  import { Dependency } from '@kapeta/schemas';
11
11
  import { Actions, Config, RegistryService } from '@kapeta/nodejs-registry-utils';
12
+ import { definitionsManager } from './definitionsManager';
12
13
 
13
14
  const INSTALL_ATTEMPTED: { [p: string]: boolean } = {};
14
15
 
@@ -41,23 +42,23 @@ class RepositoryManager {
41
42
 
42
43
  console.log('Watching local repository for provider changes: %s', baseDir);
43
44
  try {
44
- this.watcher = watch(baseDir, (filename:string) => {
45
+ this.watcher = watch(baseDir, (filename: string) => {
45
46
  if (!filename) {
46
47
  return;
47
48
  }
48
-
49
+
49
50
  const [handle, name, version] = filename.toString().split(/\//g);
50
51
  if (!name || !version) {
51
52
  return;
52
53
  }
53
-
54
+
54
55
  if (!this.changeEventsEnabled) {
55
56
  return;
56
57
  }
57
-
58
+
58
59
  const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
59
60
  const newDefinitions = ClusterConfiguration.getDefinitions();
60
-
61
+
61
62
  const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
62
63
  let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
63
64
  const ymlExists = FS.existsSync(ymlPath);
@@ -85,15 +86,16 @@ class RepositoryManager {
85
86
  return;
86
87
  }
87
88
  }
88
-
89
+
89
90
  const payload = {
90
91
  type,
91
92
  definition: currentDefinition?.definition,
92
93
  asset: { handle, name, version },
93
94
  };
94
-
95
+
95
96
  allDefinitions = newDefinitions;
96
97
  socketManager.emit(`assets`, 'changed', payload);
98
+ definitionsManager.clearCache();
97
99
  });
98
100
  } catch (e) {
99
101
  // Fallback to run without watch mode due to potential platform issues.
@@ -186,7 +188,7 @@ class RepositoryManager {
186
188
  return;
187
189
  }
188
190
 
189
- const definitions = ClusterConfiguration.getDefinitions();
191
+ const definitions = definitionsManager.getDefinitions();
190
192
  const installedAsset = definitions.find(
191
193
  (d) => d.definition.metadata.name === fullName && d.version === version
192
194
  );
@@ -221,8 +223,10 @@ class RepositoryManager {
221
223
  } else {
222
224
  //Ensure dependencies are installed
223
225
  const refs = assetVersion.dependencies.map((dep: Dependency) => dep.name);
224
- console.log(`Auto-installing dependencies: ${refs.join(', ')}`);
225
- await this._install(refs);
226
+ if (refs.length > 0) {
227
+ console.log(`Auto-installing dependencies: ${refs.join(', ')}`);
228
+ await this._install(refs);
229
+ }
226
230
  }
227
231
  }
228
232
  }
@@ -2,6 +2,7 @@ import _ from 'lodash';
2
2
  import { clusterService } from './clusterService';
3
3
  import { storageService } from './storageService';
4
4
  import { EnvironmentType } from './types';
5
+ import { normalizeKapetaUri } from './utils/utils';
5
6
 
6
7
  const DEFAULT_PORT_TYPE = 'rest';
7
8
 
@@ -42,6 +43,8 @@ class ServiceManager {
42
43
  }
43
44
 
44
45
  _ensureSystem(systemId: string) {
46
+ systemId = normalizeKapetaUri(systemId);
47
+
45
48
  if (!this._systems[systemId]) {
46
49
  this._systems[systemId] = {};
47
50
  }
@@ -60,6 +63,7 @@ class ServiceManager {
60
63
  }
61
64
 
62
65
  async ensureServicePort(systemId: string, blockInstanceId: string, portType: string = DEFAULT_PORT_TYPE) {
66
+ systemId = normalizeKapetaUri(systemId);
63
67
  if (!portType) {
64
68
  portType = DEFAULT_PORT_TYPE;
65
69
  }
@@ -94,6 +98,7 @@ class ServiceManager {
94
98
  portType: string,
95
99
  environmentType?: EnvironmentType
96
100
  ): string {
101
+ systemId = normalizeKapetaUri(systemId);
97
102
  const port = clusterService.getClusterServicePort();
98
103
  const path = clusterService.getProxyPath(systemId, consumerInstanceId, consumerResourceName, portType);
99
104
  return this._forLocal(port, path, environmentType);
@@ -108,6 +113,7 @@ class ServiceManager {
108
113
  *
109
114
  */
110
115
  async getProviderAddress(systemId: string, providerInstanceId: string, portType: string): Promise<string> {
116
+ systemId = normalizeKapetaUri(systemId);
111
117
  const port = await this.ensureServicePort(systemId, providerInstanceId, portType);
112
118
  return this._forLocal(port);
113
119
  }
@@ -53,7 +53,7 @@ class StorageService {
53
53
  this._writeConfig();
54
54
  }
55
55
 
56
- get<T = any>(section: string, property?: string, defaultValue?:T): T|undefined {
56
+ get<T = any>(section: string, property?: string, defaultValue?: T): T | undefined {
57
57
  if (!property) {
58
58
  return this.section(section);
59
59
  }
package/src/types.ts CHANGED
@@ -10,6 +10,7 @@ export type AnyMap = { [key: string]: any };
10
10
  export type LogLevel = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'TRACE' | 'FATAL';
11
11
  export type LogSource = 'stdout' | 'stderr';
12
12
  export type EnvironmentType = 'docker' | 'process';
13
+
13
14
  export interface LogEntry {
14
15
  source: LogSource;
15
16
  level: LogLevel;
@@ -23,32 +24,61 @@ export interface BlockProcessParams {
23
24
  configuration?: AnyMap;
24
25
  }
25
26
 
26
- export type ProcessType = 'docker' | 'local';
27
+ export enum InstanceType {
28
+ DOCKER = 'docker',
29
+ LOCAL = 'local',
30
+ UNKNOWN = 'unknown',
31
+ }
32
+ export enum InstanceOwner {
33
+ INTERNAL = 'internal',
34
+ EXTERNAL = 'external',
35
+ }
27
36
 
28
- export interface ProcessDetails {
29
- pid: number | string;
30
- type: ProcessType;
31
- portType?: string;
32
- output: EventEmitter;
33
- logs: () => LogEntry[];
34
- stop: () => Promise<void> | void;
37
+ export enum InstanceStatus {
38
+ STOPPED = 'stopped',
39
+ STARTING = 'starting',
40
+ BUSY = 'busy',
41
+ READY = 'ready',
42
+ STOPPING = 'stopping',
43
+ UNHEALTHY = 'unhealthy',
44
+ FAILED = 'failed',
35
45
  }
36
46
 
37
- export interface ProcessInfo extends ProcessDetails {
38
- id: string;
39
- ref: string;
40
- name: string;
47
+ export enum DesiredInstanceStatus {
48
+ STOP = 'stop',
49
+ RUN = 'run',
50
+ EXTERNAL = 'external',
41
51
  }
42
52
 
53
+ export type ProcessInfo = {
54
+ type: InstanceType;
55
+ pid?: number | string | null;
56
+ output: EventEmitter;
57
+ portType?: string;
58
+ logs: () => LogEntry[];
59
+ stop: () => Promise<void> | void;
60
+ };
61
+
43
62
  export type InstanceInfo = {
44
63
  systemId: string;
45
64
  instanceId: string;
65
+ ref: string;
66
+ name: string;
67
+ type: InstanceType;
68
+ owner: InstanceOwner;
69
+ status: InstanceStatus;
70
+ desiredStatus: DesiredInstanceStatus;
46
71
  address?: string;
72
+
73
+ startedAt?: number;
47
74
  health?: string | null;
48
- status: string;
49
75
  pid?: number | string | null;
50
- type: ProcessType;
51
76
  portType?: string;
77
+
78
+ internal?: {
79
+ output: EventEmitter;
80
+ logs: () => LogEntry[];
81
+ };
52
82
  };
53
83
 
54
84
  interface ResourceRef {
@@ -1,15 +1,15 @@
1
1
  import FS from 'node:fs';
2
2
  import ClusterConfig, { DefinitionInfo } from '@kapeta/local-cluster-config';
3
- import { getBindHost, readYML } from './utils';
3
+ import { getBindHost, getBlockInstanceContainerName, normalizeKapetaUri, readYML } from './utils';
4
4
  import { KapetaURI, parseKapetaUri } from '@kapeta/nodejs-utils';
5
5
  import { serviceManager } from '../serviceManager';
6
6
  import { containerManager, DockerMounts, toLocalBindVolume } from '../containerManager';
7
7
  import { LogData } from './LogData';
8
8
  import EventEmitter from 'events';
9
- import md5 from 'md5';
10
9
  import { clusterService } from '../clusterService';
11
- import { AnyMap, BlockProcessParams, ProcessDetails, ProcessInfo, StringMap } from '../types';
10
+ import { AnyMap, BlockProcessParams, ProcessInfo, InstanceType, StringMap } from '../types';
12
11
  import { Container } from 'node-docker-api/lib/container';
12
+ import { definitionsManager } from '../definitionsManager';
13
13
 
14
14
  const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
15
15
  const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
@@ -27,7 +27,7 @@ const DOCKER_ENV_VARS = [
27
27
  ];
28
28
 
29
29
  function getProvider(uri: KapetaURI) {
30
- return ClusterConfig.getProviderDefinitions().find((provider) => {
30
+ return definitionsManager.getProviderDefinitions().find((provider) => {
31
31
  const ref = `${provider.definition.metadata.name}:${provider.version}`;
32
32
  return parseKapetaUri(ref).id === uri.id;
33
33
  });
@@ -46,13 +46,13 @@ function getProviderPorts(assetVersion: DefinitionInfo): string[] {
46
46
  export class BlockInstanceRunner {
47
47
  private readonly _systemId: string;
48
48
 
49
- constructor(planReference: string) {
49
+ constructor(systemId: string) {
50
50
  /**
51
51
  *
52
52
  * @type {string}
53
53
  * @private
54
54
  */
55
- this._systemId = planReference ?? '';
55
+ this._systemId = normalizeKapetaUri(systemId);
56
56
  }
57
57
 
58
58
  /**
@@ -88,7 +88,7 @@ export class BlockInstanceRunner {
88
88
  blockUri.version = 'local';
89
89
  }
90
90
 
91
- const assetVersion = ClusterConfig.getDefinitions().find((definitions) => {
91
+ const assetVersion = definitionsManager.getDefinitions().find((definitions) => {
92
92
  const ref = `${definitions.definition.metadata.name}:${definitions.version}`;
93
93
  return parseKapetaUri(ref).id === blockUri.id;
94
94
  });
@@ -105,30 +105,26 @@ export class BlockInstanceRunner {
105
105
  throw new Error(`Kind not found: ${kindUri.id}`);
106
106
  }
107
107
 
108
- let processDetails: ProcessDetails;
108
+ let processInfo: ProcessInfo;
109
109
 
110
110
  if (providerVersion.definition.kind === KIND_BLOCK_TYPE_OPERATOR) {
111
- processDetails = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
111
+ processInfo = await this._startOperatorProcess(blockInstance, blockUri, providerVersion, env);
112
112
  } else {
113
113
  //We need a port type to know how to connect to the block consistently
114
114
  const portTypes = getProviderPorts(assetVersion);
115
115
 
116
116
  if (blockUri.version === 'local') {
117
- processDetails = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
117
+ processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
118
118
  } else {
119
- processDetails = await this._startDockerProcess(blockInstance, blockUri, env);
119
+ processInfo = await this._startDockerProcess(blockInstance, blockUri, env);
120
120
  }
121
121
 
122
122
  if (portTypes.length > 0) {
123
- processDetails.portType = portTypes[0];
123
+ processInfo.portType = portTypes[0];
124
124
  }
125
125
  }
126
126
 
127
- return {
128
- name: blockUri.id,
129
- ...blockInstance,
130
- ...processDetails,
131
- };
127
+ return processInfo;
132
128
  }
133
129
 
134
130
  /**
@@ -139,7 +135,7 @@ export class BlockInstanceRunner {
139
135
  blockInfo: KapetaURI,
140
136
  env: StringMap,
141
137
  assetVersion: DefinitionInfo
142
- ): Promise<ProcessDetails> {
138
+ ): Promise<ProcessInfo> {
143
139
  const baseDir = ClusterConfig.getRepositoryAssetPath(blockInfo.handle, blockInfo.name, blockInfo.version);
144
140
 
145
141
  if (!FS.existsSync(baseDir)) {
@@ -172,14 +168,16 @@ export class BlockInstanceRunner {
172
168
  throw new Error(`Missing docker image information: ${JSON.stringify(localContainer)}`);
173
169
  }
174
170
 
175
- const containerName = `kapeta-block-instance-${blockInstance.id}`;
171
+ const containerName = getBlockInstanceContainerName(blockInstance.id);
176
172
  const logs = new LogData();
177
173
  logs.addLog(`Starting block ${blockInstance.ref}`);
178
- let container: Container | null = (await containerManager.getContainerByName(containerName)) ?? null;
174
+ const containerInfo = await containerManager.getContainerByName(containerName);
175
+ let container = containerInfo?.native;
176
+
179
177
  console.log('Starting dev container', containerName);
180
178
 
181
179
  if (container) {
182
- console.log(`Container already exists. Deleting...`);
180
+ console.log(`Dev container already exists. Deleting...`);
183
181
  try {
184
182
  await container.delete({
185
183
  force: true,
@@ -187,7 +185,7 @@ export class BlockInstanceRunner {
187
185
  } catch (e: any) {
188
186
  throw new Error('Failed to delete existing container: ' + e.message);
189
187
  }
190
- container = null;
188
+ container = undefined;
191
189
  }
192
190
 
193
191
  logs.addLog(`Creating new container for block: ${containerName}`);
@@ -216,7 +214,7 @@ export class BlockInstanceRunner {
216
214
 
217
215
  PortBindings[dockerPort] = [
218
216
  {
219
- HostIp: bindHost,
217
+ HostIp: bindHost,
220
218
  HostPort: `${publicPort}`,
221
219
  },
222
220
  ];
@@ -229,6 +227,7 @@ export class BlockInstanceRunner {
229
227
  HealthCheck = containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
230
228
  }
231
229
 
230
+ console.log('Starting dev container', containerName, dockerImage);
232
231
  container = await containerManager.startContainer({
233
232
  Image: dockerImage,
234
233
  name: containerName,
@@ -274,7 +273,7 @@ export class BlockInstanceRunner {
274
273
  container: Container,
275
274
  logs: LogData,
276
275
  deleteOnExit: boolean = false
277
- ): Promise<ProcessDetails> {
276
+ ): Promise<ProcessInfo> {
278
277
  let localContainer: Container | null = container;
279
278
  const logStream = (await container.logs({
280
279
  follow: true,
@@ -306,7 +305,7 @@ export class BlockInstanceRunner {
306
305
  });
307
306
 
308
307
  return {
309
- type: 'docker',
308
+ type: InstanceType.DOCKER,
310
309
  pid: container.id,
311
310
  output: outputEvents,
312
311
  stop: async () => {
@@ -350,9 +349,10 @@ export class BlockInstanceRunner {
350
349
  throw new Error(`Missing docker image information: ${JSON.stringify(versionInfo?.artifact?.details)}`);
351
350
  }
352
351
 
353
- const containerName = `kapeta-block-instance-${blockInstance.id}`;
352
+ const containerName = getBlockInstanceContainerName(blockInstance.id);
354
353
  const logs = new LogData();
355
- let container = await containerManager.getContainerByName(containerName);
354
+ const containerInfo = await containerManager.getContainerByName(containerName);
355
+ let container = containerInfo?.native;
356
356
 
357
357
  // For windows we need to default to root
358
358
  const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
@@ -380,9 +380,7 @@ export class BlockInstanceRunner {
380
380
  ...Object.entries(env).map(([key, value]) => `${key}=${value}`),
381
381
  ],
382
382
  HostConfig: {
383
- Binds: [
384
- `${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
385
- ],
383
+ Binds: [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`],
386
384
  },
387
385
  });
388
386
 
@@ -437,9 +435,11 @@ export class BlockInstanceRunner {
437
435
  console.warn('Failed to pull image. Continuing...', e);
438
436
  }
439
437
 
440
- const containerName = `kapeta-block-instance-${md5(blockInstance.id)}`;
438
+ const containerName = getBlockInstanceContainerName(blockInstance.id);
441
439
  const logs = new LogData();
442
- let container: Container | null = (await containerManager.getContainerByName(containerName)) ?? null;
440
+ const containerInfo = await containerManager.getContainerByName(containerName);
441
+ let container = containerInfo?.native;
442
+
443
443
  if (container) {
444
444
  const containerData = container.data as any;
445
445
  if (containerData.State === 'running') {
@@ -450,7 +450,7 @@ export class BlockInstanceRunner {
450
450
  try {
451
451
  await container.delete();
452
452
  } catch (e) {}
453
- container = null;
453
+ container = undefined;
454
454
  } else {
455
455
  logs.addLog(`Found existing container for block: ${containerName}. Starting now`);
456
456
  try {
@@ -460,7 +460,7 @@ export class BlockInstanceRunner {
460
460
  try {
461
461
  await container.delete();
462
462
  } catch (e) {}
463
- container = null;
463
+ container = undefined;
464
464
  }
465
465
  }
466
466
  }