@kapeta/local-cluster-service 0.8.3 → 0.9.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.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/src/assetManager.js +7 -4
- package/dist/cjs/src/clusterService.js +2 -0
- package/dist/cjs/src/codeGeneratorManager.js +3 -3
- package/dist/cjs/src/config/routes.js +1 -1
- package/dist/cjs/src/configManager.js +13 -1
- package/dist/cjs/src/containerManager.d.ts +25 -2
- package/dist/cjs/src/containerManager.js +51 -16
- package/dist/cjs/src/definitionsManager.d.ts +11 -0
- package/dist/cjs/src/definitionsManager.js +44 -0
- package/dist/cjs/src/filesystemManager.js +0 -2
- package/dist/cjs/src/instanceManager.d.ts +23 -47
- package/dist/cjs/src/instanceManager.js +416 -235
- package/dist/cjs/src/instances/routes.js +23 -14
- package/dist/cjs/src/middleware/kapeta.js +7 -0
- package/dist/cjs/src/networkManager.js +6 -0
- package/dist/cjs/src/operatorManager.js +8 -4
- package/dist/cjs/src/providerManager.js +3 -3
- package/dist/cjs/src/repositoryManager.js +7 -3
- package/dist/cjs/src/serviceManager.js +5 -0
- package/dist/cjs/src/types.d.ts +39 -13
- package/dist/cjs/src/types.js +28 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +3 -3
- package/dist/cjs/src/utils/BlockInstanceRunner.js +34 -32
- package/dist/cjs/src/utils/utils.d.ts +2 -0
- package/dist/cjs/src/utils/utils.js +17 -1
- package/dist/esm/src/assetManager.js +7 -4
- package/dist/esm/src/clusterService.js +2 -0
- package/dist/esm/src/codeGeneratorManager.js +3 -3
- package/dist/esm/src/config/routes.js +1 -1
- package/dist/esm/src/configManager.js +13 -1
- package/dist/esm/src/containerManager.d.ts +25 -2
- package/dist/esm/src/containerManager.js +50 -15
- package/dist/esm/src/definitionsManager.d.ts +11 -0
- package/dist/esm/src/definitionsManager.js +38 -0
- package/dist/esm/src/filesystemManager.js +0 -2
- package/dist/esm/src/instanceManager.d.ts +23 -47
- package/dist/esm/src/instanceManager.js +416 -236
- package/dist/esm/src/instances/routes.js +23 -14
- package/dist/esm/src/middleware/kapeta.js +7 -0
- package/dist/esm/src/networkManager.js +6 -0
- package/dist/esm/src/operatorManager.js +8 -4
- package/dist/esm/src/providerManager.js +3 -3
- package/dist/esm/src/repositoryManager.js +7 -3
- package/dist/esm/src/serviceManager.js +5 -0
- package/dist/esm/src/types.d.ts +39 -13
- package/dist/esm/src/types.js +27 -1
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +3 -3
- package/dist/esm/src/utils/BlockInstanceRunner.js +35 -33
- package/dist/esm/src/utils/utils.d.ts +2 -0
- package/dist/esm/src/utils/utils.js +14 -0
- package/package.json +2 -1
- package/src/assetManager.ts +7 -4
- package/src/clusterService.ts +3 -0
- package/src/codeGeneratorManager.ts +3 -2
- package/src/config/routes.ts +1 -1
- package/src/configManager.ts +13 -1
- package/src/containerManager.ts +72 -16
- package/src/definitionsManager.ts +54 -0
- package/src/filesystemManager.ts +0 -2
- package/src/instanceManager.ts +495 -266
- package/src/instances/routes.ts +23 -17
- package/src/middleware/kapeta.ts +10 -0
- package/src/networkManager.ts +6 -0
- package/src/operatorManager.ts +11 -6
- package/src/providerManager.ts +3 -2
- package/src/repositoryManager.ts +7 -3
- package/src/serviceManager.ts +6 -0
- package/src/types.ts +44 -14
- package/src/utils/BlockInstanceRunner.ts +39 -36
- package/src/utils/utils.ts +18 -0
package/src/instances/routes.ts
CHANGED
@@ -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 {
|
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
|
31
|
+
const instances = await instanceManager.startAllForPlan(req.params.systemId);
|
32
32
|
|
33
33
|
res.status(202).send({
|
34
34
|
ok: true,
|
35
|
-
processes:
|
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.
|
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.
|
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
|
79
|
-
if (!
|
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:
|
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
|
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 =
|
146
|
-
} else
|
147
|
-
instance
|
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
|
-
|
151
|
-
|
152
|
-
|
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.
|
165
|
+
await instanceManager.markAsStopped(req.kapeta!.systemId, req.kapeta!.instanceId);
|
160
166
|
|
161
167
|
res.status(202).send({ ok: true });
|
162
168
|
});
|
package/src/middleware/kapeta.ts
CHANGED
@@ -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,
|
package/src/networkManager.ts
CHANGED
@@ -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);
|
package/src/operatorManager.ts
CHANGED
@@ -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 =
|
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
|
-
|
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 =
|
102
|
-
(
|
103
|
-
|
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}`);
|
package/src/providerManager.ts
CHANGED
@@ -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
|
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 =
|
46
|
+
const providerDefinitions = definitionsManager.getProviderDefinitions();
|
46
47
|
|
47
48
|
if (providerDefinitions.length > 0) {
|
48
49
|
console.log('## Loaded the following providers ##');
|
package/src/repositoryManager.ts
CHANGED
@@ -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
|
|
@@ -94,6 +95,7 @@ class RepositoryManager {
|
|
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 =
|
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
|
-
|
225
|
-
|
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
|
}
|
package/src/serviceManager.ts
CHANGED
@@ -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
|
}
|
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
|
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
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
38
|
-
|
39
|
-
|
40
|
-
|
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,
|
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
|
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(
|
49
|
+
constructor(systemId: string) {
|
50
50
|
/**
|
51
51
|
*
|
52
52
|
* @type {string}
|
53
53
|
* @private
|
54
54
|
*/
|
55
|
-
this._systemId =
|
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 =
|
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
|
108
|
+
let processInfo: ProcessInfo;
|
109
109
|
|
110
110
|
if (providerVersion.definition.kind === KIND_BLOCK_TYPE_OPERATOR) {
|
111
|
-
|
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
|
-
|
117
|
+
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
|
118
118
|
} else {
|
119
|
-
|
119
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, env);
|
120
120
|
}
|
121
121
|
|
122
122
|
if (portTypes.length > 0) {
|
123
|
-
|
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<
|
138
|
+
): Promise<ProcessInfo> {
|
143
139
|
const baseDir = ClusterConfig.getRepositoryAssetPath(blockInfo.handle, blockInfo.name, blockInfo.version);
|
144
140
|
|
145
141
|
if (!FS.existsSync(baseDir)) {
|
@@ -172,22 +168,25 @@ export class BlockInstanceRunner {
|
|
172
168
|
throw new Error(`Missing docker image information: ${JSON.stringify(localContainer)}`);
|
173
169
|
}
|
174
170
|
|
175
|
-
const containerName =
|
171
|
+
const containerName = getBlockInstanceContainerName(blockInstance.id);
|
176
172
|
const logs = new LogData();
|
177
173
|
logs.addLog(`Starting block ${blockInstance.ref}`);
|
178
|
-
let
|
174
|
+
let containerInfo = await containerManager.getContainerByName(containerName);
|
175
|
+
let container = containerInfo?.native;
|
176
|
+
|
179
177
|
console.log('Starting dev container', containerName);
|
180
178
|
|
181
|
-
if (
|
182
|
-
console.log(`
|
179
|
+
if (containerInfo) {
|
180
|
+
console.log(`Dev container already exists. Deleting...`);
|
183
181
|
try {
|
184
|
-
await
|
182
|
+
await containerInfo.remove({
|
185
183
|
force: true,
|
186
184
|
});
|
187
185
|
} catch (e: any) {
|
188
186
|
throw new Error('Failed to delete existing container: ' + e.message);
|
189
187
|
}
|
190
|
-
container =
|
188
|
+
container = undefined;
|
189
|
+
containerInfo = undefined;
|
191
190
|
}
|
192
191
|
|
193
192
|
logs.addLog(`Creating new container for block: ${containerName}`);
|
@@ -229,6 +228,7 @@ export class BlockInstanceRunner {
|
|
229
228
|
HealthCheck = containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
230
229
|
}
|
231
230
|
|
231
|
+
console.log('Starting dev container', containerName, dockerImage);
|
232
232
|
container = await containerManager.startContainer({
|
233
233
|
Image: dockerImage,
|
234
234
|
name: containerName,
|
@@ -274,7 +274,7 @@ export class BlockInstanceRunner {
|
|
274
274
|
container: Container,
|
275
275
|
logs: LogData,
|
276
276
|
deleteOnExit: boolean = false
|
277
|
-
): Promise<
|
277
|
+
): Promise<ProcessInfo> {
|
278
278
|
let localContainer: Container | null = container;
|
279
279
|
const logStream = (await container.logs({
|
280
280
|
follow: true,
|
@@ -299,14 +299,14 @@ export class BlockInstanceRunner {
|
|
299
299
|
const data = status.data as any;
|
300
300
|
if (deleteOnExit) {
|
301
301
|
try {
|
302
|
-
await
|
302
|
+
await containerManager.remove(container);
|
303
303
|
} catch (e: any) {}
|
304
304
|
}
|
305
305
|
outputEvents.emit('exit', data?.State?.ExitCode ?? 0);
|
306
306
|
});
|
307
307
|
|
308
308
|
return {
|
309
|
-
type:
|
309
|
+
type: InstanceType.DOCKER,
|
310
310
|
pid: container.id,
|
311
311
|
output: outputEvents,
|
312
312
|
stop: async () => {
|
@@ -317,7 +317,7 @@ export class BlockInstanceRunner {
|
|
317
317
|
try {
|
318
318
|
await localContainer.stop();
|
319
319
|
if (deleteOnExit) {
|
320
|
-
await
|
320
|
+
await containerManager.remove(localContainer);
|
321
321
|
}
|
322
322
|
} catch (e) {}
|
323
323
|
localContainer = null;
|
@@ -350,9 +350,10 @@ export class BlockInstanceRunner {
|
|
350
350
|
throw new Error(`Missing docker image information: ${JSON.stringify(versionInfo?.artifact?.details)}`);
|
351
351
|
}
|
352
352
|
|
353
|
-
const containerName =
|
353
|
+
const containerName = getBlockInstanceContainerName(blockInstance.id);
|
354
354
|
const logs = new LogData();
|
355
|
-
|
355
|
+
const containerInfo = await containerManager.getContainerByName(containerName);
|
356
|
+
let container = containerInfo?.native;
|
356
357
|
|
357
358
|
// For windows we need to default to root
|
358
359
|
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
@@ -435,9 +436,11 @@ export class BlockInstanceRunner {
|
|
435
436
|
console.warn('Failed to pull image. Continuing...', e);
|
436
437
|
}
|
437
438
|
|
438
|
-
const containerName =
|
439
|
+
const containerName = getBlockInstanceContainerName(blockInstance.id);
|
439
440
|
const logs = new LogData();
|
440
|
-
|
441
|
+
const containerInfo = await containerManager.getContainerByName(containerName);
|
442
|
+
let container = containerInfo?.native;
|
443
|
+
|
441
444
|
if (container) {
|
442
445
|
const containerData = container.data as any;
|
443
446
|
if (containerData.State === 'running') {
|
@@ -446,9 +449,9 @@ export class BlockInstanceRunner {
|
|
446
449
|
if (containerData.State?.ExitCode > 0) {
|
447
450
|
logs.addLog(`Container exited with code: ${containerData.State.ExitCode}. Deleting...`);
|
448
451
|
try {
|
449
|
-
await
|
452
|
+
await containerManager.remove(container);
|
450
453
|
} catch (e) {}
|
451
|
-
container =
|
454
|
+
container = undefined;
|
452
455
|
} else {
|
453
456
|
logs.addLog(`Found existing container for block: ${containerName}. Starting now`);
|
454
457
|
try {
|
@@ -456,9 +459,9 @@ export class BlockInstanceRunner {
|
|
456
459
|
} catch (e) {
|
457
460
|
console.warn('Failed to start container. Deleting...', e);
|
458
461
|
try {
|
459
|
-
await
|
462
|
+
await containerManager.remove(container);
|
460
463
|
} catch (e) {}
|
461
|
-
container =
|
464
|
+
container = undefined;
|
462
465
|
}
|
463
466
|
}
|
464
467
|
}
|
package/src/utils/utils.ts
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
import FS from 'node:fs';
|
2
2
|
import YAML from 'yaml';
|
3
|
+
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
4
|
+
|
5
|
+
export function getBlockInstanceContainerName(instanceId: string) {
|
6
|
+
return `kapeta-block-instance-${instanceId}`;
|
7
|
+
}
|
8
|
+
|
9
|
+
export function normalizeKapetaUri(uri: string) {
|
10
|
+
if (!uri) {
|
11
|
+
return '';
|
12
|
+
}
|
13
|
+
|
14
|
+
const uriObj = parseKapetaUri(uri);
|
15
|
+
if (!uriObj.version) {
|
16
|
+
return `kapeta://${parseKapetaUri(uri).fullName}`;
|
17
|
+
}
|
18
|
+
|
19
|
+
return `kapeta://${parseKapetaUri(uri).id}`;
|
20
|
+
}
|
3
21
|
|
4
22
|
export function readYML(path: string) {
|
5
23
|
const rawYaml = FS.readFileSync(path);
|