@kapeta/local-cluster-service 0.19.5 → 0.19.7
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/src/containerManager.d.ts +39 -32
- package/dist/cjs/src/containerManager.js +138 -108
- package/dist/cjs/src/instanceManager.js +28 -18
- package/dist/cjs/src/operatorManager.js +3 -0
- package/dist/cjs/src/taskManager.js +4 -1
- package/dist/cjs/src/utils/BlockInstanceRunner.js +19 -1
- package/dist/esm/src/containerManager.d.ts +39 -32
- package/dist/esm/src/containerManager.js +138 -108
- package/dist/esm/src/instanceManager.js +28 -18
- package/dist/esm/src/operatorManager.js +3 -0
- package/dist/esm/src/taskManager.js +4 -1
- package/dist/esm/src/utils/BlockInstanceRunner.js +19 -1
- package/package.json +5 -2
- package/src/containerManager.ts +188 -140
- package/src/instanceManager.ts +44 -20
- package/src/operatorManager.ts +11 -1
- package/src/taskManager.ts +4 -1
- package/src/utils/BlockInstanceRunner.ts +30 -4
package/src/instanceManager.ts
CHANGED
@@ -6,7 +6,12 @@ import { storageService } from './storageService';
|
|
6
6
|
import { EVENT_INSTANCE_CREATED, EVENT_INSTANCE_EXITED, EVENT_STATUS_CHANGED, socketManager } from './socketManager';
|
7
7
|
import { serviceManager } from './serviceManager';
|
8
8
|
import { assetManager } from './assetManager';
|
9
|
-
import {
|
9
|
+
import {
|
10
|
+
containerManager,
|
11
|
+
DockerContainerHealth,
|
12
|
+
DockerContainerStatus,
|
13
|
+
HEALTH_CHECK_TIMEOUT,
|
14
|
+
} from './containerManager';
|
10
15
|
import { configManager } from './configManager';
|
11
16
|
import { DesiredInstanceStatus, InstanceInfo, InstanceOwner, InstanceStatus, InstanceType, LogEntry } from './types';
|
12
17
|
import { BlockDefinitionSpec, BlockInstance, Plan } from '@kapeta/schemas';
|
@@ -336,6 +341,10 @@ export class InstanceManager {
|
|
336
341
|
return;
|
337
342
|
}
|
338
343
|
|
344
|
+
if (instance.status === InstanceStatus.STOPPING) {
|
345
|
+
return;
|
346
|
+
}
|
347
|
+
|
339
348
|
if (changeDesired && instance.desiredStatus !== DesiredInstanceStatus.EXTERNAL) {
|
340
349
|
instance.desiredStatus = DesiredInstanceStatus.STOP;
|
341
350
|
}
|
@@ -496,7 +505,7 @@ export class InstanceManager {
|
|
496
505
|
try {
|
497
506
|
const processInfo = await runner.start(blockRef, instanceId, instanceConfig);
|
498
507
|
|
499
|
-
instance.status = InstanceStatus.
|
508
|
+
instance.status = InstanceStatus.STARTING;
|
500
509
|
|
501
510
|
return this.saveInternalInstance({
|
502
511
|
...instance,
|
@@ -504,10 +513,10 @@ export class InstanceManager {
|
|
504
513
|
pid: processInfo.pid ?? -1,
|
505
514
|
health: null,
|
506
515
|
portType: processInfo.portType,
|
507
|
-
status: InstanceStatus.
|
516
|
+
status: InstanceStatus.STARTING,
|
508
517
|
});
|
509
518
|
} catch (e: any) {
|
510
|
-
console.warn('Failed to start instance: ', systemId, instanceId, blockRef, e
|
519
|
+
console.warn('Failed to start instance: ', systemId, instanceId, blockRef, e);
|
511
520
|
const logs: LogEntry[] = [
|
512
521
|
{
|
513
522
|
source: 'stdout',
|
@@ -686,7 +695,12 @@ export class InstanceManager {
|
|
686
695
|
try {
|
687
696
|
await this.start(instance.systemId, instance.instanceId);
|
688
697
|
} catch (e: any) {
|
689
|
-
console.warn(
|
698
|
+
console.warn(
|
699
|
+
'Failed to start previously stopped instance',
|
700
|
+
instance.systemId,
|
701
|
+
instance.instanceId,
|
702
|
+
e
|
703
|
+
);
|
690
704
|
}
|
691
705
|
return;
|
692
706
|
}
|
@@ -738,37 +752,47 @@ export class InstanceManager {
|
|
738
752
|
return InstanceStatus.STOPPED;
|
739
753
|
}
|
740
754
|
const state = await container.status();
|
755
|
+
if (!state) {
|
756
|
+
return InstanceStatus.STOPPED;
|
757
|
+
}
|
741
758
|
|
742
|
-
|
743
|
-
if (state.Health?.Status === 'healthy') {
|
744
|
-
return InstanceStatus.READY;
|
745
|
-
}
|
746
|
-
if (state.Health?.Status === 'starting') {
|
747
|
-
return InstanceStatus.STARTING;
|
748
|
-
}
|
749
|
-
if (state.Health?.Status === 'unhealthy') {
|
750
|
-
return InstanceStatus.UNHEALTHY;
|
751
|
-
}
|
759
|
+
const statusType = state.Status as DockerContainerStatus;
|
752
760
|
|
761
|
+
if (statusType === 'running') {
|
762
|
+
if (state.Health?.Status) {
|
763
|
+
const healthStatusType = state.Health.Status as DockerContainerHealth;
|
764
|
+
if (healthStatusType === 'healthy' || healthStatusType === 'none') {
|
765
|
+
return InstanceStatus.READY;
|
766
|
+
}
|
767
|
+
|
768
|
+
if (healthStatusType === 'starting') {
|
769
|
+
return InstanceStatus.STARTING;
|
770
|
+
}
|
771
|
+
|
772
|
+
if (healthStatusType === 'unhealthy') {
|
773
|
+
return InstanceStatus.UNHEALTHY;
|
774
|
+
}
|
775
|
+
}
|
753
776
|
return InstanceStatus.READY;
|
754
777
|
}
|
755
|
-
|
778
|
+
|
779
|
+
if (statusType === 'created') {
|
756
780
|
return InstanceStatus.STARTING;
|
757
781
|
}
|
758
782
|
|
759
|
-
if (
|
783
|
+
if (statusType === 'exited' || statusType === 'dead') {
|
760
784
|
return InstanceStatus.STOPPED;
|
761
785
|
}
|
762
786
|
|
763
|
-
if (
|
787
|
+
if (statusType === 'removing') {
|
764
788
|
return InstanceStatus.BUSY;
|
765
789
|
}
|
766
790
|
|
767
|
-
if (
|
791
|
+
if (statusType === 'restarting') {
|
768
792
|
return InstanceStatus.BUSY;
|
769
793
|
}
|
770
794
|
|
771
|
-
if (
|
795
|
+
if (statusType === 'paused') {
|
772
796
|
return InstanceStatus.BUSY;
|
773
797
|
}
|
774
798
|
|
package/src/operatorManager.ts
CHANGED
@@ -4,7 +4,13 @@ import md5 from 'md5';
|
|
4
4
|
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
5
5
|
import { serviceManager } from './serviceManager';
|
6
6
|
import { storageService } from './storageService';
|
7
|
-
import {
|
7
|
+
import {
|
8
|
+
COMPOSE_LABEL_PROJECT,
|
9
|
+
COMPOSE_LABEL_SERVICE,
|
10
|
+
CONTAINER_LABEL_PORT_PREFIX,
|
11
|
+
ContainerInfo,
|
12
|
+
containerManager,
|
13
|
+
} from './containerManager';
|
8
14
|
import FSExtra from 'fs-extra';
|
9
15
|
import { AnyMap, EnvironmentType, OperatorInfo, StringMap } from './types';
|
10
16
|
import { BlockInstance, Resource } from '@kapeta/schemas';
|
@@ -199,8 +205,12 @@ class OperatorManager {
|
|
199
205
|
const PortBindings: { [key: string]: any } = {};
|
200
206
|
const Env: string[] = [];
|
201
207
|
|
208
|
+
const systemUri = parseKapetaUri(systemId);
|
209
|
+
|
202
210
|
const Labels: StringMap = {
|
203
211
|
kapeta: 'true',
|
212
|
+
[COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
|
213
|
+
[COMPOSE_LABEL_SERVICE]: [resourceType, version].join('_').replace(/[^a-z0-9]/gi, '_'),
|
204
214
|
};
|
205
215
|
|
206
216
|
const operatorMetadata = operator.getDefinitionInfo().definition.metadata;
|
package/src/taskManager.ts
CHANGED
@@ -139,7 +139,9 @@ class TaskManager {
|
|
139
139
|
|
140
140
|
socketManager.emitGlobal(EVENT_TASK_ADDED, task.toData());
|
141
141
|
|
142
|
-
this.invokeTask(task).catch(() => {
|
142
|
+
this.invokeTask(task).catch((err) => {
|
143
|
+
console.warn(`Task ${task.id} failed`, err);
|
144
|
+
});
|
143
145
|
|
144
146
|
return task;
|
145
147
|
}
|
@@ -205,6 +207,7 @@ class TaskManager {
|
|
205
207
|
task.future.resolve(result);
|
206
208
|
task.emitUpdate();
|
207
209
|
} catch (e: any) {
|
210
|
+
console.warn(`Task ${task.id} failed while waiting for it to resolve`, e);
|
208
211
|
task.errorMessage = e.message;
|
209
212
|
task.status = TaskStatus.FAILED;
|
210
213
|
task.future.reject(e);
|
@@ -3,12 +3,18 @@ import ClusterConfig, { DefinitionInfo } from '@kapeta/local-cluster-config';
|
|
3
3
|
import { getBindHost, getBlockInstanceContainerName, normalizeKapetaUri, readYML } from './utils';
|
4
4
|
import { KapetaURI, parseKapetaUri } from '@kapeta/nodejs-utils';
|
5
5
|
import { serviceManager } from '../serviceManager';
|
6
|
-
import {
|
6
|
+
import {
|
7
|
+
COMPOSE_LABEL_PROJECT,
|
8
|
+
COMPOSE_LABEL_SERVICE,
|
9
|
+
containerManager,
|
10
|
+
DockerMounts,
|
11
|
+
toLocalBindVolume,
|
12
|
+
} from '../containerManager';
|
7
13
|
import { LogData } from './LogData';
|
8
14
|
import { clusterService } from '../clusterService';
|
9
15
|
import { AnyMap, BlockProcessParams, InstanceType, ProcessInfo, StringMap } from '../types';
|
10
|
-
import { Container } from 'node-docker-api/lib/container';
|
11
16
|
import { definitionsManager } from '../definitionsManager';
|
17
|
+
import Docker from 'dockerode';
|
12
18
|
|
13
19
|
const KIND_BLOCK_TYPE_OPERATOR = 'core/block-type-operator';
|
14
20
|
const KAPETA_SYSTEM_ID = 'KAPETA_SYSTEM_ID';
|
@@ -171,6 +177,13 @@ export class BlockInstanceRunner {
|
|
171
177
|
const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
|
172
178
|
const workingDir = localContainer.workingDir ? localContainer.workingDir : '/workspace';
|
173
179
|
|
180
|
+
const customHostConfigs = localContainer.HostConfig ?? {};
|
181
|
+
const customLabels = localContainer.Labels ?? {};
|
182
|
+
const customEnvs = localContainer.Env ?? [];
|
183
|
+
delete localContainer.HostConfig;
|
184
|
+
delete localContainer.Labels;
|
185
|
+
delete localContainer.Env;
|
186
|
+
|
174
187
|
const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion);
|
175
188
|
|
176
189
|
let HealthCheck = undefined;
|
@@ -178,17 +191,24 @@ export class BlockInstanceRunner {
|
|
178
191
|
HealthCheck = containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
179
192
|
}
|
180
193
|
|
194
|
+
const systemUri = parseKapetaUri(this._systemId);
|
195
|
+
|
181
196
|
return this.ensureContainer({
|
197
|
+
...dockerOpts,
|
182
198
|
Image: dockerImage,
|
183
199
|
name: containerName,
|
184
200
|
WorkingDir: workingDir,
|
185
201
|
Labels: {
|
202
|
+
...customLabels,
|
186
203
|
instance: blockInstance.id,
|
204
|
+
[COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
|
205
|
+
[COMPOSE_LABEL_SERVICE]: blockInfo.id.replace(/[^a-z0-9]/gi, '_'),
|
187
206
|
},
|
188
207
|
HealthCheck,
|
189
208
|
ExposedPorts,
|
190
209
|
Cmd: startCmd ? startCmd.split(/\s+/g) : [],
|
191
210
|
Env: [
|
211
|
+
...customEnvs,
|
192
212
|
...DOCKER_ENV_VARS,
|
193
213
|
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
|
194
214
|
...Object.entries({
|
@@ -197,13 +217,13 @@ export class BlockInstanceRunner {
|
|
197
217
|
}).map(([key, value]) => `${key}=${value}`),
|
198
218
|
],
|
199
219
|
HostConfig: {
|
220
|
+
...customHostConfigs,
|
200
221
|
Binds: [
|
201
222
|
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${homeDir}/.kapeta`,
|
202
223
|
`${toLocalBindVolume(baseDir)}:${workingDir}`,
|
203
224
|
],
|
204
225
|
PortBindings,
|
205
226
|
},
|
206
|
-
...dockerOpts,
|
207
227
|
});
|
208
228
|
}
|
209
229
|
|
@@ -240,6 +260,7 @@ export class BlockInstanceRunner {
|
|
240
260
|
|
241
261
|
// For windows we need to default to root
|
242
262
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
263
|
+
const systemUri = parseKapetaUri(this._systemId);
|
243
264
|
|
244
265
|
return this.ensureContainer({
|
245
266
|
Image: dockerImage,
|
@@ -247,6 +268,8 @@ export class BlockInstanceRunner {
|
|
247
268
|
ExposedPorts,
|
248
269
|
Labels: {
|
249
270
|
instance: blockInstance.id,
|
271
|
+
[COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
|
272
|
+
[COMPOSE_LABEL_SERVICE]: blockInfo.id.replace(/[^a-z0-9]/gi, '_'),
|
250
273
|
},
|
251
274
|
Env: [
|
252
275
|
...DOCKER_ENV_VARS,
|
@@ -344,6 +367,7 @@ export class BlockInstanceRunner {
|
|
344
367
|
// For windows we need to default to root
|
345
368
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
346
369
|
|
370
|
+
const systemUri = parseKapetaUri(this._systemId);
|
347
371
|
logs.addLog(`Creating new container for block: ${containerName}`);
|
348
372
|
const out = await this.ensureContainer({
|
349
373
|
Image: dockerImage,
|
@@ -360,6 +384,8 @@ export class BlockInstanceRunner {
|
|
360
384
|
},
|
361
385
|
Labels: {
|
362
386
|
instance: blockInstance.id,
|
387
|
+
[COMPOSE_LABEL_PROJECT]: systemUri.id.replace(/[^a-z0-9]/gi, '_'),
|
388
|
+
[COMPOSE_LABEL_SERVICE]: blockUri.id.replace(/[^a-z0-9]/gi, '_'),
|
363
389
|
},
|
364
390
|
Env: [
|
365
391
|
`KAPETA_INSTANCE_NAME=${blockInstance.ref}`,
|
@@ -414,7 +440,7 @@ export class BlockInstanceRunner {
|
|
414
440
|
return this._handleContainer(container);
|
415
441
|
}
|
416
442
|
|
417
|
-
private async _handleContainer(container: Container): Promise<ProcessInfo> {
|
443
|
+
private async _handleContainer(container: Docker.Container): Promise<ProcessInfo> {
|
418
444
|
return {
|
419
445
|
type: InstanceType.DOCKER,
|
420
446
|
pid: container.id,
|