@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
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
# [0.16.0](https://github.com/kapetacom/local-cluster-service/compare/v0.15.3...v0.16.0) (2023-08-11)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* Use chokidar lib for watching for changes on disk ([#60](https://github.com/kapetacom/local-cluster-service/issues/60)) ([f2af855](https://github.com/kapetacom/local-cluster-service/commit/f2af85554fc2a23133ce27a4f8989cabdea097d7))
|
7
|
+
|
8
|
+
## [0.15.3](https://github.com/kapetacom/local-cluster-service/compare/v0.15.2...v0.15.3) (2023-08-10)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Use fresh API every time ([05851db](https://github.com/kapetacom/local-cluster-service/commit/05851dbf8c2a690c790a2ba93b7c0a8d24a93b06))
|
14
|
+
|
1
15
|
## [0.15.2](https://github.com/kapetacom/local-cluster-service/compare/v0.15.1...v0.15.2) (2023-08-09)
|
2
16
|
|
3
17
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
export declare class RepositoryWatcher {
|
2
|
+
private watcher?;
|
3
|
+
private disabled;
|
4
|
+
private readonly baseDir;
|
5
|
+
private allDefinitions;
|
6
|
+
private symbolicLinks;
|
7
|
+
private ignoredFiles;
|
8
|
+
constructor();
|
9
|
+
setDisabled(disabled: boolean): void;
|
10
|
+
watch(): void;
|
11
|
+
ignoreChangesFor(file: string): Promise<void>;
|
12
|
+
resumeChangedFor(file: string): Promise<void>;
|
13
|
+
unwatch(): Promise<void>;
|
14
|
+
private getAssetIdentity;
|
15
|
+
private handleFileChange;
|
16
|
+
private checkForChange;
|
17
|
+
private exists;
|
18
|
+
private removeSymlinkTarget;
|
19
|
+
private updateSymlinkTarget;
|
20
|
+
private addSymlinkTarget;
|
21
|
+
private ignoreFile;
|
22
|
+
}
|
@@ -0,0 +1,273 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.RepositoryWatcher = void 0;
|
7
|
+
const chokidar_1 = __importDefault(require("chokidar"));
|
8
|
+
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
11
|
+
const yaml_1 = __importDefault(require("yaml"));
|
12
|
+
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
13
|
+
const lodash_1 = __importDefault(require("lodash"));
|
14
|
+
const socketManager_1 = require("./socketManager");
|
15
|
+
const definitionsManager_1 = require("./definitionsManager");
|
16
|
+
const assetManager_1 = require("./assetManager");
|
17
|
+
function clearAllCaches() {
|
18
|
+
definitionsManager_1.definitionsManager.clearCache();
|
19
|
+
assetManager_1.assetManager.clearCache();
|
20
|
+
}
|
21
|
+
const KAPETA_YML_RX = /^kapeta.ya?ml$/;
|
22
|
+
class RepositoryWatcher {
|
23
|
+
watcher;
|
24
|
+
disabled = false;
|
25
|
+
baseDir;
|
26
|
+
allDefinitions = [];
|
27
|
+
symbolicLinks = {};
|
28
|
+
ignoredFiles = new Set();
|
29
|
+
constructor() {
|
30
|
+
this.baseDir = local_cluster_config_1.default.getRepositoryBasedir();
|
31
|
+
}
|
32
|
+
setDisabled(disabled) {
|
33
|
+
this.disabled = disabled;
|
34
|
+
}
|
35
|
+
watch() {
|
36
|
+
if (!fs_extra_1.default.existsSync(this.baseDir)) {
|
37
|
+
fs_extra_1.default.mkdirpSync(this.baseDir);
|
38
|
+
}
|
39
|
+
this.allDefinitions = local_cluster_config_1.default.getDefinitions();
|
40
|
+
try {
|
41
|
+
this.watcher = chokidar_1.default.watch(this.baseDir, {
|
42
|
+
followSymlinks: false,
|
43
|
+
ignorePermissionErrors: true,
|
44
|
+
disableGlobbing: true,
|
45
|
+
persistent: true,
|
46
|
+
depth: 2,
|
47
|
+
ignored: (path) => this.ignoreFile(path),
|
48
|
+
});
|
49
|
+
this.watcher.on('all', this.handleFileChange.bind(this));
|
50
|
+
this.watcher.on('error', (error) => {
|
51
|
+
console.log('Error watching repository', error);
|
52
|
+
});
|
53
|
+
this.watcher.on('ready', () => {
|
54
|
+
console.log('Watching local repository for provider changes: %s', this.baseDir);
|
55
|
+
});
|
56
|
+
}
|
57
|
+
catch (e) {
|
58
|
+
// Fallback to run without watch mode due to potential platform issues.
|
59
|
+
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
60
|
+
console.log('Unable to watch for changes. Changes to assets will not update automatically.', e);
|
61
|
+
return;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
async ignoreChangesFor(file) {
|
65
|
+
this.ignoredFiles.add(file);
|
66
|
+
const realPath = await fs_extra_1.default.realpath(file);
|
67
|
+
if (realPath !== file) {
|
68
|
+
this.ignoredFiles.add(realPath);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
async resumeChangedFor(file) {
|
72
|
+
this.ignoredFiles.delete(file);
|
73
|
+
const realPath = await fs_extra_1.default.realpath(file);
|
74
|
+
if (realPath !== file) {
|
75
|
+
this.ignoredFiles.delete(realPath);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
async unwatch() {
|
79
|
+
if (!this.watcher) {
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
this.symbolicLinks = {};
|
83
|
+
await this.watcher.close();
|
84
|
+
this.watcher = undefined;
|
85
|
+
}
|
86
|
+
async getAssetIdentity(path) {
|
87
|
+
const baseName = node_path_1.default.basename(path);
|
88
|
+
let handle, name, version;
|
89
|
+
if (path.startsWith(this.baseDir)) {
|
90
|
+
const relativePath = node_path_1.default.relative(this.baseDir, path);
|
91
|
+
// Inside the repo we can use the path to determine the handle, name and version
|
92
|
+
[handle, name, version] = relativePath.split(/\//g);
|
93
|
+
if (!handle || !name || !version) {
|
94
|
+
// Do nothing with this
|
95
|
+
return;
|
96
|
+
}
|
97
|
+
return {
|
98
|
+
handle,
|
99
|
+
name,
|
100
|
+
version,
|
101
|
+
};
|
102
|
+
}
|
103
|
+
if (!KAPETA_YML_RX.test(baseName)) {
|
104
|
+
// Do nothing with this
|
105
|
+
return;
|
106
|
+
}
|
107
|
+
// Outside the repo we need to use the file content to determine the handle, name
|
108
|
+
// Version is always 'local'
|
109
|
+
version = 'local';
|
110
|
+
try {
|
111
|
+
const definition = yaml_1.default.parse((await fs_extra_1.default.readFile(path)).toString());
|
112
|
+
const uri = (0, nodejs_utils_1.parseKapetaUri)(definition.metadata.name);
|
113
|
+
handle = uri.handle;
|
114
|
+
name = uri.name;
|
115
|
+
return {
|
116
|
+
handle,
|
117
|
+
name,
|
118
|
+
version,
|
119
|
+
};
|
120
|
+
}
|
121
|
+
catch (e) {
|
122
|
+
// Ignore issues in the YML file
|
123
|
+
return;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
async handleFileChange(eventName, path) {
|
127
|
+
if (!path) {
|
128
|
+
return;
|
129
|
+
}
|
130
|
+
if (this.ignoredFiles.has(path)) {
|
131
|
+
return;
|
132
|
+
}
|
133
|
+
//console.log('File changed', eventName, path);
|
134
|
+
const assetIdentity = await this.getAssetIdentity(path);
|
135
|
+
if (!assetIdentity) {
|
136
|
+
return;
|
137
|
+
}
|
138
|
+
if (this.disabled) {
|
139
|
+
return;
|
140
|
+
}
|
141
|
+
// If this is false it's because we're watching a symlink target
|
142
|
+
const withinRepo = path.startsWith(this.baseDir);
|
143
|
+
if (withinRepo && assetIdentity.version === 'local' && path.endsWith('/local')) {
|
144
|
+
// This is likely a symlink target
|
145
|
+
if (eventName === 'add') {
|
146
|
+
//console.log('Checking if we should add symlink target', handle, name, version, path);
|
147
|
+
await this.addSymlinkTarget(path);
|
148
|
+
}
|
149
|
+
if (eventName === 'unlink') {
|
150
|
+
await this.removeSymlinkTarget(path);
|
151
|
+
}
|
152
|
+
if (eventName === 'change') {
|
153
|
+
await this.updateSymlinkTarget(path);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
await this.checkForChange(assetIdentity);
|
157
|
+
}
|
158
|
+
async checkForChange(assetIdentity) {
|
159
|
+
const ymlPath = node_path_1.default.join(this.baseDir, assetIdentity.handle, assetIdentity.name, assetIdentity.version, 'kapeta.yml');
|
160
|
+
const newDefinitions = local_cluster_config_1.default.getDefinitions();
|
161
|
+
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
162
|
+
let currentDefinition = this.allDefinitions.find((d) => d.ymlPath === ymlPath);
|
163
|
+
const ymlExists = await this.exists(ymlPath);
|
164
|
+
let type;
|
165
|
+
if (ymlExists) {
|
166
|
+
if (currentDefinition) {
|
167
|
+
if (newDefinition && lodash_1.default.isEqual(currentDefinition, newDefinition)) {
|
168
|
+
//Definition was not changed
|
169
|
+
return;
|
170
|
+
}
|
171
|
+
type = 'updated';
|
172
|
+
}
|
173
|
+
else if (newDefinition) {
|
174
|
+
type = 'added';
|
175
|
+
currentDefinition = newDefinition;
|
176
|
+
}
|
177
|
+
else {
|
178
|
+
//Other definition was added / updated - ignore
|
179
|
+
return;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
else {
|
183
|
+
if (currentDefinition) {
|
184
|
+
const ref = (0, nodejs_utils_1.parseKapetaUri)(`${currentDefinition.definition.metadata.name}:${currentDefinition.version}`).id;
|
185
|
+
//Something was removed
|
186
|
+
type = 'removed';
|
187
|
+
}
|
188
|
+
else {
|
189
|
+
//Other definition was removed - ignore
|
190
|
+
return;
|
191
|
+
}
|
192
|
+
}
|
193
|
+
const payload = {
|
194
|
+
type,
|
195
|
+
definition: newDefinition?.definition ?? currentDefinition?.definition,
|
196
|
+
asset: assetIdentity,
|
197
|
+
};
|
198
|
+
this.allDefinitions = newDefinitions;
|
199
|
+
//console.log('Asset changed', payload);
|
200
|
+
socketManager_1.socketManager.emitGlobal('asset-change', payload);
|
201
|
+
clearAllCaches();
|
202
|
+
}
|
203
|
+
async exists(path) {
|
204
|
+
try {
|
205
|
+
await fs_extra_1.default.access(path);
|
206
|
+
return true;
|
207
|
+
}
|
208
|
+
catch (e) {
|
209
|
+
return false;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
async removeSymlinkTarget(path) {
|
213
|
+
if (this.symbolicLinks[path]) {
|
214
|
+
//console.log('Unwatching symlink target %s => %s', path, this.symbolicLinks[path]);
|
215
|
+
this.watcher?.unwatch(this.symbolicLinks[path]);
|
216
|
+
delete this.symbolicLinks[path];
|
217
|
+
}
|
218
|
+
}
|
219
|
+
async updateSymlinkTarget(path) {
|
220
|
+
if (this.symbolicLinks[path]) {
|
221
|
+
//console.log('Updating symlink target %s => %s', path, this.symbolicLinks[path]);
|
222
|
+
this.watcher?.unwatch(this.symbolicLinks[path]);
|
223
|
+
delete this.symbolicLinks[path];
|
224
|
+
await this.addSymlinkTarget(path);
|
225
|
+
}
|
226
|
+
}
|
227
|
+
async addSymlinkTarget(path) {
|
228
|
+
try {
|
229
|
+
// Make sure we're not watching the symlink target
|
230
|
+
await this.removeSymlinkTarget(path);
|
231
|
+
const stat = await fs_extra_1.default.lstat(path);
|
232
|
+
if (stat.isSymbolicLink()) {
|
233
|
+
const realPath = `${await fs_extra_1.default.realpath(path)}/kapeta.yml`;
|
234
|
+
if (await this.exists(realPath)) {
|
235
|
+
//console.log('Watching symlink target %s => %s', path, realPath);
|
236
|
+
this.watcher?.add(realPath);
|
237
|
+
this.symbolicLinks[path] = realPath;
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
catch (e) {
|
242
|
+
// Ignore
|
243
|
+
console.warn('Failed to check local symlink target', e);
|
244
|
+
}
|
245
|
+
}
|
246
|
+
ignoreFile(path) {
|
247
|
+
if (!path.startsWith(this.baseDir)) {
|
248
|
+
return false;
|
249
|
+
}
|
250
|
+
if (path.includes('/node_modules/')) {
|
251
|
+
return true;
|
252
|
+
}
|
253
|
+
const filename = node_path_1.default.basename(path);
|
254
|
+
if (filename.startsWith('.')) {
|
255
|
+
return true;
|
256
|
+
}
|
257
|
+
const relativePath = node_path_1.default.relative(this.baseDir, path).split(node_path_1.default.sep);
|
258
|
+
try {
|
259
|
+
if (fs_extra_1.default.statSync(path).isDirectory()) {
|
260
|
+
if (relativePath.length > 3) {
|
261
|
+
return true;
|
262
|
+
}
|
263
|
+
return false;
|
264
|
+
}
|
265
|
+
}
|
266
|
+
catch (e) {
|
267
|
+
// Didn't exist - dont ignore
|
268
|
+
return false;
|
269
|
+
}
|
270
|
+
return !/^kapeta\.ya?ml$/.test(filename);
|
271
|
+
}
|
272
|
+
}
|
273
|
+
exports.RepositoryWatcher = RepositoryWatcher;
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.assetManager = void 0;
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
8
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
9
8
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
10
9
|
const yaml_1 = __importDefault(require("yaml"));
|
11
10
|
const node_cache_1 = __importDefault(require("node-cache"));
|
@@ -17,6 +16,10 @@ const nodejs_registry_utils_1 = require("@kapeta/nodejs-registry-utils");
|
|
17
16
|
const definitionsManager_1 = require("./definitionsManager");
|
18
17
|
const utils_1 = require("./utils/utils");
|
19
18
|
const taskManager_1 = require("./taskManager");
|
19
|
+
function clearAllCaches() {
|
20
|
+
definitionsManager_1.definitionsManager.clearCache();
|
21
|
+
exports.assetManager.clearCache();
|
22
|
+
}
|
20
23
|
function enrichAsset(asset) {
|
21
24
|
return {
|
22
25
|
ref: `kapeta://${asset.definition.metadata.name}:${asset.version}`,
|
@@ -103,19 +106,16 @@ class AssetManager {
|
|
103
106
|
return asset;
|
104
107
|
}
|
105
108
|
async createAsset(path, yaml) {
|
106
|
-
if (
|
109
|
+
if (await fs_extra_1.default.pathExists(path)) {
|
107
110
|
throw new Error('File already exists: ' + path);
|
108
111
|
}
|
109
112
|
const dirName = node_path_1.default.dirname(path);
|
110
|
-
if (!
|
111
|
-
fs_extra_1.default.
|
113
|
+
if (!(await fs_extra_1.default.pathExists(dirName))) {
|
114
|
+
await fs_extra_1.default.mkdirp(dirName);
|
112
115
|
}
|
113
|
-
|
114
|
-
node_fs_1.default.writeFileSync(path, yaml_1.default.stringify(yaml));
|
116
|
+
await fs_extra_1.default.writeFile(path, yaml_1.default.stringify(yaml));
|
115
117
|
const asset = await this.importFile(path);
|
116
|
-
|
117
|
-
this.cache.flushAll();
|
118
|
-
definitionsManager_1.definitionsManager.clearCache();
|
118
|
+
clearAllCaches();
|
119
119
|
const ref = `kapeta://${yaml.metadata.name}:local`;
|
120
120
|
this.maybeGenerateCode(ref, path, yaml);
|
121
121
|
return asset;
|
@@ -131,11 +131,23 @@ class AssetManager {
|
|
131
131
|
if (!asset.ymlPath) {
|
132
132
|
throw new Error('Attempted to update corrupted asset: ' + ref);
|
133
133
|
}
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
134
|
+
const path = asset.ymlPath;
|
135
|
+
try {
|
136
|
+
await repositoryManager_1.repositoryManager.ignoreChangesFor(path);
|
137
|
+
await fs_extra_1.default.writeFile(asset.ymlPath, yaml_1.default.stringify(yaml));
|
138
|
+
console.log('Wrote to ' + asset.ymlPath);
|
139
|
+
clearAllCaches();
|
140
|
+
this.maybeGenerateCode(asset.ref, asset.ymlPath, yaml);
|
141
|
+
}
|
142
|
+
finally {
|
143
|
+
//We need to wait a bit for the disk to settle before we can resume watching
|
144
|
+
setTimeout(async () => {
|
145
|
+
try {
|
146
|
+
await repositoryManager_1.repositoryManager.resumeChangedFor(path);
|
147
|
+
}
|
148
|
+
catch (e) { }
|
149
|
+
}, 500);
|
150
|
+
}
|
139
151
|
}
|
140
152
|
maybeGenerateCode(ref, ymlPath, block) {
|
141
153
|
ref = (0, utils_1.normalizeKapetaUri)(ref);
|
@@ -154,14 +166,15 @@ class AssetManager {
|
|
154
166
|
if (filePath.startsWith('file://')) {
|
155
167
|
filePath = filePath.substring('file://'.length);
|
156
168
|
}
|
157
|
-
if (!
|
169
|
+
if (!(await fs_extra_1.default.pathExists(filePath))) {
|
158
170
|
throw new Error('File not found: ' + filePath);
|
159
171
|
}
|
160
|
-
const
|
161
|
-
|
172
|
+
const content = await fs_extra_1.default.readFile(filePath);
|
173
|
+
const assetInfos = yaml_1.default.parseAllDocuments(content.toString()).map((doc) => doc.toJSON());
|
174
|
+
await nodejs_registry_utils_1.Actions.link(new progressListener_1.ProgressListener(), node_path_1.default.dirname(filePath));
|
162
175
|
const version = 'local';
|
163
176
|
const refs = assetInfos.map((assetInfo) => `kapeta://${assetInfo.metadata.name}:${version}`);
|
164
|
-
|
177
|
+
clearAllCaches();
|
165
178
|
return this.getAssets().filter((a) => refs.some((ref) => compareRefs(ref, a.ref)));
|
166
179
|
}
|
167
180
|
async unregisterAsset(ref) {
|
@@ -169,8 +182,8 @@ class AssetManager {
|
|
169
182
|
if (!asset) {
|
170
183
|
throw new Error('Asset does not exists: ' + ref);
|
171
184
|
}
|
172
|
-
|
173
|
-
await nodejs_registry_utils_1.Actions.uninstall(progressListener_1.
|
185
|
+
clearAllCaches();
|
186
|
+
await nodejs_registry_utils_1.Actions.uninstall(new progressListener_1.ProgressListener(), [asset.ref]);
|
174
187
|
}
|
175
188
|
async installAsset(ref) {
|
176
189
|
const asset = await this.getAsset(ref, true, false);
|
@@ -17,7 +17,6 @@ const md5_1 = __importDefault(require("md5"));
|
|
17
17
|
const utils_1 = require("./utils/utils");
|
18
18
|
const nodejs_api_client_1 = require("@kapeta/nodejs-api-client");
|
19
19
|
const taskManager_1 = require("./taskManager");
|
20
|
-
const EVENT_IMAGE_PULL = 'docker-image-pull';
|
21
20
|
exports.CONTAINER_LABEL_PORT_PREFIX = 'kapeta_port-';
|
22
21
|
const NANO_SECOND = 1000000;
|
23
22
|
const HEALTH_CHECK_INTERVAL = 3000;
|
@@ -7,10 +7,10 @@ const express_promise_router_1 = __importDefault(require("express-promise-router
|
|
7
7
|
const nodejs_api_client_1 = require("@kapeta/nodejs-api-client");
|
8
8
|
const cors_1 = require("../middleware/cors");
|
9
9
|
const router = (0, express_promise_router_1.default)();
|
10
|
-
const api = new nodejs_api_client_1.KapetaAPI();
|
11
10
|
router.use('/', cors_1.corsHandler);
|
12
11
|
router.get('/current', async (req, res) => {
|
13
12
|
try {
|
13
|
+
const api = new nodejs_api_client_1.KapetaAPI();
|
14
14
|
if (api.hasToken()) {
|
15
15
|
res.send(await api.getCurrentIdentity());
|
16
16
|
}
|
@@ -24,6 +24,7 @@ router.get('/current', async (req, res) => {
|
|
24
24
|
});
|
25
25
|
router.get('/:identityId/memberships', async (req, res) => {
|
26
26
|
try {
|
27
|
+
const api = new nodejs_api_client_1.KapetaAPI();
|
27
28
|
if (api.hasToken()) {
|
28
29
|
res.send(await api.getMemberships(req.params.identityId));
|
29
30
|
}
|
@@ -22,10 +22,6 @@ const definitionsManager_1 = require("./definitionsManager");
|
|
22
22
|
const taskManager_1 = require("./taskManager");
|
23
23
|
const CHECK_INTERVAL = 5000;
|
24
24
|
const DEFAULT_HEALTH_PORT_TYPE = 'rest';
|
25
|
-
const EVENT_STATUS_CHANGED = 'status-changed';
|
26
|
-
const EVENT_INSTANCE_CREATED = 'instance-created';
|
27
|
-
const EVENT_INSTANCE_EXITED = 'instance-exited';
|
28
|
-
const EVENT_INSTANCE_LOG = 'instance-log';
|
29
25
|
const MIN_TIME_RUNNING = 30000; //If something didnt run for more than 30 secs - it failed
|
30
26
|
class InstanceManager {
|
31
27
|
_interval = undefined;
|
@@ -61,7 +57,10 @@ class InstanceManager {
|
|
61
57
|
return [];
|
62
58
|
}
|
63
59
|
const plan = planInfo.definition;
|
64
|
-
|
60
|
+
if (!plan?.spec?.blocks) {
|
61
|
+
return [];
|
62
|
+
}
|
63
|
+
const instanceIds = plan.spec?.blocks?.map((block) => block.id) || [];
|
65
64
|
return this._instances.filter((instance) => instance.systemId === systemId && instanceIds.includes(instance.instanceId));
|
66
65
|
}
|
67
66
|
getInstance(systemId, instanceId) {
|
@@ -121,11 +120,11 @@ class InstanceManager {
|
|
121
120
|
if (existingInstance) {
|
122
121
|
const ix = this._instances.indexOf(existingInstance);
|
123
122
|
this._instances.splice(ix, 1, instance);
|
124
|
-
|
123
|
+
socketManager_1.socketManager.emitSystemEvent(instance.systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
125
124
|
}
|
126
125
|
else {
|
127
126
|
this._instances.push(instance);
|
128
|
-
|
127
|
+
socketManager_1.socketManager.emitSystemEvent(instance.systemId, socketManager_1.EVENT_INSTANCE_CREATED, instance);
|
129
128
|
}
|
130
129
|
this.save();
|
131
130
|
return instance;
|
@@ -168,7 +167,7 @@ class InstanceManager {
|
|
168
167
|
if (healthUrl) {
|
169
168
|
instance.health = healthUrl;
|
170
169
|
}
|
171
|
-
|
170
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
172
171
|
}
|
173
172
|
else {
|
174
173
|
//If instance was not found - then we're receiving an externally started instance
|
@@ -184,7 +183,7 @@ class InstanceManager {
|
|
184
183
|
address,
|
185
184
|
};
|
186
185
|
this._instances.push(instance);
|
187
|
-
|
186
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_INSTANCE_CREATED, instance);
|
188
187
|
}
|
189
188
|
this.save();
|
190
189
|
return instance;
|
@@ -209,7 +208,7 @@ class InstanceManager {
|
|
209
208
|
instance.status = types_1.InstanceStatus.STOPPED;
|
210
209
|
instance.pid = null;
|
211
210
|
instance.health = null;
|
212
|
-
|
211
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
213
212
|
this.save();
|
214
213
|
}
|
215
214
|
});
|
@@ -267,7 +266,7 @@ class InstanceManager {
|
|
267
266
|
instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
|
268
267
|
}
|
269
268
|
instance.status = types_1.InstanceStatus.STOPPING;
|
270
|
-
|
269
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
271
270
|
console.log('Stopping instance: %s::%s [desired: %s]', systemId, instanceId, instance.desiredStatus);
|
272
271
|
this.save();
|
273
272
|
try {
|
@@ -278,7 +277,7 @@ class InstanceManager {
|
|
278
277
|
try {
|
279
278
|
await container.stop();
|
280
279
|
instance.status = types_1.InstanceStatus.STOPPED;
|
281
|
-
|
280
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
282
281
|
this.save();
|
283
282
|
}
|
284
283
|
catch (e) {
|
@@ -297,7 +296,7 @@ class InstanceManager {
|
|
297
296
|
}
|
298
297
|
process.kill(instance.pid, 'SIGTERM');
|
299
298
|
instance.status = types_1.InstanceStatus.STOPPED;
|
300
|
-
|
299
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
301
300
|
this.save();
|
302
301
|
}
|
303
302
|
catch (e) {
|
@@ -422,10 +421,10 @@ class InstanceManager {
|
|
422
421
|
status: types_1.InstanceStatus.FAILED,
|
423
422
|
errorMessage: e.message ?? 'Failed to start - Check logs for details.',
|
424
423
|
});
|
425
|
-
|
426
|
-
|
424
|
+
socketManager_1.socketManager.emitInstanceLog(systemId, instanceId, logs[0]);
|
425
|
+
socketManager_1.socketManager.emitInstanceEvent(systemId, blockInstance.id, socketManager_1.EVENT_INSTANCE_EXITED, {
|
427
426
|
error: `Failed to start instance: ${e.message}`,
|
428
|
-
status: EVENT_INSTANCE_EXITED,
|
427
|
+
status: socketManager_1.EVENT_INSTANCE_EXITED,
|
429
428
|
instanceId: blockInstance.id,
|
430
429
|
});
|
431
430
|
return out;
|
@@ -512,7 +511,7 @@ class InstanceManager {
|
|
512
511
|
const oldStatus = instance.status;
|
513
512
|
instance.status = newStatus;
|
514
513
|
console.log('Instance status changed: %s %s: %s -> %s', instance.systemId, instance.instanceId, oldStatus, instance.status);
|
515
|
-
|
514
|
+
socketManager_1.socketManager.emitSystemEvent(instance.systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
516
515
|
changed = true;
|
517
516
|
}
|
518
517
|
}
|
@@ -644,24 +643,6 @@ class InstanceManager {
|
|
644
643
|
});
|
645
644
|
});
|
646
645
|
}
|
647
|
-
emitSystemEvent(systemId, type, payload) {
|
648
|
-
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
649
|
-
try {
|
650
|
-
socketManager_1.socketManager.emit(`${systemId}/instances`, type, payload);
|
651
|
-
}
|
652
|
-
catch (e) {
|
653
|
-
console.warn('Failed to emit instance event: %s', e.message);
|
654
|
-
}
|
655
|
-
}
|
656
|
-
emitInstanceEvent(systemId, instanceId, type, payload) {
|
657
|
-
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
658
|
-
try {
|
659
|
-
socketManager_1.socketManager.emit(`${systemId}/instances/${instanceId}`, type, payload);
|
660
|
-
}
|
661
|
-
catch (e) {
|
662
|
-
console.warn('Failed to emit instance event: %s', e.message);
|
663
|
-
}
|
664
|
-
}
|
665
646
|
}
|
666
647
|
exports.InstanceManager = InstanceManager;
|
667
648
|
exports.instanceManager = new InstanceManager();
|
@@ -1,8 +1,9 @@
|
|
1
1
|
/// <reference types="node" />
|
2
|
-
|
3
|
-
|
4
|
-
private
|
5
|
-
constructor(
|
2
|
+
export declare class ProgressListener {
|
3
|
+
private readonly systemId;
|
4
|
+
private readonly instanceId;
|
5
|
+
constructor(systemId?: string, instanceId?: string);
|
6
|
+
private emitLog;
|
6
7
|
run(command: string, directory?: string): Promise<{
|
7
8
|
exit: number;
|
8
9
|
signal: NodeJS.Signals | null;
|
@@ -17,5 +18,3 @@ declare class ProgressListener {
|
|
17
18
|
info(msg: string, ...args: any[]): void;
|
18
19
|
debug(msg: string, ...args: any[]): void;
|
19
20
|
}
|
20
|
-
export declare const progressListener: ProgressListener;
|
21
|
-
export {};
|