@kapeta/local-cluster-service 0.8.3 → 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.
- package/CHANGELOG.md +7 -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 +22 -2
- package/dist/cjs/src/containerManager.js +42 -15
- 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 +27 -26
- 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 +22 -2
- package/dist/esm/src/containerManager.js +41 -14
- 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 +28 -27
- 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 +62 -15
- 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 +32 -30
- package/src/utils/utils.ts +18 -0
package/src/assetManager.ts
CHANGED
@@ -10,6 +10,8 @@ import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
|
10
10
|
import { repositoryManager } from './repositoryManager';
|
11
11
|
import { BlockDefinition } from '@kapeta/schemas';
|
12
12
|
import { Actions } from '@kapeta/nodejs-registry-utils';
|
13
|
+
import { definitionsManager } from './definitionsManager';
|
14
|
+
import { normalizeKapetaUri } from './utils/utils';
|
13
15
|
|
14
16
|
export interface EnrichedAsset {
|
15
17
|
ref: string;
|
@@ -67,7 +69,7 @@ class AssetManager {
|
|
67
69
|
*/
|
68
70
|
getAssets(assetKinds?: string[]): EnrichedAsset[] {
|
69
71
|
if (!assetKinds) {
|
70
|
-
const blockTypeProviders =
|
72
|
+
const blockTypeProviders = definitionsManager.getDefinitions([
|
71
73
|
'core/block-type',
|
72
74
|
'core/block-type-operator',
|
73
75
|
]);
|
@@ -77,7 +79,7 @@ class AssetManager {
|
|
77
79
|
assetKinds.push('core/plan');
|
78
80
|
}
|
79
81
|
|
80
|
-
const assets =
|
82
|
+
const assets = definitionsManager.getDefinitions(assetKinds);
|
81
83
|
|
82
84
|
return assets.map(enrichAsset);
|
83
85
|
}
|
@@ -97,6 +99,7 @@ class AssetManager {
|
|
97
99
|
}
|
98
100
|
|
99
101
|
async getAsset(ref: string, noCache: boolean = false): Promise<EnrichedAsset | undefined> {
|
102
|
+
ref = normalizeKapetaUri(ref);
|
100
103
|
const cacheKey = `getAsset:${ref}`;
|
101
104
|
if (!noCache && this.cache.has(cacheKey)) {
|
102
105
|
return this.cache.get(cacheKey);
|
@@ -104,10 +107,10 @@ class AssetManager {
|
|
104
107
|
const uri = parseKapetaUri(ref);
|
105
108
|
await repositoryManager.ensureAsset(uri.handle, uri.name, uri.version);
|
106
109
|
|
107
|
-
let asset =
|
110
|
+
let asset = definitionsManager
|
111
|
+
.getDefinitions()
|
108
112
|
.map(enrichAsset)
|
109
113
|
.find((a) => parseKapetaUri(a.ref).equals(uri));
|
110
|
-
|
111
114
|
if (!asset) {
|
112
115
|
throw new Error('Asset not found: ' + ref);
|
113
116
|
}
|
package/src/clusterService.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import { normalizeKapetaUri } from './utils/utils';
|
2
|
+
|
1
3
|
const net = require('net');
|
2
4
|
const DEFAULT_SERVER_PORT = 35100;
|
3
5
|
const DEFAULT_START_PORT = 40000;
|
@@ -125,6 +127,7 @@ class ClusterService {
|
|
125
127
|
* @return {string}
|
126
128
|
*/
|
127
129
|
getProxyPath(systemId: string, consumerInstanceId: string, consumerResourceName: string, portType: string) {
|
130
|
+
systemId = normalizeKapetaUri(systemId);
|
128
131
|
return `/proxy/${encodeURIComponent(systemId)}/${encodeURIComponent(consumerInstanceId)}/${encodeURIComponent(
|
129
132
|
consumerResourceName
|
130
133
|
)}/${encodeURIComponent(portType)}/`;
|
@@ -2,6 +2,7 @@ import Path from 'path';
|
|
2
2
|
import { registry as Targets, BlockCodeGenerator, CodeWriter } from '@kapeta/codegen';
|
3
3
|
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
4
4
|
import { BlockDefinition } from '@kapeta/schemas';
|
5
|
+
import { definitionsManager } from './definitionsManager';
|
5
6
|
|
6
7
|
const TARGET_KIND = 'core/language-target';
|
7
8
|
const BLOCK_TYPE_KIND = 'core/block-type';
|
@@ -9,7 +10,7 @@ const BLOCK_TYPE_KIND = 'core/block-type';
|
|
9
10
|
class CodeGeneratorManager {
|
10
11
|
async reload() {
|
11
12
|
Targets.reset();
|
12
|
-
const languageTargets =
|
13
|
+
const languageTargets = definitionsManager.getDefinitions(TARGET_KIND);
|
13
14
|
for (const languageTarget of languageTargets) {
|
14
15
|
const key = `${languageTarget.definition.metadata.name}:${languageTarget.version}`;
|
15
16
|
try {
|
@@ -31,7 +32,7 @@ class CodeGeneratorManager {
|
|
31
32
|
return false;
|
32
33
|
}
|
33
34
|
|
34
|
-
const blockTypes =
|
35
|
+
const blockTypes = definitionsManager.getDefinitions(BLOCK_TYPE_KIND);
|
35
36
|
const blockTypeKinds = blockTypes.map(
|
36
37
|
(blockType) => blockType.definition.metadata.name.toLowerCase() + ':' + blockType.version
|
37
38
|
);
|
package/src/config/routes.ts
CHANGED
@@ -41,7 +41,7 @@ router.put('/instance', async (req: KapetaBodyRequest, res) => {
|
|
41
41
|
if (req.kapeta!.instanceId) {
|
42
42
|
configManager.setConfigForSection(req.kapeta!.systemId, req.kapeta!.instanceId, config);
|
43
43
|
//Restart the instance if it is running after config change
|
44
|
-
await instanceManager.
|
44
|
+
await instanceManager.restart(req.kapeta!.systemId, req.kapeta!.instanceId);
|
45
45
|
} else {
|
46
46
|
configManager.setConfigForSystem(req.kapeta!.systemId, config);
|
47
47
|
}
|
package/src/configManager.ts
CHANGED
@@ -3,6 +3,7 @@ import { BlockInstance } from '@kapeta/schemas';
|
|
3
3
|
import { storageService } from './storageService';
|
4
4
|
import { assetManager } from './assetManager';
|
5
5
|
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
6
|
+
import { normalizeKapetaUri } from './utils/utils';
|
6
7
|
|
7
8
|
type AnyMap = { [key: string]: any };
|
8
9
|
|
@@ -19,6 +20,7 @@ class ConfigManager {
|
|
19
20
|
}
|
20
21
|
|
21
22
|
_forSystem(systemId: string) {
|
23
|
+
systemId = normalizeKapetaUri(systemId);
|
22
24
|
if (!this._config[systemId]) {
|
23
25
|
this._config[systemId] = {};
|
24
26
|
}
|
@@ -27,16 +29,19 @@ class ConfigManager {
|
|
27
29
|
}
|
28
30
|
|
29
31
|
setConfigForSystem(systemId: string, config: AnyMap) {
|
32
|
+
systemId = normalizeKapetaUri(systemId);
|
30
33
|
const systemConfig = config || {};
|
31
34
|
|
32
35
|
storageService.put('config', systemId, systemConfig);
|
33
36
|
}
|
34
37
|
|
35
38
|
getConfigForSystem(systemId: string): AnyMap {
|
39
|
+
systemId = normalizeKapetaUri(systemId);
|
36
40
|
return this._forSystem(systemId);
|
37
41
|
}
|
38
42
|
|
39
43
|
setConfigForSection(systemId: string, sectionId: string, config: AnyMap) {
|
44
|
+
systemId = normalizeKapetaUri(systemId);
|
40
45
|
let systemConfig = this._forSystem(systemId);
|
41
46
|
systemConfig[sectionId] = config || {};
|
42
47
|
|
@@ -44,6 +49,7 @@ class ConfigManager {
|
|
44
49
|
}
|
45
50
|
|
46
51
|
getConfigForSection(systemId: string, sectionId: string) {
|
52
|
+
systemId = normalizeKapetaUri(systemId);
|
47
53
|
const systemConfig = this._forSystem(systemId);
|
48
54
|
|
49
55
|
if (!systemConfig[sectionId]) {
|
@@ -70,6 +76,10 @@ class ConfigManager {
|
|
70
76
|
* @returns {Promise<{systemId:string,instanceId:string}>}
|
71
77
|
*/
|
72
78
|
async resolveIdentity(blockRef: string, systemId?: string) {
|
79
|
+
blockRef = normalizeKapetaUri(blockRef);
|
80
|
+
if (systemId) {
|
81
|
+
systemId = normalizeKapetaUri(systemId);
|
82
|
+
}
|
73
83
|
const planAssets = assetManager.getPlans();
|
74
84
|
|
75
85
|
const blockUri = parseKapetaUri(blockRef);
|
@@ -89,7 +99,7 @@ class ConfigManager {
|
|
89
99
|
const refUri = parseKapetaUri(blockInstance.block.ref);
|
90
100
|
if (refUri.equals(blockUri)) {
|
91
101
|
matchingIdentities.push({
|
92
|
-
systemId: planAsset.ref,
|
102
|
+
systemId: normalizeKapetaUri(planAsset.ref),
|
93
103
|
instanceId: blockInstance.id,
|
94
104
|
});
|
95
105
|
}
|
@@ -120,6 +130,8 @@ class ConfigManager {
|
|
120
130
|
}
|
121
131
|
|
122
132
|
async verifyIdentity(blockRef: string, systemId: string, instanceId: string) {
|
133
|
+
blockRef = normalizeKapetaUri(blockRef);
|
134
|
+
systemId = normalizeKapetaUri(systemId);
|
123
135
|
const planAssets = assetManager.getPlans();
|
124
136
|
const systemUri = systemId ? parseKapetaUri(systemId) : null;
|
125
137
|
const blockUri = parseKapetaUri(blockRef);
|
package/src/containerManager.ts
CHANGED
@@ -27,6 +27,25 @@ export interface DockerMounts {
|
|
27
27
|
Consistency: string;
|
28
28
|
}
|
29
29
|
|
30
|
+
interface DockerState {
|
31
|
+
Status: 'created' | 'running' | 'paused' | 'restarting' | 'removing' | 'exited' | 'dead';
|
32
|
+
Running: boolean;
|
33
|
+
Paused: boolean;
|
34
|
+
Restarting: boolean;
|
35
|
+
OOMKilled: boolean;
|
36
|
+
Dead: boolean;
|
37
|
+
Pid: number;
|
38
|
+
ExitCode: number;
|
39
|
+
Error: string;
|
40
|
+
StartedAt: string;
|
41
|
+
FinishedAt: string;
|
42
|
+
Health?: {
|
43
|
+
Status: 'starting' | 'healthy' | 'unhealthy' | 'none';
|
44
|
+
FailingStreak: number;
|
45
|
+
Log: any[] | null;
|
46
|
+
};
|
47
|
+
}
|
48
|
+
|
30
49
|
interface Health {
|
31
50
|
cmd: string;
|
32
51
|
interval?: number;
|
@@ -36,11 +55,13 @@ interface Health {
|
|
36
55
|
|
37
56
|
const LABEL_PORT_PREFIX = 'kapeta_port-';
|
38
57
|
const NANO_SECOND = 1000000;
|
39
|
-
const HEALTH_CHECK_INTERVAL =
|
40
|
-
const HEALTH_CHECK_MAX =
|
58
|
+
const HEALTH_CHECK_INTERVAL = 3000;
|
59
|
+
const HEALTH_CHECK_MAX = 20;
|
41
60
|
const IMAGE_PULL_CACHE_TTL = 30 * 60 * 1000;
|
42
61
|
const IMAGE_PULL_CACHE: { [key: string]: number } = {};
|
43
62
|
|
63
|
+
export const HEALTH_CHECK_TIMEOUT = HEALTH_CHECK_INTERVAL * HEALTH_CHECK_MAX * 2;
|
64
|
+
|
44
65
|
const promisifyStream = (stream: ReadStream) =>
|
45
66
|
new Promise((resolve, reject) => {
|
46
67
|
stream.on('data', (d) => console.log(d.toString()));
|
@@ -165,11 +186,17 @@ class ContainerManager {
|
|
165
186
|
return this._docker;
|
166
187
|
}
|
167
188
|
|
168
|
-
async getContainerByName(containerName: string): Promise<
|
189
|
+
async getContainerByName(containerName: string): Promise<ContainerInfo | undefined> {
|
169
190
|
const containers = await this.docker().container.list({ all: true });
|
170
|
-
|
171
|
-
|
191
|
+
const out = containers.find((container) => {
|
192
|
+
const containerData = container.data as any;
|
193
|
+
return containerData.Names.indexOf(`/${containerName}`) > -1;
|
172
194
|
});
|
195
|
+
|
196
|
+
if (out) {
|
197
|
+
return new ContainerInfo(out);
|
198
|
+
}
|
199
|
+
return undefined;
|
173
200
|
}
|
174
201
|
|
175
202
|
async pull(image: string, cacheForMS: number = IMAGE_PULL_CACHE_TTL) {
|
@@ -371,18 +398,28 @@ class ContainerManager {
|
|
371
398
|
}
|
372
399
|
|
373
400
|
async _isReady(container: Container) {
|
374
|
-
|
401
|
+
let info: Container;
|
402
|
+
try {
|
403
|
+
info = await container.status();
|
404
|
+
} catch (err) {
|
405
|
+
return false;
|
406
|
+
}
|
375
407
|
const infoData: any = info?.data;
|
376
|
-
|
408
|
+
const state = infoData?.State as DockerState;
|
409
|
+
if (state?.Status === 'exited' || state?.Status === 'removing' || state?.Status === 'dead') {
|
377
410
|
throw new Error('Container exited unexpectedly');
|
378
411
|
}
|
379
412
|
return infoData?.State?.Running ?? false;
|
380
413
|
}
|
381
414
|
|
382
415
|
async _isHealthy(container: Container) {
|
383
|
-
|
384
|
-
|
385
|
-
|
416
|
+
try {
|
417
|
+
const info = await container.status();
|
418
|
+
const infoData: any = info?.data;
|
419
|
+
return infoData?.State?.Health?.Status === 'healthy';
|
420
|
+
} catch (err) {
|
421
|
+
return false;
|
422
|
+
}
|
386
423
|
}
|
387
424
|
|
388
425
|
/**
|
@@ -429,7 +466,7 @@ export class ContainerInfo {
|
|
429
466
|
}
|
430
467
|
|
431
468
|
async isRunning() {
|
432
|
-
const inspectResult = await this.
|
469
|
+
const inspectResult = await this.inspect();
|
433
470
|
|
434
471
|
if (!inspectResult || !inspectResult.State) {
|
435
472
|
return false;
|
@@ -464,14 +501,24 @@ export class ContainerInfo {
|
|
464
501
|
return null;
|
465
502
|
}
|
466
503
|
|
467
|
-
async
|
468
|
-
|
504
|
+
async inspect() {
|
505
|
+
try {
|
506
|
+
const result = await this._container.status();
|
507
|
+
|
508
|
+
return result ? (result.data as any) : null;
|
509
|
+
} catch (err) {
|
510
|
+
return null;
|
511
|
+
}
|
512
|
+
}
|
513
|
+
|
514
|
+
async status() {
|
515
|
+
const result = await this.inspect();
|
469
516
|
|
470
|
-
return result
|
517
|
+
return result.State as DockerState;
|
471
518
|
}
|
472
519
|
|
473
520
|
async getPorts(): Promise<PortMap | false> {
|
474
|
-
const inspectResult = await this.
|
521
|
+
const inspectResult = await this.inspect();
|
475
522
|
|
476
523
|
if (!inspectResult || !inspectResult.Config || !inspectResult.Config.Labels) {
|
477
524
|
return false;
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import ClusterConfiguration, { DefinitionInfo } from '@kapeta/local-cluster-config';
|
2
|
+
|
3
|
+
const CACHE_TTL = 60 * 1000; // 1 min
|
4
|
+
|
5
|
+
interface DefinitionCacheEntry {
|
6
|
+
expires: number;
|
7
|
+
definitions: DefinitionInfo[];
|
8
|
+
}
|
9
|
+
|
10
|
+
class DefinitionsManager {
|
11
|
+
private cache: { [key: string]: DefinitionCacheEntry } = {};
|
12
|
+
|
13
|
+
private getKey(kindFilter?: string | string[]) {
|
14
|
+
if (kindFilter) {
|
15
|
+
if (Array.isArray(kindFilter)) {
|
16
|
+
return kindFilter.join(',');
|
17
|
+
}
|
18
|
+
return kindFilter;
|
19
|
+
}
|
20
|
+
return 'none';
|
21
|
+
}
|
22
|
+
|
23
|
+
public clearCache() {
|
24
|
+
this.cache = {};
|
25
|
+
}
|
26
|
+
|
27
|
+
private doCached(key: string, getter: () => DefinitionInfo[]) {
|
28
|
+
if (this.cache[key]) {
|
29
|
+
if (this.cache[key].expires > Date.now()) {
|
30
|
+
return this.cache[key].definitions;
|
31
|
+
}
|
32
|
+
delete this.cache[key];
|
33
|
+
}
|
34
|
+
|
35
|
+
this.cache[key] = {
|
36
|
+
expires: Date.now() + CACHE_TTL,
|
37
|
+
definitions: getter(),
|
38
|
+
};
|
39
|
+
|
40
|
+
return this.cache[key].definitions;
|
41
|
+
}
|
42
|
+
|
43
|
+
public getDefinitions(kindFilter?: string | string[]) {
|
44
|
+
const key = this.getKey(kindFilter);
|
45
|
+
|
46
|
+
return this.doCached(key, () => ClusterConfiguration.getDefinitions(kindFilter));
|
47
|
+
}
|
48
|
+
|
49
|
+
public getProviderDefinitions() {
|
50
|
+
return this.doCached('providers', () => ClusterConfiguration.getProviderDefinitions());
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
export const definitionsManager = new DefinitionsManager();
|
package/src/filesystemManager.ts
CHANGED
@@ -17,9 +17,7 @@ function isFile(path: string) {
|
|
17
17
|
class FilesystemManager {
|
18
18
|
async writeFile(path: string, data: string | Buffer) {
|
19
19
|
const dirName = Path.dirname(path);
|
20
|
-
console.log('Dir name', dirName, path);
|
21
20
|
if (!FS.existsSync(dirName)) {
|
22
|
-
console.log('Making folder', dirName);
|
23
21
|
FSExtra.mkdirpSync(dirName, {});
|
24
22
|
}
|
25
23
|
FS.writeFileSync(path, data);
|