@xen-orchestra/rest-api 0.29.0 → 0.30.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/README.md +108 -1
- package/dist/abstract-classes/base-controller.mjs +18 -3
- package/dist/abstract-classes/listener.mjs +116 -12
- package/dist/acl-privileges/acl-privilege.controller.mjs +172 -0
- package/dist/acl-roles/acl-role.controller.mjs +384 -0
- package/dist/alarms/alarm.controller.mjs +22 -9
- package/dist/alarms/alarm.service.mjs +8 -0
- package/dist/backup-archives/backup-archive.controller.mjs +30 -21
- package/dist/backup-archives/backup-archive.service.mjs +21 -0
- package/dist/backup-jobs/backup-job.controller.mjs +59 -15
- package/dist/backup-jobs/backup-job.service.mjs +7 -0
- package/dist/backup-logs/backup-log.controller.mjs +25 -11
- package/dist/backup-logs/backup-log.service.mjs +19 -0
- package/dist/backup-repositories/backup-repositories.controller.mjs +21 -3
- package/dist/events/event.class.mjs +24 -9
- package/dist/events/event.controller.mjs +3 -0
- package/dist/events/event.service.mjs +2 -1
- package/dist/groups/group.controller.mjs +90 -6
- package/dist/hosts/host.controller.mjs +78 -7
- package/dist/ioc/ioc.mjs +13 -4
- package/dist/messages/message.controller.mjs +29 -8
- package/dist/middlewares/acl.middleware.mjs +202 -0
- package/dist/middlewares/authentication.middleware.mjs +15 -6
- package/dist/middlewares/tsoa-to-xo-error.middleware.mjs +19 -1
- package/dist/networks/network.controller.mjs +60 -9
- package/dist/open-api/oa-examples/acl-privilege.oa-example.mjs +25 -0
- package/dist/open-api/oa-examples/acl-role.oa-example.mjs +22 -0
- package/dist/open-api/oa-examples/backup-archive.oa-example.mjs +6 -6
- package/dist/open-api/oa-examples/common.oa-example.mjs +3 -0
- package/dist/open-api/routes/routes.js +676 -132
- package/dist/pbds/pbd.controller.mjs +17 -3
- package/dist/pcis/pci.controller.mjs +16 -3
- package/dist/pgpus/pgpu.controller.mjs +16 -3
- package/dist/pifs/pif.controller.mjs +44 -8
- package/dist/pools/pool.controller.mjs +154 -9
- package/dist/proxies/proxy.controller.mjs +22 -4
- package/dist/restore-logs/restore-log.controller.mjs +36 -19
- package/dist/schedules/schedule.controller.mjs +33 -3
- package/dist/servers/server.controller.mjs +65 -5
- package/dist/sms/sm.controller.mjs +14 -2
- package/dist/srs/sr.controller.mjs +62 -10
- package/dist/tasks/task.controller.mjs +71 -11
- package/dist/users/user.controller.mjs +115 -16
- package/dist/vbds/vbd.controller.mjs +65 -31
- package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +36 -6
- package/dist/vdis/vdi.controller.mjs +69 -8
- package/dist/vifs/vif.controller.mjs +43 -7
- package/dist/vm-controller/vm-controller.controller.mjs +62 -9
- package/dist/vm-snapshots/vm-snapshot.controller.mjs +70 -8
- package/dist/vm-templates/vm-template.controller.mjs +71 -8
- package/dist/vms/vm.controller.mjs +164 -12
- package/open-api/spec/swagger.json +10907 -3265
- package/package.json +4 -3
|
@@ -13,8 +13,9 @@ import { invalidParameters } from 'xo-common/api-errors.js';
|
|
|
13
13
|
import { PassThrough } from 'node:stream';
|
|
14
14
|
import { provide } from 'inversify-binding-decorators';
|
|
15
15
|
import { json } from 'express';
|
|
16
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
16
17
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
17
|
-
import { asynchronousActionResp, badRequestResp, createdResp, featureUnauthorized, internalServerErrorResp, invalidParameters as invalidParametersResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
18
|
+
import { asynchronousActionResp, badRequestResp, createdResp, featureUnauthorized, forbiddenOperationResp, internalServerErrorResp, invalidParameters as invalidParametersResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
18
19
|
import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
|
|
19
20
|
import { AlarmService } from '../alarms/alarm.service.mjs';
|
|
20
21
|
import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
|
|
@@ -40,21 +41,33 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
40
41
|
this.#networkService = networkService;
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
44
|
+
* Returns all pools that match the following privilege:
|
|
45
|
+
* - resource: pool, action: read
|
|
43
46
|
*
|
|
44
47
|
* @example fields "auto_poweron,name_label,id"
|
|
45
48
|
* @example filter "auto_poweron?"
|
|
46
49
|
* @example limit 42
|
|
47
50
|
*/
|
|
48
51
|
getPools(req, fields, ndjson, markdown, filter, limit) {
|
|
49
|
-
return this.sendObjects(Object.values(this.getObjects({ filter
|
|
52
|
+
return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
|
|
53
|
+
limit,
|
|
54
|
+
privilege: { action: 'read', resource: 'pool' },
|
|
55
|
+
});
|
|
50
56
|
}
|
|
51
57
|
/**
|
|
58
|
+
* Required privilege:
|
|
59
|
+
* - resource: pool, action: read
|
|
60
|
+
*
|
|
52
61
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
53
62
|
*/
|
|
54
63
|
getPool(id) {
|
|
55
64
|
return this.getObject(id);
|
|
56
65
|
}
|
|
57
66
|
/**
|
|
67
|
+
* Required privilege:
|
|
68
|
+
* - resource: pool, action: create:network
|
|
69
|
+
* - resource: network, action: create
|
|
70
|
+
*
|
|
58
71
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
59
72
|
* @example body {
|
|
60
73
|
* "name": "awes0me_network",
|
|
@@ -130,6 +143,9 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
130
143
|
});
|
|
131
144
|
}
|
|
132
145
|
/**
|
|
146
|
+
* Required privilege:
|
|
147
|
+
* - resource: pool, action: emergency-shutdown
|
|
148
|
+
*
|
|
133
149
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
|
|
134
150
|
*/
|
|
135
151
|
emergencyShutdown(id, sync) {
|
|
@@ -148,6 +164,9 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
148
164
|
});
|
|
149
165
|
}
|
|
150
166
|
/**
|
|
167
|
+
* Required privilege:
|
|
168
|
+
* - resource: pool, action: rolling-reboot
|
|
169
|
+
*
|
|
151
170
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
|
|
152
171
|
*/
|
|
153
172
|
rollingReboot(id, sync) {
|
|
@@ -167,6 +186,9 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
167
186
|
});
|
|
168
187
|
}
|
|
169
188
|
/**
|
|
189
|
+
* Required privilege:
|
|
190
|
+
* - resource: pool, action: rolling-update
|
|
191
|
+
*
|
|
170
192
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
|
|
171
193
|
*/
|
|
172
194
|
rollingUpdate(id, sync) {
|
|
@@ -189,6 +211,9 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
189
211
|
/**
|
|
190
212
|
* Import an XVA VM into a pool
|
|
191
213
|
*
|
|
214
|
+
* Required privilege:
|
|
215
|
+
* - resource: sr, action: import:vm
|
|
216
|
+
*
|
|
192
217
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
|
|
193
218
|
* @example sr "c787b75c-3e0d-70fa-d0c3-cbfd382d7e33"
|
|
194
219
|
*
|
|
@@ -206,6 +231,14 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
206
231
|
return { id: vmId };
|
|
207
232
|
}
|
|
208
233
|
/**
|
|
234
|
+
* Required privilege:
|
|
235
|
+
* - resource: pool, action: create:vm
|
|
236
|
+
* - resource: vm-template, action: instantiate
|
|
237
|
+
* - resource: vdi, action: create (if vdis is passed)
|
|
238
|
+
* - resource: vdi, action: boot (if install.repository is passed)
|
|
239
|
+
* - resource: vif, action: create (if vifs is passed)
|
|
240
|
+
* - resource: host, action: allow-vm (if affinity is passed)
|
|
241
|
+
*
|
|
209
242
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
|
|
210
243
|
* @example body {
|
|
211
244
|
* "name_label": "new VM from REST API",
|
|
@@ -241,12 +274,18 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
241
274
|
});
|
|
242
275
|
}
|
|
243
276
|
/**
|
|
277
|
+
* Required privilege:
|
|
278
|
+
* - resource: pool, action: read
|
|
279
|
+
*
|
|
244
280
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
|
|
245
281
|
*/
|
|
246
282
|
getStats(id, granularity) {
|
|
247
283
|
return this.restApi.xoApp.getXapiPoolStats(id, granularity);
|
|
248
284
|
}
|
|
249
285
|
/**
|
|
286
|
+
* Required privilege:
|
|
287
|
+
* - resource: pool, action: read
|
|
288
|
+
*
|
|
250
289
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
|
|
251
290
|
*/
|
|
252
291
|
async getPoolDashboard(req, id, ndjson) {
|
|
@@ -269,6 +308,9 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
269
308
|
}
|
|
270
309
|
}
|
|
271
310
|
/**
|
|
311
|
+
* Returns all alarms that match the following privilege:
|
|
312
|
+
* - resource: alarm, action: read
|
|
313
|
+
*
|
|
272
314
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
273
315
|
* @example fields "id,time"
|
|
274
316
|
* @example filter "time:>1747053793"
|
|
@@ -278,11 +320,17 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
278
320
|
const pool = this.getObject(id);
|
|
279
321
|
const alarms = this.#alarmService.getAlarms({
|
|
280
322
|
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${pool.uuid}`,
|
|
323
|
+
});
|
|
324
|
+
return this.sendObjects(Object.values(alarms), req, {
|
|
325
|
+
path: 'alarms',
|
|
281
326
|
limit,
|
|
327
|
+
privilege: { action: 'read', resource: 'alarm' },
|
|
282
328
|
});
|
|
283
|
-
return this.sendObjects(Object.values(alarms), req, 'alarms');
|
|
284
329
|
}
|
|
285
330
|
/**
|
|
331
|
+
* Required privilege:
|
|
332
|
+
* - resource: pool, action: read
|
|
333
|
+
*
|
|
286
334
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
287
335
|
*/
|
|
288
336
|
async getPoolMissingPatches(id) {
|
|
@@ -291,16 +339,26 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
291
339
|
return missingPatches;
|
|
292
340
|
}
|
|
293
341
|
/**
|
|
342
|
+
* Returns all messages that match the following privilege:
|
|
343
|
+
* - resource: message, action: read
|
|
344
|
+
*
|
|
294
345
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
295
346
|
* @example fields "name,id,$object"
|
|
296
347
|
* @example filter "name:IP_CONFIGURED_PIF_CAN_UNPLUG"
|
|
297
348
|
* @example limit 42
|
|
298
349
|
*/
|
|
299
350
|
getPoolMessages(req, id, fields, ndjson, markdown, filter, limit) {
|
|
300
|
-
const messages = this.getMessagesForObject(id, { filter
|
|
301
|
-
return this.sendObjects(Object.values(messages), req,
|
|
351
|
+
const messages = this.getMessagesForObject(id, { filter });
|
|
352
|
+
return this.sendObjects(Object.values(messages), req, {
|
|
353
|
+
path: 'messages',
|
|
354
|
+
limit,
|
|
355
|
+
privilege: { action: 'read', resource: 'message' },
|
|
356
|
+
});
|
|
302
357
|
}
|
|
303
358
|
/**
|
|
359
|
+
* Required privilege:
|
|
360
|
+
* - resource: pool, action: update:tags
|
|
361
|
+
*
|
|
304
362
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
305
363
|
* @example tag "from-rest-api"
|
|
306
364
|
*/
|
|
@@ -309,6 +367,9 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
309
367
|
await pool.$call('add_tags', tag);
|
|
310
368
|
}
|
|
311
369
|
/**
|
|
370
|
+
* Required privilege:
|
|
371
|
+
* - resource: pool, action: update:tags
|
|
372
|
+
*
|
|
312
373
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
313
374
|
* @example tag "from-rest-api"
|
|
314
375
|
*/
|
|
@@ -317,13 +378,20 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
317
378
|
await pool.$call('remove_tags', tag);
|
|
318
379
|
}
|
|
319
380
|
/**
|
|
381
|
+
* Returns all tasks that match the following privilege:
|
|
382
|
+
* - resource: task, action: read
|
|
383
|
+
*
|
|
320
384
|
* @example fields "id,status,properties"
|
|
321
385
|
* @example filter "status:failure"
|
|
322
386
|
* @example limit 42
|
|
323
387
|
*/
|
|
324
388
|
async getPoolTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
325
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
326
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
389
|
+
const tasks = await this.getTasksForObject(id, { filter });
|
|
390
|
+
return this.sendObjects(Object.values(tasks), req, {
|
|
391
|
+
path: 'tasks',
|
|
392
|
+
limit,
|
|
393
|
+
privilege: { action: 'read', resource: 'task' },
|
|
394
|
+
});
|
|
327
395
|
}
|
|
328
396
|
/**
|
|
329
397
|
* Reconfigure the management interface for all hosts in the pool to use the given network.
|
|
@@ -360,6 +428,7 @@ __decorate([
|
|
|
360
428
|
Example(poolIds),
|
|
361
429
|
Example(partialPools),
|
|
362
430
|
Get(''),
|
|
431
|
+
Security('*', ['acl']),
|
|
363
432
|
__param(0, Request()),
|
|
364
433
|
__param(1, Query()),
|
|
365
434
|
__param(2, Query()),
|
|
@@ -370,6 +439,8 @@ __decorate([
|
|
|
370
439
|
__decorate([
|
|
371
440
|
Example(pool),
|
|
372
441
|
Get('{id}'),
|
|
442
|
+
Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
|
|
443
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
373
444
|
Response(notFoundResp.status, notFoundResp.description),
|
|
374
445
|
__param(0, Path())
|
|
375
446
|
], PoolController.prototype, "getPool", null);
|
|
@@ -377,9 +448,17 @@ __decorate([
|
|
|
377
448
|
Example(taskLocation),
|
|
378
449
|
Example(createNetwork),
|
|
379
450
|
Post('{id}/actions/create_network'),
|
|
380
|
-
Middlewares(
|
|
451
|
+
Middlewares([
|
|
452
|
+
json(),
|
|
453
|
+
acl([
|
|
454
|
+
// these two rights are a bit redundant, but for now this is the only way to restrict network creation on a given pool
|
|
455
|
+
{ resource: 'pool', action: 'create:network', objectId: 'params.id' },
|
|
456
|
+
{ resource: 'network', action: 'create', object: ({ req }) => req.body },
|
|
457
|
+
]),
|
|
458
|
+
]),
|
|
381
459
|
Tags('networks'),
|
|
382
460
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
461
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
383
462
|
Response(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
384
463
|
Response(notFoundResp.status, notFoundResp.description),
|
|
385
464
|
Response(invalidParametersResp.status, invalidParametersResp.description),
|
|
@@ -421,7 +500,9 @@ __decorate([
|
|
|
421
500
|
__decorate([
|
|
422
501
|
Example(taskLocation),
|
|
423
502
|
Post('{id}/actions/emergency_shutdown'),
|
|
503
|
+
Middlewares(acl({ resource: 'pool', action: 'emergency-shutdown', objectId: 'params.id' })),
|
|
424
504
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
505
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
425
506
|
Response(noContentResp.status, noContentResp.description),
|
|
426
507
|
Response(featureUnauthorized.status, featureUnauthorized.description),
|
|
427
508
|
Response(notFoundResp.status, notFoundResp.description),
|
|
@@ -431,7 +512,9 @@ __decorate([
|
|
|
431
512
|
__decorate([
|
|
432
513
|
Example(taskLocation),
|
|
433
514
|
Post('{id}/actions/rolling_reboot'),
|
|
515
|
+
Middlewares(acl({ resource: 'pool', action: 'rolling-reboot', objectId: 'params.id' })),
|
|
434
516
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
517
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
435
518
|
Response(noContentResp.status, noContentResp.description),
|
|
436
519
|
Response(featureUnauthorized.status, featureUnauthorized.description),
|
|
437
520
|
Response(notFoundResp.status, notFoundResp.description),
|
|
@@ -441,7 +524,9 @@ __decorate([
|
|
|
441
524
|
__decorate([
|
|
442
525
|
Example(taskLocation),
|
|
443
526
|
Post('{id}/actions/rolling_update'),
|
|
527
|
+
Middlewares(acl({ resource: 'pool', action: 'rolling-update', objectId: 'params.id' })),
|
|
444
528
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
529
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
445
530
|
Response(noContentResp.status, noContentResp.description),
|
|
446
531
|
Response(featureUnauthorized.status, featureUnauthorized.description),
|
|
447
532
|
Response(notFoundResp.status, notFoundResp.description),
|
|
@@ -451,8 +536,24 @@ __decorate([
|
|
|
451
536
|
__decorate([
|
|
452
537
|
Example(importVm),
|
|
453
538
|
Post('{id}/vms'),
|
|
539
|
+
Middlewares(acl([
|
|
540
|
+
{
|
|
541
|
+
resource: 'sr',
|
|
542
|
+
action: 'import:vm',
|
|
543
|
+
objectId: ({ req, restApi }) => {
|
|
544
|
+
if (req.query.sr) {
|
|
545
|
+
return req.query.sr;
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
const pool = restApi.getObject(req.params.id, 'pool');
|
|
549
|
+
return pool.default_SR;
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
])),
|
|
454
554
|
Tags('vms'),
|
|
455
555
|
SuccessResponse(createdResp.status, 'VM imported'),
|
|
556
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
456
557
|
Response(notFoundResp.status, notFoundResp.description),
|
|
457
558
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
458
559
|
__param(0, Request()),
|
|
@@ -463,9 +564,40 @@ __decorate([
|
|
|
463
564
|
Example(taskLocation),
|
|
464
565
|
Example(createVm),
|
|
465
566
|
Post('{id}/actions/create_vm'),
|
|
466
|
-
Middlewares(
|
|
567
|
+
Middlewares([
|
|
568
|
+
json(),
|
|
569
|
+
acl([
|
|
570
|
+
{ resource: 'pool', action: 'create:vm', objectId: 'params.id' },
|
|
571
|
+
{
|
|
572
|
+
resource: 'vm-template',
|
|
573
|
+
action: 'instantiate',
|
|
574
|
+
objectId: ({ req, restApi }) => {
|
|
575
|
+
const pool = restApi.getXapiObject(req.params.id, 'pool');
|
|
576
|
+
const template = pool.$xapi.getObject(req.body.template);
|
|
577
|
+
if (template.is_default_template) {
|
|
578
|
+
return `${pool.uuid}-${template.uuid}`;
|
|
579
|
+
}
|
|
580
|
+
return req.body.template;
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
resource: 'vdi',
|
|
585
|
+
action: 'boot',
|
|
586
|
+
objectId: ({ req }) => {
|
|
587
|
+
const repository = req.body.install?.repository;
|
|
588
|
+
if (repository !== '') {
|
|
589
|
+
return repository;
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
{ resource: 'vdi', action: 'create', objects: ({ req }) => req.body.vdis },
|
|
594
|
+
{ resource: 'vif', action: 'create', objects: ({ req }) => req.body.vifs },
|
|
595
|
+
{ resource: 'host', action: 'allow-vm', objectId: 'body.affinity' },
|
|
596
|
+
]),
|
|
597
|
+
]),
|
|
467
598
|
Tags('vms'),
|
|
468
599
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
600
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
469
601
|
Response(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
470
602
|
Response(notFoundResp.status, notFoundResp.description),
|
|
471
603
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
@@ -476,6 +608,8 @@ __decorate([
|
|
|
476
608
|
__decorate([
|
|
477
609
|
Example(poolStats),
|
|
478
610
|
Get('{id}/stats'),
|
|
611
|
+
Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
|
|
612
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
479
613
|
Response(notFoundResp.status, notFoundResp.description),
|
|
480
614
|
Response(422, 'Invalid granularity'),
|
|
481
615
|
__param(0, Path()),
|
|
@@ -484,6 +618,8 @@ __decorate([
|
|
|
484
618
|
__decorate([
|
|
485
619
|
Example(poolDashboard),
|
|
486
620
|
Get('{id}/dashboard'),
|
|
621
|
+
Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
|
|
622
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
487
623
|
Response(notFoundResp.status, notFoundResp.description),
|
|
488
624
|
__param(0, Request()),
|
|
489
625
|
__param(1, Path()),
|
|
@@ -492,6 +628,7 @@ __decorate([
|
|
|
492
628
|
__decorate([
|
|
493
629
|
Example(genericAlarmsExample),
|
|
494
630
|
Get('{id}/alarms'),
|
|
631
|
+
Security('*', ['acl']),
|
|
495
632
|
Tags('alarms'),
|
|
496
633
|
Response(notFoundResp.status, notFoundResp.description),
|
|
497
634
|
__param(0, Request()),
|
|
@@ -505,6 +642,8 @@ __decorate([
|
|
|
505
642
|
__decorate([
|
|
506
643
|
Example(poolMissingPatches),
|
|
507
644
|
Get('{id}/missing_patches'),
|
|
645
|
+
Middlewares(acl({ resource: 'pool', action: 'read', objectId: 'params.id' })),
|
|
646
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
508
647
|
Response(notFoundResp.status, notFoundResp.description),
|
|
509
648
|
Response(featureUnauthorized.status, featureUnauthorized.description),
|
|
510
649
|
__param(0, Path())
|
|
@@ -513,6 +652,7 @@ __decorate([
|
|
|
513
652
|
Example(messageIds),
|
|
514
653
|
Example(partialMessages),
|
|
515
654
|
Get('{id}/messages'),
|
|
655
|
+
Security('*', ['acl']),
|
|
516
656
|
Tags('messages'),
|
|
517
657
|
Response(notFoundResp.status, notFoundResp.description),
|
|
518
658
|
__param(0, Request()),
|
|
@@ -525,14 +665,18 @@ __decorate([
|
|
|
525
665
|
], PoolController.prototype, "getPoolMessages", null);
|
|
526
666
|
__decorate([
|
|
527
667
|
Put('{id}/tags/{tag}'),
|
|
668
|
+
Middlewares(acl({ resource: 'pool', action: 'update:tags', objectId: 'params.id' })),
|
|
528
669
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
670
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
529
671
|
Response(notFoundResp.status, notFoundResp.description),
|
|
530
672
|
__param(0, Path()),
|
|
531
673
|
__param(1, Path())
|
|
532
674
|
], PoolController.prototype, "putPoolTag", null);
|
|
533
675
|
__decorate([
|
|
534
676
|
Delete('{id}/tags/{tag}'),
|
|
677
|
+
Middlewares(acl({ resource: 'pool', action: 'update:tags', objectId: 'params.id' })),
|
|
535
678
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
679
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
536
680
|
Response(notFoundResp.status, notFoundResp.description),
|
|
537
681
|
__param(0, Path()),
|
|
538
682
|
__param(1, Path())
|
|
@@ -541,6 +685,7 @@ __decorate([
|
|
|
541
685
|
Example(taskIds),
|
|
542
686
|
Example(partialTasks),
|
|
543
687
|
Get('{id}/tasks'),
|
|
688
|
+
Security('*', ['acl']),
|
|
544
689
|
Tags('tasks'),
|
|
545
690
|
Response(notFoundResp.status, notFoundResp.description),
|
|
546
691
|
__param(0, Request()),
|
|
@@ -7,10 +7,11 @@ 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, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
|
|
11
11
|
import { inject } from 'inversify';
|
|
12
12
|
import { provide } from 'inversify-binding-decorators';
|
|
13
|
-
import {
|
|
13
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
14
|
+
import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
14
15
|
import { partialProxies, proxy, proxyIds } from '../open-api/oa-examples/proxy.oa-example.mjs';
|
|
15
16
|
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
16
17
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
@@ -25,15 +26,24 @@ let ProxyController = class ProxyController extends XoController {
|
|
|
25
26
|
return this.restApi.xoApp.getProxy(id);
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
29
|
+
* Returns all proxies that match the following privilege:
|
|
30
|
+
* - resource: proxy, action: read
|
|
31
|
+
*
|
|
28
32
|
* @example fields "vmUuid,id,name"
|
|
29
33
|
* @example filter "vmUuid?"
|
|
30
34
|
* @example limit 42
|
|
31
35
|
*/
|
|
32
36
|
async getProxies(req, fields, ndjson, markdown, filter, limit) {
|
|
33
|
-
const proxies = Object.values(await this.getObjects({ filter
|
|
34
|
-
return this.sendObjects(proxies, req
|
|
37
|
+
const proxies = Object.values(await this.getObjects({ filter }));
|
|
38
|
+
return this.sendObjects(proxies, req, {
|
|
39
|
+
limit,
|
|
40
|
+
privilege: { action: 'read', resource: 'proxy' },
|
|
41
|
+
});
|
|
35
42
|
}
|
|
36
43
|
/**
|
|
44
|
+
* Required privilege:
|
|
45
|
+
* - resource: proxy, action: read
|
|
46
|
+
*
|
|
37
47
|
* @example id "e625ea0c-a876-405a-b838-109d762efe88"
|
|
38
48
|
*/
|
|
39
49
|
getProxy(id) {
|
|
@@ -44,6 +54,7 @@ __decorate([
|
|
|
44
54
|
Example(proxyIds),
|
|
45
55
|
Example(partialProxies),
|
|
46
56
|
Get(''),
|
|
57
|
+
Security('*', ['acl']),
|
|
47
58
|
__param(0, Request()),
|
|
48
59
|
__param(1, Query()),
|
|
49
60
|
__param(2, Query()),
|
|
@@ -54,6 +65,13 @@ __decorate([
|
|
|
54
65
|
__decorate([
|
|
55
66
|
Example(proxy),
|
|
56
67
|
Get('{id}'),
|
|
68
|
+
Middlewares(acl({
|
|
69
|
+
resource: 'proxy',
|
|
70
|
+
action: 'read',
|
|
71
|
+
objectId: 'params.id',
|
|
72
|
+
getObject: ({ restApi }) => restApi.xoApp.getProxy,
|
|
73
|
+
})),
|
|
74
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
57
75
|
Response(notFoundResp.status, notFoundResp.description),
|
|
58
76
|
__param(0, Path())
|
|
59
77
|
], ProxyController.prototype, "getProxy", null);
|
|
@@ -10,11 +10,11 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
10
10
|
import { createLogger } from '@xen-orchestra/log';
|
|
11
11
|
import { Deprecated, Example, Get, Middlewares, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
|
|
12
12
|
import { inject } from 'inversify';
|
|
13
|
-
import { noSuchObject } from 'xo-common/api-errors.js';
|
|
14
13
|
import { provide } from 'inversify-binding-decorators';
|
|
14
|
+
import { acl, autoBindService } from '../middlewares/acl.middleware.mjs';
|
|
15
15
|
import { BackupLogService } from '../backup-logs/backup-log.service.mjs';
|
|
16
16
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
17
|
-
import { badRequestResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
|
|
17
|
+
import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
18
18
|
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
19
19
|
import { partialRestoreLogs, restoreLog, restoreLogIds } from '../open-api/oa-examples/restore-log.oa-example.mjs';
|
|
20
20
|
const log = createLogger('xo:rest-api:restoreLog-controller');
|
|
@@ -28,24 +28,29 @@ let RestoreLogController = class RestoreLogController extends XoController {
|
|
|
28
28
|
const filter = log => !this.#backupLogService.isBackupLog(log);
|
|
29
29
|
return this.restApi.xoApp.getBackupNgLogsSorted({ filter });
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (this.#backupLogService.isBackupLog(log)) {
|
|
34
|
-
throw noSuchObject('restore-log');
|
|
35
|
-
}
|
|
36
|
-
return log;
|
|
31
|
+
getCollectionObject(id) {
|
|
32
|
+
return this.#backupLogService.getRestoreLog(id);
|
|
37
33
|
}
|
|
38
34
|
/**
|
|
35
|
+
* Returns all restore logs that match the following privilege:
|
|
36
|
+
* - resource: restore-log, action: read
|
|
37
|
+
*
|
|
39
38
|
* @example fields "jobName,status,data"
|
|
40
39
|
* @example filter "status:success"
|
|
41
40
|
* @example limit 42
|
|
42
41
|
*/
|
|
43
42
|
async getRestoreLogs(req, fields, ndjson, markdown, filter, limit) {
|
|
44
|
-
const restoreLogs = await this.getObjects({ filter
|
|
45
|
-
return this.sendObjects(Object.values(restoreLogs), req
|
|
43
|
+
const restoreLogs = await this.getObjects({ filter });
|
|
44
|
+
return this.sendObjects(Object.values(restoreLogs), req, {
|
|
45
|
+
limit,
|
|
46
|
+
privilege: { action: 'read', resource: 'restore-log' },
|
|
47
|
+
});
|
|
46
48
|
}
|
|
47
49
|
/**
|
|
48
|
-
*
|
|
50
|
+
* Required privilege:
|
|
51
|
+
* - resource: restore-log, action: read
|
|
52
|
+
*
|
|
53
|
+
* @example id "1758180544428"
|
|
49
54
|
*/
|
|
50
55
|
getRestoreLog(id) {
|
|
51
56
|
return this.getObject(id);
|
|
@@ -55,6 +60,7 @@ __decorate([
|
|
|
55
60
|
Example(restoreLogIds),
|
|
56
61
|
Example(partialRestoreLogs),
|
|
57
62
|
Get(''),
|
|
63
|
+
Security('*', ['acl']),
|
|
58
64
|
__param(0, Request()),
|
|
59
65
|
__param(1, Query()),
|
|
60
66
|
__param(2, Query()),
|
|
@@ -65,6 +71,14 @@ __decorate([
|
|
|
65
71
|
__decorate([
|
|
66
72
|
Example(restoreLog),
|
|
67
73
|
Get('{id}'),
|
|
74
|
+
Middlewares(acl({
|
|
75
|
+
resource: 'restore-log',
|
|
76
|
+
action: 'read',
|
|
77
|
+
objectId: 'params.id',
|
|
78
|
+
getObject: autoBindService(BackupLogService, 'getRestoreLog'),
|
|
79
|
+
})),
|
|
80
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
81
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
68
82
|
__param(0, Path())
|
|
69
83
|
], RestoreLogController.prototype, "getRestoreLog", null);
|
|
70
84
|
RestoreLogController = __decorate([
|
|
@@ -89,21 +103,24 @@ let DeprecatedRestoreController = class DeprecatedRestoreController extends XoCo
|
|
|
89
103
|
const filter = log => !this.#backupLogService.isBackupLog(log);
|
|
90
104
|
return this.restApi.xoApp.getBackupNgLogsSorted({ filter });
|
|
91
105
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (this.#backupLogService.isBackupLog(log)) {
|
|
95
|
-
throw noSuchObject('restore-log');
|
|
96
|
-
}
|
|
97
|
-
return log;
|
|
106
|
+
getCollectionObject(id) {
|
|
107
|
+
return this.#backupLogService.getRestoreLog(id);
|
|
98
108
|
}
|
|
99
109
|
/**
|
|
110
|
+
* Returns all restore logs that match the following privilege:
|
|
111
|
+
* - resource: restore-log, action: read
|
|
112
|
+
*
|
|
100
113
|
* @example fields "jobName,status,data"
|
|
101
114
|
* @example filter "status:success"
|
|
102
115
|
* @example limit 42
|
|
103
116
|
*/
|
|
104
117
|
async getDeprecatedRestoreLogs(req, fields, ndjson, markdown, filter, limit) {
|
|
105
|
-
const restoreLogs = await this.getObjects({ filter
|
|
106
|
-
return this.sendObjects(Object.values(restoreLogs), req,
|
|
118
|
+
const restoreLogs = await this.getObjects({ filter });
|
|
119
|
+
return this.sendObjects(Object.values(restoreLogs), req, {
|
|
120
|
+
path: 'restore-logs',
|
|
121
|
+
limit,
|
|
122
|
+
privilege: { action: 'read', resource: 'restore-log' },
|
|
123
|
+
});
|
|
107
124
|
}
|
|
108
125
|
/**
|
|
109
126
|
* @example id "1758180544428"
|
|
@@ -7,10 +7,11 @@ 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, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags } from 'tsoa';
|
|
10
|
+
import { Example, Get, Middlewares, 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 {
|
|
13
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
14
|
+
import { asynchronousActionResp, badRequestResp, featureUnauthorized, forbiddenOperationResp, internalServerErrorResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
14
15
|
import { partialSchedules, schedule, scheduleIds } from '../open-api/oa-examples/schedule.oa-example.mjs';
|
|
15
16
|
import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
16
17
|
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
@@ -27,20 +28,34 @@ let ScheduleController = class ScheduleController extends XoController {
|
|
|
27
28
|
return this.restApi.xoApp.getSchedule(id);
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
31
|
+
* Returns all schedules that match the following privilege:
|
|
32
|
+
* - resource: schedule, action: read
|
|
33
|
+
*
|
|
30
34
|
* @example fields "enabled,jobId,cron,id"
|
|
31
35
|
* @example filter "enabled?"
|
|
32
36
|
* @example limit 42
|
|
33
37
|
*/
|
|
34
38
|
async getSchedules(req, fields, ndjson, markdown, filter, limit) {
|
|
35
|
-
return this.sendObjects(Object.values(await this.getObjects({ filter
|
|
39
|
+
return this.sendObjects(Object.values(await this.getObjects({ filter })), req, {
|
|
40
|
+
limit,
|
|
41
|
+
privilege: { action: 'read', resource: 'schedule' },
|
|
42
|
+
});
|
|
36
43
|
}
|
|
37
44
|
/**
|
|
45
|
+
*
|
|
46
|
+
* Required privilege:
|
|
47
|
+
* - resource: schedule, action: read
|
|
48
|
+
*
|
|
38
49
|
* @example id "cf7249f8-d20b-494f-97f4-b1f32f94e780"
|
|
39
50
|
*/
|
|
40
51
|
async getSchedule(id) {
|
|
41
52
|
return this.getObject(id);
|
|
42
53
|
}
|
|
43
54
|
/**
|
|
55
|
+
*
|
|
56
|
+
* Required privilege:
|
|
57
|
+
* - resource: schedule, action: run
|
|
58
|
+
*
|
|
44
59
|
* @example id "cf7249f8-d20b-494f-97f4-b1f32f94e780"
|
|
45
60
|
*/
|
|
46
61
|
async runSchedule(id, sync) {
|
|
@@ -62,6 +77,7 @@ __decorate([
|
|
|
62
77
|
Example(scheduleIds),
|
|
63
78
|
Example(partialSchedules),
|
|
64
79
|
Get(''),
|
|
80
|
+
Security('*', ['acl']),
|
|
65
81
|
__param(0, Request()),
|
|
66
82
|
__param(1, Query()),
|
|
67
83
|
__param(2, Query()),
|
|
@@ -72,15 +88,29 @@ __decorate([
|
|
|
72
88
|
__decorate([
|
|
73
89
|
Example(schedule),
|
|
74
90
|
Get('{id}'),
|
|
91
|
+
Middlewares(acl({
|
|
92
|
+
resource: 'schedule',
|
|
93
|
+
action: 'read',
|
|
94
|
+
objectId: 'params.id',
|
|
95
|
+
getObject: ({ restApi }) => id => restApi.xoApp.getSchedule(id),
|
|
96
|
+
})),
|
|
97
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
75
98
|
Response(notFoundResp.status, notFoundResp.description),
|
|
76
99
|
__param(0, Path())
|
|
77
100
|
], ScheduleController.prototype, "getSchedule", null);
|
|
78
101
|
__decorate([
|
|
79
102
|
Example(taskLocation),
|
|
80
103
|
Post('{id}/actions/run'),
|
|
104
|
+
Middlewares(acl({
|
|
105
|
+
resource: 'schedule',
|
|
106
|
+
action: 'run',
|
|
107
|
+
objectId: 'params.id',
|
|
108
|
+
getObject: ({ restApi }) => id => restApi.xoApp.getSchedule(id),
|
|
109
|
+
})),
|
|
81
110
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
82
111
|
Response(noContentResp.status, noContentResp.description),
|
|
83
112
|
Response(featureUnauthorized.status, featureUnauthorized.description),
|
|
113
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
84
114
|
Response(notFoundResp.status, notFoundResp.description),
|
|
85
115
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
86
116
|
__param(0, Path()),
|