@xen-orchestra/rest-api 0.29.0 → 0.30.1
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 +101 -1
- package/dist/abstract-classes/base-controller.mjs +20 -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 +206 -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 +75 -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
|
@@ -11,7 +11,8 @@ import { Body, Delete, Example, Get, Middlewares, Path, Post, Query, Request, Re
|
|
|
11
11
|
import { json } from 'express';
|
|
12
12
|
import { inject } from 'inversify';
|
|
13
13
|
import { provide } from 'inversify-binding-decorators';
|
|
14
|
-
import {
|
|
14
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
15
|
+
import { asynchronousActionResp, badRequestResp, createdResp, forbiddenOperationResp, invalidParameters, noContentResp, notFoundResp, resourceAlreadyExists, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
15
16
|
import { partialServers, server, serverId, serverIds } from '../open-api/oa-examples/server.oa-example.mjs';
|
|
16
17
|
import { partialTasks, taskIds, taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
17
18
|
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
@@ -28,26 +29,41 @@ let ServerController = class ServerController extends XoController {
|
|
|
28
29
|
return this.restApi.xoApp.getXenServer(id);
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
32
|
+
* Returns all servers that match the following privilege:
|
|
33
|
+
* - resource: server, action: read
|
|
34
|
+
*
|
|
31
35
|
* @example fields "status,id"
|
|
32
36
|
* @example filter "status:/^connected$/"
|
|
33
37
|
* @example limit 42
|
|
34
38
|
*/
|
|
35
39
|
async getServers(req, fields, ndjson, markdown, filter, limit) {
|
|
36
|
-
return this.sendObjects(Object.values(await this.getObjects({ filter
|
|
40
|
+
return this.sendObjects(Object.values(await this.getObjects({ filter })), req, {
|
|
41
|
+
limit,
|
|
42
|
+
privilege: { action: 'read', resource: 'server' },
|
|
43
|
+
});
|
|
37
44
|
}
|
|
38
45
|
/**
|
|
46
|
+
* Required privilege:
|
|
47
|
+
* - resource: server, action: read
|
|
48
|
+
*
|
|
39
49
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
40
50
|
*/
|
|
41
51
|
getServer(id) {
|
|
42
52
|
return this.getObject(id);
|
|
43
53
|
}
|
|
44
54
|
/**
|
|
55
|
+
* Required privilege:
|
|
56
|
+
* - resource: server, action: delete
|
|
57
|
+
*
|
|
45
58
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
46
59
|
*/
|
|
47
60
|
async deleteServer(id) {
|
|
48
61
|
await this.restApi.xoApp.unregisterXenServer(id);
|
|
49
62
|
}
|
|
50
63
|
/**
|
|
64
|
+
* Required privilege:
|
|
65
|
+
* - resource: server, action: create
|
|
66
|
+
*
|
|
51
67
|
* @example body {
|
|
52
68
|
* "allowUnauthorized": true,
|
|
53
69
|
* "host": "192.168.1.10",
|
|
@@ -61,6 +77,9 @@ let ServerController = class ServerController extends XoController {
|
|
|
61
77
|
return { id: server.id };
|
|
62
78
|
}
|
|
63
79
|
/**
|
|
80
|
+
* Required privilege:
|
|
81
|
+
* - resource: server, action: connect
|
|
82
|
+
*
|
|
64
83
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
65
84
|
*/
|
|
66
85
|
connectServer(id, sync) {
|
|
@@ -75,6 +94,9 @@ let ServerController = class ServerController extends XoController {
|
|
|
75
94
|
});
|
|
76
95
|
}
|
|
77
96
|
/**
|
|
97
|
+
* Required privilege:
|
|
98
|
+
* - resource: server, action: disconnect
|
|
99
|
+
*
|
|
78
100
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
79
101
|
*/
|
|
80
102
|
disconnectServer(id, sync) {
|
|
@@ -89,20 +111,28 @@ let ServerController = class ServerController extends XoController {
|
|
|
89
111
|
});
|
|
90
112
|
}
|
|
91
113
|
/**
|
|
114
|
+
* Returns all tasks that match the following privilege:
|
|
115
|
+
* - resource: task, action: read
|
|
116
|
+
*
|
|
92
117
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
93
118
|
* @example fields "id,status,properties"
|
|
94
119
|
* @example filter "status:failure"
|
|
95
120
|
* @example limit 42
|
|
96
121
|
*/
|
|
97
122
|
async getServerTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
98
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
99
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
123
|
+
const tasks = await this.getTasksForObject(id, { filter });
|
|
124
|
+
return this.sendObjects(Object.values(tasks), req, {
|
|
125
|
+
path: 'tasks',
|
|
126
|
+
limit,
|
|
127
|
+
privilege: { action: 'read', resource: 'task' },
|
|
128
|
+
});
|
|
100
129
|
}
|
|
101
130
|
};
|
|
102
131
|
__decorate([
|
|
103
132
|
Example(serverIds),
|
|
104
133
|
Example(partialServers),
|
|
105
134
|
Get(''),
|
|
135
|
+
Security('*', ['acl']),
|
|
106
136
|
__param(0, Request()),
|
|
107
137
|
__param(1, Query()),
|
|
108
138
|
__param(2, Query()),
|
|
@@ -113,20 +143,35 @@ __decorate([
|
|
|
113
143
|
__decorate([
|
|
114
144
|
Example(server),
|
|
115
145
|
Get('{id}'),
|
|
146
|
+
Middlewares(acl({
|
|
147
|
+
resource: 'server',
|
|
148
|
+
action: 'read',
|
|
149
|
+
objectId: 'params.id',
|
|
150
|
+
getObject: ({ restApi }) => restApi.xoApp.getXenServer,
|
|
151
|
+
})),
|
|
152
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
116
153
|
Response(notFoundResp.status, notFoundResp.description),
|
|
117
154
|
__param(0, Path())
|
|
118
155
|
], ServerController.prototype, "getServer", null);
|
|
119
156
|
__decorate([
|
|
120
157
|
Delete('{id}'),
|
|
158
|
+
Middlewares(acl({
|
|
159
|
+
resource: 'server',
|
|
160
|
+
action: 'delete',
|
|
161
|
+
objectId: 'params.id',
|
|
162
|
+
getObject: ({ restApi }) => restApi.xoApp.getXenServer,
|
|
163
|
+
})),
|
|
121
164
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
165
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
122
166
|
Response(notFoundResp.status, notFoundResp.description),
|
|
123
167
|
__param(0, Path())
|
|
124
168
|
], ServerController.prototype, "deleteServer", null);
|
|
125
169
|
__decorate([
|
|
126
170
|
Example(serverId),
|
|
127
171
|
Post(''),
|
|
128
|
-
Middlewares(json()),
|
|
172
|
+
Middlewares([json(), acl({ resource: 'server', action: 'create', object: ({ req }) => req.body })]),
|
|
129
173
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
174
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
130
175
|
Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
|
|
131
176
|
Response(invalidParameters.status, invalidParameters.description),
|
|
132
177
|
__param(0, Body())
|
|
@@ -134,8 +179,15 @@ __decorate([
|
|
|
134
179
|
__decorate([
|
|
135
180
|
Example(taskLocation),
|
|
136
181
|
Post('{id}/actions/connect'),
|
|
182
|
+
Middlewares(acl({
|
|
183
|
+
resource: 'server',
|
|
184
|
+
action: 'connect',
|
|
185
|
+
objectId: 'params.id',
|
|
186
|
+
getObject: ({ restApi }) => restApi.xoApp.getXenServer,
|
|
187
|
+
})),
|
|
137
188
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
138
189
|
Response(noContentResp.status, noContentResp.description),
|
|
190
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
139
191
|
Response(notFoundResp.status, notFoundResp.description),
|
|
140
192
|
Response(409, 'The server is already connected'),
|
|
141
193
|
__param(0, Path()),
|
|
@@ -144,8 +196,15 @@ __decorate([
|
|
|
144
196
|
__decorate([
|
|
145
197
|
Example(taskLocation),
|
|
146
198
|
Post('{id}/actions/disconnect'),
|
|
199
|
+
Middlewares(acl({
|
|
200
|
+
resource: 'server',
|
|
201
|
+
action: 'disconnect',
|
|
202
|
+
objectId: 'params.id',
|
|
203
|
+
getObject: ({ restApi }) => restApi.xoApp.getXenServer,
|
|
204
|
+
})),
|
|
147
205
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
148
206
|
Response(noContentResp.status, noContentResp.description),
|
|
207
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
149
208
|
Response(notFoundResp.status, notFoundResp.description),
|
|
150
209
|
Response(409, 'The server is already disconnected'),
|
|
151
210
|
__param(0, Path()),
|
|
@@ -155,6 +214,7 @@ __decorate([
|
|
|
155
214
|
Example(taskIds),
|
|
156
215
|
Example(partialTasks),
|
|
157
216
|
Get('{id}/tasks'),
|
|
217
|
+
Security('*', ['acl']),
|
|
158
218
|
Tags('tasks'),
|
|
159
219
|
Response(notFoundResp.status, notFoundResp.description),
|
|
160
220
|
__param(0, Request()),
|
|
@@ -7,9 +7,10 @@ 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 { acl } from '../middlewares/acl.middleware.mjs';
|
|
13
14
|
import { badRequestResp, notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
|
|
14
15
|
import { partialSms, sm, smIds } from '../open-api/oa-examples/sm.oa-example.mjs';
|
|
15
16
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
@@ -19,14 +20,23 @@ let SmController = class SmController extends XapiXoController {
|
|
|
19
20
|
super('SM', restApi);
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
23
|
+
* Returns all SMs that match the following privilege:
|
|
24
|
+
* - resource: sm, action: read
|
|
25
|
+
*
|
|
22
26
|
* @example fields "uuid,name_label,SM_type"
|
|
23
27
|
* @example filter "SM_type:ext"
|
|
24
28
|
* @example limit 42
|
|
25
29
|
*/
|
|
26
30
|
getSrs(req, fields, ndjson, markdown, filter, limit) {
|
|
27
|
-
return this.sendObjects(Object.values(this.getObjects({ filter
|
|
31
|
+
return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
|
|
32
|
+
limit,
|
|
33
|
+
privilege: { action: 'read', resource: 'sm' },
|
|
34
|
+
});
|
|
28
35
|
}
|
|
29
36
|
/**
|
|
37
|
+
* Required privilege:
|
|
38
|
+
* - resource: sm, action: read
|
|
39
|
+
*
|
|
30
40
|
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
31
41
|
*/
|
|
32
42
|
getSr(id) {
|
|
@@ -37,6 +47,7 @@ __decorate([
|
|
|
37
47
|
Example(smIds),
|
|
38
48
|
Example(partialSms),
|
|
39
49
|
Get(''),
|
|
50
|
+
Security('*', ['acl']),
|
|
40
51
|
__param(0, Request()),
|
|
41
52
|
__param(1, Query()),
|
|
42
53
|
__param(2, Query()),
|
|
@@ -47,6 +58,7 @@ __decorate([
|
|
|
47
58
|
__decorate([
|
|
48
59
|
Example(sm),
|
|
49
60
|
Get('{id}'),
|
|
61
|
+
Middlewares(acl({ resource: 'sm', action: 'read', objectId: 'params.id' })),
|
|
50
62
|
Response(notFoundResp.status, notFoundResp.description),
|
|
51
63
|
__param(0, Path())
|
|
52
64
|
], SmController.prototype, "getSr", null);
|
|
@@ -7,15 +7,16 @@ 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 { Delete, Example, Get, Path, Post, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
|
|
10
|
+
import { Delete, Example, Get, Middlewares, Path, Post, Put, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
|
|
11
11
|
import { inject } from 'inversify';
|
|
12
12
|
import { provide } from 'inversify-binding-decorators';
|
|
13
13
|
import { SUPPORTED_VDI_FORMAT } from '@vates/types';
|
|
14
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
14
15
|
import { AlarmService } from '../alarms/alarm.service.mjs';
|
|
15
16
|
import { BASE_URL } from '../index.mjs';
|
|
16
17
|
import { escapeUnsafeComplexMatcher } from '../helpers/utils.helper.mjs';
|
|
17
18
|
import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
|
|
18
|
-
import { asynchronousActionResp, badRequestResp, createdResp, internalServerErrorResp, invalidParameters as invalidParametersResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
19
|
+
import { asynchronousActionResp, badRequestResp, createdResp, internalServerErrorResp, invalidParameters as invalidParametersResp, forbiddenOperationResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
19
20
|
import { partialSrs, sr, srIds } from '../open-api/oa-examples/sr.oa-example.mjs';
|
|
20
21
|
import { vdiId } from '../open-api/oa-examples/vdi.oa-example.mjs';
|
|
21
22
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
@@ -29,20 +30,32 @@ let SrController = class SrController extends XapiXoController {
|
|
|
29
30
|
this.#alarmService = alarmService;
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
33
|
+
* Returns all SRs that match the following privilege:
|
|
34
|
+
* - resource: sr, action: read
|
|
35
|
+
*
|
|
32
36
|
* @example fields "uuid,name_label,allocationStrategy"
|
|
33
37
|
* @example filter "allocationStrategy:thin"
|
|
34
38
|
* @example limit 42
|
|
35
39
|
*/
|
|
36
40
|
getSrs(req, fields, ndjson, markdown, filter, limit) {
|
|
37
|
-
return this.sendObjects(Object.values(this.getObjects({ filter
|
|
41
|
+
return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
|
|
42
|
+
limit,
|
|
43
|
+
privilege: { action: 'read', resource: 'sr' },
|
|
44
|
+
});
|
|
38
45
|
}
|
|
39
46
|
/**
|
|
47
|
+
* Required privilege:
|
|
48
|
+
* - resource: sr, action: read
|
|
49
|
+
*
|
|
40
50
|
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
41
51
|
*/
|
|
42
52
|
getSr(id) {
|
|
43
53
|
return this.getObject(id);
|
|
44
54
|
}
|
|
45
55
|
/**
|
|
56
|
+
* Returns all alarms that match the following privilege:
|
|
57
|
+
* - resource: alarm, action: read
|
|
58
|
+
*
|
|
46
59
|
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
47
60
|
* @example fields "id,time"
|
|
48
61
|
* @example filter "time:>1747053793"
|
|
@@ -52,12 +65,19 @@ let SrController = class SrController extends XapiXoController {
|
|
|
52
65
|
const sr = this.getObject(id);
|
|
53
66
|
const alarms = this.#alarmService.getAlarms({
|
|
54
67
|
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${sr.uuid}`,
|
|
68
|
+
});
|
|
69
|
+
return this.sendObjects(Object.values(alarms), req, {
|
|
70
|
+
path: 'alarms',
|
|
55
71
|
limit,
|
|
72
|
+
privilege: { action: 'read', resource: 'alarm' },
|
|
56
73
|
});
|
|
57
|
-
return this.sendObjects(Object.values(alarms), req, 'alarms');
|
|
58
74
|
}
|
|
59
75
|
/**
|
|
60
76
|
* Import an exported VDI
|
|
77
|
+
*
|
|
78
|
+
* Required privilege:
|
|
79
|
+
* - resource: sr, action: import:vdi
|
|
80
|
+
*
|
|
61
81
|
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
62
82
|
* @example name_label "VDI_foo_import"
|
|
63
83
|
* @example name_description "VDI imported by the REST API"
|
|
@@ -79,26 +99,43 @@ let SrController = class SrController extends XapiXoController {
|
|
|
79
99
|
return { id: vdiId };
|
|
80
100
|
}
|
|
81
101
|
/**
|
|
102
|
+
* Returns all messages that match the following privilege:
|
|
103
|
+
* - resource: message, action: read
|
|
104
|
+
*
|
|
82
105
|
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
83
106
|
* @example fields "name,id,$object"
|
|
84
107
|
* @example filter "name:VM_STARTED"
|
|
85
108
|
* @example limit 42
|
|
86
109
|
*/
|
|
87
110
|
getSrMessages(req, id, fields, ndjson, markdown, filter, limit) {
|
|
88
|
-
const messages = this.getMessagesForObject(id, { filter
|
|
89
|
-
return this.sendObjects(Object.values(messages), req,
|
|
111
|
+
const messages = this.getMessagesForObject(id, { filter });
|
|
112
|
+
return this.sendObjects(Object.values(messages), req, {
|
|
113
|
+
path: 'messages',
|
|
114
|
+
limit,
|
|
115
|
+
privilege: { action: 'read', resource: 'message' },
|
|
116
|
+
});
|
|
90
117
|
}
|
|
91
118
|
/**
|
|
119
|
+
* Returns all tasks that match the following privilege:
|
|
120
|
+
* - resource: task, action: read
|
|
121
|
+
*
|
|
92
122
|
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
93
123
|
* @example fields "id,status,properties"
|
|
94
124
|
* @example filter "status:failure"
|
|
95
125
|
* @example limit 42
|
|
96
126
|
*/
|
|
97
127
|
async getSrTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
98
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
99
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
128
|
+
const tasks = await this.getTasksForObject(id, { filter });
|
|
129
|
+
return this.sendObjects(Object.values(tasks), req, {
|
|
130
|
+
path: 'tasks',
|
|
131
|
+
limit,
|
|
132
|
+
privilege: { action: 'read', resource: 'task' },
|
|
133
|
+
});
|
|
100
134
|
}
|
|
101
135
|
/**
|
|
136
|
+
* Required privilege:
|
|
137
|
+
* - resource: sr, action: update:tags
|
|
138
|
+
*
|
|
102
139
|
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
103
140
|
* @example tag "from-rest-api"
|
|
104
141
|
*/
|
|
@@ -107,6 +144,9 @@ let SrController = class SrController extends XapiXoController {
|
|
|
107
144
|
await sr.$call('add_tags', tag);
|
|
108
145
|
}
|
|
109
146
|
/**
|
|
147
|
+
* Required privilege:
|
|
148
|
+
* - resource: sr, action: update:tags
|
|
149
|
+
*
|
|
110
150
|
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
111
151
|
* @example tag "from-rest-api"
|
|
112
152
|
*/
|
|
@@ -173,6 +213,7 @@ __decorate([
|
|
|
173
213
|
Example(srIds),
|
|
174
214
|
Example(partialSrs),
|
|
175
215
|
Get(''),
|
|
216
|
+
Security('*', ['acl']),
|
|
176
217
|
__param(0, Request()),
|
|
177
218
|
__param(1, Query()),
|
|
178
219
|
__param(2, Query()),
|
|
@@ -183,12 +224,15 @@ __decorate([
|
|
|
183
224
|
__decorate([
|
|
184
225
|
Example(sr),
|
|
185
226
|
Get('{id}'),
|
|
227
|
+
Middlewares(acl({ resource: 'sr', action: 'read', objectId: 'params.id' })),
|
|
228
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
186
229
|
Response(notFoundResp.status, notFoundResp.description),
|
|
187
230
|
__param(0, Path())
|
|
188
231
|
], SrController.prototype, "getSr", null);
|
|
189
232
|
__decorate([
|
|
190
233
|
Example(genericAlarmsExample),
|
|
191
234
|
Get('{id}/alarms'),
|
|
235
|
+
Security('*', ['acl']),
|
|
192
236
|
Tags('alarms'),
|
|
193
237
|
Response(notFoundResp.status, notFoundResp.description),
|
|
194
238
|
__param(0, Request()),
|
|
@@ -202,8 +246,10 @@ __decorate([
|
|
|
202
246
|
__decorate([
|
|
203
247
|
Example(vdiId),
|
|
204
248
|
Post('{id}/vdis'),
|
|
249
|
+
Middlewares(acl({ resource: 'sr', action: 'import:vdi', objectId: 'params.id' })),
|
|
205
250
|
Tags('vdis'),
|
|
206
251
|
SuccessResponse(createdResp.status, 'VDI imported'),
|
|
252
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
207
253
|
Response(notFoundResp.status, notFoundResp.description),
|
|
208
254
|
__param(0, Request()),
|
|
209
255
|
__param(1, Path()),
|
|
@@ -215,6 +261,7 @@ __decorate([
|
|
|
215
261
|
Example(messageIds),
|
|
216
262
|
Example(partialMessages),
|
|
217
263
|
Get('{id}/messages'),
|
|
264
|
+
Security('*', ['acl']),
|
|
218
265
|
Tags('messages'),
|
|
219
266
|
Response(notFoundResp.status, notFoundResp.description),
|
|
220
267
|
__param(0, Request()),
|
|
@@ -229,6 +276,7 @@ __decorate([
|
|
|
229
276
|
Example(taskIds),
|
|
230
277
|
Example(partialTasks),
|
|
231
278
|
Get('{id}/tasks'),
|
|
279
|
+
Security('*', ['acl']),
|
|
232
280
|
Tags('tasks'),
|
|
233
281
|
Response(notFoundResp.status, notFoundResp.description),
|
|
234
282
|
__param(0, Request()),
|
|
@@ -240,16 +288,20 @@ __decorate([
|
|
|
240
288
|
__param(6, Query())
|
|
241
289
|
], SrController.prototype, "getSrTasks", null);
|
|
242
290
|
__decorate([
|
|
291
|
+
Put('{id}/tags/{tag}'),
|
|
292
|
+
Middlewares(acl({ resource: 'sr', action: 'update:tags', objectId: 'params.id' })),
|
|
243
293
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
294
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
244
295
|
Response(notFoundResp.status, notFoundResp.description),
|
|
245
|
-
Put('{id}/tags/{tag}'),
|
|
246
296
|
__param(0, Path()),
|
|
247
297
|
__param(1, Path())
|
|
248
298
|
], SrController.prototype, "putSrTag", null);
|
|
249
299
|
__decorate([
|
|
300
|
+
Delete('{id}/tags/{tag}'),
|
|
301
|
+
Middlewares(acl({ resource: 'sr', action: 'update:tags', objectId: 'params.id' })),
|
|
250
302
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
303
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
251
304
|
Response(notFoundResp.status, notFoundResp.description),
|
|
252
|
-
Delete('{id}/tags/{tag}'),
|
|
253
305
|
__param(0, Path()),
|
|
254
306
|
__param(1, Path())
|
|
255
307
|
], SrController.prototype, "deleteSrTag", null);
|
|
@@ -8,8 +8,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
8
8
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
9
|
};
|
|
10
10
|
import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
11
|
-
import { Get, Path, Query, Request, Route, Security, Tags, Response, Example, Delete, Post, SuccessResponse, } from 'tsoa';
|
|
12
|
-
import {
|
|
11
|
+
import { Get, Path, Query, Request, Route, Security, Tags, Response, Example, Delete, Post, SuccessResponse, Middlewares, } from 'tsoa';
|
|
12
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
13
|
+
import { asynchronousActionResp, badRequestResp, forbiddenOperationResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
13
14
|
import { inject } from 'inversify';
|
|
14
15
|
import { provide } from 'inversify-binding-decorators';
|
|
15
16
|
import { partialTasks, task, taskIds, taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
@@ -19,6 +20,7 @@ import { Transform } from 'node:stream';
|
|
|
19
20
|
import { makeObjectMapper } from '../helpers/object-wrapper.helper.mjs';
|
|
20
21
|
import { safeParseComplexMatcher } from '../helpers/utils.helper.mjs';
|
|
21
22
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
23
|
+
import { hasPrivilegeOn } from '@xen-orchestra/acl';
|
|
22
24
|
let TaskController = class TaskController extends XoController {
|
|
23
25
|
constructor(restApi) {
|
|
24
26
|
super('task', restApi);
|
|
@@ -34,6 +36,8 @@ let TaskController = class TaskController extends XoController {
|
|
|
34
36
|
return this.restApi.tasks.get(id);
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
39
|
+
* Returns all tasks that match the following privilege:
|
|
40
|
+
* - resource: task, action: read
|
|
37
41
|
*
|
|
38
42
|
* If watch is true, ndjson must also be true
|
|
39
43
|
*
|
|
@@ -63,21 +67,40 @@ let TaskController = class TaskController extends XoController {
|
|
|
63
67
|
process.on('SIGTERM', () => {
|
|
64
68
|
req.destroy();
|
|
65
69
|
});
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
const userId = this.restApi.getCurrentUser().id;
|
|
71
|
+
const update = async (task) => {
|
|
72
|
+
const user = await this.restApi.xoApp.getUser(userId);
|
|
73
|
+
const userPrivileges = user.permission === 'admin'
|
|
74
|
+
? []
|
|
75
|
+
: (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
76
|
+
if (hasPrivilegeOn({ user, userPrivileges, action: 'read', resource: 'task', objects: task }) &&
|
|
77
|
+
(userFilter === undefined || userFilter(task))) {
|
|
68
78
|
stream.write(['update', task]);
|
|
69
79
|
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
};
|
|
81
|
+
const remove = async (task) => {
|
|
82
|
+
const user = await this.restApi.xoApp.getUser(userId);
|
|
83
|
+
const userPrivileges = user.permission === 'admin'
|
|
84
|
+
? []
|
|
85
|
+
: (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
86
|
+
if (hasPrivilegeOn({ user, userPrivileges, action: 'read', resource: 'task', objects: task }) &&
|
|
87
|
+
(userFilter === undefined || userFilter(task))) {
|
|
88
|
+
stream.write(['remove', { id: task.id }]);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
74
91
|
this.restApi.tasks.on('update', update).on('remove', remove);
|
|
75
92
|
return stream;
|
|
76
93
|
}
|
|
77
|
-
const tasks = Object.values(await this.getObjects({ filter
|
|
78
|
-
return this.sendObjects(tasks, req
|
|
94
|
+
const tasks = Object.values(await this.getObjects({ filter }));
|
|
95
|
+
return this.sendObjects(tasks, req, {
|
|
96
|
+
limit,
|
|
97
|
+
privilege: { action: 'read', resource: 'task' },
|
|
98
|
+
});
|
|
79
99
|
}
|
|
80
100
|
/**
|
|
101
|
+
* Required privilege:
|
|
102
|
+
* - resource: task, action: read
|
|
103
|
+
*
|
|
81
104
|
* @example id "0mdd1basu"
|
|
82
105
|
*/
|
|
83
106
|
async getTask(req, id, wait) {
|
|
@@ -95,10 +118,25 @@ let TaskController = class TaskController extends XoController {
|
|
|
95
118
|
}
|
|
96
119
|
return this.getObject(taskId);
|
|
97
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Deletes all tasks the current user has the following privilege on:
|
|
123
|
+
* - resource: task, action: delete
|
|
124
|
+
*/
|
|
98
125
|
async deleteTasks() {
|
|
99
|
-
|
|
126
|
+
const user = this.restApi.getCurrentUser();
|
|
127
|
+
const userPrivileges = user.permission === 'admin' ? [] : (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
128
|
+
const deletePromises = [];
|
|
129
|
+
for await (const task of this.restApi.tasks.list()) {
|
|
130
|
+
if (hasPrivilegeOn({ user, userPrivileges, resource: 'task', action: 'delete', objects: task })) {
|
|
131
|
+
deletePromises.push(this.restApi.tasks.deleteLog(task.id));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
await Promise.all(deletePromises);
|
|
100
135
|
}
|
|
101
136
|
/**
|
|
137
|
+
* Required privilege:
|
|
138
|
+
* - resource: task, action: delete
|
|
139
|
+
*
|
|
102
140
|
* @example id "0mdd1basu"
|
|
103
141
|
*/
|
|
104
142
|
async deleteTask(id) {
|
|
@@ -106,6 +144,9 @@ let TaskController = class TaskController extends XoController {
|
|
|
106
144
|
await this.restApi.tasks.deleteLog(task.id);
|
|
107
145
|
}
|
|
108
146
|
/**
|
|
147
|
+
* Required privilege:
|
|
148
|
+
* - resource: task, action: abort
|
|
149
|
+
*
|
|
109
150
|
* @example id "0mdd1basu"
|
|
110
151
|
*/
|
|
111
152
|
async abortTask(id, sync) {
|
|
@@ -127,6 +168,7 @@ __decorate([
|
|
|
127
168
|
Example(taskIds),
|
|
128
169
|
Example(partialTasks),
|
|
129
170
|
Get(''),
|
|
171
|
+
Security('*', ['acl']),
|
|
130
172
|
Response(badRequestResp.status, badRequestResp.description),
|
|
131
173
|
__param(0, Request()),
|
|
132
174
|
__param(1, Query()),
|
|
@@ -139,6 +181,13 @@ __decorate([
|
|
|
139
181
|
__decorate([
|
|
140
182
|
Example(task),
|
|
141
183
|
Get('{id}'),
|
|
184
|
+
Middlewares(acl({
|
|
185
|
+
resource: 'task',
|
|
186
|
+
action: 'read',
|
|
187
|
+
objectId: 'params.id',
|
|
188
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
189
|
+
})),
|
|
190
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
142
191
|
Response(notFoundResp.status, notFoundResp.description),
|
|
143
192
|
__param(0, Request()),
|
|
144
193
|
__param(1, Path()),
|
|
@@ -146,19 +195,34 @@ __decorate([
|
|
|
146
195
|
], TaskController.prototype, "getTask", null);
|
|
147
196
|
__decorate([
|
|
148
197
|
Delete(''),
|
|
198
|
+
Security('*', ['acl']),
|
|
149
199
|
SuccessResponse(noContentResp.status, noContentResp.description)
|
|
150
200
|
], TaskController.prototype, "deleteTasks", null);
|
|
151
201
|
__decorate([
|
|
152
202
|
Delete('{id}'),
|
|
203
|
+
Middlewares(acl({
|
|
204
|
+
resource: 'task',
|
|
205
|
+
action: 'delete',
|
|
206
|
+
objectId: 'params.id',
|
|
207
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
208
|
+
})),
|
|
153
209
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
210
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
154
211
|
Response(notFoundResp.status, notFoundResp.description),
|
|
155
212
|
__param(0, Path())
|
|
156
213
|
], TaskController.prototype, "deleteTask", null);
|
|
157
214
|
__decorate([
|
|
158
215
|
Example(taskLocation),
|
|
159
216
|
Post('{id}/actions/abort'),
|
|
217
|
+
Middlewares(acl({
|
|
218
|
+
resource: 'task',
|
|
219
|
+
action: 'abort',
|
|
220
|
+
objectId: 'params.id',
|
|
221
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
222
|
+
})),
|
|
160
223
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
161
224
|
Response(noContentResp.status, noContentResp.description),
|
|
225
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
162
226
|
Response(notFoundResp.status, notFoundResp.description),
|
|
163
227
|
__param(0, Path()),
|
|
164
228
|
__param(1, Query())
|