@kapeta/local-cluster-service 0.0.76 → 0.1.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.
@@ -1,7 +1,7 @@
1
1
  const _ = require('lodash');
2
2
  const request = require('request');
3
-
4
- const {BlockInstanceRunner} = require('@kapeta/local-cluster-executor');
3
+ const EventEmitter = require("events");
4
+ const BlockInstanceRunner = require('./utils/BlockInstanceRunner');
5
5
 
6
6
  const storageService = require('./storageService');
7
7
  const socketManager = require('./socketManager');
@@ -68,6 +68,10 @@ class InstanceManager {
68
68
 
69
69
  if (instance.status !== newStatus) {
70
70
  instance.status = newStatus;
71
+ console.log(
72
+ 'Instance status changed: %s %s -> %s',
73
+ instance.systemId, instance.instanceId, instance.status
74
+ )
71
75
  this._emit(instance.systemId, EVENT_STATUS_CHANGED, instance);
72
76
  changed = true;
73
77
  }
@@ -85,7 +89,11 @@ class InstanceManager {
85
89
 
86
90
  if (instance.type === 'docker') {
87
91
  const container = await containerManager.get(instance.pid);
88
- return await container.isRunning()
92
+ if (!container) {
93
+ console.warn('Container not found: %s', instance.pid);
94
+ return false;
95
+ }
96
+ return await container.isRunning();
89
97
  }
90
98
 
91
99
  //Otherwise its just a normal process.
@@ -185,8 +193,12 @@ class InstanceManager {
185
193
  if (instance) {
186
194
  instance.status = STATUS_STARTING;
187
195
  instance.pid = info.pid;
188
- instance.type = info.type;
189
- instance.health = healthUrl;
196
+ if (info.type) {
197
+ instance.type = info.type;
198
+ }
199
+ if (healthUrl) {
200
+ instance.health = healthUrl;
201
+ }
190
202
  this._emit(systemId, EVENT_STATUS_CHANGED, instance);
191
203
  } else {
192
204
  instance = {
@@ -268,7 +280,9 @@ class InstanceManager {
268
280
  try {
269
281
  if (instance.type === 'docker') {
270
282
  const container = await containerManager.get(instance.pid);
271
- await container.stop();
283
+ if (container) {
284
+ await container.stop();
285
+ }
272
286
  return;
273
287
  }
274
288
  process.kill(instance.pid, 'SIGTERM');
@@ -383,7 +397,8 @@ class InstanceManager {
383
397
  message: e.message,
384
398
  time: Date.now()
385
399
  }
386
- ]
400
+ ];
401
+
387
402
  await this.registerInstance(planRef, instanceId, {
388
403
  type: 'local',
389
404
  pid: null,
@@ -401,7 +416,12 @@ class InstanceManager {
401
416
  return this._processes[planRef][instanceId] = {
402
417
  pid: -1,
403
418
  type,
404
- logs: () => logs
419
+ logs: () => logs,
420
+ stop: () => Promise.resolve(),
421
+ ref: blockRef,
422
+ id: instanceId,
423
+ name: blockInstance.name,
424
+ output: new EventEmitter()
405
425
  };
406
426
  }
407
427
 
@@ -427,7 +447,11 @@ class InstanceManager {
427
447
  }
428
448
 
429
449
  if (this._processes[planRef][instanceId]) {
430
- await this._processes[planRef][instanceId].stop();
450
+ try {
451
+ await this._processes[planRef][instanceId].stop();
452
+ } catch (e) {
453
+ console.error('Failed to stop process for instance: %s -> %s', planRef, instanceId, e);
454
+ }
431
455
  delete this._processes[planRef][instanceId];
432
456
  }
433
457
  }
@@ -100,6 +100,16 @@ router.put('/', async (req, res) => {
100
100
 
101
101
  let instance = JSON.parse(req.stringBody);
102
102
 
103
+ if (req.kapeta.environment === 'docker') {
104
+ //A bit hacky but we want to avoid overwriting the docker PID with a process PID
105
+ const oldInstance = instanceManager.getInstance(
106
+ req.kapeta.systemId,
107
+ req.kapeta.instanceId
108
+ );
109
+ if (oldInstance) {
110
+ instance.pid = oldInstance.pid;
111
+ }
112
+ }
103
113
  await instanceManager.registerInstance(
104
114
  req.kapeta.systemId,
105
115
  req.kapeta.instanceId,
@@ -3,10 +3,10 @@ class NetworkManager {
3
3
 
4
4
  static toConnectionId(connection) {
5
5
  return [
6
- connection.from.blockId,
7
- connection.from.resourceName,
8
- connection.to.blockId,
9
- connection.to.resourceName
6
+ connection.provider.blockId,
7
+ connection.provider.resourceName,
8
+ connection.consumer.blockId,
9
+ connection.consumer.resourceName
10
10
  ].join('_');
11
11
  }
12
12
 
@@ -65,8 +65,8 @@ class NetworkManager {
65
65
  const traffic = new Traffic(connection, request, consumerMethodId, providerMethodId);
66
66
 
67
67
  this._ensureConnection(systemId, traffic.connectionId).push(traffic);
68
- this._ensureSource(systemId, connection.from.blockId).push(traffic);
69
- this._ensureTarget(systemId, connection.to.blockId).push(traffic);
68
+ this._ensureSource(systemId, connection.provider.blockId).push(traffic);
69
+ this._ensureTarget(systemId, connection.consumer.blockId).push(traffic);
70
70
 
71
71
  return traffic;
72
72
  }
@@ -34,11 +34,12 @@ router.all('/:systemId/:consumerInstanceId/:consumerResourceName/:type/*', async
34
34
 
35
35
  const plan = await assetManager.getPlan(req.params.systemId);
36
36
 
37
+
37
38
  // We can find the connection by the consumer information alone since
38
39
  // only 1 provider can be connected to a consumer resource at a time
39
40
  const connection = _.find(plan.spec.connections, (connection) => {
40
- return connection.to.blockId.toLowerCase() === req.params.consumerInstanceId.toLowerCase() &&
41
- connection.to.resourceName.toLowerCase() === req.params.consumerResourceName.toLowerCase();
41
+ return connection.consumer.blockId.toLowerCase() === req.params.consumerInstanceId.toLowerCase() &&
42
+ connection.consumer.resourceName.toLowerCase() === req.params.consumerResourceName.toLowerCase();
42
43
  });
43
44
 
44
45
  if (!connection) {
@@ -47,7 +48,7 @@ router.all('/:systemId/:consumerInstanceId/:consumerResourceName/:type/*', async
47
48
  }
48
49
 
49
50
  const toBlockInstance = _.find(plan.spec.blocks, (blockInstance) => {
50
- return blockInstance.id.toLowerCase() === connection.to.blockId.toLowerCase();
51
+ return blockInstance.id.toLowerCase() === connection.consumer.blockId.toLowerCase();
51
52
  });
52
53
 
53
54
  if (!toBlockInstance) {
@@ -57,9 +58,9 @@ router.all('/:systemId/:consumerInstanceId/:consumerResourceName/:type/*', async
57
58
 
58
59
  const toBlockAsset = await assetManager.getAsset(toBlockInstance.block.ref);
59
60
 
60
- const toResource = getResource(toBlockAsset.data.spec.consumers, req.params.consumerResourceName);
61
+ const consumerResource = getResource(toBlockAsset.data.spec.consumers, req.params.consumerResourceName);
61
62
 
62
- if (!toResource) {
63
+ if (!consumerResource) {
63
64
  res.status(401).send({error:`Block resource not found "${req.params.consumerInstanceId}::${req.params.consumerResourceName}`});
64
65
  return;
65
66
  }
@@ -76,23 +77,23 @@ router.all('/:systemId/:consumerInstanceId/:consumerResourceName/:type/*', async
76
77
  Note that this might not match the path the destination is expecting so we need to identify the method
77
78
  that is being called and identify the destination path from the connection.
78
79
  */
79
- const consumerPath = req.originalUrl.substr(basePath.length - 1);
80
+ const consumerPath = req.originalUrl.substring(basePath.length - 1);
80
81
 
81
82
  const fromBlockInstance = _.find(plan.spec.blocks, (blockInstance) => {
82
- return blockInstance.id.toLowerCase() === connection.from.blockId.toLowerCase();
83
+ return blockInstance.id.toLowerCase() === connection.provider.blockId.toLowerCase();
83
84
  });
84
85
 
85
86
  if (!fromBlockInstance) {
86
- res.status(401).send({error:`Block instance not found "${connection.from.blockId}`});
87
+ res.status(401).send({error:`Block instance not found "${connection.provider.blockId}`});
87
88
  return;
88
89
  }
89
90
 
90
91
  const fromBlockAsset = await assetManager.getAsset(fromBlockInstance.block.ref);
91
92
 
92
- const fromResource = getResource(fromBlockAsset.data.spec.providers, connection.from.resourceName);
93
+ const providerResource = getResource(fromBlockAsset.data.spec.providers, connection.provider.resourceName);
93
94
 
94
- if (!fromResource) {
95
- res.status(401).send({error:`Block resource not found "${connection.from.blockId}::${connection.from.resourceName}`});
95
+ if (!providerResource) {
96
+ res.status(401).send({error:`Block resource not found "${connection.provider.blockId}::${connection.provider.resourceName}`});
96
97
  return;
97
98
  }
98
99
 
@@ -100,7 +101,7 @@ router.all('/:systemId/:consumerInstanceId/:consumerResourceName/:type/*', async
100
101
  //Get target address
101
102
  let address = await serviceManager.getProviderAddress(
102
103
  req.params.systemId,
103
- connection.from.blockId,
104
+ connection.provider.blockId,
104
105
  req.params.type
105
106
  );
106
107
 
@@ -111,12 +112,13 @@ router.all('/:systemId/:consumerInstanceId/:consumerResourceName/:type/*', async
111
112
  typeHandler(req, res, {
112
113
  consumerPath,
113
114
  address,
114
- toResource,
115
- fromResource,
115
+ consumerResource,
116
+ providerResource,
116
117
  connection
117
118
  });
118
119
 
119
120
  } catch(err) {
121
+ console.warn("Failed to process proxy request", err);
120
122
  res.status(400).send({error: err.message});
121
123
  }
122
124
 
@@ -35,7 +35,7 @@ function getRestMethodId(restResource, httpMethod, httpPath) {
35
35
  * @return {{consumerMethod: *, providerMethod: *}}
36
36
  */
37
37
  function resolveMethods(req, opts) {
38
- const consumerMethodId = getRestMethodId(opts.toResource, req.method, opts.consumerPath);
38
+ const consumerMethodId = getRestMethodId(opts.consumerResource, req.method, opts.consumerPath);
39
39
 
40
40
  if (!consumerMethodId) {
41
41
  throw new Error(
@@ -43,7 +43,7 @@ function resolveMethods(req, opts) {
43
43
  );
44
44
  }
45
45
 
46
- const consumerMethod = _.cloneDeep(opts.toResource.spec.methods[consumerMethodId]);
46
+ const consumerMethod = _.cloneDeep(opts.consumerResource.spec.methods[consumerMethodId]);
47
47
 
48
48
  if (!consumerMethod) {
49
49
  throw new Error(
@@ -61,11 +61,11 @@ function resolveMethods(req, opts) {
61
61
  throw new Error(`Connection contained no mapping for consumer method "${consumerMethodId}`);
62
62
  }
63
63
 
64
- const providerMethod = _.cloneDeep(opts.fromResource.spec.methods[providerMethodId]);
64
+ const providerMethod = _.cloneDeep(opts.providerResource.spec.methods[providerMethodId]);
65
65
 
66
66
  if (!providerMethod) {
67
67
  throw new Error(
68
- `Provider method not found "${providerMethodId}" in resource "${opts.connection.from.blockId}::${opts.connection.from.resourceName}`
68
+ `Provider method not found "${providerMethodId}" in resource "${opts.connection.provider.blockId}::${opts.connection.provider.resourceName}`
69
69
  );
70
70
  }
71
71
 
@@ -106,8 +106,7 @@ module.exports = function proxyRestRequest(req, res, opts) {
106
106
  delete requestHeaders['host'];
107
107
  delete requestHeaders['origin'];
108
108
 
109
-
110
- console.log('Route to provider: %s => %s', opts.consumerPath, opts.address + providerPath);
109
+ console.log('Proxy request to provider: %s => %s [rest]', opts.consumerPath, opts.address + providerPath);
111
110
 
112
111
  const reqOpts = {
113
112
  method: providerMethod.method || 'GET',
@@ -12,7 +12,7 @@ const socketManager = require('../../socketManager');
12
12
  */
13
13
  module.exports = function proxyRestRequest(req, res, opts) {
14
14
 
15
- console.log('Route to provider: %s => %s', opts.consumerPath, opts.address);
15
+ console.log('Proxy request to provider: %s => %s [web]', opts.consumerPath, opts.address);
16
16
 
17
17
  const requestHeaders = _.clone(req.headers);
18
18
 
@@ -22,8 +22,8 @@ module.exports = function proxyRestRequest(req, res, opts) {
22
22
  delete requestHeaders['host'];
23
23
  delete requestHeaders['origin'];
24
24
 
25
- const sourceBasePath = opts.fromResource.spec.path;
26
- const targetBasePath = opts.toResource.spec.path;
25
+ const sourceBasePath = opts.providerResource.spec.path;
26
+ const targetBasePath = opts.consumerResource.spec.path;
27
27
  let path = opts.consumerPath;
28
28
  if (opts.consumerPath.startsWith(sourceBasePath)) {
29
29
  path = path.replace(sourceBasePath, targetBasePath);
@@ -37,8 +37,6 @@ module.exports = function proxyRestRequest(req, res, opts) {
37
37
  body: req.stringBody
38
38
  };
39
39
 
40
- console.log('reqOpts', reqOpts);
41
-
42
40
  const traffic = networkManager.addRequest(
43
41
  req.params.systemId,
44
42
  opts.connection,
@@ -166,7 +166,8 @@ class RepositoryManager {
166
166
  return null;
167
167
  }
168
168
 
169
- const installedAsset = ClusterConfiguration.getDefinitions().find(d =>
169
+ const definitions = ClusterConfiguration.getDefinitions();
170
+ const installedAsset = definitions.find(d =>
170
171
  d.definition.metadata.name === fullName &&
171
172
  d.version === version);
172
173
 
@@ -179,18 +180,28 @@ class RepositoryManager {
179
180
  return;
180
181
  }
181
182
 
182
- const assetVersion = await this._registryService.getVersion(fullName, version);
183
- if (!assetVersion) {
184
- this._cache[ref] = false;
185
- return;
183
+ try {
184
+ const assetVersion = await this._registryService.getVersion(fullName, version);
185
+ if (!assetVersion) {
186
+ this._cache[ref] = false;
187
+ return;
188
+ }
189
+ } catch (e) {
190
+ console.warn(`Unable to resolve asset: ${ref}`, e);
191
+ if (installedAsset) {
192
+ return;
193
+ }
194
+ throw e;
186
195
  }
187
196
 
188
197
  this._cache[ref] = true;
189
198
  if (!installedAsset) {
199
+ console.log(`Auto-installing missing asset: ${ref}`);
190
200
  await this._install([ref]);
191
201
  } else {
192
202
  //Ensure dependencies are installed
193
203
  const refs = assetVersion.dependencies.map((dep) => dep.name);
204
+ console.log(`Auto-installing dependencies: ${refs.join(', ')}`);
194
205
  await this._install(refs);
195
206
  }
196
207
 
@@ -73,7 +73,6 @@ class ServiceManager {
73
73
 
74
74
  const portTypeSection = service[portType];
75
75
 
76
-
77
76
  return portTypeSection.port;
78
77
  }
79
78