@xen-orchestra/rest-api 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abstract-classes/base-controller.mjs +4 -2
- package/dist/abstract-classes/xapi-xo-controller.mjs +2 -6
- package/dist/alarms/alarm.service.mjs +2 -1
- package/dist/backup-jobs/backup-job.controller.mjs +284 -0
- package/dist/backup-jobs/backup-job.service.mjs +25 -0
- package/dist/backup-jobs/backup-job.type.mjs +1 -0
- package/dist/backup-logs/backup-log.controller.mjs +75 -0
- package/dist/backup-logs/backup-log.service.mjs +5 -0
- package/dist/groups/group.controller.mjs +37 -1
- package/dist/helpers/error.helper.mjs +10 -0
- package/dist/hosts/host.controller.mjs +24 -4
- package/dist/hosts/host.service.mjs +6 -7
- package/dist/hosts/host.type.mjs +1 -0
- package/dist/index.mjs +4 -0
- package/dist/ioc/ioc.mjs +36 -0
- package/dist/middlewares/generic-error-handler.middleware.mjs +5 -1
- package/dist/open-api/common/response.common.mjs +8 -0
- package/dist/open-api/oa-examples/backup-job.oa-example.mjs +128 -0
- package/dist/open-api/oa-examples/backup-log.oa-example.mjs +93 -0
- package/dist/open-api/oa-examples/host.oa-example.mjs +30 -0
- package/dist/open-api/oa-examples/pool.oa-example.mjs +30 -0
- package/dist/open-api/oa-examples/proxy.oa-example.mjs +25 -0
- package/dist/open-api/oa-examples/restore-log.oa-example.mjs +53 -0
- package/dist/open-api/oa-examples/task.oa-example.mjs +46 -0
- package/dist/open-api/oa-examples/user.oa-example.mjs +32 -0
- package/dist/open-api/oa-examples/vdi.oa-example.mjs +3 -0
- package/dist/open-api/routes/routes.js +2079 -490
- package/dist/pools/pool.controller.mjs +16 -1
- package/dist/pools/pool.service.mjs +18 -8
- package/dist/proxies/proxy.controller.mjs +61 -0
- package/dist/rest-api/rest-api.mjs +6 -2
- package/dist/restore-logs/restore-log.controller.mjs +144 -0
- package/dist/srs/sr.controller.mjs +39 -2
- package/dist/tasks/task.controller.mjs +167 -0
- package/dist/tasks/task.service.mjs +24 -0
- package/dist/users/user.controller.mjs +91 -12
- package/dist/users/user.service.mjs +21 -0
- package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +46 -4
- package/dist/vdis/vdi.controller.mjs +43 -4
- package/dist/vdis/vdi.service.mjs +21 -0
- package/dist/vm-snapshots/vm-snapshot.controller.mjs +72 -3
- package/dist/vm-templates/vm-template.controller.mjs +43 -2
- package/dist/vms/vm.controller.mjs +135 -5
- package/dist/vms/vm.service.mjs +18 -0
- package/dist/xoa/xoa.service.mjs +14 -4
- package/open-api/spec/swagger.json +11733 -6660
- package/package.json +6 -5
- package/tsconfig.json +1 -0
- package/tsoa.json +27 -0
|
@@ -11,24 +11,32 @@ import { Example, Get, Path, Post, Query, Request, Response, Route, Security, Ta
|
|
|
11
11
|
import { inject } from 'inversify';
|
|
12
12
|
import { incorrectState, invalidParameters } from 'xo-common/api-errors.js';
|
|
13
13
|
import { provide } from 'inversify-binding-decorators';
|
|
14
|
-
import { AlarmService } from '../alarms/alarm.service.mjs';
|
|
15
|
-
import { asynchronousActionResp, createdResp, internalServerErrorResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
14
|
+
import { AlarmService, RAW_ALARM_FILTER } from '../alarms/alarm.service.mjs';
|
|
15
|
+
import { asynchronousActionResp, createdResp, forbiddenOperationResp, incorrectStateResp, internalServerErrorResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
16
16
|
import { BASE_URL } from '../index.mjs';
|
|
17
17
|
import { escapeUnsafeComplexMatcher, limitAndFilterArray } from '../helpers/utils.helper.mjs';
|
|
18
18
|
import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
|
|
19
19
|
import { partialVms, vm, vmIds, vmStatsExample, vmVdis } from '../open-api/oa-examples/vm.oa-example.mjs';
|
|
20
20
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
21
|
-
import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
21
|
+
import { partialTasks, taskIds, taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
22
22
|
import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
|
|
23
23
|
import { VmService } from './vm.service.mjs';
|
|
24
|
+
import { TaskService } from '../tasks/task.service.mjs';
|
|
25
|
+
import { BackupJobService } from '../backup-jobs/backup-job.service.mjs';
|
|
26
|
+
import { partialVmBackupJobs, vmBackupJobIds } from '../open-api/oa-examples/backup-job.oa-example.mjs';
|
|
27
|
+
import { messageIds, partialMessages } from '../open-api/oa-examples/message.oa-example.mjs';
|
|
24
28
|
const IGNORED_VDIS_TAG = '[NOSNAP]';
|
|
25
29
|
let VmController = class VmController extends XapiXoController {
|
|
26
30
|
#alarmService;
|
|
27
31
|
#vmService;
|
|
28
|
-
|
|
32
|
+
#taskService;
|
|
33
|
+
#backupJobService;
|
|
34
|
+
constructor(restApi, alarmService, vmService, taskService, backupJobService) {
|
|
29
35
|
super('VM', restApi);
|
|
30
36
|
this.#alarmService = alarmService;
|
|
31
37
|
this.#vmService = vmService;
|
|
38
|
+
this.#taskService = taskService;
|
|
39
|
+
this.#backupJobService = backupJobService;
|
|
32
40
|
}
|
|
33
41
|
/**
|
|
34
42
|
*
|
|
@@ -39,6 +47,18 @@ let VmController = class VmController extends XapiXoController {
|
|
|
39
47
|
getVms(req, fields, ndjson, filter, limit) {
|
|
40
48
|
return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
|
|
41
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
* Export VM. Compress is only used for XVA format
|
|
53
|
+
*
|
|
54
|
+
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
55
|
+
*/
|
|
56
|
+
async exportVm(req, id, format, compress) {
|
|
57
|
+
const stream = await this.#vmService.export(id, 'VM', { compress, format, response: req.res });
|
|
58
|
+
process.on('SIGTERM', () => req.destroy());
|
|
59
|
+
req.on('close', () => stream.destroy());
|
|
60
|
+
return stream;
|
|
61
|
+
}
|
|
42
62
|
/**
|
|
43
63
|
*
|
|
44
64
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
@@ -46,6 +66,13 @@ let VmController = class VmController extends XapiXoController {
|
|
|
46
66
|
getVm(id) {
|
|
47
67
|
return this.getObject(id);
|
|
48
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
71
|
+
*/
|
|
72
|
+
async deleteVm(id) {
|
|
73
|
+
const xapiVm = this.getXapiObject(id);
|
|
74
|
+
await xapiVm.$xapi.VM_destroy(xapiVm.$ref);
|
|
75
|
+
}
|
|
49
76
|
/**
|
|
50
77
|
*
|
|
51
78
|
* VM must be running
|
|
@@ -326,6 +353,50 @@ let VmController = class VmController extends XapiXoController {
|
|
|
326
353
|
const vdis = this.#vmService.getVmVdis(id, 'VM');
|
|
327
354
|
return this.sendObjects(limitAndFilterArray(vdis, { filter, limit }), req, obj => obj.type.toLowerCase() + 's');
|
|
328
355
|
}
|
|
356
|
+
/**
|
|
357
|
+
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
358
|
+
* @example fields "mode,name,type,id"
|
|
359
|
+
* @example filter "mode:full"
|
|
360
|
+
* @example limit 42
|
|
361
|
+
*/
|
|
362
|
+
async vmGetVmBackupJobs(req, id, fields, ndjson, filter, limit) {
|
|
363
|
+
const backupJobs = await this.restApi.xoApp.getAllJobs('backup');
|
|
364
|
+
const vmBackupJobs = [];
|
|
365
|
+
for (const backupJob of backupJobs) {
|
|
366
|
+
if (await this.#backupJobService.isVmInBackupJob(backupJob.id, id)) {
|
|
367
|
+
vmBackupJobs.push(backupJob);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return this.sendObjects(limitAndFilterArray(vmBackupJobs, { filter, limit }), req, '/backup-jobs');
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* @example id "cef5f68c-61ae-3831-d2e6-1590d4934acf"
|
|
374
|
+
* @example fields "name,id,$object"
|
|
375
|
+
* @example filter "name:VM_STARTED"
|
|
376
|
+
* @example limit 42
|
|
377
|
+
*/
|
|
378
|
+
getVmMessages(req, id, fields, ndjson, filter, limit) {
|
|
379
|
+
const vm = this.getObject(id);
|
|
380
|
+
const messages = this.restApi.getObjectsByType('message', {
|
|
381
|
+
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} $object:${vm.uuid} !${RAW_ALARM_FILTER}`,
|
|
382
|
+
limit,
|
|
383
|
+
});
|
|
384
|
+
return this.sendObjects(Object.values(messages), req, 'messages');
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* @example id "613f541c-4bed-fc77-7ca8-2db6b68f079c"
|
|
388
|
+
* @example fields "id,status,properties"
|
|
389
|
+
* @example filter "status:failure"
|
|
390
|
+
* @example limit 42
|
|
391
|
+
*/
|
|
392
|
+
async getVmTasks(req, id, fields, ndjson, filter, limit) {
|
|
393
|
+
const vm = this.getObject(id);
|
|
394
|
+
const tasks = await this.#taskService.getTasks({
|
|
395
|
+
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} |(properties:objectId:${vm.id} properties:params:id:${vm.id})`,
|
|
396
|
+
limit,
|
|
397
|
+
});
|
|
398
|
+
return this.sendObjects(tasks, req, 'tasks');
|
|
399
|
+
}
|
|
329
400
|
};
|
|
330
401
|
__decorate([
|
|
331
402
|
Example(vmIds),
|
|
@@ -337,12 +408,30 @@ __decorate([
|
|
|
337
408
|
__param(3, Query()),
|
|
338
409
|
__param(4, Query())
|
|
339
410
|
], VmController.prototype, "getVms", null);
|
|
411
|
+
__decorate([
|
|
412
|
+
Get('{id}.{format}'),
|
|
413
|
+
SuccessResponse(200, 'Download started', 'application/octet-stream'),
|
|
414
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
415
|
+
Response(422, 'Invalid format, Invalid compress'),
|
|
416
|
+
__param(0, Request()),
|
|
417
|
+
__param(1, Path()),
|
|
418
|
+
__param(2, Path()),
|
|
419
|
+
__param(3, Query())
|
|
420
|
+
], VmController.prototype, "exportVm", null);
|
|
340
421
|
__decorate([
|
|
341
422
|
Example(vm),
|
|
342
423
|
Get('{id}'),
|
|
343
424
|
Response(notFoundResp.status, notFoundResp.description),
|
|
344
425
|
__param(0, Path())
|
|
345
426
|
], VmController.prototype, "getVm", null);
|
|
427
|
+
__decorate([
|
|
428
|
+
Delete('{id}'),
|
|
429
|
+
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
430
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
431
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
432
|
+
Response(incorrectStateResp.status, incorrectStateResp.description),
|
|
433
|
+
__param(0, Path())
|
|
434
|
+
], VmController.prototype, "deleteVm", null);
|
|
346
435
|
__decorate([
|
|
347
436
|
Example(vmStatsExample),
|
|
348
437
|
Get('{id}/stats'),
|
|
@@ -489,6 +578,45 @@ __decorate([
|
|
|
489
578
|
__param(4, Query()),
|
|
490
579
|
__param(5, Query())
|
|
491
580
|
], VmController.prototype, "getVmVdis", null);
|
|
581
|
+
__decorate([
|
|
582
|
+
Example(vmBackupJobIds),
|
|
583
|
+
Example(partialVmBackupJobs),
|
|
584
|
+
Get('{id}/backup-jobs'),
|
|
585
|
+
Tags('backup-jobs'),
|
|
586
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
587
|
+
__param(0, Request()),
|
|
588
|
+
__param(1, Path()),
|
|
589
|
+
__param(2, Query()),
|
|
590
|
+
__param(3, Query()),
|
|
591
|
+
__param(4, Query()),
|
|
592
|
+
__param(5, Query())
|
|
593
|
+
], VmController.prototype, "vmGetVmBackupJobs", null);
|
|
594
|
+
__decorate([
|
|
595
|
+
Example(messageIds),
|
|
596
|
+
Example(partialMessages),
|
|
597
|
+
Get('{id}/messages'),
|
|
598
|
+
Tags('messages'),
|
|
599
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
600
|
+
__param(0, Request()),
|
|
601
|
+
__param(1, Path()),
|
|
602
|
+
__param(2, Query()),
|
|
603
|
+
__param(3, Query()),
|
|
604
|
+
__param(4, Query()),
|
|
605
|
+
__param(5, Query())
|
|
606
|
+
], VmController.prototype, "getVmMessages", null);
|
|
607
|
+
__decorate([
|
|
608
|
+
Example(taskIds),
|
|
609
|
+
Example(partialTasks),
|
|
610
|
+
Get('{id}/tasks'),
|
|
611
|
+
Tags('tasks'),
|
|
612
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
613
|
+
__param(0, Request()),
|
|
614
|
+
__param(1, Path()),
|
|
615
|
+
__param(2, Query()),
|
|
616
|
+
__param(3, Query()),
|
|
617
|
+
__param(4, Query()),
|
|
618
|
+
__param(5, Query())
|
|
619
|
+
], VmController.prototype, "getVmTasks", null);
|
|
492
620
|
VmController = __decorate([
|
|
493
621
|
Route('vms'),
|
|
494
622
|
Security('*'),
|
|
@@ -500,6 +628,8 @@ VmController = __decorate([
|
|
|
500
628
|
provide(VmController),
|
|
501
629
|
__param(0, inject(RestApi)),
|
|
502
630
|
__param(1, inject(AlarmService)),
|
|
503
|
-
__param(2, inject(VmService))
|
|
631
|
+
__param(2, inject(VmService)),
|
|
632
|
+
__param(3, inject(TaskService)),
|
|
633
|
+
__param(4, inject(BackupJobService))
|
|
504
634
|
], VmController);
|
|
505
635
|
export { VmController };
|
package/dist/vms/vm.service.mjs
CHANGED
|
@@ -97,4 +97,22 @@ export class VmService {
|
|
|
97
97
|
}
|
|
98
98
|
return vdis;
|
|
99
99
|
}
|
|
100
|
+
async export(id, vmType, { compress, format, response }) {
|
|
101
|
+
const xapiVm = this.#restApi.getXapiObject(id, vmType);
|
|
102
|
+
let stream;
|
|
103
|
+
if (format === 'xva') {
|
|
104
|
+
stream = (await xapiVm.$xapi.VM_export(xapiVm.$ref, { compress })).body;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
stream = await xapiVm.$xapi.exportVmOva(xapiVm.$ref);
|
|
108
|
+
}
|
|
109
|
+
if (response !== undefined) {
|
|
110
|
+
const headers = new Headers({
|
|
111
|
+
'content-disposition': `attachment; filename=${id}.${format}`,
|
|
112
|
+
'content-type': 'application/octet-stream',
|
|
113
|
+
});
|
|
114
|
+
response.setHeaders(headers);
|
|
115
|
+
}
|
|
116
|
+
return stream;
|
|
117
|
+
}
|
|
100
118
|
}
|
package/dist/xoa/xoa.service.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import groupBy from 'lodash/groupBy.js';
|
|
2
|
+
import { featureUnauthorized } from 'xo-common/api-errors.js';
|
|
2
3
|
import semver from 'semver';
|
|
3
4
|
import { BACKUP_TYPE, VM_POWER_STATE, } from '@vates/types';
|
|
4
5
|
import { createLogger } from '@xen-orchestra/log';
|
|
@@ -167,11 +168,11 @@ export class XoaService {
|
|
|
167
168
|
}
|
|
168
169
|
return nHostsEol;
|
|
169
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Throw if no authorization
|
|
173
|
+
*/
|
|
170
174
|
async #getMissingPatchesInfo() {
|
|
171
175
|
const missingPatchesInfo = await this.#hostService.getMissingPatchesInfo();
|
|
172
|
-
if (!missingPatchesInfo.hasAuthorization) {
|
|
173
|
-
return { hasAuthorization: false };
|
|
174
|
-
}
|
|
175
176
|
const { hasAuthorization, nHostsFailed, nHostsWithMissingPatches, nPoolsWithMissingPatches } = missingPatchesInfo;
|
|
176
177
|
return {
|
|
177
178
|
hasAuthorization,
|
|
@@ -437,7 +438,16 @@ export class XoaService {
|
|
|
437
438
|
handleError: true,
|
|
438
439
|
}),
|
|
439
440
|
promiseWriteInStream({ maybePromise: this.#getPoolsStatus(), path: 'poolsStatus', stream }),
|
|
440
|
-
promiseWriteInStream({
|
|
441
|
+
promiseWriteInStream({
|
|
442
|
+
maybePromise: this.#getMissingPatchesInfo().catch(err => {
|
|
443
|
+
if (featureUnauthorized.is(err)) {
|
|
444
|
+
return { hasAuthorization: false };
|
|
445
|
+
}
|
|
446
|
+
throw err;
|
|
447
|
+
}),
|
|
448
|
+
path: 'missingPatches',
|
|
449
|
+
stream,
|
|
450
|
+
}),
|
|
441
451
|
promiseWriteInStream({
|
|
442
452
|
maybePromise: this.#getBackupRepositoriesSizeInfo(),
|
|
443
453
|
path: 'backupRepositories',
|