@kumori/aurora-backend-handler 1.0.45 → 1.0.47
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/api/account-api-service.ts +2 -2
- package/api/service-api-service.ts +55 -60
- package/api/user-api-service.ts +203 -233
- package/helpers/account-helper.ts +1 -0
- package/helpers/link-helper.ts +3 -0
- package/helpers/revision-helper.ts +327 -278
- package/helpers/service-helper.ts +80 -189
- package/package.json +2 -2
- package/websocket-manager.ts +36 -13
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
Usage,
|
|
9
9
|
} from "@kumori/aurora-interfaces";
|
|
10
10
|
import { convertToGigabytes, getTimestamp } from "../utils/utils";
|
|
11
|
+
import { Revision } from "@kumori/aurora-interfaces/interfaces/revision-interface";
|
|
11
12
|
|
|
12
13
|
interface Role {
|
|
13
14
|
name: string;
|
|
@@ -31,21 +32,6 @@ interface Role {
|
|
|
31
32
|
hsize?: number;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
interface Revision {
|
|
35
|
-
service: string;
|
|
36
|
-
revision: string;
|
|
37
|
-
usage: Usage;
|
|
38
|
-
status: {
|
|
39
|
-
code: string;
|
|
40
|
-
message: string;
|
|
41
|
-
timestamp: string;
|
|
42
|
-
args: string[];
|
|
43
|
-
};
|
|
44
|
-
errorCode?: string;
|
|
45
|
-
errorMsg?: string;
|
|
46
|
-
createdAt?: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
35
|
interface HandleRevisionEventParams {
|
|
50
36
|
entityId: string;
|
|
51
37
|
eventData: any;
|
|
@@ -74,9 +60,6 @@ interface HandleRevisionEventResult {
|
|
|
74
60
|
|
|
75
61
|
const MAX_HISTORY = 100;
|
|
76
62
|
|
|
77
|
-
/**
|
|
78
|
-
* Process role and instance data from revision event
|
|
79
|
-
*/
|
|
80
63
|
const processRolesAndInstances = (
|
|
81
64
|
eventData: any,
|
|
82
65
|
serviceId: string,
|
|
@@ -155,7 +138,7 @@ const processRolesAndInstances = (
|
|
|
155
138
|
cost: 0,
|
|
156
139
|
},
|
|
157
140
|
logs: [],
|
|
158
|
-
containers
|
|
141
|
+
containers,
|
|
159
142
|
};
|
|
160
143
|
|
|
161
144
|
roleInstances.push(instance);
|
|
@@ -176,19 +159,15 @@ const processRolesAndInstances = (
|
|
|
176
159
|
return { roles, instances, usedCpu, usedMemory };
|
|
177
160
|
};
|
|
178
161
|
|
|
179
|
-
/**
|
|
180
|
-
* Create a new revision object from event data
|
|
181
|
-
*/
|
|
182
162
|
const createRevision = (
|
|
183
163
|
entityId: string,
|
|
184
|
-
parentParts: { [entity: string]: string },
|
|
185
164
|
eventData: any,
|
|
186
165
|
usedCpu: number,
|
|
187
166
|
usedMemory: number,
|
|
188
167
|
): Revision => {
|
|
189
168
|
return {
|
|
190
|
-
|
|
191
|
-
|
|
169
|
+
id: entityId,
|
|
170
|
+
schema: {},
|
|
192
171
|
usage: {
|
|
193
172
|
current: {
|
|
194
173
|
cpu: usedCpu,
|
|
@@ -199,14 +178,8 @@ const createRevision = (
|
|
|
199
178
|
persistentStorage: 0,
|
|
200
179
|
},
|
|
201
180
|
limit: {
|
|
202
|
-
cpu: {
|
|
203
|
-
|
|
204
|
-
min: 0,
|
|
205
|
-
},
|
|
206
|
-
memory: {
|
|
207
|
-
max: eventData.spec.intensives?.ram / 1000 || 0,
|
|
208
|
-
min: 0,
|
|
209
|
-
},
|
|
181
|
+
cpu: { max: eventData.spec.intensives?.vcpu / 1000 || 0, min: 0 },
|
|
182
|
+
memory: { max: eventData.spec.intensives?.ram / 1000 || 0, min: 0 },
|
|
210
183
|
storage: {
|
|
211
184
|
max: eventData.spec.intensives?.shared_disk / 1000 || 0,
|
|
212
185
|
min: 0,
|
|
@@ -227,22 +200,13 @@ const createRevision = (
|
|
|
227
200
|
cost: 0,
|
|
228
201
|
},
|
|
229
202
|
status: eventData.status.state,
|
|
230
|
-
errorCode:
|
|
231
|
-
|
|
232
|
-
? eventData.status.error.code
|
|
233
|
-
: "",
|
|
234
|
-
errorMsg:
|
|
235
|
-
eventData.status && eventData.status.error
|
|
236
|
-
? eventData.status.error.message
|
|
237
|
-
: "",
|
|
203
|
+
errorCode: eventData.status?.error ? eventData.status.error.code : "",
|
|
204
|
+
errorMsg: eventData.status?.error ? eventData.status.error.message : "",
|
|
238
205
|
createdAt:
|
|
239
206
|
(eventData.status && eventData.status.runtime?.status?.createdAt) || "",
|
|
240
207
|
};
|
|
241
208
|
};
|
|
242
209
|
|
|
243
|
-
/**
|
|
244
|
-
* Update service with new revision data
|
|
245
|
-
*/
|
|
246
210
|
const updateServiceWithRevision = (
|
|
247
211
|
existingService: Service,
|
|
248
212
|
entityId: string,
|
|
@@ -251,23 +215,19 @@ const updateServiceWithRevision = (
|
|
|
251
215
|
roles: Role[],
|
|
252
216
|
): { updatedService: Service; deploymentErrorEvent: Service | null } => {
|
|
253
217
|
const existingRevisionIndex = existingService.revisions.findIndex(
|
|
254
|
-
(rev) => rev === entityId,
|
|
218
|
+
(rev) => rev.id === entityId,
|
|
255
219
|
);
|
|
256
|
-
const updatedRevisions =
|
|
220
|
+
const updatedRevisions: Revision[] =
|
|
257
221
|
existingRevisionIndex === -1
|
|
258
|
-
? [...existingService.revisions,
|
|
259
|
-
: existingService.revisions
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const updatedCurrentRevision =
|
|
263
|
-
incomingRevisionTimestamp > currentRevisionTimestamp
|
|
264
|
-
? entityId
|
|
265
|
-
: existingService.currentRevision;
|
|
222
|
+
? [...existingService.revisions, newRevision]
|
|
223
|
+
: existingService.revisions.map((rev) =>
|
|
224
|
+
rev.id === entityId ? newRevision : rev,
|
|
225
|
+
);
|
|
266
226
|
|
|
267
227
|
const updatedService: Service = {
|
|
268
228
|
...existingService,
|
|
269
229
|
revisions: updatedRevisions,
|
|
270
|
-
currentRevision:
|
|
230
|
+
currentRevision: entityId,
|
|
271
231
|
role: roles.length > 0 ? roles : existingService.role,
|
|
272
232
|
usage: newRevision.usage,
|
|
273
233
|
startedAt: newRevision.createdAt || existingService.startedAt,
|
|
@@ -281,7 +241,6 @@ const updateServiceWithRevision = (
|
|
|
281
241
|
|
|
282
242
|
if (incomingTs > currentTs) {
|
|
283
243
|
updatedService.status = incomingStatus;
|
|
284
|
-
|
|
285
244
|
if (eventData.status.error) {
|
|
286
245
|
updatedService.error = {
|
|
287
246
|
code: eventData.status.error.code,
|
|
@@ -295,7 +254,6 @@ const updateServiceWithRevision = (
|
|
|
295
254
|
} else if (eventData.status.error) {
|
|
296
255
|
const incomingErrorTs = getTimestamp(eventData.status.error.timestamp);
|
|
297
256
|
const currentErrorTs = getTimestamp(existingService.error?.timestamp);
|
|
298
|
-
|
|
299
257
|
if (incomingErrorTs > currentErrorTs) {
|
|
300
258
|
updatedService.error = {
|
|
301
259
|
code: eventData.status.error.code,
|
|
@@ -309,9 +267,6 @@ const updateServiceWithRevision = (
|
|
|
309
267
|
return { updatedService, deploymentErrorEvent };
|
|
310
268
|
};
|
|
311
269
|
|
|
312
|
-
/**
|
|
313
|
-
* Update environment consumption history
|
|
314
|
-
*/
|
|
315
270
|
const updateEnvironmentConsumption = (
|
|
316
271
|
environment: Environment,
|
|
317
272
|
servicesMap: Map<string, Service>,
|
|
@@ -332,31 +287,24 @@ const updateEnvironmentConsumption = (
|
|
|
332
287
|
}
|
|
333
288
|
});
|
|
334
289
|
|
|
335
|
-
if (!environment.usage.current.cpuConsuption)
|
|
290
|
+
if (!environment.usage.current.cpuConsuption)
|
|
336
291
|
environment.usage.current.cpuConsuption = [];
|
|
337
|
-
|
|
338
|
-
if (!environment.usage.current.memoryConsuption) {
|
|
292
|
+
if (!environment.usage.current.memoryConsuption)
|
|
339
293
|
environment.usage.current.memoryConsuption = [];
|
|
340
|
-
}
|
|
341
294
|
|
|
342
295
|
environment.usage.current.cpuConsuption.push(totalEnvCpu);
|
|
343
296
|
environment.usage.current.memoryConsuption.push(totalEnvMemory);
|
|
344
297
|
|
|
345
|
-
if (environment.usage.current.cpuConsuption.length > MAX_HISTORY)
|
|
298
|
+
if (environment.usage.current.cpuConsuption.length > MAX_HISTORY)
|
|
346
299
|
environment.usage.current.cpuConsuption =
|
|
347
300
|
environment.usage.current.cpuConsuption.slice(-MAX_HISTORY);
|
|
348
|
-
|
|
349
|
-
if (environment.usage.current.memoryConsuption.length > MAX_HISTORY) {
|
|
301
|
+
if (environment.usage.current.memoryConsuption.length > MAX_HISTORY)
|
|
350
302
|
environment.usage.current.memoryConsuption =
|
|
351
303
|
environment.usage.current.memoryConsuption.slice(-MAX_HISTORY);
|
|
352
|
-
}
|
|
353
304
|
|
|
354
305
|
return environment;
|
|
355
306
|
};
|
|
356
307
|
|
|
357
|
-
/**
|
|
358
|
-
* Update account consumption history
|
|
359
|
-
*/
|
|
360
308
|
const updateAccountConsumption = (
|
|
361
309
|
account: Account,
|
|
362
310
|
servicesMap: Map<string, Service>,
|
|
@@ -377,31 +325,24 @@ const updateAccountConsumption = (
|
|
|
377
325
|
}
|
|
378
326
|
});
|
|
379
327
|
|
|
380
|
-
if (!account.usage.current.cpuConsuption)
|
|
328
|
+
if (!account.usage.current.cpuConsuption)
|
|
381
329
|
account.usage.current.cpuConsuption = [];
|
|
382
|
-
|
|
383
|
-
if (!account.usage.current.memoryConsuption) {
|
|
330
|
+
if (!account.usage.current.memoryConsuption)
|
|
384
331
|
account.usage.current.memoryConsuption = [];
|
|
385
|
-
}
|
|
386
332
|
|
|
387
333
|
account.usage.current.cpuConsuption.push(totalAccountCpu);
|
|
388
334
|
account.usage.current.memoryConsuption.push(totalAccountMemory);
|
|
389
335
|
|
|
390
|
-
if (account.usage.current.cpuConsuption.length > MAX_HISTORY)
|
|
336
|
+
if (account.usage.current.cpuConsuption.length > MAX_HISTORY)
|
|
391
337
|
account.usage.current.cpuConsuption =
|
|
392
338
|
account.usage.current.cpuConsuption.slice(-MAX_HISTORY);
|
|
393
|
-
|
|
394
|
-
if (account.usage.current.memoryConsuption.length > MAX_HISTORY) {
|
|
339
|
+
if (account.usage.current.memoryConsuption.length > MAX_HISTORY)
|
|
395
340
|
account.usage.current.memoryConsuption =
|
|
396
341
|
account.usage.current.memoryConsuption.slice(-MAX_HISTORY);
|
|
397
|
-
}
|
|
398
342
|
|
|
399
343
|
return account;
|
|
400
344
|
};
|
|
401
|
-
|
|
402
|
-
* Handles the "revision" event from WebSocket messages
|
|
403
|
-
* Processes revision data, updates services, environments, and accounts
|
|
404
|
-
*/
|
|
345
|
+
|
|
405
346
|
export const handleRevisionEvent = ({
|
|
406
347
|
entityId,
|
|
407
348
|
eventData,
|
|
@@ -419,13 +360,15 @@ export const handleRevisionEvent = ({
|
|
|
419
360
|
serviceId,
|
|
420
361
|
roleMap,
|
|
421
362
|
);
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
363
|
+
const existingRevision = revisionsMap.get(revisionKey);
|
|
364
|
+
const newRevision = createRevision(entityId, eventData, usedCpu, usedMemory);
|
|
365
|
+
if (
|
|
366
|
+
existingRevision?.schema &&
|
|
367
|
+
Object.keys(existingRevision.schema).length > 0
|
|
368
|
+
) {
|
|
369
|
+
newRevision.schema = existingRevision.schema;
|
|
370
|
+
}
|
|
371
|
+
|
|
429
372
|
let updatedService: Service | null = null;
|
|
430
373
|
let updatedEnvironment: Environment | null = null;
|
|
431
374
|
let updatedAccount: Account | null = null;
|
|
@@ -446,9 +389,9 @@ export const handleRevisionEvent = ({
|
|
|
446
389
|
newRevision,
|
|
447
390
|
roles,
|
|
448
391
|
);
|
|
449
|
-
|
|
450
392
|
updatedService = serviceUpdateResult.updatedService;
|
|
451
393
|
serviceDeploymentErrorEvent = serviceUpdateResult.deploymentErrorEvent;
|
|
394
|
+
|
|
452
395
|
const serviceEnvironmentId = updatedService.environment;
|
|
453
396
|
if (serviceEnvironmentId) {
|
|
454
397
|
const environment = environmentsMap.get(serviceEnvironmentId);
|
|
@@ -457,7 +400,6 @@ export const handleRevisionEvent = ({
|
|
|
457
400
|
tempServicesMap.set(serviceId, updatedService);
|
|
458
401
|
const tempRevisionsMap = new Map(revisionsMap);
|
|
459
402
|
tempRevisionsMap.set(revisionKey, newRevision);
|
|
460
|
-
|
|
461
403
|
updatedEnvironment = updateEnvironmentConsumption(
|
|
462
404
|
{ ...environment },
|
|
463
405
|
tempServicesMap,
|
|
@@ -466,16 +408,15 @@ export const handleRevisionEvent = ({
|
|
|
466
408
|
);
|
|
467
409
|
}
|
|
468
410
|
}
|
|
411
|
+
|
|
469
412
|
const serviceAccountId = updatedService.account;
|
|
470
413
|
if (serviceAccountId) {
|
|
471
414
|
const account = accountsMap.get(serviceAccountId);
|
|
472
415
|
if (account) {
|
|
473
416
|
const tempServicesMap = new Map(servicesMap);
|
|
474
417
|
tempServicesMap.set(serviceId, updatedService);
|
|
475
|
-
|
|
476
418
|
const tempRevisionsMap = new Map(revisionsMap);
|
|
477
419
|
tempRevisionsMap.set(revisionKey, newRevision);
|
|
478
|
-
|
|
479
420
|
updatedAccount = updateAccountConsumption(
|
|
480
421
|
{ ...account },
|
|
481
422
|
tempServicesMap,
|
|
@@ -487,11 +428,9 @@ export const handleRevisionEvent = ({
|
|
|
487
428
|
} else if (eventData.status && eventData.status.error) {
|
|
488
429
|
newRevision.errorCode = eventData.status.error.code;
|
|
489
430
|
newRevision.errorMsg = eventData.status.error.message;
|
|
490
|
-
pendingRevisionError = {
|
|
491
|
-
service: serviceId,
|
|
492
|
-
revision: newRevision,
|
|
493
|
-
};
|
|
431
|
+
pendingRevisionError = { service: serviceId, revision: newRevision };
|
|
494
432
|
}
|
|
433
|
+
|
|
495
434
|
if (
|
|
496
435
|
!eventData.meta.deleted &&
|
|
497
436
|
eventData.status &&
|
|
@@ -519,45 +458,288 @@ export const handleRevisionEvent = ({
|
|
|
519
458
|
serviceDeploymentErrorEvent,
|
|
520
459
|
};
|
|
521
460
|
};
|
|
461
|
+
|
|
462
|
+
const collectNamedTypes = (schema: any): string[] => {
|
|
463
|
+
if (!schema || typeof schema !== "object") return [];
|
|
464
|
+
const names: string[] = [];
|
|
465
|
+
if (schema.$kdsl?.const?.NamedType?.Name)
|
|
466
|
+
names.push(schema.$kdsl.const.NamedType.Name as string);
|
|
467
|
+
if (Array.isArray(schema.oneOf)) {
|
|
468
|
+
for (const branch of schema.oneOf) names.push(...collectNamedTypes(branch));
|
|
469
|
+
}
|
|
470
|
+
return names;
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
const namedTypeToResourceKind = (
|
|
474
|
+
namedTypes: string[],
|
|
475
|
+
): { type: string; kind?: string } | null => {
|
|
476
|
+
for (const name of namedTypes) {
|
|
477
|
+
switch (name) {
|
|
478
|
+
case "Secret":
|
|
479
|
+
return { type: "secret" };
|
|
480
|
+
case "Domain":
|
|
481
|
+
return { type: "domain" };
|
|
482
|
+
case "Port":
|
|
483
|
+
return { type: "port" };
|
|
484
|
+
case "Certificate":
|
|
485
|
+
return { type: "certificate" };
|
|
486
|
+
case "CA":
|
|
487
|
+
return { type: "ca" };
|
|
488
|
+
case "Volatile":
|
|
489
|
+
case "Ephemeral":
|
|
490
|
+
return { type: "volume", kind: "volatile" };
|
|
491
|
+
case "NonReplicated":
|
|
492
|
+
return { type: "volume", kind: "nonReplicated" };
|
|
493
|
+
case "Persisted":
|
|
494
|
+
case "Persistent":
|
|
495
|
+
return { type: "volume", kind: "persistent" };
|
|
496
|
+
case "Registered":
|
|
497
|
+
return { type: "volume" };
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return null;
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
export const extractStructuredSchema = (
|
|
504
|
+
revisionData: any,
|
|
505
|
+
):
|
|
506
|
+
| {
|
|
507
|
+
parameters: {
|
|
508
|
+
name: string;
|
|
509
|
+
type: string;
|
|
510
|
+
required: boolean;
|
|
511
|
+
defaultValue?: any;
|
|
512
|
+
}[];
|
|
513
|
+
resources: {
|
|
514
|
+
name: string;
|
|
515
|
+
type: string;
|
|
516
|
+
kind?: string;
|
|
517
|
+
required: boolean;
|
|
518
|
+
}[];
|
|
519
|
+
}
|
|
520
|
+
| {} => {
|
|
521
|
+
const configSchema = revisionData?.configSchema;
|
|
522
|
+
if (!configSchema) return {};
|
|
523
|
+
|
|
524
|
+
const deploymentName = revisionData?.solution?.top;
|
|
525
|
+
const deployment = deploymentName
|
|
526
|
+
? revisionData?.solution?.deployments?.[deploymentName]
|
|
527
|
+
: Object.values(revisionData?.solution?.deployments ?? {})[0];
|
|
528
|
+
|
|
529
|
+
const parameterValues: Record<string, any> =
|
|
530
|
+
(deployment as any)?.config?.parameter ?? {};
|
|
531
|
+
const configResourceValues: Record<string, any> =
|
|
532
|
+
(deployment as any)?.config?.resource ?? {};
|
|
533
|
+
|
|
534
|
+
const requiredParams: string[] =
|
|
535
|
+
configSchema?.properties?.config?.required ?? [];
|
|
536
|
+
const requiredResources: string[] =
|
|
537
|
+
configSchema?.properties?.resource?.required ?? [];
|
|
538
|
+
const schemaConfigProps: Record<string, any> =
|
|
539
|
+
configSchema?.properties?.config?.properties ?? {};
|
|
540
|
+
|
|
541
|
+
const parameters = Object.entries(schemaConfigProps).map(
|
|
542
|
+
([name, propSchema]) => {
|
|
543
|
+
const entry: {
|
|
544
|
+
name: string;
|
|
545
|
+
type: string;
|
|
546
|
+
required: boolean;
|
|
547
|
+
defaultValue?: any;
|
|
548
|
+
} = {
|
|
549
|
+
name,
|
|
550
|
+
type: propSchema?.type ?? "string",
|
|
551
|
+
required: requiredParams.includes(name),
|
|
552
|
+
};
|
|
553
|
+
const currentValue = parameterValues[name];
|
|
554
|
+
if (currentValue !== undefined) entry.defaultValue = currentValue;
|
|
555
|
+
else if (propSchema?.default !== undefined)
|
|
556
|
+
entry.defaultValue = propSchema.default;
|
|
557
|
+
return entry;
|
|
558
|
+
},
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
const resolveResourceType = (
|
|
562
|
+
configValue: any,
|
|
563
|
+
): { type: string; kind?: string } | null => {
|
|
564
|
+
if (!configValue || typeof configValue !== "object") return null;
|
|
565
|
+
if ("secret" in configValue) return { type: "secret" };
|
|
566
|
+
if ("domain" in configValue) return { type: "domain" };
|
|
567
|
+
if ("port" in configValue) return { type: "port" };
|
|
568
|
+
if ("certificate" in configValue) return { type: "certificate" };
|
|
569
|
+
if ("ca" in configValue) return { type: "ca" };
|
|
570
|
+
if ("volume" in configValue) {
|
|
571
|
+
const volType = configValue.volume?.type;
|
|
572
|
+
if (volType === "persistent" || volType === "Persisted")
|
|
573
|
+
return { type: "volume", kind: "persistent" };
|
|
574
|
+
if (volType === "nonReplicated" || volType === "NonReplicated")
|
|
575
|
+
return { type: "volume", kind: "nonReplicated" };
|
|
576
|
+
if (
|
|
577
|
+
volType === "volatile" ||
|
|
578
|
+
volType === "Volatile" ||
|
|
579
|
+
volType === "ephemeral" ||
|
|
580
|
+
volType === "Ephemeral"
|
|
581
|
+
)
|
|
582
|
+
return { type: "volume", kind: "volatile" };
|
|
583
|
+
return { type: "volume" };
|
|
584
|
+
}
|
|
585
|
+
return null;
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
const allResourceNames = new Set<string>([
|
|
589
|
+
...Object.keys(configResourceValues),
|
|
590
|
+
...Object.keys(configSchema?.properties?.resource?.properties ?? {}),
|
|
591
|
+
]);
|
|
592
|
+
|
|
593
|
+
const resources = Array.from(allResourceNames)
|
|
594
|
+
.map((name) => {
|
|
595
|
+
const configValue = configResourceValues[name];
|
|
596
|
+
const fromConfig = resolveResourceType(configValue);
|
|
597
|
+
const schemaProps =
|
|
598
|
+
configSchema?.properties?.resource?.properties?.[name];
|
|
599
|
+
const fromSchema = schemaProps
|
|
600
|
+
? namedTypeToResourceKind(collectNamedTypes(schemaProps))
|
|
601
|
+
: null;
|
|
602
|
+
const resolved = fromConfig ?? fromSchema;
|
|
603
|
+
if (!resolved) return null;
|
|
604
|
+
const entry: {
|
|
605
|
+
name: string;
|
|
606
|
+
type: string;
|
|
607
|
+
kind?: string;
|
|
608
|
+
required: boolean;
|
|
609
|
+
} = {
|
|
610
|
+
name,
|
|
611
|
+
type: resolved.type,
|
|
612
|
+
required: requiredResources.includes(name),
|
|
613
|
+
};
|
|
614
|
+
if (resolved.kind) entry.kind = resolved.kind;
|
|
615
|
+
return entry;
|
|
616
|
+
})
|
|
617
|
+
.filter(Boolean) as {
|
|
618
|
+
name: string;
|
|
619
|
+
type: string;
|
|
620
|
+
kind?: string;
|
|
621
|
+
required: boolean;
|
|
622
|
+
}[];
|
|
623
|
+
|
|
624
|
+
return { parameters, resources };
|
|
625
|
+
};
|
|
626
|
+
|
|
522
627
|
export const processRevisionData = (
|
|
523
628
|
service: Service,
|
|
524
629
|
revisionData: any,
|
|
630
|
+
revisionsMap?: Map<string, Revision>,
|
|
631
|
+
serviceId?: string,
|
|
525
632
|
): Service => {
|
|
526
633
|
const { solution } = revisionData;
|
|
634
|
+
|
|
635
|
+
const config = revisionData?.config?.config || {};
|
|
636
|
+
const parameters = extractParametersFromConfig(config.parameter || {});
|
|
637
|
+
const resources = extractResources(config.resource || {});
|
|
638
|
+
|
|
639
|
+
const schemaResult = revisionData.revision
|
|
640
|
+
? extractStructuredSchema(revisionData)
|
|
641
|
+
: {};
|
|
642
|
+
const schema =
|
|
643
|
+
schemaResult && "parameters" in schemaResult ? schemaResult : {};
|
|
644
|
+
|
|
645
|
+
if (
|
|
646
|
+
revisionsMap &&
|
|
647
|
+
serviceId &&
|
|
648
|
+
revisionData.revision &&
|
|
649
|
+
"parameters" in schema
|
|
650
|
+
) {
|
|
651
|
+
const revisionId: string = revisionData.revision;
|
|
652
|
+
const revisionKey = `${serviceId}-${revisionId}`;
|
|
653
|
+
const existing = revisionsMap.get(revisionKey);
|
|
654
|
+
if (existing) {
|
|
655
|
+
revisionsMap.set(revisionKey, { ...existing, schema });
|
|
656
|
+
} else {
|
|
657
|
+
revisionsMap.set(revisionKey, {
|
|
658
|
+
id: revisionId,
|
|
659
|
+
schema,
|
|
660
|
+
usage: {
|
|
661
|
+
current: {
|
|
662
|
+
cpu: 0,
|
|
663
|
+
memory: 0,
|
|
664
|
+
storage: 0,
|
|
665
|
+
volatileStorage: 0,
|
|
666
|
+
nonReplicatedStorage: 0,
|
|
667
|
+
persistentStorage: 0,
|
|
668
|
+
},
|
|
669
|
+
limit: {
|
|
670
|
+
cpu: { max: revisionData.intensives?.vcpu / 1000 || 0, min: 0 },
|
|
671
|
+
memory: { max: revisionData.intensives?.ram / 1000 || 0, min: 0 },
|
|
672
|
+
storage: {
|
|
673
|
+
max: revisionData.intensives?.shared_disk / 1000 || 0,
|
|
674
|
+
min: 0,
|
|
675
|
+
},
|
|
676
|
+
volatileStorage: {
|
|
677
|
+
max: revisionData.intensives?.volatile_disk / 1000 || 0,
|
|
678
|
+
min: 0,
|
|
679
|
+
},
|
|
680
|
+
nonReplicatedStorage: {
|
|
681
|
+
max: revisionData.intensives?.nrpersistent_disk / 1000 || 0,
|
|
682
|
+
min: 0,
|
|
683
|
+
},
|
|
684
|
+
persistentStorage: {
|
|
685
|
+
max: revisionData.intensives?.persistent_disk / 1000 || 0,
|
|
686
|
+
min: 0,
|
|
687
|
+
},
|
|
688
|
+
},
|
|
689
|
+
cost: 0,
|
|
690
|
+
},
|
|
691
|
+
status: { code: "", message: "", timestamp: "", args: [] },
|
|
692
|
+
errorCode: "",
|
|
693
|
+
errorMsg: "",
|
|
694
|
+
createdAt: "",
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
527
699
|
const deploymentName = solution.top || service.name;
|
|
528
700
|
const deployment = solution.deployments[deploymentName];
|
|
529
701
|
|
|
702
|
+
const applySchemaToService = (svc: Service): Service => {
|
|
703
|
+
if (!revisionData.revision || !("parameters" in schema)) return svc;
|
|
704
|
+
const revisionId: string = revisionData.revision;
|
|
705
|
+
return {
|
|
706
|
+
...svc,
|
|
707
|
+
revisions: svc.revisions.map((rev) =>
|
|
708
|
+
rev.id === revisionId ? { ...rev, schema } : rev,
|
|
709
|
+
),
|
|
710
|
+
};
|
|
711
|
+
};
|
|
712
|
+
|
|
530
713
|
if (!deployment) {
|
|
531
|
-
console.warn(
|
|
532
|
-
`No deployment found with name ${deploymentName} in solution. Available deployments:`,
|
|
533
|
-
Object.keys(solution.deployments),
|
|
534
|
-
);
|
|
535
714
|
const firstDeploymentKey = Object.keys(solution.deployments)[0];
|
|
536
715
|
if (firstDeploymentKey) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
716
|
+
return applySchemaToService(
|
|
717
|
+
processDeployment(
|
|
718
|
+
service,
|
|
719
|
+
solution.deployments[firstDeploymentKey],
|
|
720
|
+
revisionData,
|
|
721
|
+
parameters,
|
|
722
|
+
resources,
|
|
723
|
+
),
|
|
542
724
|
);
|
|
543
725
|
}
|
|
544
|
-
return service;
|
|
726
|
+
return applySchemaToService({ ...service, parameters, resources });
|
|
545
727
|
}
|
|
546
728
|
|
|
547
|
-
return
|
|
729
|
+
return applySchemaToService(
|
|
730
|
+
processDeployment(service, deployment, revisionData, parameters, resources),
|
|
731
|
+
);
|
|
548
732
|
};
|
|
733
|
+
|
|
549
734
|
export const processDeployment = (
|
|
550
735
|
service: Service,
|
|
551
736
|
deployment: any,
|
|
552
737
|
revisionData: any,
|
|
738
|
+
parameters: { [key: string]: string }[],
|
|
739
|
+
resources: Resource[],
|
|
553
740
|
): Service => {
|
|
554
741
|
const artifact = deployment.artifact;
|
|
555
742
|
const deploymentConfig = deployment.config || {};
|
|
556
|
-
const serviceResources = extractResources(deploymentConfig.resource || {});
|
|
557
|
-
const allServiceParameters = extractParametersFromConfig(
|
|
558
|
-
deploymentConfig.parameter || {},
|
|
559
|
-
);
|
|
560
|
-
|
|
561
743
|
const rolesDefinition = artifact.description?.role || {};
|
|
562
744
|
const hasRoles = Object.keys(rolesDefinition).length > 0;
|
|
563
745
|
let updatedRoles: Role[] = [];
|
|
@@ -565,27 +747,12 @@ export const processDeployment = (
|
|
|
565
747
|
if (hasRoles) {
|
|
566
748
|
Object.entries(rolesDefinition).forEach(
|
|
567
749
|
([roleName, roleData]: [string, any]) => {
|
|
568
|
-
const fileSystemParameters = extractParametersFromFilesystem(
|
|
569
|
-
roleData.artifact.description?.code?.[roleName]?.mapping
|
|
570
|
-
?.filesystem || [],
|
|
571
|
-
allServiceParameters,
|
|
572
|
-
);
|
|
573
|
-
allServiceParameters.push(...fileSystemParameters);
|
|
574
|
-
const fileSystemResources = extractResourcesFromFilesystem(
|
|
575
|
-
roleData.artifact.description?.code?.[roleName]?.mapping
|
|
576
|
-
?.filesystem || [],
|
|
577
|
-
serviceResources,
|
|
578
|
-
);
|
|
579
|
-
serviceResources.push(...fileSystemResources);
|
|
580
|
-
const roleResources = extractResources(roleData.config?.resource || {});
|
|
581
750
|
const existingRole = service.role.find((r) => r.name === roleName);
|
|
582
751
|
let hsize = 1;
|
|
583
|
-
if (roleData.config?.scale?.hsize !== undefined)
|
|
752
|
+
if (roleData.config?.scale?.hsize !== undefined)
|
|
584
753
|
hsize = roleData.config.scale.hsize;
|
|
585
|
-
|
|
586
|
-
if (deploymentConfig.scale?.detail?.[roleName]?.hsize !== undefined) {
|
|
754
|
+
if (deploymentConfig.scale?.detail?.[roleName]?.hsize !== undefined)
|
|
587
755
|
hsize = deploymentConfig.scale.detail[roleName].hsize;
|
|
588
|
-
}
|
|
589
756
|
const hasDuplex =
|
|
590
757
|
roleData.artifact?.description?.srv?.duplex?.length > 0;
|
|
591
758
|
const hasVolumeResource = Object.values(
|
|
@@ -597,31 +764,25 @@ export const processDeployment = (
|
|
|
597
764
|
logo: service.logo,
|
|
598
765
|
description:
|
|
599
766
|
roleData.artifact?.ref?.module || roleData.ref?.module || "",
|
|
600
|
-
resource:
|
|
601
|
-
parameters
|
|
602
|
-
hsize
|
|
767
|
+
resource: resources,
|
|
768
|
+
parameters,
|
|
769
|
+
hsize,
|
|
603
770
|
category: hasDuplex || hasVolumeResource ? "stateful" : "",
|
|
604
771
|
};
|
|
605
772
|
if (
|
|
606
773
|
deployment.meta?.scaling &&
|
|
607
774
|
Object.keys(deployment.meta.scaling.simple || {}).length > 0
|
|
608
|
-
)
|
|
775
|
+
)
|
|
609
776
|
role.scalling = processScalingConfig(deployment.meta);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
777
|
updatedRoles.push(role);
|
|
613
778
|
},
|
|
614
779
|
);
|
|
615
780
|
} else {
|
|
616
781
|
let hsize = 1;
|
|
617
|
-
|
|
618
|
-
if (deploymentConfig.scale?.hsize !== undefined) {
|
|
782
|
+
if (deploymentConfig.scale?.hsize !== undefined)
|
|
619
783
|
hsize = deploymentConfig.scale.hsize;
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
if (deploymentConfig.scale?.detail?.[""]?.hsize !== undefined) {
|
|
784
|
+
if (deploymentConfig.scale?.detail?.[""]?.hsize !== undefined)
|
|
623
785
|
hsize = deploymentConfig.scale.detail[""].hsize;
|
|
624
|
-
}
|
|
625
786
|
updatedRoles = [
|
|
626
787
|
{
|
|
627
788
|
name: service.name,
|
|
@@ -630,9 +791,9 @@ export const processDeployment = (
|
|
|
630
791
|
description:
|
|
631
792
|
artifact.ref?.module ||
|
|
632
793
|
(artifact.description?.builtin ? "Builtin Service" : ""),
|
|
633
|
-
resource:
|
|
634
|
-
parameters
|
|
635
|
-
hsize
|
|
794
|
+
resource: resources,
|
|
795
|
+
parameters,
|
|
796
|
+
hsize,
|
|
636
797
|
...(deployment.meta?.scaling &&
|
|
637
798
|
Object.keys(deployment.meta.scaling.simple || {}).length > 0 && {
|
|
638
799
|
scalling: processScalingConfig(deployment.meta),
|
|
@@ -641,60 +802,43 @@ export const processDeployment = (
|
|
|
641
802
|
];
|
|
642
803
|
}
|
|
643
804
|
|
|
644
|
-
return {
|
|
645
|
-
...service,
|
|
646
|
-
resources: serviceResources,
|
|
647
|
-
parameters: allServiceParameters,
|
|
648
|
-
role: updatedRoles,
|
|
649
|
-
};
|
|
805
|
+
return { ...service, resources, parameters, role: updatedRoles };
|
|
650
806
|
};
|
|
807
|
+
|
|
651
808
|
export const extractParametersFromConfig = (
|
|
652
809
|
parameterConfig: any,
|
|
653
810
|
): { [key: string]: string }[] => {
|
|
654
811
|
const parameters: { [key: string]: string }[] = [];
|
|
655
|
-
|
|
656
|
-
if (!parameterConfig || typeof parameterConfig !== "object") {
|
|
812
|
+
if (!parameterConfig || typeof parameterConfig !== "object")
|
|
657
813
|
return parameters;
|
|
658
|
-
}
|
|
659
814
|
|
|
660
815
|
Object.entries(parameterConfig).forEach(
|
|
661
816
|
([paramName, paramValue]: [string, any]) => {
|
|
662
817
|
let value: string;
|
|
663
818
|
let description: string | undefined;
|
|
664
|
-
|
|
665
819
|
if (typeof paramValue === "object" && paramValue !== null) {
|
|
666
|
-
if (paramValue.value !== undefined)
|
|
667
|
-
|
|
668
|
-
} else if (paramValue.default !== undefined) {
|
|
820
|
+
if (paramValue.value !== undefined) value = paramValue.value;
|
|
821
|
+
else if (paramValue.default !== undefined)
|
|
669
822
|
value = String(paramValue.default);
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
if (paramValue.description) {
|
|
675
|
-
description = paramValue.description;
|
|
676
|
-
}
|
|
823
|
+
else value = JSON.stringify(paramValue);
|
|
824
|
+
if (paramValue.description) description = paramValue.description;
|
|
677
825
|
} else {
|
|
678
826
|
value = String(paramValue);
|
|
679
827
|
}
|
|
680
|
-
|
|
681
828
|
const parameter: { [key: string]: string } = {
|
|
682
829
|
name: paramName,
|
|
683
|
-
value
|
|
830
|
+
value,
|
|
684
831
|
type: typeof paramValue,
|
|
685
832
|
configKey: paramName,
|
|
686
833
|
};
|
|
687
|
-
|
|
688
|
-
if (description) {
|
|
689
|
-
parameter.description = description;
|
|
690
|
-
}
|
|
691
|
-
|
|
834
|
+
if (description) parameter.description = description;
|
|
692
835
|
parameters.push(parameter);
|
|
693
836
|
},
|
|
694
837
|
);
|
|
695
838
|
|
|
696
839
|
return parameters;
|
|
697
840
|
};
|
|
841
|
+
|
|
698
842
|
export const extractParametersFromFilesystem = (
|
|
699
843
|
filesystem: any,
|
|
700
844
|
currentParameters: { [key: string]: string }[],
|
|
@@ -711,13 +855,13 @@ export const extractParametersFromFilesystem = (
|
|
|
711
855
|
value: value.data.value,
|
|
712
856
|
type: "file",
|
|
713
857
|
});
|
|
714
|
-
if (existingParam)
|
|
858
|
+
if (existingParam)
|
|
715
859
|
currentParameters.splice(currentParameters.indexOf(existingParam), 1);
|
|
716
|
-
}
|
|
717
860
|
}
|
|
718
861
|
});
|
|
719
862
|
return parameters;
|
|
720
863
|
};
|
|
864
|
+
|
|
721
865
|
export const extractResourcesFromFilesystem = (
|
|
722
866
|
filesystem: any,
|
|
723
867
|
currentResources: Resource[],
|
|
@@ -741,16 +885,15 @@ export const extractResourcesFromFilesystem = (
|
|
|
741
885
|
status: existingResource?.status || "available",
|
|
742
886
|
tenant: "",
|
|
743
887
|
});
|
|
744
|
-
if (existingResource)
|
|
888
|
+
if (existingResource)
|
|
745
889
|
currentResources.splice(currentResources.indexOf(existingResource), 1);
|
|
746
|
-
}
|
|
747
890
|
}
|
|
748
891
|
});
|
|
749
892
|
return resources;
|
|
750
893
|
};
|
|
894
|
+
|
|
751
895
|
export const extractResources = (resourceConfig: any): Resource[] => {
|
|
752
896
|
const resources: Resource[] = [];
|
|
753
|
-
|
|
754
897
|
Object.entries(resourceConfig).forEach(
|
|
755
898
|
([resourceName, resourceData]: [string, any]) => {
|
|
756
899
|
let resource: Resource;
|
|
@@ -819,42 +962,34 @@ export const extractResources = (resourceConfig: any): Resource[] => {
|
|
|
819
962
|
status: "available",
|
|
820
963
|
tenant: "",
|
|
821
964
|
};
|
|
822
|
-
|
|
823
965
|
if (resourceData.kind) resource.kind = resourceData.kind;
|
|
824
966
|
if (resourceData.domain) resource.domain = resourceData.domain;
|
|
825
967
|
if (resourceData.key) resource.key = resourceData.key;
|
|
826
968
|
if (resourceData.maxItems) resource.maxItems = resourceData.maxItems;
|
|
827
969
|
}
|
|
828
|
-
|
|
829
970
|
resources.push(resource);
|
|
830
971
|
},
|
|
831
972
|
);
|
|
832
|
-
|
|
833
973
|
return resources;
|
|
834
974
|
};
|
|
975
|
+
|
|
835
976
|
const processScalingConfig = (meta: any): any => {
|
|
836
|
-
if (!meta?.scaling?.simple || Object.keys(meta.scaling.simple).length === 0)
|
|
977
|
+
if (!meta?.scaling?.simple || Object.keys(meta.scaling.simple).length === 0)
|
|
837
978
|
return {
|
|
838
979
|
cpu: { up: "80%", down: "20%" },
|
|
839
980
|
memory: { up: "80%", down: "20%" },
|
|
840
981
|
instances: { max: 1, min: 1 },
|
|
841
982
|
histeresys: "5",
|
|
842
983
|
};
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
const roleNames = Object.keys(meta.scaling.simple);
|
|
846
|
-
const firstRoleName = roleNames[0];
|
|
984
|
+
const firstRoleName = Object.keys(meta.scaling.simple)[0];
|
|
847
985
|
const roleScaling = meta.scaling.simple[firstRoleName];
|
|
848
|
-
|
|
849
|
-
if (!roleScaling) {
|
|
986
|
+
if (!roleScaling)
|
|
850
987
|
return {
|
|
851
988
|
cpu: { up: "80%", down: "20%" },
|
|
852
989
|
memory: { up: "80%", down: "20%" },
|
|
853
990
|
instances: { max: 1, min: 1 },
|
|
854
991
|
histeresys: "5",
|
|
855
992
|
};
|
|
856
|
-
}
|
|
857
|
-
|
|
858
993
|
return {
|
|
859
994
|
cpu: {
|
|
860
995
|
up: `${roleScaling.scale_up?.cpu || 80}%`,
|
|
@@ -871,99 +1006,13 @@ const processScalingConfig = (meta: any): any => {
|
|
|
871
1006
|
histeresys: `${roleScaling.hysteresis || 5}`,
|
|
872
1007
|
};
|
|
873
1008
|
};
|
|
1009
|
+
|
|
874
1010
|
const extractResourceName = (resourcePath: string): string => {
|
|
875
1011
|
if (!resourcePath) return "";
|
|
876
|
-
|
|
877
1012
|
const parts = resourcePath.split("/");
|
|
878
|
-
|
|
879
1013
|
if (parts.length === 2) {
|
|
880
|
-
if (parts[0] === "cluster.core")
|
|
881
|
-
return resourcePath;
|
|
882
|
-
}
|
|
1014
|
+
if (parts[0] === "cluster.core") return resourcePath;
|
|
883
1015
|
return parts[1];
|
|
884
1016
|
}
|
|
885
1017
|
return resourcePath;
|
|
886
1018
|
};
|
|
887
|
-
//UNUSED KEEPING IT JUST IN CASE:
|
|
888
|
-
const extractParameters = (
|
|
889
|
-
parameterConfig: any,
|
|
890
|
-
roleData?: any,
|
|
891
|
-
roleName?: string,
|
|
892
|
-
): { [key: string]: string }[] => {
|
|
893
|
-
const parameters: { [key: string]: string }[] = [];
|
|
894
|
-
|
|
895
|
-
if (roleData?.artifact?.description?.code) {
|
|
896
|
-
const codeEntries = Object.entries(roleData.artifact.description.code);
|
|
897
|
-
|
|
898
|
-
for (const [codeName, codeData] of codeEntries) {
|
|
899
|
-
const mapping = (codeData as any)?.mapping?.env;
|
|
900
|
-
|
|
901
|
-
if (mapping && typeof mapping === "object") {
|
|
902
|
-
Object.entries(mapping).forEach(([envName, envData]: [string, any]) => {
|
|
903
|
-
const envValue = envData.value || "";
|
|
904
|
-
let configKey = envName;
|
|
905
|
-
const matchedParam = Object.entries(parameterConfig).find(
|
|
906
|
-
([configParamName, paramData]: [string, any]) => {
|
|
907
|
-
const configValue =
|
|
908
|
-
typeof paramData === "object"
|
|
909
|
-
? paramData.value || paramData.default || ""
|
|
910
|
-
: String(paramData);
|
|
911
|
-
const envLower = envName.toLowerCase();
|
|
912
|
-
const configLower = configParamName.toLowerCase();
|
|
913
|
-
|
|
914
|
-
if (
|
|
915
|
-
envLower.includes(configLower) ||
|
|
916
|
-
configLower.includes(envLower)
|
|
917
|
-
) {
|
|
918
|
-
return configValue === envValue;
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
return false;
|
|
922
|
-
},
|
|
923
|
-
);
|
|
924
|
-
|
|
925
|
-
if (matchedParam) {
|
|
926
|
-
configKey = matchedParam[0];
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
const parameter: { [key: string]: string } = {
|
|
930
|
-
name: envName,
|
|
931
|
-
value: envValue,
|
|
932
|
-
type: configKey,
|
|
933
|
-
configKey: configKey,
|
|
934
|
-
...(roleName && { fromRole: roleName }),
|
|
935
|
-
};
|
|
936
|
-
|
|
937
|
-
parameters.push(parameter);
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
if (parameters.length === 0 && parameterConfig) {
|
|
944
|
-
Object.entries(parameterConfig).forEach(
|
|
945
|
-
([paramName, paramData]: [string, any]) => {
|
|
946
|
-
const paramValue =
|
|
947
|
-
typeof paramData === "object"
|
|
948
|
-
? paramData.value || paramData.default || ""
|
|
949
|
-
: String(paramData);
|
|
950
|
-
|
|
951
|
-
const parameter: { [key: string]: string } = {
|
|
952
|
-
name: paramName,
|
|
953
|
-
value: paramValue,
|
|
954
|
-
type: paramName,
|
|
955
|
-
configKey: paramName,
|
|
956
|
-
...(roleName && { fromRole: roleName }),
|
|
957
|
-
};
|
|
958
|
-
|
|
959
|
-
if (typeof paramData === "object" && paramData.description) {
|
|
960
|
-
parameter.description = paramData.description;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
parameters.push(parameter);
|
|
964
|
-
},
|
|
965
|
-
);
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
return parameters;
|
|
969
|
-
};
|