@kapeta/local-cluster-service 0.16.7 → 0.17.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 +20 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/src/instanceManager.js +30 -0
- package/dist/cjs/src/socketManager.js +6 -0
- package/dist/cjs/src/utils/DefaultProviderInstaller.d.ts +11 -0
- package/dist/cjs/src/utils/DefaultProviderInstaller.js +129 -0
- package/dist/esm/index.js +64 -57
- package/dist/esm/src/RepositoryWatcher.js +40 -33
- package/dist/esm/src/api.js +14 -9
- package/dist/esm/src/assetManager.js +62 -56
- package/dist/esm/src/assets/routes.js +22 -17
- package/dist/esm/src/attachments/routes.js +14 -9
- package/dist/esm/src/cacheManager.js +13 -5
- package/dist/esm/src/clusterService.js +6 -3
- package/dist/esm/src/codeGeneratorManager.js +19 -13
- package/dist/esm/src/config/routes.js +30 -25
- package/dist/esm/src/configManager.js +29 -26
- package/dist/esm/src/containerManager.js +48 -39
- package/dist/esm/src/definitionsManager.js +15 -9
- package/dist/esm/src/filesystem/routes.js +21 -16
- package/dist/esm/src/filesystemManager.js +23 -17
- package/dist/esm/src/identities/routes.js +13 -8
- package/dist/esm/src/instanceManager.js +186 -149
- package/dist/esm/src/instances/routes.js +38 -33
- package/dist/esm/src/middleware/cors.js +5 -1
- package/dist/esm/src/middleware/kapeta.js +8 -4
- package/dist/esm/src/middleware/stringBody.js +5 -1
- package/dist/esm/src/networkManager.js +15 -9
- package/dist/esm/src/operatorManager.js +45 -39
- package/dist/esm/src/progressListener.js +16 -12
- package/dist/esm/src/providerManager.js +22 -16
- package/dist/esm/src/providers/routes.js +14 -9
- package/dist/esm/src/proxy/routes.js +26 -21
- package/dist/esm/src/proxy/types/rest.js +29 -22
- package/dist/esm/src/proxy/types/web.js +18 -11
- package/dist/esm/src/repositoryManager.js +28 -22
- package/dist/esm/src/serviceManager.js +25 -19
- package/dist/esm/src/socketManager.js +31 -18
- package/dist/esm/src/storageService.js +18 -12
- package/dist/esm/src/taskManager.js +12 -8
- package/dist/esm/src/tasks/routes.js +14 -9
- package/dist/esm/src/traffic/routes.js +12 -7
- package/dist/esm/src/types.js +11 -8
- package/dist/esm/src/utils/BlockInstanceRunner.js +57 -50
- package/dist/esm/src/utils/DefaultProviderInstaller.d.ts +11 -0
- package/dist/esm/src/utils/DefaultProviderInstaller.js +129 -0
- package/dist/esm/src/utils/LogData.js +5 -1
- package/dist/esm/src/utils/commandLineUtils.js +12 -7
- package/dist/esm/src/utils/pathTemplateParser.js +7 -2
- package/dist/esm/src/utils/utils.js +30 -17
- package/dist/esm/start.js +7 -2
- package/index.ts +3 -0
- package/package.json +10 -4
- package/src/instanceManager.ts +34 -8
- package/src/socketManager.ts +6 -0
- package/src/utils/DefaultProviderInstaller.ts +141 -0
- package/tsconfig.json +3 -2
@@ -1,28 +1,34 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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.instanceManager = exports.InstanceManager = void 0;
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
8
|
+
const request_1 = __importDefault(require("request"));
|
9
|
+
const async_lock_1 = __importDefault(require("async-lock"));
|
10
|
+
const BlockInstanceRunner_1 = require("./utils/BlockInstanceRunner");
|
11
|
+
const storageService_1 = require("./storageService");
|
12
|
+
const socketManager_1 = require("./socketManager");
|
13
|
+
const serviceManager_1 = require("./serviceManager");
|
14
|
+
const assetManager_1 = require("./assetManager");
|
15
|
+
const containerManager_1 = require("./containerManager");
|
16
|
+
const configManager_1 = require("./configManager");
|
17
|
+
const types_1 = require("./types");
|
18
|
+
const utils_1 = require("./utils/utils");
|
19
|
+
const operatorManager_1 = require("./operatorManager");
|
20
|
+
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
21
|
+
const definitionsManager_1 = require("./definitionsManager");
|
22
|
+
const taskManager_1 = require("./taskManager");
|
17
23
|
const CHECK_INTERVAL = 5000;
|
18
24
|
const DEFAULT_HEALTH_PORT_TYPE = 'rest';
|
19
25
|
const MIN_TIME_RUNNING = 30000; //If something didnt run for more than 30 secs - it failed
|
20
|
-
|
26
|
+
class InstanceManager {
|
21
27
|
_interval = undefined;
|
22
28
|
_instances = [];
|
23
|
-
instanceLocks = new
|
29
|
+
instanceLocks = new async_lock_1.default();
|
24
30
|
constructor() {
|
25
|
-
this._instances = storageService.section('instances', []);
|
31
|
+
this._instances = storageService_1.storageService.section('instances', []);
|
26
32
|
// We need to wait a bit before running the first check
|
27
33
|
this.checkInstancesLater(1000);
|
28
34
|
}
|
@@ -45,8 +51,8 @@ export class InstanceManager {
|
|
45
51
|
if (!this._instances) {
|
46
52
|
return [];
|
47
53
|
}
|
48
|
-
systemId = normalizeKapetaUri(systemId);
|
49
|
-
const planInfo = definitionsManager.getDefinition(systemId);
|
54
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
55
|
+
const planInfo = definitionsManager_1.definitionsManager.getDefinition(systemId);
|
50
56
|
if (!planInfo) {
|
51
57
|
return [];
|
52
58
|
}
|
@@ -58,11 +64,11 @@ export class InstanceManager {
|
|
58
64
|
return this._instances.filter((instance) => instance.systemId === systemId && instanceIds.includes(instance.instanceId));
|
59
65
|
}
|
60
66
|
getInstance(systemId, instanceId) {
|
61
|
-
systemId = normalizeKapetaUri(systemId);
|
67
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
62
68
|
return this._instances.find((i) => i.systemId === systemId && i.instanceId === instanceId);
|
63
69
|
}
|
64
70
|
async exclusive(systemId, instanceId, fn) {
|
65
|
-
systemId = normalizeKapetaUri(systemId);
|
71
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
66
72
|
const key = `${systemId}/${instanceId}`;
|
67
73
|
//console.log(`Acquiring lock for ${key}`, this.instanceLocks.isBusy(key));
|
68
74
|
const result = await this.instanceLocks.acquire(key, fn);
|
@@ -75,9 +81,9 @@ export class InstanceManager {
|
|
75
81
|
throw new Error(`Instance ${systemId}/${instanceId} not found`);
|
76
82
|
}
|
77
83
|
switch (instance.type) {
|
78
|
-
case InstanceType.DOCKER:
|
79
|
-
return await containerManager.getLogs(instance);
|
80
|
-
case InstanceType.UNKNOWN:
|
84
|
+
case types_1.InstanceType.DOCKER:
|
85
|
+
return await containerManager_1.containerManager.getLogs(instance);
|
86
|
+
case types_1.InstanceType.UNKNOWN:
|
81
87
|
return [
|
82
88
|
{
|
83
89
|
level: 'INFO',
|
@@ -86,7 +92,7 @@ export class InstanceManager {
|
|
86
92
|
source: 'stdout',
|
87
93
|
},
|
88
94
|
];
|
89
|
-
case InstanceType.LOCAL:
|
95
|
+
case types_1.InstanceType.LOCAL:
|
90
96
|
return [
|
91
97
|
{
|
92
98
|
level: 'INFO',
|
@@ -99,12 +105,12 @@ export class InstanceManager {
|
|
99
105
|
return [];
|
100
106
|
}
|
101
107
|
async saveInternalInstance(instance) {
|
102
|
-
instance.systemId = normalizeKapetaUri(instance.systemId);
|
108
|
+
instance.systemId = (0, utils_1.normalizeKapetaUri)(instance.systemId);
|
103
109
|
if (instance.ref) {
|
104
|
-
instance.ref = normalizeKapetaUri(instance.ref);
|
110
|
+
instance.ref = (0, utils_1.normalizeKapetaUri)(instance.ref);
|
105
111
|
}
|
106
112
|
//Get target address
|
107
|
-
let address = await serviceManager.getProviderAddress(instance.systemId, instance.instanceId, instance.portType ?? DEFAULT_HEALTH_PORT_TYPE);
|
113
|
+
let address = await serviceManager_1.serviceManager.getProviderAddress(instance.systemId, instance.instanceId, instance.portType ?? DEFAULT_HEALTH_PORT_TYPE);
|
108
114
|
const healthUrl = this.getHealthUrl(instance, address);
|
109
115
|
instance.address = address;
|
110
116
|
if (healthUrl) {
|
@@ -114,11 +120,11 @@ export class InstanceManager {
|
|
114
120
|
if (existingInstance) {
|
115
121
|
const ix = this._instances.indexOf(existingInstance);
|
116
122
|
this._instances.splice(ix, 1, instance);
|
117
|
-
socketManager.emitSystemEvent(instance.systemId, EVENT_STATUS_CHANGED, instance);
|
123
|
+
socketManager_1.socketManager.emitSystemEvent(instance.systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
118
124
|
}
|
119
125
|
else {
|
120
126
|
this._instances.push(instance);
|
121
|
-
socketManager.emitSystemEvent(instance.systemId, EVENT_INSTANCE_CREATED, instance);
|
127
|
+
socketManager_1.socketManager.emitSystemEvent(instance.systemId, socketManager_1.EVENT_INSTANCE_CREATED, instance);
|
122
128
|
}
|
123
129
|
this.save();
|
124
130
|
return instance;
|
@@ -129,28 +135,28 @@ export class InstanceManager {
|
|
129
135
|
*/
|
130
136
|
async registerInstanceFromSDK(systemId, instanceId, info) {
|
131
137
|
return this.exclusive(systemId, instanceId, async () => {
|
132
|
-
systemId = normalizeKapetaUri(systemId);
|
138
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
133
139
|
let instance = this.getInstance(systemId, instanceId);
|
134
140
|
//Get target address
|
135
|
-
const address = await serviceManager.getProviderAddress(systemId, instanceId, info.portType ?? DEFAULT_HEALTH_PORT_TYPE);
|
141
|
+
const address = await serviceManager_1.serviceManager.getProviderAddress(systemId, instanceId, info.portType ?? DEFAULT_HEALTH_PORT_TYPE);
|
136
142
|
const healthUrl = this.getHealthUrl(info, address);
|
137
143
|
if (instance) {
|
138
|
-
if (instance.status === InstanceStatus.STOPPING &&
|
139
|
-
instance.desiredStatus === DesiredInstanceStatus.STOP) {
|
144
|
+
if (instance.status === types_1.InstanceStatus.STOPPING &&
|
145
|
+
instance.desiredStatus === types_1.DesiredInstanceStatus.STOP) {
|
140
146
|
//If instance is stopping do not interfere
|
141
147
|
return;
|
142
148
|
}
|
143
|
-
if (info.owner === InstanceOwner.EXTERNAL) {
|
149
|
+
if (info.owner === types_1.InstanceOwner.EXTERNAL) {
|
144
150
|
//If instance was started externally - then we want to replace the internal instance with that
|
145
|
-
if (instance.owner === InstanceOwner.INTERNAL &&
|
146
|
-
(instance.status === InstanceStatus.READY ||
|
147
|
-
instance.status === InstanceStatus.STARTING ||
|
148
|
-
instance.status === InstanceStatus.UNHEALTHY)) {
|
151
|
+
if (instance.owner === types_1.InstanceOwner.INTERNAL &&
|
152
|
+
(instance.status === types_1.InstanceStatus.READY ||
|
153
|
+
instance.status === types_1.InstanceStatus.STARTING ||
|
154
|
+
instance.status === types_1.InstanceStatus.UNHEALTHY)) {
|
149
155
|
throw new Error(`Instance ${instanceId} is already running`);
|
150
156
|
}
|
151
157
|
instance.desiredStatus = info.desiredStatus;
|
152
158
|
instance.owner = info.owner;
|
153
|
-
instance.status = InstanceStatus.STARTING;
|
159
|
+
instance.status = types_1.InstanceStatus.STARTING;
|
154
160
|
instance.startedAt = Date.now();
|
155
161
|
}
|
156
162
|
instance.pid = info.pid;
|
@@ -161,7 +167,7 @@ export class InstanceManager {
|
|
161
167
|
if (healthUrl) {
|
162
168
|
instance.health = healthUrl;
|
163
169
|
}
|
164
|
-
socketManager.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
170
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
165
171
|
}
|
166
172
|
else {
|
167
173
|
//If instance was not found - then we're receiving an externally started instance
|
@@ -169,15 +175,15 @@ export class InstanceManager {
|
|
169
175
|
...info,
|
170
176
|
systemId,
|
171
177
|
instanceId,
|
172
|
-
status: InstanceStatus.STARTING,
|
178
|
+
status: types_1.InstanceStatus.STARTING,
|
173
179
|
startedAt: Date.now(),
|
174
|
-
desiredStatus: DesiredInstanceStatus.EXTERNAL,
|
175
|
-
owner: InstanceOwner.EXTERNAL,
|
180
|
+
desiredStatus: types_1.DesiredInstanceStatus.EXTERNAL,
|
181
|
+
owner: types_1.InstanceOwner.EXTERNAL,
|
176
182
|
health: healthUrl,
|
177
183
|
address,
|
178
184
|
};
|
179
185
|
this._instances.push(instance);
|
180
|
-
socketManager.emitSystemEvent(systemId, EVENT_INSTANCE_CREATED, instance);
|
186
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_INSTANCE_CREATED, instance);
|
181
187
|
}
|
182
188
|
this.save();
|
183
189
|
return instance;
|
@@ -196,33 +202,33 @@ export class InstanceManager {
|
|
196
202
|
}
|
197
203
|
markAsStopped(systemId, instanceId) {
|
198
204
|
return this.exclusive(systemId, instanceId, async () => {
|
199
|
-
systemId = normalizeKapetaUri(systemId);
|
200
|
-
const instance =
|
201
|
-
if (instance && instance.owner === InstanceOwner.EXTERNAL && instance.status !== InstanceStatus.STOPPED) {
|
202
|
-
instance.status = InstanceStatus.STOPPED;
|
205
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
206
|
+
const instance = lodash_1.default.find(this._instances, { systemId, instanceId });
|
207
|
+
if (instance && instance.owner === types_1.InstanceOwner.EXTERNAL && instance.status !== types_1.InstanceStatus.STOPPED) {
|
208
|
+
instance.status = types_1.InstanceStatus.STOPPED;
|
203
209
|
instance.pid = null;
|
204
210
|
instance.health = null;
|
205
|
-
socketManager.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
211
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
206
212
|
this.save();
|
207
213
|
}
|
208
214
|
});
|
209
215
|
}
|
210
216
|
async startAllForPlan(systemId) {
|
211
|
-
systemId = normalizeKapetaUri(systemId);
|
212
|
-
const plan = await assetManager.getPlan(systemId, true);
|
217
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
218
|
+
const plan = await assetManager_1.assetManager.getPlan(systemId, true);
|
213
219
|
if (!plan) {
|
214
220
|
throw new Error(`Plan not found: ${systemId}`);
|
215
221
|
}
|
216
222
|
if (!plan.spec.blocks) {
|
217
223
|
throw new Error(`No blocks found in plan: ${systemId}`);
|
218
224
|
}
|
219
|
-
return taskManager.add(`plan:start:${systemId}`, async () => {
|
225
|
+
return taskManager_1.taskManager.add(`plan:start:${systemId}`, async () => {
|
220
226
|
let promises = [];
|
221
227
|
let errors = [];
|
222
228
|
for (let blockInstance of Object.values(plan.spec.blocks)) {
|
223
229
|
try {
|
224
230
|
promises.push(this.start(systemId, blockInstance.id).then((taskOrInstance) => {
|
225
|
-
if (taskOrInstance instanceof Task) {
|
231
|
+
if (taskOrInstance instanceof taskManager_1.Task) {
|
226
232
|
return taskOrInstance.wait();
|
227
233
|
}
|
228
234
|
return taskOrInstance;
|
@@ -248,30 +254,30 @@ export class InstanceManager {
|
|
248
254
|
}
|
249
255
|
async stopInner(systemId, instanceId, changeDesired = false) {
|
250
256
|
return this.exclusive(systemId, instanceId, async () => {
|
251
|
-
systemId = normalizeKapetaUri(systemId);
|
257
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
252
258
|
const instance = this.getInstance(systemId, instanceId);
|
253
259
|
if (!instance) {
|
254
260
|
return;
|
255
261
|
}
|
256
|
-
if (instance.status === InstanceStatus.STOPPED) {
|
262
|
+
if (instance.status === types_1.InstanceStatus.STOPPED) {
|
257
263
|
return;
|
258
264
|
}
|
259
|
-
if (changeDesired && instance.desiredStatus !== DesiredInstanceStatus.EXTERNAL) {
|
260
|
-
instance.desiredStatus = DesiredInstanceStatus.STOP;
|
265
|
+
if (changeDesired && instance.desiredStatus !== types_1.DesiredInstanceStatus.EXTERNAL) {
|
266
|
+
instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
|
261
267
|
}
|
262
|
-
instance.status = InstanceStatus.STOPPING;
|
263
|
-
socketManager.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
268
|
+
instance.status = types_1.InstanceStatus.STOPPING;
|
269
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
264
270
|
console.log('Stopping instance: %s::%s [desired: %s]', systemId, instanceId, instance.desiredStatus);
|
265
271
|
this.save();
|
266
272
|
try {
|
267
273
|
if (instance.type === 'docker') {
|
268
|
-
const containerName = getBlockInstanceContainerName(instance.systemId, instance.instanceId);
|
269
|
-
const container = await containerManager.getContainerByName(containerName);
|
274
|
+
const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.systemId, instance.instanceId);
|
275
|
+
const container = await containerManager_1.containerManager.getContainerByName(containerName);
|
270
276
|
if (container) {
|
271
277
|
try {
|
272
278
|
await container.stop();
|
273
|
-
instance.status = InstanceStatus.STOPPED;
|
274
|
-
socketManager.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
279
|
+
instance.status = types_1.InstanceStatus.STOPPED;
|
280
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
275
281
|
this.save();
|
276
282
|
}
|
277
283
|
catch (e) {
|
@@ -284,13 +290,13 @@ export class InstanceManager {
|
|
284
290
|
return;
|
285
291
|
}
|
286
292
|
if (!instance.pid) {
|
287
|
-
instance.status = InstanceStatus.STOPPED;
|
293
|
+
instance.status = types_1.InstanceStatus.STOPPED;
|
288
294
|
this.save();
|
289
295
|
return;
|
290
296
|
}
|
291
297
|
process.kill(instance.pid, 'SIGTERM');
|
292
|
-
instance.status = InstanceStatus.STOPPED;
|
293
|
-
socketManager.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
298
|
+
instance.status = types_1.InstanceStatus.STOPPED;
|
299
|
+
socketManager_1.socketManager.emitSystemEvent(systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
294
300
|
this.save();
|
295
301
|
}
|
296
302
|
catch (e) {
|
@@ -299,9 +305,9 @@ export class InstanceManager {
|
|
299
305
|
});
|
300
306
|
}
|
301
307
|
stopAllForPlan(systemId) {
|
302
|
-
systemId = normalizeKapetaUri(systemId);
|
308
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
303
309
|
const instancesForPlan = this._instances.filter((instance) => instance.systemId === systemId);
|
304
|
-
return taskManager.add(`plan:stop:${systemId}`, async () => {
|
310
|
+
return taskManager_1.taskManager.add(`plan:stop:${systemId}`, async () => {
|
305
311
|
return this.stopInstances(instancesForPlan);
|
306
312
|
}, {
|
307
313
|
name: `Stopping plan ${systemId}`,
|
@@ -309,33 +315,33 @@ export class InstanceManager {
|
|
309
315
|
}
|
310
316
|
async start(systemId, instanceId) {
|
311
317
|
return this.exclusive(systemId, instanceId, async () => {
|
312
|
-
systemId = normalizeKapetaUri(systemId);
|
313
|
-
const plan = await assetManager.getPlan(systemId, true);
|
318
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
319
|
+
const plan = await assetManager_1.assetManager.getPlan(systemId, true);
|
314
320
|
if (!plan) {
|
315
321
|
throw new Error('Plan not found: ' + systemId);
|
316
322
|
}
|
317
|
-
const blockInstance = plan.spec && plan.spec.blocks ?
|
323
|
+
const blockInstance = plan.spec && plan.spec.blocks ? lodash_1.default.find(plan.spec.blocks, { id: instanceId }) : null;
|
318
324
|
if (!blockInstance) {
|
319
325
|
throw new Error('Block instance not found: ' + instanceId);
|
320
326
|
}
|
321
|
-
const blockRef = normalizeKapetaUri(blockInstance.block.ref);
|
322
|
-
const blockAsset = await assetManager.getAsset(blockRef, true);
|
327
|
+
const blockRef = (0, utils_1.normalizeKapetaUri)(blockInstance.block.ref);
|
328
|
+
const blockAsset = await assetManager_1.assetManager.getAsset(blockRef, true);
|
323
329
|
if (!blockAsset) {
|
324
330
|
throw new Error('Block not found: ' + blockRef);
|
325
331
|
}
|
326
332
|
const existingInstance = this.getInstance(systemId, instanceId);
|
327
333
|
if (existingInstance) {
|
328
|
-
if (existingInstance.status === InstanceStatus.READY) {
|
334
|
+
if (existingInstance.status === types_1.InstanceStatus.READY) {
|
329
335
|
// Instance is already running
|
330
336
|
return existingInstance;
|
331
337
|
}
|
332
|
-
if (existingInstance.desiredStatus === DesiredInstanceStatus.RUN &&
|
333
|
-
existingInstance.status === InstanceStatus.STARTING) {
|
338
|
+
if (existingInstance.desiredStatus === types_1.DesiredInstanceStatus.RUN &&
|
339
|
+
existingInstance.status === types_1.InstanceStatus.STARTING) {
|
334
340
|
// Internal instance is already starting - don't start it again
|
335
341
|
return existingInstance;
|
336
342
|
}
|
337
|
-
if (existingInstance.owner === InstanceOwner.EXTERNAL &&
|
338
|
-
existingInstance.status === InstanceStatus.STARTING) {
|
343
|
+
if (existingInstance.owner === types_1.InstanceOwner.EXTERNAL &&
|
344
|
+
existingInstance.status === types_1.InstanceStatus.STARTING) {
|
339
345
|
// External instance is already starting - don't start it again
|
340
346
|
return existingInstance;
|
341
347
|
}
|
@@ -345,10 +351,10 @@ export class InstanceManager {
|
|
345
351
|
instanceId,
|
346
352
|
ref: blockRef,
|
347
353
|
name: blockAsset.data.metadata.name,
|
348
|
-
desiredStatus: DesiredInstanceStatus.RUN,
|
349
|
-
owner: InstanceOwner.INTERNAL,
|
350
|
-
type: existingInstance?.type ?? InstanceType.UNKNOWN,
|
351
|
-
status: InstanceStatus.STARTING,
|
354
|
+
desiredStatus: types_1.DesiredInstanceStatus.RUN,
|
355
|
+
owner: types_1.InstanceOwner.INTERNAL,
|
356
|
+
type: existingInstance?.type ?? types_1.InstanceType.UNKNOWN,
|
357
|
+
status: types_1.InstanceStatus.STARTING,
|
352
358
|
startedAt: Date.now(),
|
353
359
|
};
|
354
360
|
console.log('Starting instance: %s::%s [desired: %s]', systemId, instanceId, instance.desiredStatus);
|
@@ -357,43 +363,43 @@ export class InstanceManager {
|
|
357
363
|
const blockSpec = blockAsset.data.spec;
|
358
364
|
if (blockSpec.consumers) {
|
359
365
|
const promises = blockSpec.consumers.map((consumer) => {
|
360
|
-
const consumerUri = parseKapetaUri(consumer.kind);
|
361
|
-
const asset = definitionsManager.getDefinition(consumer.kind);
|
366
|
+
const consumerUri = (0, nodejs_utils_1.parseKapetaUri)(consumer.kind);
|
367
|
+
const asset = definitionsManager_1.definitionsManager.getDefinition(consumer.kind);
|
362
368
|
if (!asset) {
|
363
369
|
// Definition not found
|
364
370
|
return Promise.resolve();
|
365
371
|
}
|
366
|
-
if (KIND_OPERATOR.toLowerCase() !== asset.definition.kind.toLowerCase()) {
|
372
|
+
if (operatorManager_1.KIND_OPERATOR.toLowerCase() !== asset.definition.kind.toLowerCase()) {
|
367
373
|
// Not an operator
|
368
374
|
return Promise.resolve();
|
369
375
|
}
|
370
376
|
console.log('Ensuring resource: %s in %s', consumerUri.id, systemId);
|
371
|
-
return operatorManager.ensureResource(systemId, consumerUri.fullName, consumerUri.version);
|
377
|
+
return operatorManager_1.operatorManager.ensureResource(systemId, consumerUri.fullName, consumerUri.version);
|
372
378
|
});
|
373
379
|
await Promise.all(promises);
|
374
380
|
}
|
375
381
|
if (existingInstance) {
|
376
382
|
// Check if the instance is already running - but after we've commmuicated the desired status
|
377
383
|
const currentStatus = await this.requestInstanceStatus(existingInstance);
|
378
|
-
if (currentStatus === InstanceStatus.READY) {
|
384
|
+
if (currentStatus === types_1.InstanceStatus.READY) {
|
379
385
|
// Instance is already running
|
380
386
|
return existingInstance;
|
381
387
|
}
|
382
388
|
}
|
383
|
-
const instanceConfig = await configManager.getConfigForSection(systemId, instanceId);
|
384
|
-
const task = taskManager.add(`instance:start:${systemId}:${instanceId}`, async () => {
|
385
|
-
const runner = new BlockInstanceRunner(systemId);
|
389
|
+
const instanceConfig = await configManager_1.configManager.getConfigForSection(systemId, instanceId);
|
390
|
+
const task = taskManager_1.taskManager.add(`instance:start:${systemId}:${instanceId}`, async () => {
|
391
|
+
const runner = new BlockInstanceRunner_1.BlockInstanceRunner(systemId);
|
386
392
|
const startTime = Date.now();
|
387
393
|
try {
|
388
394
|
const processInfo = await runner.start(blockRef, instanceId, instanceConfig);
|
389
|
-
instance.status = InstanceStatus.READY;
|
395
|
+
instance.status = types_1.InstanceStatus.READY;
|
390
396
|
return this.saveInternalInstance({
|
391
397
|
...instance,
|
392
398
|
type: processInfo.type,
|
393
399
|
pid: processInfo.pid ?? -1,
|
394
400
|
health: null,
|
395
401
|
portType: processInfo.portType,
|
396
|
-
status: InstanceStatus.READY,
|
402
|
+
status: types_1.InstanceStatus.READY,
|
397
403
|
});
|
398
404
|
}
|
399
405
|
catch (e) {
|
@@ -408,17 +414,17 @@ export class InstanceManager {
|
|
408
414
|
];
|
409
415
|
const out = await this.saveInternalInstance({
|
410
416
|
...instance,
|
411
|
-
type: InstanceType.UNKNOWN,
|
417
|
+
type: types_1.InstanceType.UNKNOWN,
|
412
418
|
pid: null,
|
413
419
|
health: null,
|
414
420
|
portType: DEFAULT_HEALTH_PORT_TYPE,
|
415
|
-
status: InstanceStatus.FAILED,
|
421
|
+
status: types_1.InstanceStatus.FAILED,
|
416
422
|
errorMessage: e.message ?? 'Failed to start - Check logs for details.',
|
417
423
|
});
|
418
|
-
socketManager.emitInstanceLog(systemId, instanceId, logs[0]);
|
419
|
-
socketManager.emitInstanceEvent(systemId, blockInstance.id, EVENT_INSTANCE_EXITED, {
|
424
|
+
socketManager_1.socketManager.emitInstanceLog(systemId, instanceId, logs[0]);
|
425
|
+
socketManager_1.socketManager.emitInstanceEvent(systemId, blockInstance.id, socketManager_1.EVENT_INSTANCE_EXITED, {
|
420
426
|
error: `Failed to start instance: ${e.message}`,
|
421
|
-
status: EVENT_INSTANCE_EXITED,
|
427
|
+
status: socketManager_1.EVENT_INSTANCE_EXITED,
|
422
428
|
instanceId: blockInstance.id,
|
423
429
|
});
|
424
430
|
return out;
|
@@ -438,7 +444,7 @@ export class InstanceManager {
|
|
438
444
|
* We do it this way to not cause the user to wait for the instance to start again
|
439
445
|
*/
|
440
446
|
async prepareForRestart(systemId, instanceId) {
|
441
|
-
systemId = normalizeKapetaUri(systemId);
|
447
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
442
448
|
await this.stopInner(systemId, instanceId);
|
443
449
|
}
|
444
450
|
async stopAll() {
|
@@ -451,7 +457,7 @@ export class InstanceManager {
|
|
451
457
|
}
|
452
458
|
save() {
|
453
459
|
try {
|
454
|
-
storageService.put('instances', this._instances.map((instance) => {
|
460
|
+
storageService_1.storageService.put('instances', this._instances.map((instance) => {
|
455
461
|
return { ...instance };
|
456
462
|
}));
|
457
463
|
}
|
@@ -470,24 +476,54 @@ export class InstanceManager {
|
|
470
476
|
if (!instance.systemId) {
|
471
477
|
return;
|
472
478
|
}
|
473
|
-
instance.systemId = normalizeKapetaUri(instance.systemId);
|
479
|
+
instance.systemId = (0, utils_1.normalizeKapetaUri)(instance.systemId);
|
474
480
|
if (instance.ref) {
|
475
|
-
instance.ref = normalizeKapetaUri(instance.ref);
|
481
|
+
instance.ref = (0, utils_1.normalizeKapetaUri)(instance.ref);
|
482
|
+
}
|
483
|
+
if (instance.desiredStatus === types_1.DesiredInstanceStatus.RUN) {
|
484
|
+
// Check if the plan still exists and the instance is still in the plan
|
485
|
+
// - and that the block definition exists
|
486
|
+
try {
|
487
|
+
const plan = await assetManager_1.assetManager.getAsset(instance.systemId, true, false);
|
488
|
+
if (!plan) {
|
489
|
+
instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
|
490
|
+
changed = true;
|
491
|
+
return;
|
492
|
+
}
|
493
|
+
const planData = plan.data;
|
494
|
+
const planInstance = planData?.spec?.blocks?.find((b) => b.id === instance.instanceId);
|
495
|
+
if (!planInstance || !planInstance?.block?.ref) {
|
496
|
+
instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
|
497
|
+
changed = true;
|
498
|
+
return;
|
499
|
+
}
|
500
|
+
const blockDef = await assetManager_1.assetManager.getAsset(instance.ref, true, false);
|
501
|
+
if (!blockDef) {
|
502
|
+
instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
|
503
|
+
changed = true;
|
504
|
+
return;
|
505
|
+
}
|
506
|
+
}
|
507
|
+
catch (e) {
|
508
|
+
console.warn('Failed to check assets', instance.systemId, e);
|
509
|
+
instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
|
510
|
+
return;
|
511
|
+
}
|
476
512
|
}
|
477
513
|
const newStatus = await this.requestInstanceStatus(instance);
|
478
514
|
/*
|
479
515
|
console.log('Check instance %s %s: [current: %s, new: %s, desired: %s]',
|
480
516
|
instance.systemId, instance.instanceId, instance.status, newStatus, instance.desiredStatus);
|
481
517
|
*/
|
482
|
-
if (newStatus === InstanceStatus.BUSY) {
|
518
|
+
if (newStatus === types_1.InstanceStatus.BUSY) {
|
483
519
|
// If instance is busy we skip it
|
484
520
|
//console.log('Instance %s %s is busy', instance.systemId, instance.instanceId);
|
485
521
|
return;
|
486
522
|
}
|
487
523
|
if (instance.startedAt !== undefined &&
|
488
|
-
newStatus === InstanceStatus.UNHEALTHY &&
|
489
|
-
instance.startedAt + HEALTH_CHECK_TIMEOUT < Date.now() &&
|
490
|
-
instance.status === InstanceStatus.STARTING) {
|
524
|
+
newStatus === types_1.InstanceStatus.UNHEALTHY &&
|
525
|
+
instance.startedAt + containerManager_1.HEALTH_CHECK_TIMEOUT < Date.now() &&
|
526
|
+
instance.status === types_1.InstanceStatus.STARTING) {
|
491
527
|
// If instance is starting we consider unhealthy an indication
|
492
528
|
// that it is still starting
|
493
529
|
//console.log('Instance %s %s is still starting', instance.systemId, instance.instanceId);
|
@@ -495,22 +531,22 @@ export class InstanceManager {
|
|
495
531
|
}
|
496
532
|
if (instance.status !== newStatus) {
|
497
533
|
const oldStatus = instance.status;
|
498
|
-
const skipUpdate = (newStatus === InstanceStatus.STOPPED && instance.status === InstanceStatus.FAILED) ||
|
499
|
-
([InstanceStatus.READY, InstanceStatus.UNHEALTHY].includes(newStatus) &&
|
500
|
-
instance.status === InstanceStatus.STOPPING) ||
|
501
|
-
(newStatus === InstanceStatus.STOPPED &&
|
502
|
-
instance.status === InstanceStatus.STARTING &&
|
503
|
-
instance.desiredStatus === DesiredInstanceStatus.RUN);
|
534
|
+
const skipUpdate = (newStatus === types_1.InstanceStatus.STOPPED && instance.status === types_1.InstanceStatus.FAILED) ||
|
535
|
+
([types_1.InstanceStatus.READY, types_1.InstanceStatus.UNHEALTHY].includes(newStatus) &&
|
536
|
+
instance.status === types_1.InstanceStatus.STOPPING) ||
|
537
|
+
(newStatus === types_1.InstanceStatus.STOPPED &&
|
538
|
+
instance.status === types_1.InstanceStatus.STARTING &&
|
539
|
+
instance.desiredStatus === types_1.DesiredInstanceStatus.RUN);
|
504
540
|
if (!skipUpdate) {
|
505
541
|
const oldStatus = instance.status;
|
506
542
|
instance.status = newStatus;
|
507
543
|
console.log('Instance status changed: %s %s: %s -> %s', instance.systemId, instance.instanceId, oldStatus, instance.status);
|
508
|
-
socketManager.emitSystemEvent(instance.systemId, EVENT_STATUS_CHANGED, instance);
|
544
|
+
socketManager_1.socketManager.emitSystemEvent(instance.systemId, socketManager_1.EVENT_STATUS_CHANGED, instance);
|
509
545
|
changed = true;
|
510
546
|
}
|
511
547
|
}
|
512
|
-
if (instance.desiredStatus === DesiredInstanceStatus.RUN &&
|
513
|
-
[InstanceStatus.STOPPED, InstanceStatus.FAILED, InstanceStatus.STOPPING].includes(newStatus)) {
|
548
|
+
if (instance.desiredStatus === types_1.DesiredInstanceStatus.RUN &&
|
549
|
+
[types_1.InstanceStatus.STOPPED, types_1.InstanceStatus.FAILED, types_1.InstanceStatus.STOPPING].includes(newStatus)) {
|
514
550
|
//If the instance is stopped but we want it to run, start it
|
515
551
|
try {
|
516
552
|
await this.start(instance.systemId, instance.instanceId);
|
@@ -520,8 +556,8 @@ export class InstanceManager {
|
|
520
556
|
}
|
521
557
|
return;
|
522
558
|
}
|
523
|
-
if (instance.desiredStatus === DesiredInstanceStatus.STOP &&
|
524
|
-
[InstanceStatus.READY, InstanceStatus.STARTING, InstanceStatus.UNHEALTHY].includes(newStatus)) {
|
559
|
+
if (instance.desiredStatus === types_1.DesiredInstanceStatus.STOP &&
|
560
|
+
[types_1.InstanceStatus.READY, types_1.InstanceStatus.STARTING, types_1.InstanceStatus.UNHEALTHY].includes(newStatus)) {
|
525
561
|
//If the instance is running but we want it to stop, stop it
|
526
562
|
try {
|
527
563
|
await this.stopInner(instance.systemId, instance.instanceId);
|
@@ -531,9 +567,9 @@ export class InstanceManager {
|
|
531
567
|
}
|
532
568
|
return;
|
533
569
|
}
|
534
|
-
if (instance.desiredStatus === DesiredInstanceStatus.RUN &&
|
570
|
+
if (instance.desiredStatus === types_1.DesiredInstanceStatus.RUN &&
|
535
571
|
instance.status !== newStatus &&
|
536
|
-
newStatus === InstanceStatus.UNHEALTHY) {
|
572
|
+
newStatus === types_1.InstanceStatus.UNHEALTHY) {
|
537
573
|
//If the instance is unhealthy, try to restart it
|
538
574
|
console.log('Restarting unhealthy instance', instance);
|
539
575
|
try {
|
@@ -552,93 +588,94 @@ export class InstanceManager {
|
|
552
588
|
//console.log('\n##\n');
|
553
589
|
}
|
554
590
|
async getExternalStatus(instance) {
|
555
|
-
if (instance.type === InstanceType.DOCKER) {
|
556
|
-
const containerName = getBlockInstanceContainerName(instance.systemId, instance.instanceId);
|
557
|
-
const container = await containerManager.getContainerByName(containerName);
|
591
|
+
if (instance.type === types_1.InstanceType.DOCKER) {
|
592
|
+
const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.systemId, instance.instanceId);
|
593
|
+
const container = await containerManager_1.containerManager.getContainerByName(containerName);
|
558
594
|
if (!container) {
|
559
595
|
// If the container doesn't exist, we consider the instance stopped
|
560
|
-
return InstanceStatus.STOPPED;
|
596
|
+
return types_1.InstanceStatus.STOPPED;
|
561
597
|
}
|
562
598
|
const state = await container.status();
|
563
599
|
if (state.Status === 'running') {
|
564
600
|
if (state.Health?.Status === 'healthy') {
|
565
|
-
return InstanceStatus.READY;
|
601
|
+
return types_1.InstanceStatus.READY;
|
566
602
|
}
|
567
603
|
if (state.Health?.Status === 'starting') {
|
568
|
-
return InstanceStatus.STARTING;
|
604
|
+
return types_1.InstanceStatus.STARTING;
|
569
605
|
}
|
570
606
|
if (state.Health?.Status === 'unhealthy') {
|
571
|
-
return InstanceStatus.UNHEALTHY;
|
607
|
+
return types_1.InstanceStatus.UNHEALTHY;
|
572
608
|
}
|
573
|
-
return InstanceStatus.READY;
|
609
|
+
return types_1.InstanceStatus.READY;
|
574
610
|
}
|
575
611
|
if (state.Status === 'created') {
|
576
|
-
return InstanceStatus.STARTING;
|
612
|
+
return types_1.InstanceStatus.STARTING;
|
577
613
|
}
|
578
614
|
if (state.Status === 'exited' || state.Status === 'dead') {
|
579
|
-
return InstanceStatus.STOPPED;
|
615
|
+
return types_1.InstanceStatus.STOPPED;
|
580
616
|
}
|
581
617
|
if (state.Status === 'removing') {
|
582
|
-
return InstanceStatus.BUSY;
|
618
|
+
return types_1.InstanceStatus.BUSY;
|
583
619
|
}
|
584
620
|
if (state.Status === 'restarting') {
|
585
|
-
return InstanceStatus.BUSY;
|
621
|
+
return types_1.InstanceStatus.BUSY;
|
586
622
|
}
|
587
623
|
if (state.Status === 'paused') {
|
588
|
-
return InstanceStatus.BUSY;
|
624
|
+
return types_1.InstanceStatus.BUSY;
|
589
625
|
}
|
590
|
-
return InstanceStatus.STOPPED;
|
626
|
+
return types_1.InstanceStatus.STOPPED;
|
591
627
|
}
|
592
628
|
if (!instance.pid) {
|
593
|
-
return InstanceStatus.STOPPED;
|
629
|
+
return types_1.InstanceStatus.STOPPED;
|
594
630
|
}
|
595
631
|
//Otherwise its just a normal process.
|
596
632
|
//TODO: Handle for Windows
|
597
633
|
try {
|
598
634
|
if (process.kill(instance.pid, 0)) {
|
599
|
-
return InstanceStatus.READY;
|
635
|
+
return types_1.InstanceStatus.READY;
|
600
636
|
}
|
601
637
|
}
|
602
638
|
catch (err) {
|
603
639
|
if (err.code === 'EPERM') {
|
604
|
-
return InstanceStatus.READY;
|
640
|
+
return types_1.InstanceStatus.READY;
|
605
641
|
}
|
606
642
|
}
|
607
|
-
return InstanceStatus.STOPPED;
|
643
|
+
return types_1.InstanceStatus.STOPPED;
|
608
644
|
}
|
609
645
|
async requestInstanceStatus(instance) {
|
610
646
|
const externalStatus = await this.getExternalStatus(instance);
|
611
|
-
if (instance.type === InstanceType.DOCKER) {
|
647
|
+
if (instance.type === types_1.InstanceType.DOCKER) {
|
612
648
|
// For docker instances we can rely on docker status
|
613
649
|
return externalStatus;
|
614
650
|
}
|
615
|
-
if (externalStatus === InstanceStatus.STOPPED) {
|
651
|
+
if (externalStatus === types_1.InstanceStatus.STOPPED) {
|
616
652
|
return externalStatus;
|
617
653
|
}
|
618
654
|
if (!instance.health) {
|
619
655
|
//No health url means we assume it's healthy as soon as it's running
|
620
|
-
return InstanceStatus.READY;
|
656
|
+
return types_1.InstanceStatus.READY;
|
621
657
|
}
|
622
658
|
return new Promise((resolve) => {
|
623
659
|
if (!instance.health) {
|
624
|
-
resolve(InstanceStatus.READY);
|
660
|
+
resolve(types_1.InstanceStatus.READY);
|
625
661
|
return;
|
626
662
|
}
|
627
|
-
|
663
|
+
(0, request_1.default)(instance.health, (err, response) => {
|
628
664
|
if (err) {
|
629
|
-
resolve(InstanceStatus.UNHEALTHY);
|
665
|
+
resolve(types_1.InstanceStatus.UNHEALTHY);
|
630
666
|
return;
|
631
667
|
}
|
632
668
|
if (response.statusCode > 399) {
|
633
|
-
resolve(InstanceStatus.UNHEALTHY);
|
669
|
+
resolve(types_1.InstanceStatus.UNHEALTHY);
|
634
670
|
return;
|
635
671
|
}
|
636
|
-
resolve(InstanceStatus.READY);
|
672
|
+
resolve(types_1.InstanceStatus.READY);
|
637
673
|
});
|
638
674
|
});
|
639
675
|
}
|
640
676
|
}
|
641
|
-
|
677
|
+
exports.InstanceManager = InstanceManager;
|
678
|
+
exports.instanceManager = new InstanceManager();
|
642
679
|
process.on('exit', async () => {
|
643
|
-
await instanceManager.stopAll();
|
680
|
+
await exports.instanceManager.stopAll();
|
644
681
|
});
|