@kapeta/local-cluster-service 0.15.2 → 0.16.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/src/RepositoryWatcher.d.ts +22 -0
- package/dist/cjs/src/RepositoryWatcher.js +273 -0
- package/dist/cjs/src/assetManager.js +33 -20
- package/dist/cjs/src/containerManager.js +0 -1
- package/dist/cjs/src/identities/routes.js +2 -1
- package/dist/cjs/src/instanceManager.d.ts +0 -2
- package/dist/cjs/src/instanceManager.js +16 -35
- package/dist/cjs/src/progressListener.d.ts +5 -6
- package/dist/cjs/src/progressListener.js +54 -36
- package/dist/cjs/src/repositoryManager.d.ts +4 -4
- package/dist/cjs/src/repositoryManager.js +20 -93
- package/dist/cjs/src/socketManager.d.ts +18 -6
- package/dist/cjs/src/socketManager.js +35 -1
- package/dist/esm/src/RepositoryWatcher.d.ts +22 -0
- package/dist/esm/src/RepositoryWatcher.js +266 -0
- package/dist/esm/src/assetManager.js +35 -22
- package/dist/esm/src/containerManager.js +0 -1
- package/dist/esm/src/identities/routes.js +2 -1
- package/dist/esm/src/instanceManager.d.ts +0 -2
- package/dist/esm/src/instanceManager.js +16 -35
- package/dist/esm/src/progressListener.d.ts +5 -6
- package/dist/esm/src/progressListener.js +53 -36
- package/dist/esm/src/repositoryManager.d.ts +4 -4
- package/dist/esm/src/repositoryManager.js +20 -93
- package/dist/esm/src/socketManager.d.ts +18 -6
- package/dist/esm/src/socketManager.js +34 -0
- package/package.json +2 -2
- package/src/RepositoryWatcher.ts +304 -0
- package/src/assetManager.ts +39 -25
- package/src/containerManager.ts +0 -5
- package/src/identities/routes.ts +2 -1
- package/src/instanceManager.ts +22 -35
- package/src/progressListener.ts +59 -39
- package/src/repositoryManager.ts +26 -100
- package/src/socketManager.ts +44 -5
@@ -1,16 +1,31 @@
|
|
1
1
|
import { spawn } from '@kapeta/nodejs-process';
|
2
2
|
import { socketManager } from './socketManager';
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
import { format } from 'node:util';
|
4
|
+
export class ProgressListener {
|
5
|
+
systemId;
|
6
|
+
instanceId;
|
7
|
+
constructor(systemId, instanceId) {
|
8
|
+
this.systemId = systemId;
|
9
|
+
this.instanceId = instanceId;
|
10
|
+
}
|
11
|
+
emitLog(payload) {
|
12
|
+
const logEntry = {
|
13
|
+
...payload,
|
14
|
+
source: 'stdout',
|
15
|
+
time: Date.now(),
|
16
|
+
};
|
17
|
+
if (this.systemId && this.instanceId) {
|
18
|
+
socketManager.emitInstanceLog(this.systemId, this.instanceId, logEntry);
|
19
|
+
return;
|
20
|
+
}
|
21
|
+
if (this.systemId) {
|
22
|
+
socketManager.emitSystemLog(this.systemId, logEntry);
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
socketManager.emitGlobalLog(logEntry);
|
7
26
|
}
|
8
27
|
run(command, directory) {
|
9
|
-
this.
|
10
|
-
type: 'info',
|
11
|
-
message: `Running command "${command}"`,
|
12
|
-
});
|
13
|
-
const firstCommand = command.split(' ')[0];
|
28
|
+
this.info(`Running command "${command}"`);
|
14
29
|
return new Promise(async (resolve, reject) => {
|
15
30
|
try {
|
16
31
|
const chunks = [];
|
@@ -20,7 +35,10 @@ class ProgressListener {
|
|
20
35
|
shell: true,
|
21
36
|
});
|
22
37
|
child.onData((data) => {
|
23
|
-
this.
|
38
|
+
this.emitLog({
|
39
|
+
level: data.type === 'stdout' ? 'INFO' : 'WARN',
|
40
|
+
message: data.line,
|
41
|
+
});
|
24
42
|
});
|
25
43
|
if (child.process.stdout) {
|
26
44
|
child.process.stdout.on('data', (data) => {
|
@@ -29,25 +47,16 @@ class ProgressListener {
|
|
29
47
|
}
|
30
48
|
child.process.on('exit', (exit, signal) => {
|
31
49
|
if (exit !== 0) {
|
32
|
-
this.
|
33
|
-
type: 'info',
|
34
|
-
message: `"${command}" failed: "${exit}"`,
|
35
|
-
});
|
50
|
+
this.warn(`Command "${command}" failed: ${exit}`);
|
36
51
|
reject(new Error(`Command "${command}" exited with code ${exit}`));
|
37
52
|
}
|
38
53
|
else {
|
39
|
-
this.
|
40
|
-
type: 'info',
|
41
|
-
message: `Command OK: "${command}"`,
|
42
|
-
});
|
54
|
+
this.info(`Command OK: "${command}"`);
|
43
55
|
resolve({ exit, signal, output: Buffer.concat(chunks).toString() });
|
44
56
|
}
|
45
57
|
});
|
46
58
|
child.process.on('error', (err) => {
|
47
|
-
this.
|
48
|
-
type: 'info',
|
49
|
-
message: `"${command}" failed: "${err.message}"`,
|
50
|
-
});
|
59
|
+
this.warn(`"${command}" failed: "${err.message}"`);
|
51
60
|
reject(err);
|
52
61
|
});
|
53
62
|
await child.wait();
|
@@ -58,41 +67,49 @@ class ProgressListener {
|
|
58
67
|
});
|
59
68
|
}
|
60
69
|
async progress(label, callback) {
|
61
|
-
this.
|
70
|
+
this.info(`${label}: started`);
|
62
71
|
try {
|
63
72
|
const result = await callback();
|
64
|
-
this.
|
73
|
+
this.info(`${label}: done`);
|
65
74
|
return result;
|
66
75
|
}
|
67
76
|
catch (e) {
|
68
|
-
this.
|
69
|
-
type: 'info',
|
70
|
-
message: `${label}: failed. ${e.message}`,
|
71
|
-
});
|
77
|
+
this.warn(`${label}: failed. ${e.message}`);
|
72
78
|
throw e;
|
73
79
|
}
|
74
80
|
}
|
75
81
|
async check(message, ok) {
|
76
82
|
const wasOk = await ok;
|
77
|
-
this.
|
83
|
+
this.info(`${message}: ${wasOk}`);
|
78
84
|
}
|
79
85
|
start(label) {
|
80
|
-
this.
|
86
|
+
this.info(label);
|
81
87
|
}
|
82
88
|
showValue(label, value) {
|
83
|
-
this.
|
89
|
+
this.info(`${label}: ${value}`);
|
84
90
|
}
|
85
91
|
error(msg, ...args) {
|
86
|
-
this.
|
92
|
+
this.emitLog({
|
93
|
+
message: format(msg, args),
|
94
|
+
level: 'ERROR',
|
95
|
+
});
|
87
96
|
}
|
88
97
|
warn(msg, ...args) {
|
89
|
-
this.
|
98
|
+
this.emitLog({
|
99
|
+
message: format(msg, args),
|
100
|
+
level: 'WARN',
|
101
|
+
});
|
90
102
|
}
|
91
103
|
info(msg, ...args) {
|
92
|
-
this.
|
104
|
+
this.emitLog({
|
105
|
+
message: format(msg, args),
|
106
|
+
level: 'INFO',
|
107
|
+
});
|
93
108
|
}
|
94
109
|
debug(msg, ...args) {
|
95
|
-
this.
|
110
|
+
this.emitLog({
|
111
|
+
message: format(msg, args),
|
112
|
+
level: 'DEBUG',
|
113
|
+
});
|
96
114
|
}
|
97
115
|
}
|
98
|
-
export const progressListener = new ProgressListener(socketManager);
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import { Task } from './taskManager';
|
2
2
|
declare class RepositoryManager {
|
3
|
-
private changeEventsEnabled;
|
4
3
|
private _registryService;
|
5
4
|
private _cache;
|
6
|
-
private watcher
|
5
|
+
private watcher;
|
7
6
|
constructor();
|
8
|
-
setChangeEventsEnabled(enabled: boolean): void;
|
9
7
|
listenForChanges(): void;
|
10
|
-
stopListening(): void
|
8
|
+
stopListening(): Promise<void>;
|
9
|
+
ignoreChangesFor(file: string): Promise<void>;
|
10
|
+
resumeChangedFor(file: string): Promise<void>;
|
11
11
|
ensureDefaultProviders(): void;
|
12
12
|
private _install;
|
13
13
|
ensureAsset(handle: string, name: string, version: string, wait?: boolean): Promise<undefined | Task[]>;
|
@@ -1,17 +1,16 @@
|
|
1
|
-
import FS from 'node:fs';
|
2
1
|
import os from 'node:os';
|
3
|
-
import Path from 'node:path';
|
4
|
-
import watch from 'recursive-watch';
|
5
|
-
import FSExtra from 'fs-extra';
|
6
|
-
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
7
|
-
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
8
2
|
import { socketManager } from './socketManager';
|
9
|
-
import { progressListener } from './progressListener';
|
10
3
|
import { Actions, Config, RegistryService } from '@kapeta/nodejs-registry-utils';
|
11
4
|
import { definitionsManager } from './definitionsManager';
|
12
5
|
import { taskManager } from './taskManager';
|
13
6
|
import { normalizeKapetaUri } from './utils/utils';
|
7
|
+
import { ProgressListener } from './progressListener';
|
8
|
+
import { RepositoryWatcher } from './RepositoryWatcher';
|
14
9
|
import { assetManager } from './assetManager';
|
10
|
+
function clearAllCaches() {
|
11
|
+
definitionsManager.clearCache();
|
12
|
+
assetManager.clearCache();
|
13
|
+
}
|
15
14
|
const EVENT_DEFAULT_PROVIDERS_START = 'default-providers-start';
|
16
15
|
const EVENT_DEFAULT_PROVIDERS_END = 'default-providers-end';
|
17
16
|
const DEFAULT_PROVIDERS = [
|
@@ -30,97 +29,31 @@ const DEFAULT_PROVIDERS = [
|
|
30
29
|
];
|
31
30
|
const INSTALL_ATTEMPTED = {};
|
32
31
|
class RepositoryManager {
|
33
|
-
changeEventsEnabled;
|
34
32
|
_registryService;
|
35
33
|
_cache;
|
36
34
|
watcher;
|
37
35
|
constructor() {
|
38
|
-
this.changeEventsEnabled = true;
|
39
|
-
this.listenForChanges();
|
40
36
|
this._registryService = new RegistryService(Config.data.registry.url);
|
41
37
|
this._cache = {};
|
42
|
-
|
43
|
-
|
44
|
-
this.changeEventsEnabled = enabled;
|
38
|
+
this.watcher = new RepositoryWatcher();
|
39
|
+
this.listenForChanges();
|
45
40
|
}
|
46
41
|
listenForChanges() {
|
47
|
-
|
48
|
-
if (!FS.existsSync(baseDir)) {
|
49
|
-
FSExtra.mkdirpSync(baseDir);
|
50
|
-
}
|
51
|
-
let allDefinitions = ClusterConfiguration.getDefinitions();
|
52
|
-
console.log('Watching local repository for provider changes: %s', baseDir);
|
53
|
-
try {
|
54
|
-
this.watcher = watch(baseDir, (filename) => {
|
55
|
-
if (!filename) {
|
56
|
-
return;
|
57
|
-
}
|
58
|
-
const [handle, name, version] = filename.toString().split(/\//g);
|
59
|
-
if (!name || !version) {
|
60
|
-
return;
|
61
|
-
}
|
62
|
-
if (!this.changeEventsEnabled) {
|
63
|
-
return;
|
64
|
-
}
|
65
|
-
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
66
|
-
const newDefinitions = ClusterConfiguration.getDefinitions();
|
67
|
-
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
68
|
-
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
69
|
-
const ymlExists = FS.existsSync(ymlPath);
|
70
|
-
let type;
|
71
|
-
if (ymlExists) {
|
72
|
-
if (currentDefinition) {
|
73
|
-
type = 'updated';
|
74
|
-
}
|
75
|
-
else if (newDefinition) {
|
76
|
-
type = 'added';
|
77
|
-
currentDefinition = newDefinition;
|
78
|
-
}
|
79
|
-
else {
|
80
|
-
//Other definition was added / updated - ignore
|
81
|
-
return;
|
82
|
-
}
|
83
|
-
}
|
84
|
-
else {
|
85
|
-
if (currentDefinition) {
|
86
|
-
const ref = parseKapetaUri(`${currentDefinition.definition.metadata.name}:${currentDefinition.version}`).id;
|
87
|
-
delete INSTALL_ATTEMPTED[ref];
|
88
|
-
//Something was removed
|
89
|
-
type = 'removed';
|
90
|
-
}
|
91
|
-
else {
|
92
|
-
//Other definition was removed - ignore
|
93
|
-
return;
|
94
|
-
}
|
95
|
-
}
|
96
|
-
const payload = {
|
97
|
-
type,
|
98
|
-
definition: currentDefinition?.definition,
|
99
|
-
asset: { handle, name, version },
|
100
|
-
};
|
101
|
-
allDefinitions = newDefinitions;
|
102
|
-
socketManager.emit(`assets`, 'changed', payload);
|
103
|
-
definitionsManager.clearCache();
|
104
|
-
});
|
105
|
-
}
|
106
|
-
catch (e) {
|
107
|
-
// Fallback to run without watch mode due to potential platform issues.
|
108
|
-
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
109
|
-
console.log('Unable to watch for changes. Changes to assets will not update automatically.', e);
|
110
|
-
return;
|
111
|
-
}
|
42
|
+
this.watcher.watch();
|
112
43
|
}
|
113
|
-
stopListening() {
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
this.watcher();
|
118
|
-
|
44
|
+
async stopListening() {
|
45
|
+
return this.watcher.unwatch();
|
46
|
+
}
|
47
|
+
ignoreChangesFor(file) {
|
48
|
+
return this.watcher.ignoreChangesFor(file);
|
49
|
+
}
|
50
|
+
resumeChangedFor(file) {
|
51
|
+
return this.watcher.resumeChangedFor(file);
|
119
52
|
}
|
120
53
|
ensureDefaultProviders() {
|
121
54
|
socketManager.emitGlobal(EVENT_DEFAULT_PROVIDERS_START, { providers: DEFAULT_PROVIDERS });
|
122
55
|
const tasks = this._install(DEFAULT_PROVIDERS);
|
123
|
-
Promise.allSettled(tasks.map(t => t.wait())).then(() => {
|
56
|
+
Promise.allSettled(tasks.map((t) => t.wait())).then(() => {
|
124
57
|
socketManager.emitGlobal(EVENT_DEFAULT_PROVIDERS_END, {});
|
125
58
|
});
|
126
59
|
}
|
@@ -140,19 +73,13 @@ class RepositoryManager {
|
|
140
73
|
try {
|
141
74
|
//We change to a temp dir to avoid issues with the current working directory
|
142
75
|
process.chdir(os.tmpdir());
|
143
|
-
|
144
|
-
this.setChangeEventsEnabled(false);
|
145
|
-
await Actions.install(progressListener, [ref], {});
|
76
|
+
await Actions.install(new ProgressListener(), [ref], {});
|
146
77
|
}
|
147
78
|
catch (e) {
|
148
79
|
console.error(`Failed to install asset: ${ref}`, e);
|
149
80
|
throw e;
|
150
81
|
}
|
151
|
-
|
152
|
-
this.setChangeEventsEnabled(true);
|
153
|
-
}
|
154
|
-
definitionsManager.clearCache();
|
155
|
-
assetManager.clearCache();
|
82
|
+
clearAllCaches();
|
156
83
|
//console.log(`Asset installed: ${ref}`);
|
157
84
|
};
|
158
85
|
};
|
@@ -1,16 +1,28 @@
|
|
1
|
-
import {
|
1
|
+
import { Server } from 'socket.io';
|
2
|
+
import { LogEntry } from './types';
|
3
|
+
export declare const EVENT_STATUS_CHANGED = "status-changed";
|
4
|
+
export declare const EVENT_INSTANCE_CREATED = "instance-created";
|
5
|
+
export declare const EVENT_INSTANCE_EXITED = "instance-exited";
|
6
|
+
export declare const EVENT_INSTANCE_LOG = "instance-log";
|
7
|
+
export declare const EVENT_SYSTEM_LOG = "system-log";
|
8
|
+
export declare const EVENT_LOG = "log";
|
2
9
|
export declare class SocketManager {
|
3
10
|
private _io;
|
4
|
-
private _sockets;
|
11
|
+
private readonly _sockets;
|
5
12
|
constructor();
|
6
13
|
setIo(io: Server): void;
|
7
14
|
isAlive(): boolean;
|
8
15
|
private get io();
|
9
16
|
emit(context: string, type: string, payload: any): void;
|
10
17
|
emitGlobal(type: string, payload: any): void;
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
18
|
+
emitSystemEvent(systemId: string, type: string, payload: any): void;
|
19
|
+
emitInstanceLog(systemId: string, instanceId: string, payload: LogEntry): void;
|
20
|
+
emitSystemLog(systemId: string, payload: LogEntry): void;
|
21
|
+
emitGlobalLog(payload: LogEntry): void;
|
22
|
+
emitInstanceEvent(systemId: string, instanceId: string, type: string, payload: any): void;
|
23
|
+
private _bindIO;
|
24
|
+
private _handleSocketCreated;
|
25
|
+
private _bindSocket;
|
26
|
+
private _handleSocketDestroyed;
|
15
27
|
}
|
16
28
|
export declare const socketManager: SocketManager;
|
@@ -1,4 +1,11 @@
|
|
1
1
|
import _ from 'lodash';
|
2
|
+
import { normalizeKapetaUri } from './utils/utils';
|
3
|
+
export const EVENT_STATUS_CHANGED = 'status-changed';
|
4
|
+
export const EVENT_INSTANCE_CREATED = 'instance-created';
|
5
|
+
export const EVENT_INSTANCE_EXITED = 'instance-exited';
|
6
|
+
export const EVENT_INSTANCE_LOG = 'instance-log';
|
7
|
+
export const EVENT_SYSTEM_LOG = 'system-log';
|
8
|
+
export const EVENT_LOG = 'log';
|
2
9
|
export class SocketManager {
|
3
10
|
_io;
|
4
11
|
_sockets;
|
@@ -26,6 +33,33 @@ export class SocketManager {
|
|
26
33
|
emitGlobal(type, payload) {
|
27
34
|
this.io.emit(type, payload);
|
28
35
|
}
|
36
|
+
emitSystemEvent(systemId, type, payload) {
|
37
|
+
systemId = normalizeKapetaUri(systemId);
|
38
|
+
try {
|
39
|
+
socketManager.emit(`${systemId}/instances`, type, payload);
|
40
|
+
}
|
41
|
+
catch (e) {
|
42
|
+
console.warn('Failed to emit instance event: %s', e.message);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
emitInstanceLog(systemId, instanceId, payload) {
|
46
|
+
this.emitInstanceEvent(systemId, instanceId, EVENT_INSTANCE_LOG, payload);
|
47
|
+
}
|
48
|
+
emitSystemLog(systemId, payload) {
|
49
|
+
this.emitSystemEvent(systemId, EVENT_SYSTEM_LOG, payload);
|
50
|
+
}
|
51
|
+
emitGlobalLog(payload) {
|
52
|
+
this.emitGlobal(EVENT_LOG, payload);
|
53
|
+
}
|
54
|
+
emitInstanceEvent(systemId, instanceId, type, payload) {
|
55
|
+
systemId = normalizeKapetaUri(systemId);
|
56
|
+
try {
|
57
|
+
socketManager.emit(`${systemId}/instances/${instanceId}`, type, payload);
|
58
|
+
}
|
59
|
+
catch (e) {
|
60
|
+
console.warn('Failed to emit instance event: %s', e.message);
|
61
|
+
}
|
62
|
+
}
|
29
63
|
_bindIO() {
|
30
64
|
this.io.on('connection', (socket) => this._handleSocketCreated(socket));
|
31
65
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.16.0",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -53,6 +53,7 @@
|
|
53
53
|
"@kapeta/sdk-config": "<2",
|
54
54
|
"@kapeta/web-microfrontend": "^0.2.1",
|
55
55
|
"async-lock": "^1.4.0",
|
56
|
+
"chokidar": "^3.5.3",
|
56
57
|
"express": "4.17.1",
|
57
58
|
"express-promise-router": "^4.1.1",
|
58
59
|
"fs-extra": "^11.1.0",
|
@@ -62,7 +63,6 @@
|
|
62
63
|
"node-cache": "^5.1.2",
|
63
64
|
"node-docker-api": "1.1.22",
|
64
65
|
"node-uuid": "^1.4.8",
|
65
|
-
"recursive-watch": "^1.1.4",
|
66
66
|
"request": "2.88.2",
|
67
67
|
"request-promise": "4.2.6",
|
68
68
|
"socket.io": "^4.5.2",
|