@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
|
@@ -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,36 @@ 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 = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
74
|
+
if (hasPrivilegeOn({ user, userPrivileges, action: 'read', resource: 'task', objects: task }) &&
|
|
75
|
+
(userFilter === undefined || userFilter(task))) {
|
|
68
76
|
stream.write(['update', task]);
|
|
69
77
|
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
};
|
|
79
|
+
const remove = async (task) => {
|
|
80
|
+
const user = await this.restApi.xoApp.getUser(userId);
|
|
81
|
+
const userPrivileges = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
82
|
+
if (hasPrivilegeOn({ user, userPrivileges, action: 'read', resource: 'task', objects: task }) &&
|
|
83
|
+
(userFilter === undefined || userFilter(task))) {
|
|
84
|
+
stream.write(['remove', { id: task.id }]);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
74
87
|
this.restApi.tasks.on('update', update).on('remove', remove);
|
|
75
88
|
return stream;
|
|
76
89
|
}
|
|
77
|
-
const tasks = Object.values(await this.getObjects({ filter
|
|
78
|
-
return this.sendObjects(tasks, req
|
|
90
|
+
const tasks = Object.values(await this.getObjects({ filter }));
|
|
91
|
+
return this.sendObjects(tasks, req, {
|
|
92
|
+
limit,
|
|
93
|
+
privilege: { action: 'read', resource: 'task' },
|
|
94
|
+
});
|
|
79
95
|
}
|
|
80
96
|
/**
|
|
97
|
+
* Required privilege:
|
|
98
|
+
* - resource: task, action: read
|
|
99
|
+
*
|
|
81
100
|
* @example id "0mdd1basu"
|
|
82
101
|
*/
|
|
83
102
|
async getTask(req, id, wait) {
|
|
@@ -95,10 +114,25 @@ let TaskController = class TaskController extends XoController {
|
|
|
95
114
|
}
|
|
96
115
|
return this.getObject(taskId);
|
|
97
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Deletes all tasks the current user has the following privilege on:
|
|
119
|
+
* - resource: task, action: delete
|
|
120
|
+
*/
|
|
98
121
|
async deleteTasks() {
|
|
99
|
-
|
|
122
|
+
const user = this.restApi.getCurrentUser();
|
|
123
|
+
const userPrivileges = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
124
|
+
const deletePromises = [];
|
|
125
|
+
for await (const task of this.restApi.tasks.list()) {
|
|
126
|
+
if (hasPrivilegeOn({ user, userPrivileges, resource: 'task', action: 'delete', objects: task })) {
|
|
127
|
+
deletePromises.push(this.restApi.tasks.deleteLog(task.id));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
await Promise.all(deletePromises);
|
|
100
131
|
}
|
|
101
132
|
/**
|
|
133
|
+
* Required privilege:
|
|
134
|
+
* - resource: task, action: delete
|
|
135
|
+
*
|
|
102
136
|
* @example id "0mdd1basu"
|
|
103
137
|
*/
|
|
104
138
|
async deleteTask(id) {
|
|
@@ -106,6 +140,9 @@ let TaskController = class TaskController extends XoController {
|
|
|
106
140
|
await this.restApi.tasks.deleteLog(task.id);
|
|
107
141
|
}
|
|
108
142
|
/**
|
|
143
|
+
* Required privilege:
|
|
144
|
+
* - resource: task, action: abort
|
|
145
|
+
*
|
|
109
146
|
* @example id "0mdd1basu"
|
|
110
147
|
*/
|
|
111
148
|
async abortTask(id, sync) {
|
|
@@ -127,6 +164,7 @@ __decorate([
|
|
|
127
164
|
Example(taskIds),
|
|
128
165
|
Example(partialTasks),
|
|
129
166
|
Get(''),
|
|
167
|
+
Security('*', ['acl']),
|
|
130
168
|
Response(badRequestResp.status, badRequestResp.description),
|
|
131
169
|
__param(0, Request()),
|
|
132
170
|
__param(1, Query()),
|
|
@@ -139,6 +177,13 @@ __decorate([
|
|
|
139
177
|
__decorate([
|
|
140
178
|
Example(task),
|
|
141
179
|
Get('{id}'),
|
|
180
|
+
Middlewares(acl({
|
|
181
|
+
resource: 'task',
|
|
182
|
+
action: 'read',
|
|
183
|
+
objectId: 'params.id',
|
|
184
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
185
|
+
})),
|
|
186
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
142
187
|
Response(notFoundResp.status, notFoundResp.description),
|
|
143
188
|
__param(0, Request()),
|
|
144
189
|
__param(1, Path()),
|
|
@@ -146,19 +191,34 @@ __decorate([
|
|
|
146
191
|
], TaskController.prototype, "getTask", null);
|
|
147
192
|
__decorate([
|
|
148
193
|
Delete(''),
|
|
194
|
+
Security('*', ['acl']),
|
|
149
195
|
SuccessResponse(noContentResp.status, noContentResp.description)
|
|
150
196
|
], TaskController.prototype, "deleteTasks", null);
|
|
151
197
|
__decorate([
|
|
152
198
|
Delete('{id}'),
|
|
199
|
+
Middlewares(acl({
|
|
200
|
+
resource: 'task',
|
|
201
|
+
action: 'delete',
|
|
202
|
+
objectId: 'params.id',
|
|
203
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
204
|
+
})),
|
|
153
205
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
206
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
154
207
|
Response(notFoundResp.status, notFoundResp.description),
|
|
155
208
|
__param(0, Path())
|
|
156
209
|
], TaskController.prototype, "deleteTask", null);
|
|
157
210
|
__decorate([
|
|
158
211
|
Example(taskLocation),
|
|
159
212
|
Post('{id}/actions/abort'),
|
|
213
|
+
Middlewares(acl({
|
|
214
|
+
resource: 'task',
|
|
215
|
+
action: 'abort',
|
|
216
|
+
objectId: 'params.id',
|
|
217
|
+
getObject: ({ restApi }) => restApi.xoApp.tasks.get.bind(restApi.xoApp.tasks),
|
|
218
|
+
})),
|
|
160
219
|
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
161
220
|
Response(noContentResp.status, noContentResp.description),
|
|
221
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
162
222
|
Response(notFoundResp.status, notFoundResp.description),
|
|
163
223
|
__param(0, Path()),
|
|
164
224
|
__param(1, Query())
|