@kumori/aurora-backend-handler 1.0.50 → 1.0.52
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 +6 -0
- package/api/service-api-service.ts +217 -210
- package/api/user-api-service.ts +203 -233
- package/helpers/revision-helper.ts +355 -278
- package/helpers/service-helper.ts +80 -189
- package/package.json +2 -2
- package/websocket-manager.ts +5 -12
|
@@ -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,27 +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
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
updatedRevisions =
|
|
263
|
-
existingRevisionIndex === -1
|
|
264
|
-
? [...existingService.revisions, entityId]
|
|
265
|
-
: existingService.revisions;
|
|
266
|
-
} else {
|
|
267
|
-
updatedRevisions = existingService.revisions.filter(
|
|
268
|
-
(rev) => rev !== entityId,
|
|
269
|
-
);
|
|
270
|
-
}
|
|
220
|
+
const updatedRevisions: Revision[] =
|
|
221
|
+
existingRevisionIndex === -1
|
|
222
|
+
? [...existingService.revisions, newRevision]
|
|
223
|
+
: existingService.revisions.map((rev) =>
|
|
224
|
+
rev.id === entityId ? newRevision : rev,
|
|
225
|
+
);
|
|
271
226
|
|
|
272
227
|
const updatedService: Service = {
|
|
273
228
|
...existingService,
|
|
274
229
|
revisions: updatedRevisions,
|
|
230
|
+
currentRevision: entityId,
|
|
275
231
|
role: roles.length > 0 ? roles : existingService.role,
|
|
276
232
|
usage: newRevision.usage,
|
|
277
233
|
startedAt: newRevision.createdAt || existingService.startedAt,
|
|
@@ -285,7 +241,6 @@ const updateServiceWithRevision = (
|
|
|
285
241
|
|
|
286
242
|
if (incomingTs > currentTs) {
|
|
287
243
|
updatedService.status = incomingStatus;
|
|
288
|
-
|
|
289
244
|
if (eventData.status.error) {
|
|
290
245
|
updatedService.error = {
|
|
291
246
|
code: eventData.status.error.code,
|
|
@@ -299,7 +254,6 @@ const updateServiceWithRevision = (
|
|
|
299
254
|
} else if (eventData.status.error) {
|
|
300
255
|
const incomingErrorTs = getTimestamp(eventData.status.error.timestamp);
|
|
301
256
|
const currentErrorTs = getTimestamp(existingService.error?.timestamp);
|
|
302
|
-
|
|
303
257
|
if (incomingErrorTs > currentErrorTs) {
|
|
304
258
|
updatedService.error = {
|
|
305
259
|
code: eventData.status.error.code,
|
|
@@ -313,9 +267,6 @@ const updateServiceWithRevision = (
|
|
|
313
267
|
return { updatedService, deploymentErrorEvent };
|
|
314
268
|
};
|
|
315
269
|
|
|
316
|
-
/**
|
|
317
|
-
* Update environment consumption history
|
|
318
|
-
*/
|
|
319
270
|
const updateEnvironmentConsumption = (
|
|
320
271
|
environment: Environment,
|
|
321
272
|
servicesMap: Map<string, Service>,
|
|
@@ -336,31 +287,24 @@ const updateEnvironmentConsumption = (
|
|
|
336
287
|
}
|
|
337
288
|
});
|
|
338
289
|
|
|
339
|
-
if (!environment.usage.current.cpuConsuption)
|
|
290
|
+
if (!environment.usage.current.cpuConsuption)
|
|
340
291
|
environment.usage.current.cpuConsuption = [];
|
|
341
|
-
|
|
342
|
-
if (!environment.usage.current.memoryConsuption) {
|
|
292
|
+
if (!environment.usage.current.memoryConsuption)
|
|
343
293
|
environment.usage.current.memoryConsuption = [];
|
|
344
|
-
}
|
|
345
294
|
|
|
346
295
|
environment.usage.current.cpuConsuption.push(totalEnvCpu);
|
|
347
296
|
environment.usage.current.memoryConsuption.push(totalEnvMemory);
|
|
348
297
|
|
|
349
|
-
if (environment.usage.current.cpuConsuption.length > MAX_HISTORY)
|
|
298
|
+
if (environment.usage.current.cpuConsuption.length > MAX_HISTORY)
|
|
350
299
|
environment.usage.current.cpuConsuption =
|
|
351
300
|
environment.usage.current.cpuConsuption.slice(-MAX_HISTORY);
|
|
352
|
-
|
|
353
|
-
if (environment.usage.current.memoryConsuption.length > MAX_HISTORY) {
|
|
301
|
+
if (environment.usage.current.memoryConsuption.length > MAX_HISTORY)
|
|
354
302
|
environment.usage.current.memoryConsuption =
|
|
355
303
|
environment.usage.current.memoryConsuption.slice(-MAX_HISTORY);
|
|
356
|
-
}
|
|
357
304
|
|
|
358
305
|
return environment;
|
|
359
306
|
};
|
|
360
307
|
|
|
361
|
-
/**
|
|
362
|
-
* Update account consumption history
|
|
363
|
-
*/
|
|
364
308
|
const updateAccountConsumption = (
|
|
365
309
|
account: Account,
|
|
366
310
|
servicesMap: Map<string, Service>,
|
|
@@ -381,31 +325,24 @@ const updateAccountConsumption = (
|
|
|
381
325
|
}
|
|
382
326
|
});
|
|
383
327
|
|
|
384
|
-
if (!account.usage.current.cpuConsuption)
|
|
328
|
+
if (!account.usage.current.cpuConsuption)
|
|
385
329
|
account.usage.current.cpuConsuption = [];
|
|
386
|
-
|
|
387
|
-
if (!account.usage.current.memoryConsuption) {
|
|
330
|
+
if (!account.usage.current.memoryConsuption)
|
|
388
331
|
account.usage.current.memoryConsuption = [];
|
|
389
|
-
}
|
|
390
332
|
|
|
391
333
|
account.usage.current.cpuConsuption.push(totalAccountCpu);
|
|
392
334
|
account.usage.current.memoryConsuption.push(totalAccountMemory);
|
|
393
335
|
|
|
394
|
-
if (account.usage.current.cpuConsuption.length > MAX_HISTORY)
|
|
336
|
+
if (account.usage.current.cpuConsuption.length > MAX_HISTORY)
|
|
395
337
|
account.usage.current.cpuConsuption =
|
|
396
338
|
account.usage.current.cpuConsuption.slice(-MAX_HISTORY);
|
|
397
|
-
|
|
398
|
-
if (account.usage.current.memoryConsuption.length > MAX_HISTORY) {
|
|
339
|
+
if (account.usage.current.memoryConsuption.length > MAX_HISTORY)
|
|
399
340
|
account.usage.current.memoryConsuption =
|
|
400
341
|
account.usage.current.memoryConsuption.slice(-MAX_HISTORY);
|
|
401
|
-
}
|
|
402
342
|
|
|
403
343
|
return account;
|
|
404
344
|
};
|
|
405
|
-
|
|
406
|
-
* Handles the "revision" event from WebSocket messages
|
|
407
|
-
* Processes revision data, updates services, environments, and accounts
|
|
408
|
-
*/
|
|
345
|
+
|
|
409
346
|
export const handleRevisionEvent = ({
|
|
410
347
|
entityId,
|
|
411
348
|
eventData,
|
|
@@ -423,13 +360,15 @@ export const handleRevisionEvent = ({
|
|
|
423
360
|
serviceId,
|
|
424
361
|
roleMap,
|
|
425
362
|
);
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
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
|
+
|
|
433
372
|
let updatedService: Service | null = null;
|
|
434
373
|
let updatedEnvironment: Environment | null = null;
|
|
435
374
|
let updatedAccount: Account | null = null;
|
|
@@ -450,9 +389,9 @@ export const handleRevisionEvent = ({
|
|
|
450
389
|
newRevision,
|
|
451
390
|
roles,
|
|
452
391
|
);
|
|
453
|
-
|
|
454
392
|
updatedService = serviceUpdateResult.updatedService;
|
|
455
393
|
serviceDeploymentErrorEvent = serviceUpdateResult.deploymentErrorEvent;
|
|
394
|
+
|
|
456
395
|
const serviceEnvironmentId = updatedService.environment;
|
|
457
396
|
if (serviceEnvironmentId) {
|
|
458
397
|
const environment = environmentsMap.get(serviceEnvironmentId);
|
|
@@ -461,7 +400,6 @@ export const handleRevisionEvent = ({
|
|
|
461
400
|
tempServicesMap.set(serviceId, updatedService);
|
|
462
401
|
const tempRevisionsMap = new Map(revisionsMap);
|
|
463
402
|
tempRevisionsMap.set(revisionKey, newRevision);
|
|
464
|
-
|
|
465
403
|
updatedEnvironment = updateEnvironmentConsumption(
|
|
466
404
|
{ ...environment },
|
|
467
405
|
tempServicesMap,
|
|
@@ -470,16 +408,15 @@ export const handleRevisionEvent = ({
|
|
|
470
408
|
);
|
|
471
409
|
}
|
|
472
410
|
}
|
|
411
|
+
|
|
473
412
|
const serviceAccountId = updatedService.account;
|
|
474
413
|
if (serviceAccountId) {
|
|
475
414
|
const account = accountsMap.get(serviceAccountId);
|
|
476
415
|
if (account) {
|
|
477
416
|
const tempServicesMap = new Map(servicesMap);
|
|
478
417
|
tempServicesMap.set(serviceId, updatedService);
|
|
479
|
-
|
|
480
418
|
const tempRevisionsMap = new Map(revisionsMap);
|
|
481
419
|
tempRevisionsMap.set(revisionKey, newRevision);
|
|
482
|
-
|
|
483
420
|
updatedAccount = updateAccountConsumption(
|
|
484
421
|
{ ...account },
|
|
485
422
|
tempServicesMap,
|
|
@@ -491,11 +428,9 @@ export const handleRevisionEvent = ({
|
|
|
491
428
|
} else if (eventData.status && eventData.status.error) {
|
|
492
429
|
newRevision.errorCode = eventData.status.error.code;
|
|
493
430
|
newRevision.errorMsg = eventData.status.error.message;
|
|
494
|
-
pendingRevisionError = {
|
|
495
|
-
service: serviceId,
|
|
496
|
-
revision: newRevision,
|
|
497
|
-
};
|
|
431
|
+
pendingRevisionError = { service: serviceId, revision: newRevision };
|
|
498
432
|
}
|
|
433
|
+
|
|
499
434
|
if (
|
|
500
435
|
!eventData.meta.deleted &&
|
|
501
436
|
eventData.status &&
|
|
@@ -523,45 +458,290 @@ export const handleRevisionEvent = ({
|
|
|
523
458
|
serviceDeploymentErrorEvent,
|
|
524
459
|
};
|
|
525
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
|
+
const rolesDefinition: Record<string, any> =
|
|
529
|
+
(deployment as any)?.artifact?.description?.role ?? {};
|
|
530
|
+
|
|
531
|
+
const mergedParameterValues: Record<string, any> = {};
|
|
532
|
+
const mergedResourceValues: Record<string, any> = {};
|
|
533
|
+
|
|
534
|
+
Object.values(rolesDefinition).forEach((roleData: any) => {
|
|
535
|
+
const roleConfig = roleData?.artifact?.description?.config ?? {};
|
|
536
|
+
Object.assign(mergedParameterValues, roleConfig.parameter ?? {});
|
|
537
|
+
Object.assign(mergedResourceValues, roleConfig.resource ?? {});
|
|
538
|
+
});
|
|
539
|
+
const topLevelConfig = (deployment as any)?.config ?? {};
|
|
540
|
+
const parameterValues: Record<string, any> = {
|
|
541
|
+
...topLevelConfig.parameter ?? {},
|
|
542
|
+
...mergedParameterValues,
|
|
543
|
+
};
|
|
544
|
+
const configResourceValues: Record<string, any> = {
|
|
545
|
+
...topLevelConfig.resource ?? {},
|
|
546
|
+
...mergedResourceValues,
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
const requiredParams: string[] =
|
|
550
|
+
configSchema?.properties?.config?.required ?? [];
|
|
551
|
+
const requiredResources: string[] =
|
|
552
|
+
configSchema?.properties?.resource?.required ?? [];
|
|
553
|
+
const schemaConfigProps: Record<string, any> =
|
|
554
|
+
configSchema?.properties?.config?.properties ?? {};
|
|
555
|
+
|
|
556
|
+
const parameters = Object.entries(schemaConfigProps).map(
|
|
557
|
+
([name, propSchema]) => {
|
|
558
|
+
const entry: {
|
|
559
|
+
name: string;
|
|
560
|
+
type: string;
|
|
561
|
+
required: boolean;
|
|
562
|
+
defaultValue?: any;
|
|
563
|
+
} = {
|
|
564
|
+
name,
|
|
565
|
+
type: propSchema?.type ?? "string",
|
|
566
|
+
required: requiredParams.includes(name),
|
|
567
|
+
};
|
|
568
|
+
const currentValue = parameterValues[name];
|
|
569
|
+
if (currentValue !== undefined) entry.defaultValue = currentValue;
|
|
570
|
+
else if (propSchema?.default !== undefined)
|
|
571
|
+
entry.defaultValue = propSchema.default;
|
|
572
|
+
return entry;
|
|
573
|
+
},
|
|
574
|
+
);
|
|
575
|
+
|
|
576
|
+
const resolveResourceType = (
|
|
577
|
+
configValue: any,
|
|
578
|
+
): { type: string; kind?: string } | null => {
|
|
579
|
+
if (!configValue || typeof configValue !== "object") return null;
|
|
580
|
+
if ("secret" in configValue) return { type: "secret" };
|
|
581
|
+
if ("domain" in configValue) return { type: "domain" };
|
|
582
|
+
if ("port" in configValue) return { type: "port" };
|
|
583
|
+
if ("certificate" in configValue) return { type: "certificate" };
|
|
584
|
+
if ("ca" in configValue) return { type: "ca" };
|
|
585
|
+
if ("volume" in configValue) {
|
|
586
|
+
const volType = configValue.volume?.type;
|
|
587
|
+
if (volType === "persistent" || volType === "Persisted")
|
|
588
|
+
return { type: "volume", kind: "persistent" };
|
|
589
|
+
if (volType === "nonReplicated" || volType === "NonReplicated")
|
|
590
|
+
return { type: "volume", kind: "nonReplicated" };
|
|
591
|
+
if (
|
|
592
|
+
volType === "volatile" ||
|
|
593
|
+
volType === "Volatile" ||
|
|
594
|
+
volType === "ephemeral" ||
|
|
595
|
+
volType === "Ephemeral"
|
|
596
|
+
)
|
|
597
|
+
return { type: "volume", kind: "volatile" };
|
|
598
|
+
return { type: "volume" };
|
|
599
|
+
}
|
|
600
|
+
return null;
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
const allResourceNames = new Set<string>([
|
|
604
|
+
...Object.keys(configResourceValues),
|
|
605
|
+
...Object.keys(configSchema?.properties?.resource?.properties ?? {}),
|
|
606
|
+
]);
|
|
607
|
+
|
|
608
|
+
const resources = Array.from(allResourceNames)
|
|
609
|
+
.map((name) => {
|
|
610
|
+
const configValue = configResourceValues[name];
|
|
611
|
+
const fromConfig = resolveResourceType(configValue);
|
|
612
|
+
const schemaProps =
|
|
613
|
+
configSchema?.properties?.resource?.properties?.[name];
|
|
614
|
+
const fromSchema = schemaProps
|
|
615
|
+
? namedTypeToResourceKind(collectNamedTypes(schemaProps))
|
|
616
|
+
: null;
|
|
617
|
+
const resolved = fromConfig ?? fromSchema;
|
|
618
|
+
if (!resolved) return null;
|
|
619
|
+
const entry: {
|
|
620
|
+
name: string;
|
|
621
|
+
type: string;
|
|
622
|
+
kind?: string;
|
|
623
|
+
required: boolean;
|
|
624
|
+
} = {
|
|
625
|
+
name,
|
|
626
|
+
type: resolved.type,
|
|
627
|
+
required: requiredResources.includes(name),
|
|
628
|
+
};
|
|
629
|
+
if (resolved.kind) entry.kind = resolved.kind;
|
|
630
|
+
return entry;
|
|
631
|
+
})
|
|
632
|
+
.filter(Boolean) as {
|
|
633
|
+
name: string;
|
|
634
|
+
type: string;
|
|
635
|
+
kind?: string;
|
|
636
|
+
required: boolean;
|
|
637
|
+
}[];
|
|
638
|
+
|
|
639
|
+
return { parameters, resources };
|
|
640
|
+
};
|
|
641
|
+
|
|
526
642
|
export const processRevisionData = (
|
|
527
643
|
service: Service,
|
|
528
644
|
revisionData: any,
|
|
645
|
+
revisionsMap?: Map<string, Revision>,
|
|
646
|
+
serviceId?: string,
|
|
529
647
|
): Service => {
|
|
530
648
|
const { solution } = revisionData;
|
|
649
|
+
const topLevelConfig = revisionData?.config?.config ?? {};
|
|
650
|
+
const topLevelParameters = extractParametersFromConfig(topLevelConfig.parameter || {});
|
|
651
|
+
const topLevelResources = extractResources(topLevelConfig.resource || {});
|
|
531
652
|
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
653
|
+
const schemaResult = revisionData.revision
|
|
654
|
+
? extractStructuredSchema(revisionData)
|
|
655
|
+
: {};
|
|
656
|
+
const schema =
|
|
657
|
+
schemaResult && "parameters" in schemaResult ? schemaResult : {};
|
|
658
|
+
|
|
659
|
+
if (
|
|
660
|
+
revisionsMap &&
|
|
661
|
+
serviceId &&
|
|
662
|
+
revisionData.revision &&
|
|
663
|
+
"parameters" in schema
|
|
664
|
+
) {
|
|
665
|
+
const revisionId: string = revisionData.revision;
|
|
666
|
+
const revisionKey = `${serviceId}-${revisionId}`;
|
|
667
|
+
const existing = revisionsMap.get(revisionKey);
|
|
668
|
+
if (existing) {
|
|
669
|
+
revisionsMap.set(revisionKey, { ...existing, schema });
|
|
670
|
+
} else {
|
|
671
|
+
revisionsMap.set(revisionKey, {
|
|
672
|
+
id: revisionId,
|
|
673
|
+
schema,
|
|
674
|
+
usage: {
|
|
675
|
+
current: {
|
|
676
|
+
cpu: 0,
|
|
677
|
+
memory: 0,
|
|
678
|
+
storage: 0,
|
|
679
|
+
volatileStorage: 0,
|
|
680
|
+
nonReplicatedStorage: 0,
|
|
681
|
+
persistentStorage: 0,
|
|
682
|
+
},
|
|
683
|
+
limit: {
|
|
684
|
+
cpu: { max: revisionData.intensives?.vcpu / 1000 || 0, min: 0 },
|
|
685
|
+
memory: { max: revisionData.intensives?.ram / 1000 || 0, min: 0 },
|
|
686
|
+
storage: {
|
|
687
|
+
max: revisionData.intensives?.shared_disk / 1000 || 0,
|
|
688
|
+
min: 0,
|
|
689
|
+
},
|
|
690
|
+
volatileStorage: {
|
|
691
|
+
max: revisionData.intensives?.volatile_disk / 1000 || 0,
|
|
692
|
+
min: 0,
|
|
693
|
+
},
|
|
694
|
+
nonReplicatedStorage: {
|
|
695
|
+
max: revisionData.intensives?.nrpersistent_disk / 1000 || 0,
|
|
696
|
+
min: 0,
|
|
697
|
+
},
|
|
698
|
+
persistentStorage: {
|
|
699
|
+
max: revisionData.intensives?.persistent_disk / 1000 || 0,
|
|
700
|
+
min: 0,
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
cost: 0,
|
|
704
|
+
},
|
|
705
|
+
status: { code: "", message: "", timestamp: "", args: [] },
|
|
706
|
+
errorCode: "",
|
|
707
|
+
errorMsg: "",
|
|
708
|
+
createdAt: "",
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
}
|
|
537
712
|
|
|
538
713
|
const deploymentName = solution.top || service.name;
|
|
539
714
|
const deployment = solution.deployments[deploymentName];
|
|
540
715
|
|
|
716
|
+
const applySchemaToService = (svc: Service): Service => {
|
|
717
|
+
if (!revisionData.revision || !("parameters" in schema)) return svc;
|
|
718
|
+
const revisionId: string = revisionData.revision;
|
|
719
|
+
return {
|
|
720
|
+
...svc,
|
|
721
|
+
revisions: svc.revisions.map((rev) =>
|
|
722
|
+
rev.id === revisionId ? { ...rev, schema } : rev,
|
|
723
|
+
),
|
|
724
|
+
};
|
|
725
|
+
};
|
|
726
|
+
|
|
541
727
|
if (!deployment) {
|
|
542
728
|
const firstDeploymentKey = Object.keys(solution.deployments)[0];
|
|
543
729
|
if (firstDeploymentKey) {
|
|
544
|
-
return
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
730
|
+
return applySchemaToService(
|
|
731
|
+
processDeployment(
|
|
732
|
+
service,
|
|
733
|
+
solution.deployments[firstDeploymentKey],
|
|
734
|
+
revisionData,
|
|
735
|
+
topLevelParameters,
|
|
736
|
+
topLevelResources,
|
|
737
|
+
),
|
|
550
738
|
);
|
|
551
739
|
}
|
|
552
|
-
return {
|
|
553
|
-
...service,
|
|
554
|
-
parameters: parameters,
|
|
555
|
-
resources: resources,
|
|
556
|
-
};
|
|
740
|
+
return applySchemaToService({ ...service, parameters: topLevelParameters, resources: topLevelResources });
|
|
557
741
|
}
|
|
558
742
|
|
|
559
|
-
return
|
|
560
|
-
service,
|
|
561
|
-
deployment,
|
|
562
|
-
revisionData,
|
|
563
|
-
parameters,
|
|
564
|
-
resources,
|
|
743
|
+
return applySchemaToService(
|
|
744
|
+
processDeployment(service, deployment, revisionData, topLevelParameters, topLevelResources),
|
|
565
745
|
);
|
|
566
746
|
};
|
|
567
747
|
|
|
@@ -569,12 +749,11 @@ export const processDeployment = (
|
|
|
569
749
|
service: Service,
|
|
570
750
|
deployment: any,
|
|
571
751
|
revisionData: any,
|
|
572
|
-
|
|
573
|
-
|
|
752
|
+
fallbackParameters: { [key: string]: string }[],
|
|
753
|
+
fallbackResources: Resource[],
|
|
574
754
|
): Service => {
|
|
575
755
|
const artifact = deployment.artifact;
|
|
576
756
|
const deploymentConfig = deployment.config || {};
|
|
577
|
-
|
|
578
757
|
const rolesDefinition = artifact.description?.role || {};
|
|
579
758
|
const hasRoles = Object.keys(rolesDefinition).length > 0;
|
|
580
759
|
let updatedRoles: Role[] = [];
|
|
@@ -583,18 +762,29 @@ export const processDeployment = (
|
|
|
583
762
|
Object.entries(rolesDefinition).forEach(
|
|
584
763
|
([roleName, roleData]: [string, any]) => {
|
|
585
764
|
const existingRole = service.role.find((r) => r.name === roleName);
|
|
765
|
+
const roleArtifactConfig = roleData?.artifact?.description?.config ?? {};
|
|
766
|
+
|
|
767
|
+
const roleParameters = extractParametersFromConfig(
|
|
768
|
+
roleArtifactConfig.parameter ?? {}
|
|
769
|
+
);
|
|
770
|
+
const roleResources = extractResources(
|
|
771
|
+
roleArtifactConfig.resource ?? {}
|
|
772
|
+
);
|
|
773
|
+
const parameters = roleParameters;
|
|
774
|
+
const resources = roleResources;
|
|
775
|
+
|
|
586
776
|
let hsize = 1;
|
|
587
|
-
if (roleData.config?.scale?.hsize !== undefined)
|
|
777
|
+
if (roleData.config?.scale?.hsize !== undefined)
|
|
588
778
|
hsize = roleData.config.scale.hsize;
|
|
589
|
-
|
|
590
|
-
if (deploymentConfig.scale?.detail?.[roleName]?.hsize !== undefined) {
|
|
779
|
+
if (deploymentConfig.scale?.detail?.[roleName]?.hsize !== undefined)
|
|
591
780
|
hsize = deploymentConfig.scale.detail[roleName].hsize;
|
|
592
|
-
|
|
781
|
+
|
|
593
782
|
const hasDuplex =
|
|
594
783
|
roleData.artifact?.description?.srv?.duplex?.length > 0;
|
|
595
784
|
const hasVolumeResource = Object.values(
|
|
596
|
-
|
|
785
|
+
roleArtifactConfig.resource || {},
|
|
597
786
|
).some((resourceData: any) => resourceData.volume);
|
|
787
|
+
|
|
598
788
|
const role: Role = {
|
|
599
789
|
name: roleName,
|
|
600
790
|
instances: existingRole?.instances || [],
|
|
@@ -602,27 +792,27 @@ export const processDeployment = (
|
|
|
602
792
|
description:
|
|
603
793
|
roleData.artifact?.ref?.module || roleData.ref?.module || "",
|
|
604
794
|
resource: resources,
|
|
605
|
-
parameters
|
|
606
|
-
hsize
|
|
795
|
+
parameters,
|
|
796
|
+
hsize,
|
|
607
797
|
category: hasDuplex || hasVolumeResource ? "stateful" : "",
|
|
608
798
|
};
|
|
799
|
+
|
|
609
800
|
if (
|
|
610
801
|
deployment.meta?.scaling &&
|
|
611
802
|
Object.keys(deployment.meta.scaling.simple || {}).length > 0
|
|
612
|
-
)
|
|
803
|
+
)
|
|
613
804
|
role.scalling = processScalingConfig(deployment.meta);
|
|
614
|
-
|
|
805
|
+
|
|
615
806
|
updatedRoles.push(role);
|
|
616
807
|
},
|
|
617
808
|
);
|
|
618
809
|
} else {
|
|
619
810
|
let hsize = 1;
|
|
620
|
-
if (deploymentConfig.scale?.hsize !== undefined)
|
|
811
|
+
if (deploymentConfig.scale?.hsize !== undefined)
|
|
621
812
|
hsize = deploymentConfig.scale.hsize;
|
|
622
|
-
|
|
623
|
-
if (deploymentConfig.scale?.detail?.[""]?.hsize !== undefined) {
|
|
813
|
+
if (deploymentConfig.scale?.detail?.[""]?.hsize !== undefined)
|
|
624
814
|
hsize = deploymentConfig.scale.detail[""].hsize;
|
|
625
|
-
|
|
815
|
+
|
|
626
816
|
updatedRoles = [
|
|
627
817
|
{
|
|
628
818
|
name: service.name,
|
|
@@ -631,9 +821,9 @@ export const processDeployment = (
|
|
|
631
821
|
description:
|
|
632
822
|
artifact.ref?.module ||
|
|
633
823
|
(artifact.description?.builtin ? "Builtin Service" : ""),
|
|
634
|
-
resource:
|
|
635
|
-
parameters:
|
|
636
|
-
hsize
|
|
824
|
+
resource: [],
|
|
825
|
+
parameters: [],
|
|
826
|
+
hsize,
|
|
637
827
|
...(deployment.meta?.scaling &&
|
|
638
828
|
Object.keys(deployment.meta.scaling.simple || {}).length > 0 && {
|
|
639
829
|
scalling: processScalingConfig(deployment.meta),
|
|
@@ -641,61 +831,43 @@ export const processDeployment = (
|
|
|
641
831
|
},
|
|
642
832
|
];
|
|
643
833
|
}
|
|
644
|
-
|
|
645
|
-
return {
|
|
646
|
-
...service,
|
|
647
|
-
resources: resources,
|
|
648
|
-
parameters: parameters,
|
|
649
|
-
role: updatedRoles,
|
|
650
|
-
};
|
|
834
|
+
return { ...service, resources: fallbackResources, parameters: fallbackParameters, role: updatedRoles };
|
|
651
835
|
};
|
|
836
|
+
|
|
652
837
|
export const extractParametersFromConfig = (
|
|
653
838
|
parameterConfig: any,
|
|
654
839
|
): { [key: string]: string }[] => {
|
|
655
840
|
const parameters: { [key: string]: string }[] = [];
|
|
656
|
-
|
|
657
|
-
if (!parameterConfig || typeof parameterConfig !== "object") {
|
|
841
|
+
if (!parameterConfig || typeof parameterConfig !== "object")
|
|
658
842
|
return parameters;
|
|
659
|
-
}
|
|
660
843
|
|
|
661
844
|
Object.entries(parameterConfig).forEach(
|
|
662
845
|
([paramName, paramValue]: [string, any]) => {
|
|
663
846
|
let value: string;
|
|
664
847
|
let description: string | undefined;
|
|
665
|
-
|
|
666
848
|
if (typeof paramValue === "object" && paramValue !== null) {
|
|
667
|
-
if (paramValue.value !== undefined)
|
|
668
|
-
|
|
669
|
-
} else if (paramValue.default !== undefined) {
|
|
849
|
+
if (paramValue.value !== undefined) value = paramValue.value;
|
|
850
|
+
else if (paramValue.default !== undefined)
|
|
670
851
|
value = String(paramValue.default);
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
if (paramValue.description) {
|
|
676
|
-
description = paramValue.description;
|
|
677
|
-
}
|
|
852
|
+
else value = JSON.stringify(paramValue);
|
|
853
|
+
if (paramValue.description) description = paramValue.description;
|
|
678
854
|
} else {
|
|
679
855
|
value = String(paramValue);
|
|
680
856
|
}
|
|
681
|
-
|
|
682
857
|
const parameter: { [key: string]: string } = {
|
|
683
858
|
name: paramName,
|
|
684
|
-
value
|
|
859
|
+
value,
|
|
685
860
|
type: typeof paramValue,
|
|
686
861
|
configKey: paramName,
|
|
687
862
|
};
|
|
688
|
-
|
|
689
|
-
if (description) {
|
|
690
|
-
parameter.description = description;
|
|
691
|
-
}
|
|
692
|
-
|
|
863
|
+
if (description) parameter.description = description;
|
|
693
864
|
parameters.push(parameter);
|
|
694
865
|
},
|
|
695
866
|
);
|
|
696
867
|
|
|
697
868
|
return parameters;
|
|
698
869
|
};
|
|
870
|
+
|
|
699
871
|
export const extractParametersFromFilesystem = (
|
|
700
872
|
filesystem: any,
|
|
701
873
|
currentParameters: { [key: string]: string }[],
|
|
@@ -712,13 +884,13 @@ export const extractParametersFromFilesystem = (
|
|
|
712
884
|
value: value.data.value,
|
|
713
885
|
type: "file",
|
|
714
886
|
});
|
|
715
|
-
if (existingParam)
|
|
887
|
+
if (existingParam)
|
|
716
888
|
currentParameters.splice(currentParameters.indexOf(existingParam), 1);
|
|
717
|
-
}
|
|
718
889
|
}
|
|
719
890
|
});
|
|
720
891
|
return parameters;
|
|
721
892
|
};
|
|
893
|
+
|
|
722
894
|
export const extractResourcesFromFilesystem = (
|
|
723
895
|
filesystem: any,
|
|
724
896
|
currentResources: Resource[],
|
|
@@ -742,16 +914,15 @@ export const extractResourcesFromFilesystem = (
|
|
|
742
914
|
status: existingResource?.status || "available",
|
|
743
915
|
tenant: "",
|
|
744
916
|
});
|
|
745
|
-
if (existingResource)
|
|
917
|
+
if (existingResource)
|
|
746
918
|
currentResources.splice(currentResources.indexOf(existingResource), 1);
|
|
747
|
-
}
|
|
748
919
|
}
|
|
749
920
|
});
|
|
750
921
|
return resources;
|
|
751
922
|
};
|
|
923
|
+
|
|
752
924
|
export const extractResources = (resourceConfig: any): Resource[] => {
|
|
753
925
|
const resources: Resource[] = [];
|
|
754
|
-
|
|
755
926
|
Object.entries(resourceConfig).forEach(
|
|
756
927
|
([resourceName, resourceData]: [string, any]) => {
|
|
757
928
|
let resource: Resource;
|
|
@@ -820,42 +991,34 @@ export const extractResources = (resourceConfig: any): Resource[] => {
|
|
|
820
991
|
status: "available",
|
|
821
992
|
tenant: "",
|
|
822
993
|
};
|
|
823
|
-
|
|
824
994
|
if (resourceData.kind) resource.kind = resourceData.kind;
|
|
825
995
|
if (resourceData.domain) resource.domain = resourceData.domain;
|
|
826
996
|
if (resourceData.key) resource.key = resourceData.key;
|
|
827
997
|
if (resourceData.maxItems) resource.maxItems = resourceData.maxItems;
|
|
828
998
|
}
|
|
829
|
-
|
|
830
999
|
resources.push(resource);
|
|
831
1000
|
},
|
|
832
1001
|
);
|
|
833
|
-
|
|
834
1002
|
return resources;
|
|
835
1003
|
};
|
|
1004
|
+
|
|
836
1005
|
const processScalingConfig = (meta: any): any => {
|
|
837
|
-
if (!meta?.scaling?.simple || Object.keys(meta.scaling.simple).length === 0)
|
|
1006
|
+
if (!meta?.scaling?.simple || Object.keys(meta.scaling.simple).length === 0)
|
|
838
1007
|
return {
|
|
839
1008
|
cpu: { up: "80%", down: "20%" },
|
|
840
1009
|
memory: { up: "80%", down: "20%" },
|
|
841
1010
|
instances: { max: 1, min: 1 },
|
|
842
1011
|
histeresys: "5",
|
|
843
1012
|
};
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
const roleNames = Object.keys(meta.scaling.simple);
|
|
847
|
-
const firstRoleName = roleNames[0];
|
|
1013
|
+
const firstRoleName = Object.keys(meta.scaling.simple)[0];
|
|
848
1014
|
const roleScaling = meta.scaling.simple[firstRoleName];
|
|
849
|
-
|
|
850
|
-
if (!roleScaling) {
|
|
1015
|
+
if (!roleScaling)
|
|
851
1016
|
return {
|
|
852
1017
|
cpu: { up: "80%", down: "20%" },
|
|
853
1018
|
memory: { up: "80%", down: "20%" },
|
|
854
1019
|
instances: { max: 1, min: 1 },
|
|
855
1020
|
histeresys: "5",
|
|
856
1021
|
};
|
|
857
|
-
}
|
|
858
|
-
|
|
859
1022
|
return {
|
|
860
1023
|
cpu: {
|
|
861
1024
|
up: `${roleScaling.scale_up?.cpu || 80}%`,
|
|
@@ -872,99 +1035,13 @@ const processScalingConfig = (meta: any): any => {
|
|
|
872
1035
|
histeresys: `${roleScaling.hysteresis || 5}`,
|
|
873
1036
|
};
|
|
874
1037
|
};
|
|
1038
|
+
|
|
875
1039
|
const extractResourceName = (resourcePath: string): string => {
|
|
876
1040
|
if (!resourcePath) return "";
|
|
877
|
-
|
|
878
1041
|
const parts = resourcePath.split("/");
|
|
879
|
-
|
|
880
1042
|
if (parts.length === 2) {
|
|
881
|
-
if (parts[0] === "cluster.core")
|
|
882
|
-
return resourcePath;
|
|
883
|
-
}
|
|
1043
|
+
if (parts[0] === "cluster.core") return resourcePath;
|
|
884
1044
|
return parts[1];
|
|
885
1045
|
}
|
|
886
1046
|
return resourcePath;
|
|
887
|
-
};
|
|
888
|
-
//UNUSED KEEPING IT JUST IN CASE:
|
|
889
|
-
const extractParameters = (
|
|
890
|
-
parameterConfig: any,
|
|
891
|
-
roleData?: any,
|
|
892
|
-
roleName?: string,
|
|
893
|
-
): { [key: string]: string }[] => {
|
|
894
|
-
const parameters: { [key: string]: string }[] = [];
|
|
895
|
-
|
|
896
|
-
if (roleData?.artifact?.description?.code) {
|
|
897
|
-
const codeEntries = Object.entries(roleData.artifact.description.code);
|
|
898
|
-
|
|
899
|
-
for (const [codeName, codeData] of codeEntries) {
|
|
900
|
-
const mapping = (codeData as any)?.mapping?.env;
|
|
901
|
-
|
|
902
|
-
if (mapping && typeof mapping === "object") {
|
|
903
|
-
Object.entries(mapping).forEach(([envName, envData]: [string, any]) => {
|
|
904
|
-
const envValue = envData.value || "";
|
|
905
|
-
let configKey = envName;
|
|
906
|
-
const matchedParam = Object.entries(parameterConfig).find(
|
|
907
|
-
([configParamName, paramData]: [string, any]) => {
|
|
908
|
-
const configValue =
|
|
909
|
-
typeof paramData === "object"
|
|
910
|
-
? paramData.value || paramData.default || ""
|
|
911
|
-
: String(paramData);
|
|
912
|
-
const envLower = envName.toLowerCase();
|
|
913
|
-
const configLower = configParamName.toLowerCase();
|
|
914
|
-
|
|
915
|
-
if (
|
|
916
|
-
envLower.includes(configLower) ||
|
|
917
|
-
configLower.includes(envLower)
|
|
918
|
-
) {
|
|
919
|
-
return configValue === envValue;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
return false;
|
|
923
|
-
},
|
|
924
|
-
);
|
|
925
|
-
|
|
926
|
-
if (matchedParam) {
|
|
927
|
-
configKey = matchedParam[0];
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
const parameter: { [key: string]: string } = {
|
|
931
|
-
name: envName,
|
|
932
|
-
value: envValue,
|
|
933
|
-
type: configKey,
|
|
934
|
-
configKey: configKey,
|
|
935
|
-
...(roleName && { fromRole: roleName }),
|
|
936
|
-
};
|
|
937
|
-
|
|
938
|
-
parameters.push(parameter);
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
if (parameters.length === 0 && parameterConfig) {
|
|
945
|
-
Object.entries(parameterConfig).forEach(
|
|
946
|
-
([paramName, paramData]: [string, any]) => {
|
|
947
|
-
const paramValue =
|
|
948
|
-
typeof paramData === "object"
|
|
949
|
-
? paramData.value || paramData.default || ""
|
|
950
|
-
: String(paramData);
|
|
951
|
-
|
|
952
|
-
const parameter: { [key: string]: string } = {
|
|
953
|
-
name: paramName,
|
|
954
|
-
value: paramValue,
|
|
955
|
-
type: paramName,
|
|
956
|
-
configKey: paramName,
|
|
957
|
-
...(roleName && { fromRole: roleName }),
|
|
958
|
-
};
|
|
959
|
-
|
|
960
|
-
if (typeof paramData === "object" && paramData.description) {
|
|
961
|
-
parameter.description = paramData.description;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
parameters.push(parameter);
|
|
965
|
-
},
|
|
966
|
-
);
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
return parameters;
|
|
970
|
-
};
|
|
1047
|
+
};
|