@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
package/src/instanceManager.ts
CHANGED
@@ -28,17 +28,20 @@ import {
|
|
28
28
|
KIND_BLOCK_TYPE_EXECUTABLE,
|
29
29
|
KIND_BLOCK_TYPE_OPERATOR,
|
30
30
|
KIND_RESOURCE_OPERATOR,
|
31
|
-
LocalImageOptions,
|
32
31
|
LogEntry,
|
33
|
-
OperatorInstanceInfo,
|
34
|
-
OperatorInstancePort,
|
35
32
|
} from './types';
|
36
|
-
import { BlockDefinitionSpec,
|
37
|
-
import {
|
33
|
+
import { BlockDefinitionSpec, LocalInstance, Plan } from '@kapeta/schemas';
|
34
|
+
import {
|
35
|
+
getBlockInstanceContainerName,
|
36
|
+
getOperatorInstancePorts,
|
37
|
+
getRemoteHostForEnvironment,
|
38
|
+
getResolvedConfiguration,
|
39
|
+
} from './utils/utils';
|
38
40
|
import { operatorManager } from './operatorManager';
|
39
41
|
import { normalizeKapetaUri, parseKapetaUri } from '@kapeta/nodejs-utils';
|
40
42
|
import { definitionsManager } from './definitionsManager';
|
41
43
|
import { Task, taskManager } from './taskManager';
|
44
|
+
import { InstanceOperator, InstanceOperatorPort } from '@kapeta/sdk-config';
|
42
45
|
|
43
46
|
const CHECK_INTERVAL = 5000;
|
44
47
|
const DEFAULT_HEALTH_PORT_TYPE = 'http';
|
@@ -118,6 +121,10 @@ export class InstanceManager {
|
|
118
121
|
return result;
|
119
122
|
}
|
120
123
|
|
124
|
+
private isLocked(systemId: string, instanceId: string) {
|
125
|
+
return this.instanceLocks.isBusy(`${systemId}/${instanceId}`);
|
126
|
+
}
|
127
|
+
|
121
128
|
public async getLogs(systemId: string, instanceId: string): Promise<LogEntry[]> {
|
122
129
|
const instance = this.getInstance(systemId, instanceId);
|
123
130
|
if (!instance) {
|
@@ -293,7 +300,9 @@ export class InstanceManager {
|
|
293
300
|
systemId = normalizeKapetaUri(systemId);
|
294
301
|
const instance = _.find(this._instances, { systemId, instanceId });
|
295
302
|
if (instance && instance.owner === InstanceOwner.EXTERNAL && instance.status !== InstanceStatus.STOPPED) {
|
296
|
-
instance.status
|
303
|
+
if (instance.status != InstanceStatus.FAILED) {
|
304
|
+
instance.status = InstanceStatus.STOPPED;
|
305
|
+
}
|
297
306
|
instance.pid = null;
|
298
307
|
instance.health = null;
|
299
308
|
socketManager.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
@@ -367,8 +376,9 @@ export class InstanceManager {
|
|
367
376
|
public async getInstanceOperator(
|
368
377
|
systemId: string,
|
369
378
|
instanceId: string,
|
370
|
-
environment?: EnvironmentType
|
371
|
-
|
379
|
+
environment?: EnvironmentType,
|
380
|
+
ensureContainer: boolean = true
|
381
|
+
): Promise<InstanceOperator<any, any>> {
|
372
382
|
const blockInstance = await assetManager.getBlockInstance(systemId, instanceId);
|
373
383
|
if (!blockInstance) {
|
374
384
|
throw new Error(`Instance not found: ${systemId}/${instanceId}`);
|
@@ -381,36 +391,55 @@ export class InstanceManager {
|
|
381
391
|
|
382
392
|
const operatorDefinition = await definitionsManager.getDefinition(block.kind);
|
383
393
|
|
384
|
-
if (!operatorDefinition
|
385
|
-
throw new Error(`Operator
|
394
|
+
if (!operatorDefinition) {
|
395
|
+
throw new Error(`Operator not found: ${block.kind}`);
|
386
396
|
}
|
387
397
|
|
388
|
-
|
389
|
-
|
390
|
-
let instance = await this.start(systemId, instanceId);
|
391
|
-
if (instance instanceof Task) {
|
392
|
-
instance = await instance.wait();
|
398
|
+
if (operatorDefinition.definition.kind !== KIND_BLOCK_TYPE_OPERATOR) {
|
399
|
+
throw new Error(`Block is not an operator: ${blockRef}`);
|
393
400
|
}
|
394
401
|
|
395
|
-
|
396
|
-
|
397
|
-
throw new Error(`Container not found: ${instance.pid}`);
|
402
|
+
if (!operatorDefinition.definition.spec.local) {
|
403
|
+
throw new Error(`Operator block has no local definition: ${blockRef}`);
|
398
404
|
}
|
399
405
|
|
400
|
-
const
|
401
|
-
|
402
|
-
throw new Error(`No ports found for instance: ${instanceId}`);
|
403
|
-
}
|
406
|
+
const localConfig = operatorDefinition.definition.spec.local as LocalInstance;
|
407
|
+
const ports: { [key: string]: InstanceOperatorPort } = {};
|
404
408
|
|
405
|
-
|
406
|
-
|
409
|
+
if (ensureContainer) {
|
410
|
+
let instance = await this.start(systemId, instanceId);
|
411
|
+
if (instance instanceof Task) {
|
412
|
+
instance = await instance.wait();
|
413
|
+
}
|
407
414
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
415
|
+
const container = await containerManager.get(instance.pid as string);
|
416
|
+
if (!container) {
|
417
|
+
throw new Error(`Container not found: ${instance.pid}`);
|
418
|
+
}
|
419
|
+
|
420
|
+
const portInfo = await container.getPorts();
|
421
|
+
if (!portInfo) {
|
422
|
+
throw new Error(`No ports found for instance: ${instanceId}`);
|
423
|
+
}
|
424
|
+
|
425
|
+
Object.entries(portInfo).forEach(([key, value]) => {
|
426
|
+
ports[key] = {
|
427
|
+
protocol: value.protocol as 'udp' | 'tcp',
|
428
|
+
port: parseInt(value.hostPort),
|
429
|
+
};
|
430
|
+
});
|
431
|
+
} else {
|
432
|
+
// If we're not ensuring the container is running we just get the ports from the local config
|
433
|
+
const instancePorts = await getOperatorInstancePorts(systemId, instanceId, localConfig);
|
434
|
+
instancePorts.forEach((port) => {
|
435
|
+
ports[port.portType] = {
|
436
|
+
protocol: port.protocol as 'udp' | 'tcp',
|
437
|
+
port: port.hostPort,
|
438
|
+
};
|
439
|
+
});
|
440
|
+
}
|
441
|
+
|
442
|
+
const hostname = getRemoteHostForEnvironment(environment);
|
414
443
|
|
415
444
|
return {
|
416
445
|
hostname,
|
@@ -471,6 +500,8 @@ export class InstanceManager {
|
|
471
500
|
instance.desiredStatus = DesiredInstanceStatus.STOP;
|
472
501
|
}
|
473
502
|
|
503
|
+
const wasFailed = instance.status === InstanceStatus.FAILED;
|
504
|
+
|
474
505
|
instance.status = InstanceStatus.STOPPING;
|
475
506
|
|
476
507
|
socketManager.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
@@ -489,7 +520,11 @@ export class InstanceManager {
|
|
489
520
|
const container = await containerManager.getContainerByName(containerName);
|
490
521
|
if (container) {
|
491
522
|
try {
|
492
|
-
|
523
|
+
if (wasFailed) {
|
524
|
+
await container.remove();
|
525
|
+
} else {
|
526
|
+
await container.stop();
|
527
|
+
}
|
493
528
|
instance.status = InstanceStatus.STOPPED;
|
494
529
|
socketManager.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
495
530
|
this.save();
|
@@ -555,7 +590,7 @@ export class InstanceManager {
|
|
555
590
|
}
|
556
591
|
}
|
557
592
|
|
558
|
-
if (existingInstance
|
593
|
+
if (existingInstance && existingInstance.pid) {
|
559
594
|
if (existingInstance.status === InstanceStatus.READY) {
|
560
595
|
// Instance is already running
|
561
596
|
return existingInstance;
|
@@ -623,18 +658,15 @@ export class InstanceManager {
|
|
623
658
|
if (existingInstance) {
|
624
659
|
// Check if the instance is already running - but after we've commmuicated the desired status
|
625
660
|
const currentStatus = await this.requestInstanceStatus(existingInstance);
|
661
|
+
|
626
662
|
if (currentStatus === InstanceStatus.READY) {
|
627
663
|
// Instance is already running
|
628
664
|
return existingInstance;
|
629
665
|
}
|
630
666
|
}
|
631
667
|
|
632
|
-
const
|
633
|
-
|
634
|
-
blockSpec.configuration,
|
635
|
-
instanceConfig,
|
636
|
-
blockInstance.defaultConfiguration
|
637
|
-
);
|
668
|
+
const resolvedConfig = await configManager.getConfigForBlockInstance(systemId, instanceId);
|
669
|
+
|
638
670
|
const task = taskManager.add(
|
639
671
|
`instance:start:${systemId}:${instanceId}`,
|
640
672
|
async () => {
|
@@ -666,8 +698,7 @@ export class InstanceManager {
|
|
666
698
|
|
667
699
|
const out = await this.saveInternalInstance({
|
668
700
|
...instance,
|
669
|
-
type: InstanceType.
|
670
|
-
pid: null,
|
701
|
+
type: InstanceType.DOCKER,
|
671
702
|
health: null,
|
672
703
|
portType: DEFAULT_HEALTH_PORT_TYPE,
|
673
704
|
status: InstanceStatus.FAILED,
|
@@ -811,7 +842,6 @@ export class InstanceManager {
|
|
811
842
|
if (instance.status !== newStatus) {
|
812
843
|
const oldStatus = instance.status;
|
813
844
|
const skipUpdate =
|
814
|
-
(newStatus === InstanceStatus.STOPPED && instance.status === InstanceStatus.FAILED) ||
|
815
845
|
([InstanceStatus.READY, InstanceStatus.UNHEALTHY].includes(newStatus) &&
|
816
846
|
instance.status === InstanceStatus.STOPPING) ||
|
817
847
|
(newStatus === InstanceStatus.STOPPED &&
|
@@ -835,7 +865,7 @@ export class InstanceManager {
|
|
835
865
|
|
836
866
|
if (
|
837
867
|
instance.desiredStatus === DesiredInstanceStatus.RUN &&
|
838
|
-
[InstanceStatus.STOPPED, InstanceStatus.
|
868
|
+
[InstanceStatus.STOPPED, InstanceStatus.STOPPING].includes(newStatus)
|
839
869
|
) {
|
840
870
|
//If the instance is stopped but we want it to run, start it
|
841
871
|
try {
|
@@ -928,11 +958,23 @@ export class InstanceManager {
|
|
928
958
|
}
|
929
959
|
|
930
960
|
if (statusType === 'created') {
|
961
|
+
if (state.ExitCode !== undefined && state.ExitCode !== 0) {
|
962
|
+
// Failed during creation. Exit code is not always reliable though
|
963
|
+
if (state.Error) {
|
964
|
+
return InstanceStatus.FAILED;
|
965
|
+
} else {
|
966
|
+
return InstanceStatus.STOPPED;
|
967
|
+
}
|
968
|
+
}
|
931
969
|
return InstanceStatus.STARTING;
|
932
970
|
}
|
933
971
|
|
934
972
|
if (statusType === 'exited' || statusType === 'dead') {
|
935
|
-
|
973
|
+
if (!state.Error) {
|
974
|
+
// Exit code is not always reliable - if there is no error we assume it's stopped
|
975
|
+
return InstanceStatus.STOPPED;
|
976
|
+
}
|
977
|
+
return InstanceStatus.FAILED;
|
936
978
|
}
|
937
979
|
|
938
980
|
if (statusType === 'removing') {
|
@@ -1013,7 +1055,7 @@ export class InstanceManager {
|
|
1013
1055
|
}
|
1014
1056
|
|
1015
1057
|
if (parseKapetaUri(provider.kind).fullName === KIND_BLOCK_TYPE_OPERATOR) {
|
1016
|
-
const localConfig = provider.data.spec.local as
|
1058
|
+
const localConfig = provider.data.spec.local as LocalInstance;
|
1017
1059
|
return localConfig.singleton ?? false;
|
1018
1060
|
}
|
1019
1061
|
|
package/src/operatorManager.ts
CHANGED
@@ -16,22 +16,15 @@ import {
|
|
16
16
|
containerManager,
|
17
17
|
} from './containerManager';
|
18
18
|
import FSExtra from 'fs-extra';
|
19
|
-
import {
|
20
|
-
|
21
|
-
EnvironmentType,
|
22
|
-
KIND_BLOCK_TYPE_OPERATOR,
|
23
|
-
KIND_RESOURCE_OPERATOR,
|
24
|
-
LocalImageOptions,
|
25
|
-
OperatorInfo,
|
26
|
-
StringMap,
|
27
|
-
} from './types';
|
28
|
-
import { BlockInstance, Resource } from '@kapeta/schemas';
|
19
|
+
import { AnyMap, EnvironmentType, KIND_BLOCK_TYPE_OPERATOR, KIND_RESOURCE_OPERATOR, StringMap } from './types';
|
20
|
+
import { BlockInstance, LocalInstance, Resource } from '@kapeta/schemas';
|
29
21
|
import { definitionsManager } from './definitionsManager';
|
30
|
-
import {
|
22
|
+
import { getDockerHostIp, getRemoteHostForEnvironment, toPortInfo } from './utils/utils';
|
31
23
|
import { parseKapetaUri, normalizeKapetaUri } from '@kapeta/nodejs-utils';
|
32
24
|
import _ from 'lodash';
|
33
25
|
import AsyncLock from 'async-lock';
|
34
26
|
import { taskManager } from './taskManager';
|
27
|
+
import { ResourceInfo } from '@kapeta/sdk-config';
|
35
28
|
|
36
29
|
const KIND_PLAN = 'core/plan';
|
37
30
|
|
@@ -42,7 +35,7 @@ class Operator {
|
|
42
35
|
this._data = data;
|
43
36
|
}
|
44
37
|
|
45
|
-
getLocalData():
|
38
|
+
getLocalData(): LocalInstance {
|
46
39
|
return this._data.definition.spec.local;
|
47
40
|
}
|
48
41
|
|
@@ -105,8 +98,9 @@ class OperatorManager {
|
|
105
98
|
resourceType: string,
|
106
99
|
portType: string,
|
107
100
|
name: string,
|
108
|
-
environment?: EnvironmentType
|
109
|
-
|
101
|
+
environment?: EnvironmentType,
|
102
|
+
ensureContainer: boolean = true
|
103
|
+
): Promise<ResourceInfo<any, any>> {
|
110
104
|
systemId = normalizeKapetaUri(systemId);
|
111
105
|
const plans = await definitionsManager.getDefinitions(KIND_PLAN);
|
112
106
|
|
@@ -145,10 +139,13 @@ class OperatorManager {
|
|
145
139
|
const kindUri = parseKapetaUri(blockResource.kind);
|
146
140
|
const operator = await this.getOperator(resourceType, kindUri.version);
|
147
141
|
const credentials = operator.getCredentials();
|
148
|
-
|
149
|
-
|
142
|
+
if (ensureContainer) {
|
143
|
+
await this.ensureOperator(systemId, resourceType, kindUri.version);
|
144
|
+
}
|
145
|
+
|
146
|
+
const hostPort = await serviceManager.ensureServicePort(systemId, resourceType, portType);
|
150
147
|
|
151
|
-
if (!
|
148
|
+
if (!hostPort) {
|
152
149
|
throw new Error('Unknown resource port type : ' + resourceType + '#' + portType);
|
153
150
|
}
|
154
151
|
|
@@ -156,10 +153,10 @@ class OperatorManager {
|
|
156
153
|
const safeName = dbName.replace('_', '-');
|
157
154
|
|
158
155
|
return {
|
159
|
-
host: environment
|
160
|
-
port:
|
156
|
+
host: getRemoteHostForEnvironment(environment),
|
157
|
+
port: hostPort,
|
161
158
|
type: portType,
|
162
|
-
protocol:
|
159
|
+
protocol: 'tcp',
|
163
160
|
options: {
|
164
161
|
// expose as fullName since that is not operator specific, but unique
|
165
162
|
fullName: safeName,
|
@@ -169,6 +166,34 @@ class OperatorManager {
|
|
169
166
|
};
|
170
167
|
}
|
171
168
|
|
169
|
+
async getOperatorPorts(systemId: string, kind: string, version: string) {
|
170
|
+
const operator = await this.getOperator(kind, version);
|
171
|
+
|
172
|
+
const operatorData = operator.getLocalData();
|
173
|
+
|
174
|
+
const portTypes = Object.keys(operatorData.ports);
|
175
|
+
|
176
|
+
portTypes.sort();
|
177
|
+
|
178
|
+
const ports: AnyMap = {};
|
179
|
+
|
180
|
+
for (let i = 0; i < portTypes.length; i++) {
|
181
|
+
const portType = portTypes[i];
|
182
|
+
let containerPortInfo = operatorData.ports[portType];
|
183
|
+
const hostPort = await serviceManager.ensureServicePort(systemId, kind, portType);
|
184
|
+
const portInfo = toPortInfo(containerPortInfo);
|
185
|
+
const portId = portInfo.port + '/' + portInfo.type;
|
186
|
+
|
187
|
+
ports[portId] = {
|
188
|
+
type: portType,
|
189
|
+
hostPort,
|
190
|
+
protocol: portInfo.type,
|
191
|
+
};
|
192
|
+
}
|
193
|
+
|
194
|
+
return ports;
|
195
|
+
}
|
196
|
+
|
172
197
|
/**
|
173
198
|
* Ensure we have a running operator of given type
|
174
199
|
*
|
@@ -186,24 +211,7 @@ class OperatorManager {
|
|
186
211
|
|
187
212
|
const operatorData = operator.getLocalData();
|
188
213
|
|
189
|
-
const
|
190
|
-
|
191
|
-
portTypes.sort();
|
192
|
-
|
193
|
-
const ports: AnyMap = {};
|
194
|
-
|
195
|
-
for (let i = 0; i < portTypes.length; i++) {
|
196
|
-
const portType = portTypes[i];
|
197
|
-
let containerPortInfo = operatorData.ports[portType];
|
198
|
-
const hostPort = await serviceManager.ensureServicePort(systemId, kind, portType);
|
199
|
-
const portInfo = toPortInfo(containerPortInfo);
|
200
|
-
const portId = portInfo.port + '/' + portInfo.type;
|
201
|
-
|
202
|
-
ports[portId] = {
|
203
|
-
type: portType,
|
204
|
-
hostPort,
|
205
|
-
};
|
206
|
-
}
|
214
|
+
const ports = await this.getOperatorPorts(systemId, kind, version);
|
207
215
|
|
208
216
|
const nameParts = [systemId, kind.toLowerCase(), version];
|
209
217
|
|
@@ -222,7 +230,7 @@ class OperatorManager {
|
|
222
230
|
|
223
231
|
const operatorMetadata = operator.getDefinitionInfo().definition.metadata;
|
224
232
|
|
225
|
-
const
|
233
|
+
const hostIp = getDockerHostIp();
|
226
234
|
|
227
235
|
const ExposedPorts: { [key: string]: any } = {};
|
228
236
|
|
@@ -231,7 +239,7 @@ class OperatorManager {
|
|
231
239
|
PortBindings['' + containerPort] = [
|
232
240
|
{
|
233
241
|
HostPort: '' + portInfo.hostPort,
|
234
|
-
HostIp:
|
242
|
+
HostIp: hostIp,
|
235
243
|
},
|
236
244
|
];
|
237
245
|
|
package/src/progressListener.ts
CHANGED
@@ -7,6 +7,7 @@ import { spawn } from '@kapeta/nodejs-process';
|
|
7
7
|
import { socketManager } from './socketManager';
|
8
8
|
import { LogEntry } from './types';
|
9
9
|
import { format } from 'node:util';
|
10
|
+
import { Task } from './taskManager';
|
10
11
|
|
11
12
|
export class ProgressListener {
|
12
13
|
private readonly systemId: string | undefined;
|
@@ -17,7 +18,7 @@ export class ProgressListener {
|
|
17
18
|
this.instanceId = instanceId;
|
18
19
|
}
|
19
20
|
|
20
|
-
|
21
|
+
protected emitLog(payload: Omit<LogEntry, 'time' | 'source'>) {
|
21
22
|
const logEntry: LogEntry = {
|
22
23
|
...payload,
|
23
24
|
source: 'stdout',
|
@@ -135,3 +136,16 @@ export class ProgressListener {
|
|
135
136
|
});
|
136
137
|
}
|
137
138
|
}
|
139
|
+
|
140
|
+
export class TaskProgressListener extends ProgressListener {
|
141
|
+
private readonly task: Task;
|
142
|
+
|
143
|
+
constructor(task: Task) {
|
144
|
+
super();
|
145
|
+
this.task = task;
|
146
|
+
}
|
147
|
+
|
148
|
+
protected emitLog(payload: Omit<LogEntry, 'time' | 'source'>) {
|
149
|
+
this.task.addLog(payload.message, payload.level);
|
150
|
+
}
|
151
|
+
}
|
package/src/repositoryManager.ts
CHANGED
@@ -10,7 +10,7 @@ import { Actions, AssetVersion, Config, RegistryService } from '@kapeta/nodejs-r
|
|
10
10
|
import { definitionsManager } from './definitionsManager';
|
11
11
|
import { Task, taskManager } from './taskManager';
|
12
12
|
import { normalizeKapetaUri, parseKapetaUri, parseVersion } from '@kapeta/nodejs-utils';
|
13
|
-
import {
|
13
|
+
import { TaskProgressListener } from './progressListener';
|
14
14
|
import { RepositoryWatcher } from './RepositoryWatcher';
|
15
15
|
import { SourceOfChange } from './types';
|
16
16
|
import { cacheManager } from './cacheManager';
|
@@ -191,16 +191,18 @@ class RepositoryManager extends EventEmitter {
|
|
191
191
|
private async scheduleInstallation(refs: string[]): Promise<Task[]> {
|
192
192
|
//We make sure to only install one asset at a time - otherwise unexpected things might happen
|
193
193
|
const createInstaller = (ref: string) => {
|
194
|
-
return async () => {
|
194
|
+
return async (task: Task) => {
|
195
195
|
if (await definitionsManager.exists(ref)) {
|
196
196
|
return;
|
197
197
|
}
|
198
|
+
|
199
|
+
const progressListener = new TaskProgressListener(task);
|
198
200
|
//console.log(`Installing asset: ${ref}`);
|
199
201
|
//Auto-install missing asset
|
200
202
|
try {
|
201
203
|
//We change to a temp dir to avoid issues with the current working directory
|
202
204
|
process.chdir(os.tmpdir());
|
203
|
-
await Actions.install(
|
205
|
+
await Actions.install(progressListener, [ref], {});
|
204
206
|
} catch (e) {
|
205
207
|
console.error(`Failed to install asset: ${ref}`, e);
|
206
208
|
throw e;
|
package/src/serviceManager.ts
CHANGED
@@ -6,9 +6,10 @@
|
|
6
6
|
import _ from 'lodash';
|
7
7
|
import { clusterService } from './clusterService';
|
8
8
|
import { storageService } from './storageService';
|
9
|
-
import { EnvironmentType } from './types';
|
9
|
+
import { DOCKER_HOST_INTERNAL, EnvironmentType } from './types';
|
10
10
|
import { normalizeKapetaUri } from '@kapeta/nodejs-utils';
|
11
11
|
import { resolvePortType } from './utils/BlockInstanceRunner';
|
12
|
+
import { getRemoteHostForEnvironment } from './utils/utils';
|
12
13
|
|
13
14
|
export const HTTP_PORT_TYPE = 'http';
|
14
15
|
|
@@ -34,20 +35,11 @@ class ServiceManager {
|
|
34
35
|
});
|
35
36
|
}
|
36
37
|
|
37
|
-
public getLocalHost(environmentType?: EnvironmentType) {
|
38
|
-
if (environmentType === 'docker') {
|
39
|
-
//We're inside a docker container, so we can use this special host name to access the host machine
|
40
|
-
return 'host.docker.internal';
|
41
|
-
}
|
42
|
-
|
43
|
-
return clusterService.getClusterServiceHost();
|
44
|
-
}
|
45
|
-
|
46
38
|
_forLocal(port: string | number, path?: string, environmentType?: EnvironmentType) {
|
47
39
|
if (!path) {
|
48
40
|
path = '';
|
49
41
|
}
|
50
|
-
const hostname =
|
42
|
+
const hostname = getRemoteHostForEnvironment(environmentType);
|
51
43
|
|
52
44
|
if (path.startsWith('/')) {
|
53
45
|
path = path.substring(1);
|
package/src/taskManager.ts
CHANGED
@@ -7,10 +7,12 @@
|
|
7
7
|
* Class that handles processing background tasks.
|
8
8
|
*/
|
9
9
|
import { socketManager } from './socketManager';
|
10
|
+
import { LogLevel } from './types';
|
10
11
|
|
11
12
|
const EVENT_TASK_UPDATED = 'task-updated';
|
12
13
|
const EVENT_TASK_ADDED = 'task-added';
|
13
14
|
const EVENT_TASK_REMOVED = 'task-removed';
|
15
|
+
const EVENT_TASK_LOG = 'task-log';
|
14
16
|
|
15
17
|
export type TaskRunner<T> = (task: Task<T>) => Promise<T>;
|
16
18
|
|
@@ -94,6 +96,15 @@ export class Task<T = void> implements TaskData<T> {
|
|
94
96
|
socketManager.emitGlobal(EVENT_TASK_UPDATED, this.toData());
|
95
97
|
}
|
96
98
|
|
99
|
+
public addLog(log: string, level: LogLevel = 'INFO') {
|
100
|
+
socketManager.emitGlobal(EVENT_TASK_LOG, {
|
101
|
+
id: this.id,
|
102
|
+
message: log,
|
103
|
+
level,
|
104
|
+
time: Date.now(),
|
105
|
+
});
|
106
|
+
}
|
107
|
+
|
97
108
|
async wait(): Promise<T> {
|
98
109
|
return this.future.promise;
|
99
110
|
}
|
package/src/types.ts
CHANGED
@@ -21,6 +21,8 @@ export type LogLevel = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG' | 'TRACE' | 'FATAL';
|
|
21
21
|
export type LogSource = 'stdout' | 'stderr';
|
22
22
|
export type EnvironmentType = 'docker' | 'process';
|
23
23
|
|
24
|
+
export const DOCKER_HOST_INTERNAL = 'host.docker.internal';
|
25
|
+
|
24
26
|
export interface LogEntry {
|
25
27
|
source: LogSource;
|
26
28
|
level: LogLevel;
|
@@ -66,27 +68,6 @@ export type ProcessInfo = {
|
|
66
68
|
portType?: string;
|
67
69
|
};
|
68
70
|
|
69
|
-
export interface Health {
|
70
|
-
cmd: string;
|
71
|
-
interval?: number;
|
72
|
-
timeout?: number;
|
73
|
-
retries?: number;
|
74
|
-
}
|
75
|
-
|
76
|
-
export type PortInfo = { port: number; type: 'tcp' | 'udp' } | number | string;
|
77
|
-
|
78
|
-
export type LocalImageOptions<Credentials = AnyMap, Options = AnyMap> = {
|
79
|
-
image: string;
|
80
|
-
ports: { [key: string]: PortInfo };
|
81
|
-
credentials?: Credentials;
|
82
|
-
options?: Options;
|
83
|
-
cmd?: string;
|
84
|
-
env?: AnyMap;
|
85
|
-
health?: Health;
|
86
|
-
singleton?: boolean;
|
87
|
-
mounts?: { [key: string]: string };
|
88
|
-
};
|
89
|
-
|
90
71
|
export type InstanceInfo = {
|
91
72
|
systemId: string;
|
92
73
|
instanceId: string;
|
@@ -105,37 +86,8 @@ export type InstanceInfo = {
|
|
105
86
|
portType?: string;
|
106
87
|
};
|
107
88
|
|
108
|
-
interface ResourceRef {
|
109
|
-
blockId: string;
|
110
|
-
resourceName: string;
|
111
|
-
}
|
112
|
-
|
113
89
|
export type ProxyRequestHandler = (req: StringBodyRequest, res: express.Response, info: ProxyRequestInfo) => void;
|
114
90
|
|
115
|
-
export interface OperatorInstancePort {
|
116
|
-
protocol: string;
|
117
|
-
port: number;
|
118
|
-
}
|
119
|
-
|
120
|
-
export interface OperatorInstanceInfo {
|
121
|
-
hostname: string;
|
122
|
-
ports: { [portType: string]: OperatorInstancePort };
|
123
|
-
path?: string;
|
124
|
-
query?: string;
|
125
|
-
hash?: string;
|
126
|
-
options?: AnyMap;
|
127
|
-
credentials?: AnyMap;
|
128
|
-
}
|
129
|
-
|
130
|
-
export interface OperatorInfo {
|
131
|
-
host: string;
|
132
|
-
port: string;
|
133
|
-
type: string;
|
134
|
-
protocol: string;
|
135
|
-
options: AnyMap;
|
136
|
-
credentials: AnyMap;
|
137
|
-
}
|
138
|
-
|
139
91
|
export interface ProxyRequestInfo {
|
140
92
|
address: string;
|
141
93
|
connection: Connection;
|