@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.
Files changed (49) hide show
  1. package/dist/abstract-classes/base-controller.mjs +4 -2
  2. package/dist/abstract-classes/xapi-xo-controller.mjs +2 -6
  3. package/dist/alarms/alarm.service.mjs +2 -1
  4. package/dist/backup-jobs/backup-job.controller.mjs +284 -0
  5. package/dist/backup-jobs/backup-job.service.mjs +25 -0
  6. package/dist/backup-jobs/backup-job.type.mjs +1 -0
  7. package/dist/backup-logs/backup-log.controller.mjs +75 -0
  8. package/dist/backup-logs/backup-log.service.mjs +5 -0
  9. package/dist/groups/group.controller.mjs +37 -1
  10. package/dist/helpers/error.helper.mjs +10 -0
  11. package/dist/hosts/host.controller.mjs +24 -4
  12. package/dist/hosts/host.service.mjs +6 -7
  13. package/dist/hosts/host.type.mjs +1 -0
  14. package/dist/index.mjs +4 -0
  15. package/dist/ioc/ioc.mjs +36 -0
  16. package/dist/middlewares/generic-error-handler.middleware.mjs +5 -1
  17. package/dist/open-api/common/response.common.mjs +8 -0
  18. package/dist/open-api/oa-examples/backup-job.oa-example.mjs +128 -0
  19. package/dist/open-api/oa-examples/backup-log.oa-example.mjs +93 -0
  20. package/dist/open-api/oa-examples/host.oa-example.mjs +30 -0
  21. package/dist/open-api/oa-examples/pool.oa-example.mjs +30 -0
  22. package/dist/open-api/oa-examples/proxy.oa-example.mjs +25 -0
  23. package/dist/open-api/oa-examples/restore-log.oa-example.mjs +53 -0
  24. package/dist/open-api/oa-examples/task.oa-example.mjs +46 -0
  25. package/dist/open-api/oa-examples/user.oa-example.mjs +32 -0
  26. package/dist/open-api/oa-examples/vdi.oa-example.mjs +3 -0
  27. package/dist/open-api/routes/routes.js +2079 -490
  28. package/dist/pools/pool.controller.mjs +16 -1
  29. package/dist/pools/pool.service.mjs +18 -8
  30. package/dist/proxies/proxy.controller.mjs +61 -0
  31. package/dist/rest-api/rest-api.mjs +6 -2
  32. package/dist/restore-logs/restore-log.controller.mjs +144 -0
  33. package/dist/srs/sr.controller.mjs +39 -2
  34. package/dist/tasks/task.controller.mjs +167 -0
  35. package/dist/tasks/task.service.mjs +24 -0
  36. package/dist/users/user.controller.mjs +91 -12
  37. package/dist/users/user.service.mjs +21 -0
  38. package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +46 -4
  39. package/dist/vdis/vdi.controller.mjs +43 -4
  40. package/dist/vdis/vdi.service.mjs +21 -0
  41. package/dist/vm-snapshots/vm-snapshot.controller.mjs +72 -3
  42. package/dist/vm-templates/vm-template.controller.mjs +43 -2
  43. package/dist/vms/vm.controller.mjs +135 -5
  44. package/dist/vms/vm.service.mjs +18 -0
  45. package/dist/xoa/xoa.service.mjs +14 -4
  46. package/open-api/spec/swagger.json +11733 -6660
  47. package/package.json +6 -5
  48. package/tsconfig.json +1 -0
  49. 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
- async #getMissingPatches(poolId) {
49
- const missingPatchesInfo = await this.#hostService.getMissingPatchesInfo({ filter: host => host.$pool === poolId });
50
- if (!missingPatchesInfo.hasAuthorization) {
51
- return {
52
- hasAuthorization: false,
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({ maybePromise: this.#getMissingPatches(id), path: 'hosts.missingPatches', stream }),
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
- return this.#xoApp.getObjectsByType(type, opts);
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
+ }