@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
|
@@ -17,7 +17,7 @@ import { asynchronousActionResp, createdResp, featureUnauthorized, internalServe
|
|
|
17
17
|
import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
|
|
18
18
|
import { AlarmService } from '../alarms/alarm.service.mjs';
|
|
19
19
|
import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
|
|
20
|
-
import { createVm, importVm, partialPools, pool, poolDashboard, poolIds, poolStats, } from '../open-api/oa-examples/pool.oa-example.mjs';
|
|
20
|
+
import { createVm, importVm, partialPools, pool, poolDashboard, poolIds, poolMissingPatches, poolStats, } from '../open-api/oa-examples/pool.oa-example.mjs';
|
|
21
21
|
import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
22
22
|
import { createNetwork } from '../open-api/oa-examples/schedule.oa-example.mjs';
|
|
23
23
|
import { BASE_URL } from '../index.mjs';
|
|
@@ -221,6 +221,14 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
221
221
|
});
|
|
222
222
|
return this.sendObjects(Object.values(alarms), req, 'alarms');
|
|
223
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
226
|
+
*/
|
|
227
|
+
async getPoolMissingPatches(id) {
|
|
228
|
+
const pool = this.getObject(id);
|
|
229
|
+
const { missingPatches } = await this.#poolService.getMissingPatches(pool.id);
|
|
230
|
+
return missingPatches;
|
|
231
|
+
}
|
|
224
232
|
};
|
|
225
233
|
__decorate([
|
|
226
234
|
Example(poolIds),
|
|
@@ -335,6 +343,13 @@ __decorate([
|
|
|
335
343
|
__param(4, Query()),
|
|
336
344
|
__param(5, Query())
|
|
337
345
|
], PoolController.prototype, "getPoolAlarms", null);
|
|
346
|
+
__decorate([
|
|
347
|
+
Example(poolMissingPatches),
|
|
348
|
+
Get('{id}/missing_patches'),
|
|
349
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
350
|
+
Response(featureUnauthorized.status, featureUnauthorized.description),
|
|
351
|
+
__param(0, Path())
|
|
352
|
+
], PoolController.prototype, "getPoolMissingPatches", null);
|
|
338
353
|
PoolController = __decorate([
|
|
339
354
|
Route('pools'),
|
|
340
355
|
Security('*'),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createLogger } from '@xen-orchestra/log';
|
|
2
|
+
import { featureUnauthorized } from 'xo-common/api-errors.js';
|
|
2
3
|
import { HOST_POWER_STATE, VM_POWER_STATE, } from '@vates/types';
|
|
3
4
|
import { HostService } from '../hosts/host.service.mjs';
|
|
4
5
|
import { VmService } from '../vms/vm.service.mjs';
|
|
@@ -45,13 +46,13 @@ export class PoolService {
|
|
|
45
46
|
const alarms = this.#alarmService.getAlarms({ filter: alarm => alarm.$pool === poolId });
|
|
46
47
|
return Object.keys(alarms);
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
49
|
+
/**
|
|
50
|
+
* Throw if no authorization
|
|
51
|
+
*/
|
|
52
|
+
async getMissingPatches(poolId) {
|
|
53
|
+
const missingPatchesInfo = await this.#hostService.getMissingPatchesInfo({
|
|
54
|
+
filter: host => host.$pool === poolId,
|
|
55
|
+
});
|
|
55
56
|
const { hasAuthorization, missingPatches } = missingPatchesInfo;
|
|
56
57
|
return {
|
|
57
58
|
hasAuthorization,
|
|
@@ -182,7 +183,16 @@ export class PoolService {
|
|
|
182
183
|
promiseWriteInStream({ maybePromise: this.#getHostsStatus(id), path: 'hosts.status', stream }),
|
|
183
184
|
promiseWriteInStream({ maybePromise: this.#getVmsStatus(id), path: 'vms.status', stream }),
|
|
184
185
|
promiseWriteInStream({ maybePromise: this.#getAlarms(id), path: 'alarms', stream }),
|
|
185
|
-
promiseWriteInStream({
|
|
186
|
+
promiseWriteInStream({
|
|
187
|
+
maybePromise: this.getMissingPatches(id).catch(err => {
|
|
188
|
+
if (featureUnauthorized.is(err)) {
|
|
189
|
+
return { hasAuthorization: false };
|
|
190
|
+
}
|
|
191
|
+
throw err;
|
|
192
|
+
}),
|
|
193
|
+
path: 'hosts.missingPatches',
|
|
194
|
+
stream,
|
|
195
|
+
}),
|
|
186
196
|
promiseWriteInStream({ maybePromise: this.#getTopFiveSrsUsage(id), path: 'srs.topFiveUsage', stream }),
|
|
187
197
|
promiseWriteInStream({ maybePromise: this.#getTopFiveHostsRamUsage(id), path: 'hosts.topFiveUsage.ram', stream }),
|
|
188
198
|
promiseWriteInStream({ maybePromise: this.#getTopFiveHostsCpuUsage(id), path: 'hosts.topFiveUsage.cpu', stream }),
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
|
|
11
|
+
import { provide } from 'inversify-binding-decorators';
|
|
12
|
+
import { notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
|
|
13
|
+
import { partialProxies, proxy, proxyIds } from '../open-api/oa-examples/proxy.oa-example.mjs';
|
|
14
|
+
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
15
|
+
let ProxyController = class ProxyController extends XoController {
|
|
16
|
+
getAllCollectionObjects() {
|
|
17
|
+
return this.restApi.xoApp.getAllProxies();
|
|
18
|
+
}
|
|
19
|
+
getCollectionObject(id) {
|
|
20
|
+
return this.restApi.xoApp.getProxy(id);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @example fields "vmUuid,id,name"
|
|
24
|
+
* @example filter "vmUuid?"
|
|
25
|
+
* @example limit 42
|
|
26
|
+
*/
|
|
27
|
+
async getProxies(req, fields, ndjson, filter, limit) {
|
|
28
|
+
const proxies = Object.values(await this.getObjects({ filter, limit }));
|
|
29
|
+
return this.sendObjects(proxies, req);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* @example id "e625ea0c-a876-405a-b838-109d762efe88"
|
|
33
|
+
*/
|
|
34
|
+
getProxy(id) {
|
|
35
|
+
return this.getObject(id);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
__decorate([
|
|
39
|
+
Example(proxyIds),
|
|
40
|
+
Example(partialProxies),
|
|
41
|
+
Get(''),
|
|
42
|
+
__param(0, Request()),
|
|
43
|
+
__param(1, Query()),
|
|
44
|
+
__param(2, Query()),
|
|
45
|
+
__param(3, Query()),
|
|
46
|
+
__param(4, Query())
|
|
47
|
+
], ProxyController.prototype, "getProxies", null);
|
|
48
|
+
__decorate([
|
|
49
|
+
Example(proxy),
|
|
50
|
+
Get('{id}'),
|
|
51
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
52
|
+
__param(0, Path())
|
|
53
|
+
], ProxyController.prototype, "getProxy", null);
|
|
54
|
+
ProxyController = __decorate([
|
|
55
|
+
Route('proxies'),
|
|
56
|
+
Security('*'),
|
|
57
|
+
Response(unauthorizedResp.status, unauthorizedResp.description),
|
|
58
|
+
Tags('proxies'),
|
|
59
|
+
provide(ProxyController)
|
|
60
|
+
], ProxyController);
|
|
61
|
+
export { ProxyController };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as CM from 'complex-matcher';
|
|
1
2
|
import { createLogger } from '@xen-orchestra/log';
|
|
2
3
|
import { invalidCredentials } from 'xo-common/api-errors.js';
|
|
3
4
|
const log = createLogger('xo:rest-api:error-handler');
|
|
@@ -31,8 +32,11 @@ export class RestApi {
|
|
|
31
32
|
getObject(id, type) {
|
|
32
33
|
return this.#xoApp.getObject(id, type);
|
|
33
34
|
}
|
|
34
|
-
getObjectsByType(type, opts) {
|
|
35
|
-
|
|
35
|
+
getObjectsByType(type, { filter, ...opts } = {}) {
|
|
36
|
+
if (filter !== undefined && typeof filter === 'string') {
|
|
37
|
+
filter = CM.parse(filter).createPredicate();
|
|
38
|
+
}
|
|
39
|
+
return this.#xoApp.getObjectsByType(type, { filter, ...opts });
|
|
36
40
|
}
|
|
37
41
|
getXapiObject(maybeId, type) {
|
|
38
42
|
return this.#xoApp.getXapiObject(maybeId, type);
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { createLogger } from '@xen-orchestra/log';
|
|
11
|
+
import { Deprecated, Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
|
|
12
|
+
import { inject } from 'inversify';
|
|
13
|
+
import { noSuchObject } from 'xo-common/api-errors.js';
|
|
14
|
+
import { provide } from 'inversify-binding-decorators';
|
|
15
|
+
import { BackupLogService } from '../backup-logs/backup-log.service.mjs';
|
|
16
|
+
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
17
|
+
import { unauthorizedResp } from '../open-api/common/response.common.mjs';
|
|
18
|
+
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
19
|
+
import { partialRestoreLogs, restoreLog, restoreLogIds } from '../open-api/oa-examples/restore-log.oa-example.mjs';
|
|
20
|
+
const log = createLogger('xo:rest-api:restoreLog-controller');
|
|
21
|
+
let RestoreLogController = class RestoreLogController extends XoController {
|
|
22
|
+
#backupLogService;
|
|
23
|
+
constructor(restApi, backupLogService) {
|
|
24
|
+
super(restApi);
|
|
25
|
+
this.#backupLogService = backupLogService;
|
|
26
|
+
}
|
|
27
|
+
getAllCollectionObjects() {
|
|
28
|
+
const filter = log => !this.#backupLogService.isBackupLog(log);
|
|
29
|
+
return this.restApi.xoApp.getBackupNgLogsSorted({ filter });
|
|
30
|
+
}
|
|
31
|
+
async getCollectionObject(id) {
|
|
32
|
+
const log = await this.restApi.xoApp.getBackupNgLogs(id);
|
|
33
|
+
if (this.#backupLogService.isBackupLog(log)) {
|
|
34
|
+
throw noSuchObject('restore-log');
|
|
35
|
+
}
|
|
36
|
+
return log;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @example fields "jobName,status,data"
|
|
40
|
+
* @example filter "status:success"
|
|
41
|
+
* @example limit 42
|
|
42
|
+
*/
|
|
43
|
+
async getRestoreLogs(req, fields, ndjson, filter, limit) {
|
|
44
|
+
const restoreLogs = await this.getObjects({ filter, limit });
|
|
45
|
+
return this.sendObjects(Object.values(restoreLogs), req);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @example id "fo"
|
|
49
|
+
*/
|
|
50
|
+
getRestoreLog(id) {
|
|
51
|
+
return this.getObject(id);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
__decorate([
|
|
55
|
+
Example(restoreLogIds),
|
|
56
|
+
Example(partialRestoreLogs),
|
|
57
|
+
Get(''),
|
|
58
|
+
__param(0, Request()),
|
|
59
|
+
__param(1, Query()),
|
|
60
|
+
__param(2, Query()),
|
|
61
|
+
__param(3, Query()),
|
|
62
|
+
__param(4, Query())
|
|
63
|
+
], RestoreLogController.prototype, "getRestoreLogs", null);
|
|
64
|
+
__decorate([
|
|
65
|
+
Example(restoreLog),
|
|
66
|
+
Get('{id}'),
|
|
67
|
+
__param(0, Path())
|
|
68
|
+
], RestoreLogController.prototype, "getRestoreLog", null);
|
|
69
|
+
RestoreLogController = __decorate([
|
|
70
|
+
Route('restore-logs'),
|
|
71
|
+
Security('*'),
|
|
72
|
+
Response(unauthorizedResp.status, unauthorizedResp.description),
|
|
73
|
+
Tags('restore-logs'),
|
|
74
|
+
provide(RestoreLogController),
|
|
75
|
+
__param(0, inject(RestApi)),
|
|
76
|
+
__param(1, inject(BackupLogService))
|
|
77
|
+
], RestoreLogController);
|
|
78
|
+
export { RestoreLogController };
|
|
79
|
+
// ----------- DEPRECATED TO BE REMOVED IN ONE YEAR (09-12-2026)--------------------
|
|
80
|
+
let DeprecatedRestoreController = class DeprecatedRestoreController extends XoController {
|
|
81
|
+
#backupLogService;
|
|
82
|
+
constructor(restApi, backupLogService) {
|
|
83
|
+
super(restApi);
|
|
84
|
+
this.#backupLogService = backupLogService;
|
|
85
|
+
}
|
|
86
|
+
getAllCollectionObjects() {
|
|
87
|
+
const filter = log => !this.#backupLogService.isBackupLog(log);
|
|
88
|
+
return this.restApi.xoApp.getBackupNgLogsSorted({ filter });
|
|
89
|
+
}
|
|
90
|
+
async getCollectionObject(id) {
|
|
91
|
+
const log = await this.restApi.xoApp.getBackupNgLogs(id);
|
|
92
|
+
if (this.#backupLogService.isBackupLog(log)) {
|
|
93
|
+
throw noSuchObject('restore-log');
|
|
94
|
+
}
|
|
95
|
+
return log;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* @example fields "jobName,status,data"
|
|
99
|
+
* @example filter "status:success"
|
|
100
|
+
* @example limit 42
|
|
101
|
+
*/
|
|
102
|
+
async getDeprecatedRestoreLogs(req, fields, ndjson, filter, limit) {
|
|
103
|
+
const restoreLogs = await this.getObjects({ filter, limit });
|
|
104
|
+
return this.sendObjects(Object.values(restoreLogs), req, 'restore-logs');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* @example id "1758180544428"
|
|
108
|
+
*/
|
|
109
|
+
getDeprecatedRestoreLog(id) {
|
|
110
|
+
return this.getObject(id);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
__decorate([
|
|
114
|
+
Example(restoreLogIds),
|
|
115
|
+
Example(partialRestoreLogs),
|
|
116
|
+
Deprecated(),
|
|
117
|
+
Get(''),
|
|
118
|
+
__param(0, Request()),
|
|
119
|
+
__param(1, Query()),
|
|
120
|
+
__param(2, Query()),
|
|
121
|
+
__param(3, Query()),
|
|
122
|
+
__param(4, Query())
|
|
123
|
+
], DeprecatedRestoreController.prototype, "getDeprecatedRestoreLogs", null);
|
|
124
|
+
__decorate([
|
|
125
|
+
Example(restoreLog),
|
|
126
|
+
Deprecated(),
|
|
127
|
+
Get('{id}'),
|
|
128
|
+
__param(0, Path())
|
|
129
|
+
], DeprecatedRestoreController.prototype, "getDeprecatedRestoreLog", null);
|
|
130
|
+
DeprecatedRestoreController = __decorate([
|
|
131
|
+
Route('restore/logs'),
|
|
132
|
+
Security('*'),
|
|
133
|
+
Response(unauthorizedResp.status, unauthorizedResp.description),
|
|
134
|
+
Middlewares((_req, _res, next) => {
|
|
135
|
+
log.warn('You are calling a deprecated route. It will be removed in the futur. Please use `/rest/v0/restore-logs` instead');
|
|
136
|
+
next();
|
|
137
|
+
}),
|
|
138
|
+
Tags('restore-logs'),
|
|
139
|
+
provide(DeprecatedRestoreController),
|
|
140
|
+
__param(0, inject(RestApi)),
|
|
141
|
+
__param(1, inject(BackupLogService))
|
|
142
|
+
], DeprecatedRestoreController);
|
|
143
|
+
export { DeprecatedRestoreController };
|
|
144
|
+
// ----------- DEPRECATED TO BE REMOVED IN ONE YEAR (09-12-2026)--------------------
|
|
@@ -7,14 +7,17 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
8
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
9
|
};
|
|
10
|
-
import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
|
|
10
|
+
import { Example, Get, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags } from 'tsoa';
|
|
11
11
|
import { inject } from 'inversify';
|
|
12
12
|
import { provide } from 'inversify-binding-decorators';
|
|
13
|
+
import { SUPPORTED_VDI_FORMAT } from '@vates/types';
|
|
13
14
|
import { AlarmService } from '../alarms/alarm.service.mjs';
|
|
15
|
+
import { BASE_URL } from '../index.mjs';
|
|
14
16
|
import { escapeUnsafeComplexMatcher } from '../helpers/utils.helper.mjs';
|
|
15
17
|
import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
|
|
16
|
-
import { notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
|
|
18
|
+
import { createdResp, notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
|
|
17
19
|
import { partialSrs, sr, srIds } from '../open-api/oa-examples/sr.oa-example.mjs';
|
|
20
|
+
import { vdiId } from '../open-api/oa-examples/vdi.oa-example.mjs';
|
|
18
21
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
19
22
|
import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
|
|
20
23
|
let SrController = class SrController extends XapiXoController {
|
|
@@ -51,6 +54,28 @@ let SrController = class SrController extends XapiXoController {
|
|
|
51
54
|
});
|
|
52
55
|
return this.sendObjects(Object.values(alarms), req, 'alarms');
|
|
53
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Import an exported VDI
|
|
59
|
+
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
60
|
+
* @example name_label "VDI_foo_import"
|
|
61
|
+
* @example name_description "VDI imported by the REST API"
|
|
62
|
+
* @example raw true
|
|
63
|
+
*/
|
|
64
|
+
async srImportVdi(req, id, name_label, name_description, raw) {
|
|
65
|
+
const xapiSr = this.getXapiObject(id);
|
|
66
|
+
const xapi = xapiSr.$xapi;
|
|
67
|
+
if (req.headers['content-length'] !== undefined) {
|
|
68
|
+
req.length = +req.headers['content-length'];
|
|
69
|
+
}
|
|
70
|
+
const vdiRef = await xapi.SR_importVdi(xapiSr.$ref, req, {
|
|
71
|
+
format: raw ? SUPPORTED_VDI_FORMAT.raw : SUPPORTED_VDI_FORMAT.vhd,
|
|
72
|
+
name_label,
|
|
73
|
+
name_description,
|
|
74
|
+
});
|
|
75
|
+
const vdiId = await xapi.getField('VDI', vdiRef, 'uuid');
|
|
76
|
+
this.setHeader('Location', `${BASE_URL}/vdis/${vdiId}`);
|
|
77
|
+
return { id: vdiId };
|
|
78
|
+
}
|
|
54
79
|
};
|
|
55
80
|
__decorate([
|
|
56
81
|
Example(srIds),
|
|
@@ -80,6 +105,18 @@ __decorate([
|
|
|
80
105
|
__param(4, Query()),
|
|
81
106
|
__param(5, Query())
|
|
82
107
|
], SrController.prototype, "getSrAlarms", null);
|
|
108
|
+
__decorate([
|
|
109
|
+
Example(vdiId),
|
|
110
|
+
Post('{id}/vdis'),
|
|
111
|
+
Tags('vdis'),
|
|
112
|
+
SuccessResponse(createdResp.status, 'VDI imported'),
|
|
113
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
114
|
+
__param(0, Request()),
|
|
115
|
+
__param(1, Path()),
|
|
116
|
+
__param(2, Query()),
|
|
117
|
+
__param(3, Query()),
|
|
118
|
+
__param(4, Query())
|
|
119
|
+
], SrController.prototype, "srImportVdi", null);
|
|
83
120
|
SrController = __decorate([
|
|
84
121
|
Route('srs'),
|
|
85
122
|
Security('*'),
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import * as CM from 'complex-matcher';
|
|
11
|
+
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
12
|
+
import { Get, Path, Query, Request, Route, Security, Tags, Response, Example, Delete, Post, SuccessResponse } from 'tsoa';
|
|
13
|
+
import { asynchronousActionResp, badRequestResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
14
|
+
import { provide } from 'inversify-binding-decorators';
|
|
15
|
+
import { partialTasks, task, taskIds, taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
16
|
+
import pDefer from 'promise-toolbox/defer';
|
|
17
|
+
import { ApiError } from '../helpers/error.helper.mjs';
|
|
18
|
+
import { Transform } from 'node:stream';
|
|
19
|
+
import { makeObjectMapper } from '../helpers/object-wrapper.helper.mjs';
|
|
20
|
+
let TaskController = class TaskController extends XoController {
|
|
21
|
+
async getAllCollectionObjects() {
|
|
22
|
+
const result = [];
|
|
23
|
+
for await (const task of this.restApi.tasks.list()) {
|
|
24
|
+
result.push(task);
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
getCollectionObject(id) {
|
|
29
|
+
return this.restApi.tasks.get(id);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* If watch is true, ndjson must also be true
|
|
34
|
+
*
|
|
35
|
+
* @example fields "status,id,properties"
|
|
36
|
+
* @example filter "status:failure"
|
|
37
|
+
* @example limit 42
|
|
38
|
+
*/
|
|
39
|
+
async getTasks(req, fields, ndjson, watch, filter, limit) {
|
|
40
|
+
if (watch) {
|
|
41
|
+
if (!ndjson) {
|
|
42
|
+
throw new ApiError('watch=true requires ndjson=true', 400);
|
|
43
|
+
}
|
|
44
|
+
const userFilter = filter === undefined ? undefined : CM.parse(filter).createPredicate();
|
|
45
|
+
const stream = new Transform({
|
|
46
|
+
objectMode: true,
|
|
47
|
+
transform([event, object], encoding, callback) {
|
|
48
|
+
const mapper = makeObjectMapper(req);
|
|
49
|
+
callback(null, JSON.stringify([event, mapper(object)]) + '\n');
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
stream.on('close', () => {
|
|
53
|
+
this.restApi.tasks.off('update', update).off('remove', remove);
|
|
54
|
+
});
|
|
55
|
+
req.on('close', () => {
|
|
56
|
+
stream.destroy();
|
|
57
|
+
});
|
|
58
|
+
process.on('SIGTERM', () => {
|
|
59
|
+
req.destroy();
|
|
60
|
+
});
|
|
61
|
+
function update(task) {
|
|
62
|
+
if (userFilter === undefined || userFilter(task)) {
|
|
63
|
+
stream.write(['update', task]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function remove(taskId) {
|
|
67
|
+
stream.write(['remove', { id: taskId }]);
|
|
68
|
+
}
|
|
69
|
+
this.restApi.tasks.on('update', update).on('remove', remove);
|
|
70
|
+
return stream;
|
|
71
|
+
}
|
|
72
|
+
const tasks = Object.values(await this.getObjects({ filter, limit }));
|
|
73
|
+
return this.sendObjects(tasks, req);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* @example id "0mdd1basu"
|
|
77
|
+
*/
|
|
78
|
+
async getTask(req, id, wait) {
|
|
79
|
+
const taskId = id;
|
|
80
|
+
if (wait) {
|
|
81
|
+
const { promise, resolve } = pDefer();
|
|
82
|
+
const stopWatch = await this.restApi.tasks.watch(taskId, task => {
|
|
83
|
+
if (task.status !== 'pending') {
|
|
84
|
+
stopWatch();
|
|
85
|
+
resolve(task);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
req.on('close', stopWatch);
|
|
89
|
+
return promise;
|
|
90
|
+
}
|
|
91
|
+
return this.getObject(taskId);
|
|
92
|
+
}
|
|
93
|
+
async deleteTasks() {
|
|
94
|
+
await this.restApi.tasks.clearLogs();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* @example id "0mdd1basu"
|
|
98
|
+
*/
|
|
99
|
+
async deleteTask(id) {
|
|
100
|
+
const task = await this.getObject(id);
|
|
101
|
+
await this.restApi.tasks.deleteLog(task.id);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @example id "0mdd1basu"
|
|
105
|
+
*/
|
|
106
|
+
async abortTask(id, sync) {
|
|
107
|
+
const taskId = id;
|
|
108
|
+
const action = async () => {
|
|
109
|
+
await this.restApi.tasks.abort(taskId);
|
|
110
|
+
};
|
|
111
|
+
return this.createAction(action, {
|
|
112
|
+
sync,
|
|
113
|
+
statusCode: noContentResp.status,
|
|
114
|
+
taskProperties: {
|
|
115
|
+
name: 'abort task',
|
|
116
|
+
objectId: taskId,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
__decorate([
|
|
122
|
+
Example(taskIds),
|
|
123
|
+
Example(partialTasks),
|
|
124
|
+
Get(''),
|
|
125
|
+
Response(badRequestResp.status, badRequestResp.description),
|
|
126
|
+
__param(0, Request()),
|
|
127
|
+
__param(1, Query()),
|
|
128
|
+
__param(2, Query()),
|
|
129
|
+
__param(3, Query()),
|
|
130
|
+
__param(4, Query()),
|
|
131
|
+
__param(5, Query())
|
|
132
|
+
], TaskController.prototype, "getTasks", null);
|
|
133
|
+
__decorate([
|
|
134
|
+
Example(task),
|
|
135
|
+
Get('{id}'),
|
|
136
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
137
|
+
__param(0, Request()),
|
|
138
|
+
__param(1, Path()),
|
|
139
|
+
__param(2, Query())
|
|
140
|
+
], TaskController.prototype, "getTask", null);
|
|
141
|
+
__decorate([
|
|
142
|
+
Delete(''),
|
|
143
|
+
SuccessResponse(noContentResp.status, noContentResp.description)
|
|
144
|
+
], TaskController.prototype, "deleteTasks", null);
|
|
145
|
+
__decorate([
|
|
146
|
+
Delete('{id}'),
|
|
147
|
+
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
148
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
149
|
+
__param(0, Path())
|
|
150
|
+
], TaskController.prototype, "deleteTask", null);
|
|
151
|
+
__decorate([
|
|
152
|
+
Example(taskLocation),
|
|
153
|
+
Post('{id}/actions/abort'),
|
|
154
|
+
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description, asynchronousActionResp.produce),
|
|
155
|
+
Response(noContentResp.status, noContentResp.description),
|
|
156
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
157
|
+
__param(0, Path()),
|
|
158
|
+
__param(1, Query())
|
|
159
|
+
], TaskController.prototype, "abortTask", null);
|
|
160
|
+
TaskController = __decorate([
|
|
161
|
+
Route('tasks'),
|
|
162
|
+
Security('*'),
|
|
163
|
+
Response(unauthorizedResp.status, unauthorizedResp.description),
|
|
164
|
+
Tags('tasks'),
|
|
165
|
+
provide(TaskController)
|
|
166
|
+
], TaskController);
|
|
167
|
+
export { TaskController };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as CM from 'complex-matcher';
|
|
2
|
+
export class TaskService {
|
|
3
|
+
#restApi;
|
|
4
|
+
constructor(restApi) {
|
|
5
|
+
this.#restApi = restApi;
|
|
6
|
+
}
|
|
7
|
+
async getTasks({ filter, limit = Infinity } = {}) {
|
|
8
|
+
const tasks = [];
|
|
9
|
+
let userFilter = () => true;
|
|
10
|
+
if (filter !== undefined) {
|
|
11
|
+
userFilter = typeof filter === 'string' ? CM.parse(filter).createPredicate() : filter;
|
|
12
|
+
}
|
|
13
|
+
for await (const task of this.#restApi.tasks.list()) {
|
|
14
|
+
if (limit === 0) {
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
if (userFilter(task)) {
|
|
18
|
+
tasks.push(task);
|
|
19
|
+
limit--;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return tasks;
|
|
23
|
+
}
|
|
24
|
+
}
|