@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
|
@@ -20,6 +20,7 @@ import { RestApi } from '../rest-api/rest-api.mjs';
|
|
|
20
20
|
import { limitAndFilterArray } from '../helpers/utils.helper.mjs';
|
|
21
21
|
import { partialUsers, userIds } from '../open-api/oa-examples/user.oa-example.mjs';
|
|
22
22
|
import { partialTasks, taskIds } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
23
|
+
import { acl, actionFromBody } from '../middlewares/acl.middleware.mjs';
|
|
23
24
|
let GroupController = class GroupController extends XoController {
|
|
24
25
|
#userService;
|
|
25
26
|
constructor(restApi, userService) {
|
|
@@ -34,20 +35,35 @@ let GroupController = class GroupController extends XoController {
|
|
|
34
35
|
return this.restApi.xoApp.getGroup(id);
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
38
|
+
* Returns all groups that match the following privilege:
|
|
39
|
+
* - resource: group, action: read
|
|
40
|
+
*
|
|
37
41
|
* @example fields "name,id,users"
|
|
38
42
|
* @example filter "users:length:>0"
|
|
39
43
|
* @example limit 42
|
|
40
44
|
*/
|
|
41
45
|
async getGroups(req, fields, ndjson, markdown, filter, limit) {
|
|
42
|
-
return this.sendObjects(Object.values(await this.getObjects({ filter
|
|
46
|
+
return this.sendObjects(Object.values(await this.getObjects({ filter })), req, {
|
|
47
|
+
limit,
|
|
48
|
+
privilege: { action: 'read', resource: 'group' },
|
|
49
|
+
});
|
|
43
50
|
}
|
|
44
51
|
/**
|
|
52
|
+
* Required privilege:
|
|
53
|
+
* - resource: group, action: read
|
|
54
|
+
*
|
|
45
55
|
* @example id "7d98fee4-3357-41a7-ac3f-9124212badb7"
|
|
46
56
|
*/
|
|
47
57
|
getGroup(id) {
|
|
48
58
|
return this.getObject(id);
|
|
49
59
|
}
|
|
50
60
|
/**
|
|
61
|
+
* You cannot patch `synchronized` groups (even with the right privilege)
|
|
62
|
+
*
|
|
63
|
+
* Required privileges:
|
|
64
|
+
* - resource: group, action: update (grants all fields)
|
|
65
|
+
* - resource: group, action: update:name (if name is passed)
|
|
66
|
+
*
|
|
51
67
|
* @example id "c98395a7-26d8-4e09-b055-d5f0f4a98312"
|
|
52
68
|
* @example body { "name": "new group name" }
|
|
53
69
|
*/
|
|
@@ -59,6 +75,9 @@ let GroupController = class GroupController extends XoController {
|
|
|
59
75
|
await this.restApi.xoApp.updateGroup(group.id, body);
|
|
60
76
|
}
|
|
61
77
|
/**
|
|
78
|
+
* Required privilege:
|
|
79
|
+
* - resource: group, action: create
|
|
80
|
+
*
|
|
62
81
|
* @example body {
|
|
63
82
|
* "name": "new group"
|
|
64
83
|
* }
|
|
@@ -68,6 +87,9 @@ let GroupController = class GroupController extends XoController {
|
|
|
68
87
|
return { id: group.id };
|
|
69
88
|
}
|
|
70
89
|
/**
|
|
90
|
+
* Required privilege:
|
|
91
|
+
* - resource: group, action: delete
|
|
92
|
+
*
|
|
71
93
|
* @example id "7d98fee4-3357-41a7-ac3f-9124212badb7"
|
|
72
94
|
*/
|
|
73
95
|
async deleteGroup(id) {
|
|
@@ -75,6 +97,11 @@ let GroupController = class GroupController extends XoController {
|
|
|
75
97
|
await this.restApi.xoApp.deleteGroup(groupId);
|
|
76
98
|
}
|
|
77
99
|
/**
|
|
100
|
+
* You cannot manage users of `synchronized` groups (even with the right privilege)
|
|
101
|
+
*
|
|
102
|
+
* Required privilege:
|
|
103
|
+
* - resource: group, action: update:users
|
|
104
|
+
*
|
|
78
105
|
* @example id "c98395a7-26d8-4e09-b055-d5f0f4a98312"
|
|
79
106
|
* @example userId "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
80
107
|
*/
|
|
@@ -86,6 +113,11 @@ let GroupController = class GroupController extends XoController {
|
|
|
86
113
|
await this.restApi.xoApp.removeUserFromGroup(userId, group.id);
|
|
87
114
|
}
|
|
88
115
|
/**
|
|
116
|
+
* You cannot manage users of `synchronized` groups (even with the right privilege)
|
|
117
|
+
*
|
|
118
|
+
* Required privilege:
|
|
119
|
+
* - resource: group, action: update:users
|
|
120
|
+
*
|
|
89
121
|
* @example id "6c81b5e1-afc1-43ea-8f8d-939ceb5f3f90"
|
|
90
122
|
* @example userId "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
91
123
|
*/
|
|
@@ -97,6 +129,9 @@ let GroupController = class GroupController extends XoController {
|
|
|
97
129
|
await this.restApi.xoApp.addUserToGroup(userId, group.id);
|
|
98
130
|
}
|
|
99
131
|
/**
|
|
132
|
+
* Returns all users that match the following privilege:
|
|
133
|
+
* - resource: user, action: read
|
|
134
|
+
*
|
|
100
135
|
* @example id "6c81b5e1-afc1-43ea-8f8d-939ceb5f3f90"
|
|
101
136
|
* @example fields "permission,name,id"
|
|
102
137
|
* @example filter "permission:none"
|
|
@@ -105,23 +140,35 @@ let GroupController = class GroupController extends XoController {
|
|
|
105
140
|
async getGroupUsers(req, id, fields, ndjson, markdown, filter, limit) {
|
|
106
141
|
const group = await this.getObject(id);
|
|
107
142
|
const users = await Promise.all(group.users.map(id => this.#userService.getUser(id)));
|
|
108
|
-
return this.sendObjects(limitAndFilterArray(users, { filter
|
|
143
|
+
return this.sendObjects(limitAndFilterArray(users, { filter }), req, {
|
|
144
|
+
path: 'users',
|
|
145
|
+
limit,
|
|
146
|
+
privilege: { action: 'read', resource: 'user' },
|
|
147
|
+
});
|
|
109
148
|
}
|
|
110
149
|
/**
|
|
150
|
+
* Returns all tasks that match the following privilege:
|
|
151
|
+
* - resource: task, action: read
|
|
152
|
+
*
|
|
111
153
|
* @example id "6c81b5e1-afc1-43ea-8f8d-939ceb5f3f90"
|
|
112
154
|
* @example fields "id,status,properties"
|
|
113
155
|
* @example filter "status:failure"
|
|
114
156
|
* @example limit 42
|
|
115
157
|
*/
|
|
116
158
|
async getGroupTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
117
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
118
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
159
|
+
const tasks = await this.getTasksForObject(id, { filter });
|
|
160
|
+
return this.sendObjects(Object.values(tasks), req, {
|
|
161
|
+
path: 'tasks',
|
|
162
|
+
limit,
|
|
163
|
+
privilege: { action: 'read', resource: 'task' },
|
|
164
|
+
});
|
|
119
165
|
}
|
|
120
166
|
};
|
|
121
167
|
__decorate([
|
|
122
168
|
Example(groupIds),
|
|
123
169
|
Example(partialGroups),
|
|
124
170
|
Get(''),
|
|
171
|
+
Security('*', ['acl']),
|
|
125
172
|
__param(0, Request()),
|
|
126
173
|
__param(1, Query()),
|
|
127
174
|
__param(2, Query()),
|
|
@@ -132,12 +179,27 @@ __decorate([
|
|
|
132
179
|
__decorate([
|
|
133
180
|
Example(group),
|
|
134
181
|
Get('{id}'),
|
|
182
|
+
Middlewares(acl({
|
|
183
|
+
resource: 'group',
|
|
184
|
+
action: 'read',
|
|
185
|
+
objectId: 'params.id',
|
|
186
|
+
getObject: ({ restApi }) => restApi.xoApp.getGroup,
|
|
187
|
+
})),
|
|
188
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
135
189
|
Response(notFoundResp.status, notFoundResp.description),
|
|
136
190
|
__param(0, Path())
|
|
137
191
|
], GroupController.prototype, "getGroup", null);
|
|
138
192
|
__decorate([
|
|
139
193
|
Patch('{id}'),
|
|
140
|
-
Middlewares(
|
|
194
|
+
Middlewares([
|
|
195
|
+
json(),
|
|
196
|
+
acl({
|
|
197
|
+
resource: 'group',
|
|
198
|
+
action: actionFromBody('update:name'),
|
|
199
|
+
objectId: 'params.id',
|
|
200
|
+
getObject: ({ restApi }) => restApi.xoApp.getGroup,
|
|
201
|
+
}),
|
|
202
|
+
]),
|
|
141
203
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
142
204
|
Response(notFoundResp.status, notFoundResp.description),
|
|
143
205
|
Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
|
|
@@ -148,20 +210,34 @@ __decorate([
|
|
|
148
210
|
__decorate([
|
|
149
211
|
Example(groupId),
|
|
150
212
|
Post(''),
|
|
151
|
-
Middlewares(json()),
|
|
213
|
+
Middlewares([json(), acl({ resource: 'group', action: 'create', object: ({ req }) => req.body })]),
|
|
152
214
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
215
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
153
216
|
Response(invalidParameters.status, invalidParameters.description),
|
|
154
217
|
Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
|
|
155
218
|
__param(0, Body())
|
|
156
219
|
], GroupController.prototype, "createGroup", null);
|
|
157
220
|
__decorate([
|
|
158
221
|
Delete('{id}'),
|
|
222
|
+
Middlewares(acl({
|
|
223
|
+
resource: 'group',
|
|
224
|
+
action: 'delete',
|
|
225
|
+
objectId: 'params.id',
|
|
226
|
+
getObject: ({ restApi }) => restApi.xoApp.getGroup,
|
|
227
|
+
})),
|
|
159
228
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
229
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
160
230
|
Response(notFoundResp.status, notFoundResp.description),
|
|
161
231
|
__param(0, Path())
|
|
162
232
|
], GroupController.prototype, "deleteGroup", null);
|
|
163
233
|
__decorate([
|
|
164
234
|
Delete('{id}/users/{userId}'),
|
|
235
|
+
Middlewares(acl({
|
|
236
|
+
resource: 'group',
|
|
237
|
+
action: 'update:users',
|
|
238
|
+
objectId: 'params.id',
|
|
239
|
+
getObject: ({ restApi }) => restApi.xoApp.getGroup,
|
|
240
|
+
})),
|
|
165
241
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
166
242
|
Response(notFoundResp.status, notFoundResp.description),
|
|
167
243
|
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
@@ -170,6 +246,12 @@ __decorate([
|
|
|
170
246
|
], GroupController.prototype, "removeUserFromGroup", null);
|
|
171
247
|
__decorate([
|
|
172
248
|
Put('{id}/users/{userId}'),
|
|
249
|
+
Middlewares(acl({
|
|
250
|
+
resource: 'group',
|
|
251
|
+
action: 'update:users',
|
|
252
|
+
objectId: 'params.id',
|
|
253
|
+
getObject: ({ restApi }) => restApi.xoApp.getGroup,
|
|
254
|
+
})),
|
|
173
255
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
174
256
|
Response(notFoundResp.status, notFoundResp.description),
|
|
175
257
|
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
@@ -180,6 +262,7 @@ __decorate([
|
|
|
180
262
|
Example(userIds),
|
|
181
263
|
Example(partialUsers),
|
|
182
264
|
Get('{id}/users'),
|
|
265
|
+
Security('*', ['acl']),
|
|
183
266
|
Tags('users'),
|
|
184
267
|
Response(notFoundResp.status, notFoundResp.description),
|
|
185
268
|
__param(0, Request()),
|
|
@@ -194,6 +277,7 @@ __decorate([
|
|
|
194
277
|
Example(taskIds),
|
|
195
278
|
Example(partialTasks),
|
|
196
279
|
Get('{id}/tasks'),
|
|
280
|
+
Security('*', ['acl']),
|
|
197
281
|
Tags('tasks'),
|
|
198
282
|
Response(notFoundResp.status, notFoundResp.description),
|
|
199
283
|
__param(0, Request()),
|
|
@@ -15,13 +15,14 @@ import { inject } from 'inversify';
|
|
|
15
15
|
import { invalidParameters } from 'xo-common/api-errors.js';
|
|
16
16
|
import { pipeline } from 'node:stream/promises';
|
|
17
17
|
import { provide } from 'inversify-binding-decorators';
|
|
18
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
18
19
|
import { AlarmService } from '../alarms/alarm.service.mjs';
|
|
19
20
|
import { escapeUnsafeComplexMatcher } from '../helpers/utils.helper.mjs';
|
|
20
21
|
import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
|
|
21
22
|
import { host, hostIds, hostSmt, hostMissingPatches, hostStats, partialHosts, } from '../open-api/oa-examples/host.oa-example.mjs';
|
|
22
23
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
23
24
|
import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
|
|
24
|
-
import { asynchronousActionResp, badRequestResp, featureUnauthorized, internalServerErrorResp, invalidParameters as invalidParametersResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
25
|
+
import { asynchronousActionResp, badRequestResp, featureUnauthorized, forbiddenOperationResp, internalServerErrorResp, invalidParameters as invalidParametersResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
25
26
|
import { HostService } from './host.service.mjs';
|
|
26
27
|
import { messageIds, partialMessages } from '../open-api/oa-examples/message.oa-example.mjs';
|
|
27
28
|
import { partialTasks, taskIds, taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
@@ -34,20 +35,32 @@ let HostController = class HostController extends XapiXoController {
|
|
|
34
35
|
this.#hostService = hostService;
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
38
|
+
* Returns all hosts that match the following privilege:
|
|
39
|
+
* - resource: host, action: read
|
|
40
|
+
*
|
|
37
41
|
* @example fields "id,name_label,productBrand"
|
|
38
42
|
* @example filter "productBrand:XCP-ng"
|
|
39
43
|
* @example limit 42
|
|
40
44
|
*/
|
|
41
45
|
getHosts(req, fields, ndjson, markdown, filter, limit) {
|
|
42
|
-
return this.sendObjects(Object.values(this.getObjects({ filter
|
|
46
|
+
return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
|
|
47
|
+
limit,
|
|
48
|
+
privilege: { action: 'read', resource: 'host' },
|
|
49
|
+
});
|
|
43
50
|
}
|
|
44
51
|
/**
|
|
52
|
+
* Required privilege:
|
|
53
|
+
* - resource: host, action: read
|
|
54
|
+
*
|
|
45
55
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
46
56
|
*/
|
|
47
57
|
getHost(id) {
|
|
48
58
|
return this.getObject(id);
|
|
49
59
|
}
|
|
50
60
|
/**
|
|
61
|
+
* Required privilege:
|
|
62
|
+
* - resource: host, action: read
|
|
63
|
+
*
|
|
51
64
|
* Host must be running
|
|
52
65
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
53
66
|
*/
|
|
@@ -55,6 +68,9 @@ let HostController = class HostController extends XapiXoController {
|
|
|
55
68
|
return this.restApi.xoApp.getXapiHostStats(id, granularity);
|
|
56
69
|
}
|
|
57
70
|
/**
|
|
71
|
+
* Required privilege:
|
|
72
|
+
* - resource: host, action: export:logs
|
|
73
|
+
*
|
|
58
74
|
* Host must be running
|
|
59
75
|
*
|
|
60
76
|
* Download the audit log of a host.
|
|
@@ -75,6 +91,9 @@ let HostController = class HostController extends XapiXoController {
|
|
|
75
91
|
await pipeline(response.body, this.maybeCompressResponse(req, res));
|
|
76
92
|
}
|
|
77
93
|
/**
|
|
94
|
+
* Required privilege:
|
|
95
|
+
* - resource: host, action: export:logs
|
|
96
|
+
*
|
|
78
97
|
* Host must be running
|
|
79
98
|
*
|
|
80
99
|
* Download all logs of a host.
|
|
@@ -90,6 +109,9 @@ let HostController = class HostController extends XapiXoController {
|
|
|
90
109
|
await pipeline(response.body, res);
|
|
91
110
|
}
|
|
92
111
|
/**
|
|
112
|
+
* Returns all alarms that match the following privilege:
|
|
113
|
+
* - resource: alarm, action: read
|
|
114
|
+
*
|
|
93
115
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
94
116
|
* @example fields "id,time"
|
|
95
117
|
* @example filter "time:>1747053793"
|
|
@@ -99,11 +121,17 @@ let HostController = class HostController extends XapiXoController {
|
|
|
99
121
|
const host = this.getObject(id);
|
|
100
122
|
const alarms = this.#alarmService.getAlarms({
|
|
101
123
|
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${host.uuid}`,
|
|
124
|
+
});
|
|
125
|
+
return this.sendObjects(Object.values(alarms), req, {
|
|
126
|
+
path: 'alarms',
|
|
102
127
|
limit,
|
|
128
|
+
privilege: { action: 'read', resource: 'alarm' },
|
|
103
129
|
});
|
|
104
|
-
return this.sendObjects(Object.values(alarms), req, 'alarms');
|
|
105
130
|
}
|
|
106
131
|
/**
|
|
132
|
+
* Required privilege:
|
|
133
|
+
* - resource: host, action: read
|
|
134
|
+
*
|
|
107
135
|
* Returns a boolean indicating whether SMT (Simultaneous Multi-Threading) is enabled
|
|
108
136
|
*
|
|
109
137
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
@@ -115,6 +143,9 @@ let HostController = class HostController extends XapiXoController {
|
|
|
115
143
|
return { enabled };
|
|
116
144
|
}
|
|
117
145
|
/**
|
|
146
|
+
* Required privilege:
|
|
147
|
+
* - resource: host, action: read
|
|
148
|
+
*
|
|
118
149
|
* Host must be running
|
|
119
150
|
*
|
|
120
151
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
@@ -124,26 +155,43 @@ let HostController = class HostController extends XapiXoController {
|
|
|
124
155
|
return missingPatches;
|
|
125
156
|
}
|
|
126
157
|
/**
|
|
158
|
+
* Returns all messages that match the following privilege:
|
|
159
|
+
* - resource: message, action: read
|
|
160
|
+
*
|
|
127
161
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
128
162
|
* @example fields "name,id,$object"
|
|
129
163
|
* @example filter "name:PBD_PLUG_FAILED_ON_SERVER_START"
|
|
130
164
|
* @example limit 42
|
|
131
165
|
*/
|
|
132
166
|
getHostMessages(req, id, fields, ndjson, markdown, filter, limit) {
|
|
133
|
-
const messages = this.getMessagesForObject(id, { filter
|
|
134
|
-
return this.sendObjects(Object.values(messages), req,
|
|
167
|
+
const messages = this.getMessagesForObject(id, { filter });
|
|
168
|
+
return this.sendObjects(Object.values(messages), req, {
|
|
169
|
+
path: 'messages',
|
|
170
|
+
limit,
|
|
171
|
+
privilege: { action: 'read', resource: 'message' },
|
|
172
|
+
});
|
|
135
173
|
}
|
|
136
174
|
/**
|
|
175
|
+
* Returns all tasks that match the following privilege:
|
|
176
|
+
* - resource: task, action: read
|
|
177
|
+
*
|
|
137
178
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
138
179
|
* @example fields "id,status,properties"
|
|
139
180
|
* @example filter "status:failure"
|
|
140
181
|
* @example limit 42
|
|
141
182
|
*/
|
|
142
183
|
async getHostTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
143
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
144
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
184
|
+
const tasks = await this.getTasksForObject(id, { filter });
|
|
185
|
+
return this.sendObjects(Object.values(tasks), req, {
|
|
186
|
+
path: 'tasks',
|
|
187
|
+
limit,
|
|
188
|
+
privilege: { action: 'read', resource: 'task' },
|
|
189
|
+
});
|
|
145
190
|
}
|
|
146
191
|
/**
|
|
192
|
+
* Required privilege:
|
|
193
|
+
* - resource: host, action: update:tags
|
|
194
|
+
*
|
|
147
195
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
148
196
|
* @example tag "from-rest-api"
|
|
149
197
|
*/
|
|
@@ -152,6 +200,9 @@ let HostController = class HostController extends XapiXoController {
|
|
|
152
200
|
await host.$call('add_tags', tag);
|
|
153
201
|
}
|
|
154
202
|
/**
|
|
203
|
+
* Required privilege:
|
|
204
|
+
* - resource: host, action: update:tags
|
|
205
|
+
*
|
|
155
206
|
* @example id "b61a5c92-700e-4966-a13b-00633f03eea8"
|
|
156
207
|
* @example tag "from-rest-api"
|
|
157
208
|
*/
|
|
@@ -257,6 +308,7 @@ __decorate([
|
|
|
257
308
|
Example(hostIds),
|
|
258
309
|
Example(partialHosts),
|
|
259
310
|
Get(''),
|
|
311
|
+
Security('*', ['acl']),
|
|
260
312
|
__param(0, Request()),
|
|
261
313
|
__param(1, Query()),
|
|
262
314
|
__param(2, Query()),
|
|
@@ -267,12 +319,16 @@ __decorate([
|
|
|
267
319
|
__decorate([
|
|
268
320
|
Example(host),
|
|
269
321
|
Get('{id}'),
|
|
322
|
+
Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
|
|
323
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
270
324
|
Response(notFoundResp.status, notFoundResp.description),
|
|
271
325
|
__param(0, Path())
|
|
272
326
|
], HostController.prototype, "getHost", null);
|
|
273
327
|
__decorate([
|
|
274
328
|
Example(hostStats),
|
|
275
329
|
Get('{id}/stats'),
|
|
330
|
+
Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
|
|
331
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
276
332
|
Response(notFoundResp.status, notFoundResp.description),
|
|
277
333
|
Response(422, 'Invalid granularity'),
|
|
278
334
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
@@ -281,7 +337,9 @@ __decorate([
|
|
|
281
337
|
], HostController.prototype, "getHostStats", null);
|
|
282
338
|
__decorate([
|
|
283
339
|
Get('{id}/audit.txt'),
|
|
340
|
+
Middlewares(acl({ resource: 'host', action: 'export:logs', objectId: 'params.id' })),
|
|
284
341
|
SuccessResponse(200, 'Download started', 'application/octet-stream'),
|
|
342
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
285
343
|
Response(notFoundResp.status, notFoundResp.description),
|
|
286
344
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
287
345
|
__param(0, Request()),
|
|
@@ -289,7 +347,9 @@ __decorate([
|
|
|
289
347
|
], HostController.prototype, "getAuditLog", null);
|
|
290
348
|
__decorate([
|
|
291
349
|
Get('{id}/logs.tgz'),
|
|
350
|
+
Middlewares(acl({ resource: 'host', action: 'export:logs', objectId: 'params.id' })),
|
|
292
351
|
SuccessResponse(200, 'Download started', 'application/gzip'),
|
|
352
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
293
353
|
Response(notFoundResp.status, notFoundResp.description),
|
|
294
354
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
295
355
|
__param(0, Request()),
|
|
@@ -298,6 +358,7 @@ __decorate([
|
|
|
298
358
|
__decorate([
|
|
299
359
|
Example(genericAlarmsExample),
|
|
300
360
|
Get('{id}/alarms'),
|
|
361
|
+
Security('*', ['acl']),
|
|
301
362
|
Tags('alarms'),
|
|
302
363
|
Response(notFoundResp.status, notFoundResp.description),
|
|
303
364
|
__param(0, Request()),
|
|
@@ -311,6 +372,8 @@ __decorate([
|
|
|
311
372
|
__decorate([
|
|
312
373
|
Example(hostSmt),
|
|
313
374
|
Get('{id}/smt'),
|
|
375
|
+
Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
|
|
376
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
314
377
|
Response(notFoundResp.status, notFoundResp.description),
|
|
315
378
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
316
379
|
__param(0, Path())
|
|
@@ -318,6 +381,8 @@ __decorate([
|
|
|
318
381
|
__decorate([
|
|
319
382
|
Example(hostMissingPatches),
|
|
320
383
|
Get('{id}/missing_patches'),
|
|
384
|
+
Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
|
|
385
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
321
386
|
Response(notFoundResp.status, notFoundResp.description),
|
|
322
387
|
Response(featureUnauthorized.status, featureUnauthorized.description),
|
|
323
388
|
__param(0, Path())
|
|
@@ -326,6 +391,7 @@ __decorate([
|
|
|
326
391
|
Example(messageIds),
|
|
327
392
|
Example(partialMessages),
|
|
328
393
|
Get('{id}/messages'),
|
|
394
|
+
Security('*', ['acl']),
|
|
329
395
|
Tags('messages'),
|
|
330
396
|
Response(notFoundResp.status, notFoundResp.description),
|
|
331
397
|
__param(0, Request()),
|
|
@@ -340,6 +406,7 @@ __decorate([
|
|
|
340
406
|
Example(taskIds),
|
|
341
407
|
Example(partialTasks),
|
|
342
408
|
Get('{id}/tasks'),
|
|
409
|
+
Security('*', ['acl']),
|
|
343
410
|
Tags('tasks'),
|
|
344
411
|
Response(notFoundResp.status, notFoundResp.description),
|
|
345
412
|
__param(0, Request()),
|
|
@@ -352,14 +419,18 @@ __decorate([
|
|
|
352
419
|
], HostController.prototype, "getHostTasks", null);
|
|
353
420
|
__decorate([
|
|
354
421
|
Put('{id}/tags/{tag}'),
|
|
422
|
+
Middlewares(acl({ resource: 'host', action: 'update:tags', objectId: 'params.id' })),
|
|
355
423
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
424
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
356
425
|
Response(notFoundResp.status, notFoundResp.description),
|
|
357
426
|
__param(0, Path()),
|
|
358
427
|
__param(1, Path())
|
|
359
428
|
], HostController.prototype, "putHostTag", null);
|
|
360
429
|
__decorate([
|
|
361
430
|
Delete('{id}/tags/{tag}'),
|
|
431
|
+
Middlewares(acl({ resource: 'host', action: 'update:tags', objectId: 'params.id' })),
|
|
362
432
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
433
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
363
434
|
Response(notFoundResp.status, notFoundResp.description),
|
|
364
435
|
__param(0, Path()),
|
|
365
436
|
__param(1, Path())
|
package/dist/ioc/ioc.mjs
CHANGED
|
@@ -13,10 +13,11 @@ import { BackupJobService } from '../backup-jobs/backup-job.service.mjs';
|
|
|
13
13
|
import { BackupLogService } from '../backup-logs/backup-log.service.mjs';
|
|
14
14
|
import { EventService } from '../events/event.service.mjs';
|
|
15
15
|
import { NetworkService } from '../networks/network.service.mjs';
|
|
16
|
+
import { BackupArchiveService } from '../backup-archives/backup-archive.service.mjs';
|
|
16
17
|
const iocContainer = new Container();
|
|
17
|
-
decorate(injectable(), Controller);
|
|
18
|
-
iocContainer.load(buildProviderModule());
|
|
19
18
|
export function setupContainer(xoApp) {
|
|
19
|
+
decorate(injectable(), Controller);
|
|
20
|
+
iocContainer.load(buildProviderModule());
|
|
20
21
|
if (iocContainer.isBound(RestApi)) {
|
|
21
22
|
iocContainer.unbind(RestApi);
|
|
22
23
|
}
|
|
@@ -82,8 +83,9 @@ export function setupContainer(xoApp) {
|
|
|
82
83
|
.inSingletonScope();
|
|
83
84
|
iocContainer
|
|
84
85
|
.bind(BackupLogService)
|
|
85
|
-
.toDynamicValue(
|
|
86
|
-
|
|
86
|
+
.toDynamicValue(ctx => {
|
|
87
|
+
const restApi = ctx.container.get(RestApi);
|
|
88
|
+
return new BackupLogService(restApi);
|
|
87
89
|
})
|
|
88
90
|
.inSingletonScope();
|
|
89
91
|
iocContainer
|
|
@@ -100,5 +102,12 @@ export function setupContainer(xoApp) {
|
|
|
100
102
|
return new NetworkService(restApi);
|
|
101
103
|
})
|
|
102
104
|
.inSingletonScope();
|
|
105
|
+
iocContainer
|
|
106
|
+
.bind(BackupArchiveService)
|
|
107
|
+
.toDynamicValue(ctx => {
|
|
108
|
+
const restApi = ctx.container.get(RestApi);
|
|
109
|
+
return new BackupArchiveService(restApi);
|
|
110
|
+
})
|
|
111
|
+
.inSingletonScope();
|
|
103
112
|
}
|
|
104
113
|
export { iocContainer };
|
|
@@ -7,16 +7,24 @@ 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 { noSuchObject } from 'xo-common/api-errors.js';
|
|
13
13
|
import { provide } from 'inversify-binding-decorators';
|
|
14
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
14
15
|
import { alarmPredicate } from '../alarms/alarm.service.mjs';
|
|
15
16
|
import { message, messageIds, partialMessages } from '../open-api/oa-examples/message.oa-example.mjs';
|
|
16
17
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
17
|
-
import { badRequestResp, notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
|
|
18
|
+
import { badRequestResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
18
19
|
import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
|
|
19
20
|
import { safeParseComplexMatcher } from '../helpers/utils.helper.mjs';
|
|
21
|
+
function getMessage(restApi, id) {
|
|
22
|
+
const message = restApi.getObject(id, 'message');
|
|
23
|
+
if (alarmPredicate(message)) {
|
|
24
|
+
throw noSuchObject(id, 'message');
|
|
25
|
+
}
|
|
26
|
+
return message;
|
|
27
|
+
}
|
|
20
28
|
let MessageController = class MessageController extends XapiXoController {
|
|
21
29
|
constructor(restapi) {
|
|
22
30
|
super('message', restapi);
|
|
@@ -36,21 +44,26 @@ let MessageController = class MessageController extends XapiXoController {
|
|
|
36
44
|
* Override parent getObject in order to exclude`ALARM` message
|
|
37
45
|
*/
|
|
38
46
|
getObject(id) {
|
|
39
|
-
|
|
40
|
-
if (alarmPredicate(message)) {
|
|
41
|
-
throw noSuchObject(id, 'message');
|
|
42
|
-
}
|
|
43
|
-
return message;
|
|
47
|
+
return getMessage(this.restApi, id);
|
|
44
48
|
}
|
|
45
49
|
/**
|
|
50
|
+
* Returns all messages that match the following privilege:
|
|
51
|
+
* - resource: message, action: read
|
|
52
|
+
*
|
|
46
53
|
* @example fields "name,body,id,$object"
|
|
47
54
|
* @example filter "name:VM_STARTED"
|
|
48
55
|
* @example limit 42
|
|
49
56
|
*/
|
|
50
57
|
getMessages(req, fields, ndjson, markdown, filter, limit) {
|
|
51
|
-
return this.sendObjects(Object.values(this.getObjects({ filter
|
|
58
|
+
return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
|
|
59
|
+
limit,
|
|
60
|
+
privilege: { action: 'read', resource: 'message' },
|
|
61
|
+
});
|
|
52
62
|
}
|
|
53
63
|
/**
|
|
64
|
+
* Required privilege:
|
|
65
|
+
* - resource: message, action: read
|
|
66
|
+
*
|
|
54
67
|
* @example id "f775eaeb-abe5-94e0-9682-14c37c3a1dfe"
|
|
55
68
|
*/
|
|
56
69
|
getMessage(id) {
|
|
@@ -61,6 +74,7 @@ __decorate([
|
|
|
61
74
|
Example(messageIds),
|
|
62
75
|
Example(partialMessages),
|
|
63
76
|
Get(''),
|
|
77
|
+
Security('*', ['acl']),
|
|
64
78
|
__param(0, Request()),
|
|
65
79
|
__param(1, Query()),
|
|
66
80
|
__param(2, Query()),
|
|
@@ -71,6 +85,13 @@ __decorate([
|
|
|
71
85
|
__decorate([
|
|
72
86
|
Example(message),
|
|
73
87
|
Get('{id}'),
|
|
88
|
+
Middlewares(acl({
|
|
89
|
+
resource: 'message',
|
|
90
|
+
action: 'read',
|
|
91
|
+
objectId: 'params.id',
|
|
92
|
+
getObject: ({ restApi }) => id => getMessage(restApi, id),
|
|
93
|
+
})),
|
|
94
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
74
95
|
Response(notFoundResp.status, notFoundResp.description),
|
|
75
96
|
__param(0, Path())
|
|
76
97
|
], MessageController.prototype, "getMessage", null);
|