@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
|
@@ -9,11 +9,12 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
9
9
|
};
|
|
10
10
|
import { Body, Delete, Deprecated, Example, Get, Middlewares, Patch, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
|
|
11
11
|
import { createLogger } from '@xen-orchestra/log';
|
|
12
|
+
import { forbiddenOperation } from 'xo-common/api-errors.js';
|
|
12
13
|
import { inject } from 'inversify';
|
|
13
14
|
import { json } from 'express';
|
|
14
15
|
import { provide } from 'inversify-binding-decorators';
|
|
16
|
+
import { acl, actionIfNotSelfUser, actionsFromBody } from '../middlewares/acl.middleware.mjs';
|
|
15
17
|
import { badRequestResp, createdResp, forbiddenOperationResp, internalServerErrorResp, invalidParameters, noContentResp, notFoundResp, resourceAlreadyExists, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
16
|
-
import { forbiddenOperation } from 'xo-common/api-errors.js';
|
|
17
18
|
import { partialUsers, user, authenticationTokens, userId, userIds, authenticationToken, } from '../open-api/oa-examples/user.oa-example.mjs';
|
|
18
19
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
19
20
|
import { limitAndFilterArray } from '../helpers/utils.helper.mjs';
|
|
@@ -22,6 +23,7 @@ import { XoController } from '../abstract-classes/xo-controller.mjs';
|
|
|
22
23
|
import { groupIds, partialGroups } from '../open-api/oa-examples/group.oa-example.mjs';
|
|
23
24
|
import { partialTasks, taskIds } from '../open-api/oa-examples/task.oa-example.mjs';
|
|
24
25
|
import { redirectMeAlias } from './user.middleware.mjs';
|
|
26
|
+
import { aclPrivilegeIds, partialAclPrivileges } from '../open-api/oa-examples/acl-privilege.oa-example.mjs';
|
|
25
27
|
const log = createLogger('xo:rest-api:user-controller');
|
|
26
28
|
let UserController = class UserController extends XoController {
|
|
27
29
|
#userService;
|
|
@@ -37,21 +39,39 @@ let UserController = class UserController extends XoController {
|
|
|
37
39
|
return this.#userService.getUser(id);
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
42
|
+
* Returns all users that match the following privilege:
|
|
43
|
+
* - resource: user, action: read
|
|
44
|
+
*
|
|
40
45
|
* @example fields "permission,name,id"
|
|
41
46
|
* @example filter "permission:none"
|
|
42
47
|
* @example limit 42
|
|
43
48
|
*/
|
|
44
49
|
async getUsers(req, fields, ndjson, markdown, filter, limit) {
|
|
45
|
-
const users = Object.values(await this.getObjects({ filter
|
|
46
|
-
return this.sendObjects(users, req
|
|
50
|
+
const users = Object.values(await this.getObjects({ filter }));
|
|
51
|
+
return this.sendObjects(users, req, {
|
|
52
|
+
limit,
|
|
53
|
+
privilege: { action: 'read', resource: 'user' },
|
|
54
|
+
});
|
|
47
55
|
}
|
|
48
56
|
/**
|
|
57
|
+
* Required privilege:
|
|
58
|
+
* - resource: user, action: read (if not self)
|
|
59
|
+
*
|
|
49
60
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
50
61
|
*/
|
|
51
62
|
getUser(id) {
|
|
52
63
|
return this.getObject(id);
|
|
53
64
|
}
|
|
54
65
|
/**
|
|
66
|
+
* You cannot change your own `permission` (even with the right privilege)
|
|
67
|
+
*
|
|
68
|
+
* Required privileges:
|
|
69
|
+
* - resource: user, action: update (grants all fields)
|
|
70
|
+
* - resource: user, action: update:name (if name is passed)
|
|
71
|
+
* - resource: user, action: update:password (if password is passed)
|
|
72
|
+
* - resource: user, action: update:permission (if permission is passed)
|
|
73
|
+
* - resource: user, action: update:preferences (if preferences is passed)
|
|
74
|
+
*
|
|
55
75
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
56
76
|
* @example body {
|
|
57
77
|
* "name": "updated user name",
|
|
@@ -62,14 +82,8 @@ let UserController = class UserController extends XoController {
|
|
|
62
82
|
*/
|
|
63
83
|
async updateUser(id, body) {
|
|
64
84
|
const currentUser = this.restApi.getCurrentUser();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (body.permission !== undefined && currentUser.id === id) {
|
|
68
|
-
throw forbiddenOperation('update user', 'cannot change own permission');
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else if (body.name !== undefined || body.password !== undefined || body.permission !== undefined) {
|
|
72
|
-
throw forbiddenOperation('update user', 'cannot change these fields without admin rights');
|
|
85
|
+
if (body.permission !== undefined && currentUser.id === id) {
|
|
86
|
+
throw forbiddenOperation('update user', 'cannot change own permission');
|
|
73
87
|
}
|
|
74
88
|
const user = await this.getObject(id);
|
|
75
89
|
if (user.authProviders !== undefined &&
|
|
@@ -80,6 +94,9 @@ let UserController = class UserController extends XoController {
|
|
|
80
94
|
await this.restApi.xoApp.updateUser(user.id, body);
|
|
81
95
|
}
|
|
82
96
|
/**
|
|
97
|
+
* Required privilege:
|
|
98
|
+
* - resource: user, action: create
|
|
99
|
+
*
|
|
83
100
|
* @example body { "name": "new user", "password": "password", "permission": "none" }
|
|
84
101
|
*/
|
|
85
102
|
async createUser(body) {
|
|
@@ -87,12 +104,18 @@ let UserController = class UserController extends XoController {
|
|
|
87
104
|
return { id: user.id };
|
|
88
105
|
}
|
|
89
106
|
/**
|
|
107
|
+
* Required privilege:
|
|
108
|
+
* - resource: user, action: delete
|
|
109
|
+
*
|
|
90
110
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
91
111
|
*/
|
|
92
112
|
async deleteUser(id) {
|
|
93
113
|
await this.restApi.xoApp.deleteUser(id);
|
|
94
114
|
}
|
|
95
115
|
/**
|
|
116
|
+
* Returns all groups that match the following privilege:
|
|
117
|
+
* - resource: group, action: read
|
|
118
|
+
*
|
|
96
119
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
97
120
|
* @example fields "name,id,users"
|
|
98
121
|
* @example filter "users:length:>0"
|
|
@@ -101,9 +124,15 @@ let UserController = class UserController extends XoController {
|
|
|
101
124
|
async getUserGroups(req, id, fields, ndjson, markdown, filter, limit) {
|
|
102
125
|
const user = await this.getObject(id);
|
|
103
126
|
const groups = await Promise.all(user.groups.map(group => this.restApi.xoApp.getGroup(group)));
|
|
104
|
-
return this.sendObjects(limitAndFilterArray(groups, { filter
|
|
127
|
+
return this.sendObjects(limitAndFilterArray(groups, { filter }), req, {
|
|
128
|
+
path: 'groups',
|
|
129
|
+
limit,
|
|
130
|
+
privilege: { action: 'read', resource: 'group' },
|
|
131
|
+
});
|
|
105
132
|
}
|
|
106
133
|
/**
|
|
134
|
+
* You can only see your own authentication tokens
|
|
135
|
+
*
|
|
107
136
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
108
137
|
* @example filter "expiration:>1757371582496"
|
|
109
138
|
* @example limit 42
|
|
@@ -118,14 +147,21 @@ let UserController = class UserController extends XoController {
|
|
|
118
147
|
return limitAndFilterArray(tokens, { filter, limit });
|
|
119
148
|
}
|
|
120
149
|
/**
|
|
150
|
+
* Returns all tasks that match the following privilege:
|
|
151
|
+
* - resource: task, action: read
|
|
152
|
+
*
|
|
121
153
|
* @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
|
|
122
154
|
* @example fields "id,status,properties"
|
|
123
155
|
* @example filter "status:failure"
|
|
124
156
|
* @example limit 42
|
|
125
157
|
*/
|
|
126
158
|
async getUserTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
127
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
128
|
-
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
|
+
});
|
|
129
165
|
}
|
|
130
166
|
// ----------- DEPRECATED TO BE REMOVED IN ONE YEAR (10-13-2026)--------------------
|
|
131
167
|
/**
|
|
@@ -142,6 +178,8 @@ let UserController = class UserController extends XoController {
|
|
|
142
178
|
}
|
|
143
179
|
// ----------- DEPRECATED TO BE REMOVED IN ONE YEAR (10-13-2026)--------------------
|
|
144
180
|
/**
|
|
181
|
+
* You can only create authentication token for yourself
|
|
182
|
+
*
|
|
145
183
|
* @example id "me"
|
|
146
184
|
* @example body {"client": {"id": "my-fav-client"}, "description": "token for CLI usage", "expiresIn": "1 hour"}
|
|
147
185
|
*/
|
|
@@ -156,11 +194,31 @@ let UserController = class UserController extends XoController {
|
|
|
156
194
|
});
|
|
157
195
|
return { token };
|
|
158
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Returns all ACL privileges that match the following privilege:
|
|
199
|
+
* - resource: acl-privilege, action: read (if not self)
|
|
200
|
+
*
|
|
201
|
+
* @example id "me"
|
|
202
|
+
* @example fields "id,action,resource"
|
|
203
|
+
* @example filter "action:create"
|
|
204
|
+
* @example limit 42
|
|
205
|
+
*/
|
|
206
|
+
async getUserPrivileges(req, id, fields, ndjson, filter, limit) {
|
|
207
|
+
const user = await this.getObject(id);
|
|
208
|
+
const currentUser = this.restApi.getCurrentUser();
|
|
209
|
+
const userPrivileges = (await this.restApi.xoApp.getAclV2UserPrivileges(user.id));
|
|
210
|
+
return this.sendObjects(limitAndFilterArray(userPrivileges, { filter }), req, {
|
|
211
|
+
path: 'acl-privileges',
|
|
212
|
+
limit,
|
|
213
|
+
privilege: currentUser.id === user.id ? undefined : { action: 'read', resource: 'acl-privilege' },
|
|
214
|
+
});
|
|
215
|
+
}
|
|
159
216
|
};
|
|
160
217
|
__decorate([
|
|
161
218
|
Example(userIds),
|
|
162
219
|
Example(partialUsers),
|
|
163
220
|
Get(''),
|
|
221
|
+
Security('*', ['acl']),
|
|
164
222
|
__param(0, Request()),
|
|
165
223
|
__param(1, Query()),
|
|
166
224
|
__param(2, Query()),
|
|
@@ -171,12 +229,27 @@ __decorate([
|
|
|
171
229
|
__decorate([
|
|
172
230
|
Example(user),
|
|
173
231
|
Get('{id}'),
|
|
232
|
+
Middlewares(acl({
|
|
233
|
+
resource: 'user',
|
|
234
|
+
action: actionIfNotSelfUser('read'),
|
|
235
|
+
objectId: 'params.id',
|
|
236
|
+
getObject: ({ restApi }) => restApi.xoApp.getUser,
|
|
237
|
+
})),
|
|
238
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
174
239
|
Response(notFoundResp.status, notFoundResp.description),
|
|
175
240
|
__param(0, Path())
|
|
176
241
|
], UserController.prototype, "getUser", null);
|
|
177
242
|
__decorate([
|
|
178
243
|
Patch('{id}'),
|
|
179
|
-
Middlewares(
|
|
244
|
+
Middlewares([
|
|
245
|
+
json(),
|
|
246
|
+
acl({
|
|
247
|
+
resource: 'user',
|
|
248
|
+
actions: actionsFromBody(['update:name', 'update:password', 'update:permission', 'update:preferences']),
|
|
249
|
+
objectId: 'params.id',
|
|
250
|
+
getObject: ({ restApi }) => restApi.xoApp.getUser,
|
|
251
|
+
}),
|
|
252
|
+
]),
|
|
180
253
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
181
254
|
Response(notFoundResp.status, notFoundResp.description),
|
|
182
255
|
Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
|
|
@@ -187,15 +260,23 @@ __decorate([
|
|
|
187
260
|
__decorate([
|
|
188
261
|
Example(userId),
|
|
189
262
|
Post(''),
|
|
190
|
-
Middlewares(json()),
|
|
263
|
+
Middlewares([json(), acl({ resource: 'user', action: 'create', object: ({ req }) => req.body })]),
|
|
191
264
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
192
265
|
Response(unauthorizedResp.status, unauthorizedResp.description),
|
|
266
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
193
267
|
Response(invalidParameters.status, invalidParameters.description),
|
|
194
268
|
__param(0, Body())
|
|
195
269
|
], UserController.prototype, "createUser", null);
|
|
196
270
|
__decorate([
|
|
197
271
|
Delete('{id}'),
|
|
272
|
+
Middlewares(acl({
|
|
273
|
+
resource: 'user',
|
|
274
|
+
action: 'delete',
|
|
275
|
+
objectId: 'params.id',
|
|
276
|
+
getObject: ({ restApi }) => restApi.xoApp.getUser,
|
|
277
|
+
})),
|
|
198
278
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
279
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
199
280
|
Response(notFoundResp.status, notFoundResp.description),
|
|
200
281
|
__param(0, Path())
|
|
201
282
|
], UserController.prototype, "deleteUser", null);
|
|
@@ -203,6 +284,7 @@ __decorate([
|
|
|
203
284
|
Example(groupIds),
|
|
204
285
|
Example(partialGroups),
|
|
205
286
|
Get('{id}/groups'),
|
|
287
|
+
Security('*', ['acl']),
|
|
206
288
|
Tags('groups'),
|
|
207
289
|
Response(notFoundResp.status, notFoundResp.description),
|
|
208
290
|
__param(0, Request()),
|
|
@@ -216,6 +298,7 @@ __decorate([
|
|
|
216
298
|
__decorate([
|
|
217
299
|
Example(authenticationTokens),
|
|
218
300
|
Get('{id}/authentication_tokens'),
|
|
301
|
+
Security('*', ['acl']),
|
|
219
302
|
Response(notFoundResp.status, notFoundResp.description),
|
|
220
303
|
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
221
304
|
__param(0, Request()),
|
|
@@ -227,6 +310,7 @@ __decorate([
|
|
|
227
310
|
Example(taskIds),
|
|
228
311
|
Example(partialTasks),
|
|
229
312
|
Get('{id}/tasks'),
|
|
313
|
+
Security('*', ['acl']),
|
|
230
314
|
Tags('tasks'),
|
|
231
315
|
Response(notFoundResp.status, notFoundResp.description),
|
|
232
316
|
__param(0, Request()),
|
|
@@ -250,12 +334,27 @@ __decorate([
|
|
|
250
334
|
Example(authenticationToken),
|
|
251
335
|
Post('{id}/authentication_tokens'),
|
|
252
336
|
Middlewares(json()),
|
|
337
|
+
Security('*', ['acl']),
|
|
253
338
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
254
339
|
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
255
340
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
256
341
|
__param(0, Body()),
|
|
257
342
|
__param(1, Path())
|
|
258
343
|
], UserController.prototype, "postAuthenticationTokens", null);
|
|
344
|
+
__decorate([
|
|
345
|
+
Example(aclPrivilegeIds),
|
|
346
|
+
Example(partialAclPrivileges),
|
|
347
|
+
Get('{id}/acl-privileges'),
|
|
348
|
+
Security('*', ['acl']),
|
|
349
|
+
Tags('acls'),
|
|
350
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
351
|
+
__param(0, Request()),
|
|
352
|
+
__param(1, Path()),
|
|
353
|
+
__param(2, Query()),
|
|
354
|
+
__param(3, Query()),
|
|
355
|
+
__param(4, Query()),
|
|
356
|
+
__param(5, Query())
|
|
357
|
+
], UserController.prototype, "getUserPrivileges", null);
|
|
259
358
|
UserController = __decorate([
|
|
260
359
|
Route('users'),
|
|
261
360
|
Security('*'),
|
|
@@ -12,10 +12,11 @@ import { json } from 'express';
|
|
|
12
12
|
import { inject } from 'inversify';
|
|
13
13
|
import { invalidParameters as invalidParametersError } from 'xo-common/api-errors.js';
|
|
14
14
|
import { provide } from 'inversify-binding-decorators';
|
|
15
|
+
import { acl } from '../middlewares/acl.middleware.mjs';
|
|
15
16
|
import { AlarmService } from '../alarms/alarm.service.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, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
19
|
+
import { asynchronousActionResp, badRequestResp, createdResp, internalServerErrorResp, invalidParameters, noContentResp, forbiddenOperationResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
|
|
19
20
|
import { BASE_URL } from '../index.mjs';
|
|
20
21
|
import { partialVbds, vbd, vbdId, vbdIds } from '../open-api/oa-examples/vbd.oa-example.mjs';
|
|
21
22
|
import { RestApi } from '../rest-api/rest-api.mjs';
|
|
@@ -28,6 +29,29 @@ let VbdController = class VbdController extends XapiXoController {
|
|
|
28
29
|
super('VBD', restApi);
|
|
29
30
|
this.#alarmService = alarmService;
|
|
30
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns all VBDs that match the following privilege:
|
|
34
|
+
* - resource: vbd, action: read
|
|
35
|
+
*
|
|
36
|
+
* @example fields "device,bootable,uuid"
|
|
37
|
+
* @example filter "!bootable?"
|
|
38
|
+
* @example limit 42
|
|
39
|
+
*/
|
|
40
|
+
getVbds(req, fields, ndjson, markdown, filter, limit) {
|
|
41
|
+
return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
|
|
42
|
+
limit,
|
|
43
|
+
privilege: { action: 'read', resource: 'vbd' },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Required privilege:
|
|
48
|
+
* - resource: vbd, action: read
|
|
49
|
+
*
|
|
50
|
+
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
51
|
+
*/
|
|
52
|
+
getVbd(id) {
|
|
53
|
+
return this.getObject(id);
|
|
54
|
+
}
|
|
31
55
|
/**
|
|
32
56
|
* Create a VBD to attach a VDI to a VM
|
|
33
57
|
*
|
|
@@ -51,22 +75,6 @@ let VbdController = class VbdController extends XapiXoController {
|
|
|
51
75
|
this.setHeader('Location', `${BASE_URL}/vbds/${vbdUuid}`);
|
|
52
76
|
return { id: vbdUuid };
|
|
53
77
|
}
|
|
54
|
-
/**
|
|
55
|
-
*
|
|
56
|
-
* @example fields "device,bootable,uuid"
|
|
57
|
-
* @example filter "!bootable?"
|
|
58
|
-
* @example limit 42
|
|
59
|
-
*/
|
|
60
|
-
getVbds(req, fields, ndjson, markdown, filter, limit) {
|
|
61
|
-
return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
*
|
|
65
|
-
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
66
|
-
*/
|
|
67
|
-
getVbd(id) {
|
|
68
|
-
return this.getObject(id);
|
|
69
|
-
}
|
|
70
78
|
/**
|
|
71
79
|
* Delete a VBD
|
|
72
80
|
*
|
|
@@ -80,6 +88,9 @@ let VbdController = class VbdController extends XapiXoController {
|
|
|
80
88
|
await xapiVbd.$xapi.VBD_destroy(xapiVbd.$ref);
|
|
81
89
|
}
|
|
82
90
|
/**
|
|
91
|
+
* Returns all alarms that match the following privilege:
|
|
92
|
+
* - resource: alarm, action: read
|
|
93
|
+
*
|
|
83
94
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
84
95
|
* @example fields "id,time"
|
|
85
96
|
* @example filter "time:>1747053793"
|
|
@@ -89,29 +100,46 @@ let VbdController = class VbdController extends XapiXoController {
|
|
|
89
100
|
const vbd = this.getObject(id);
|
|
90
101
|
const alarms = this.#alarmService.getAlarms({
|
|
91
102
|
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${vbd.uuid}`,
|
|
103
|
+
});
|
|
104
|
+
return this.sendObjects(Object.values(alarms), req, {
|
|
105
|
+
path: 'alarms',
|
|
92
106
|
limit,
|
|
107
|
+
privilege: { action: 'read', resource: 'alarm' },
|
|
93
108
|
});
|
|
94
|
-
return this.sendObjects(Object.values(alarms), req, 'alarms');
|
|
95
109
|
}
|
|
96
110
|
/**
|
|
111
|
+
* Returns all messages that match the following privilege:
|
|
112
|
+
* - resource: message, action: read
|
|
113
|
+
*
|
|
97
114
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
98
115
|
* @example fields "name,id,$object"
|
|
99
116
|
* @example filter "name:VM_STARTED"
|
|
100
117
|
* @example limit 42
|
|
101
118
|
*/
|
|
102
119
|
getVbdMessages(req, id, fields, ndjson, markdown, filter, limit) {
|
|
103
|
-
const messages = this.getMessagesForObject(id, { filter
|
|
104
|
-
return this.sendObjects(Object.values(messages), req,
|
|
120
|
+
const messages = this.getMessagesForObject(id, { filter });
|
|
121
|
+
return this.sendObjects(Object.values(messages), req, {
|
|
122
|
+
path: 'messages',
|
|
123
|
+
limit,
|
|
124
|
+
privilege: { action: 'read', resource: 'message' },
|
|
125
|
+
});
|
|
105
126
|
}
|
|
106
127
|
/**
|
|
128
|
+
* Returns all tasks that match the following privilege:
|
|
129
|
+
* - resource: task, action: read
|
|
130
|
+
*
|
|
107
131
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
108
132
|
* @example fields "id,status,properties"
|
|
109
133
|
* @example filter "status:failure"
|
|
110
134
|
* @example limit 42
|
|
111
135
|
*/
|
|
112
136
|
async getVbdTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
113
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
114
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
137
|
+
const tasks = await this.getTasksForObject(id, { filter });
|
|
138
|
+
return this.sendObjects(Object.values(tasks), req, {
|
|
139
|
+
path: 'tasks',
|
|
140
|
+
limit,
|
|
141
|
+
privilege: { action: 'read', resource: 'task' },
|
|
142
|
+
});
|
|
115
143
|
}
|
|
116
144
|
/**
|
|
117
145
|
* Hotplug the VBD, dynamically attaching it to the running VM
|
|
@@ -152,19 +180,11 @@ let VbdController = class VbdController extends XapiXoController {
|
|
|
152
180
|
});
|
|
153
181
|
}
|
|
154
182
|
};
|
|
155
|
-
__decorate([
|
|
156
|
-
Example(vbdId),
|
|
157
|
-
Post(''),
|
|
158
|
-
Middlewares(json()),
|
|
159
|
-
SuccessResponse(createdResp.status, createdResp.description),
|
|
160
|
-
Response(notFoundResp.status, notFoundResp.description),
|
|
161
|
-
Response(invalidParameters.status, invalidParameters.description),
|
|
162
|
-
__param(0, Body())
|
|
163
|
-
], VbdController.prototype, "createVbd", null);
|
|
164
183
|
__decorate([
|
|
165
184
|
Example(vbdIds),
|
|
166
185
|
Example(partialVbds),
|
|
167
186
|
Get(''),
|
|
187
|
+
Security('*', ['acl']),
|
|
168
188
|
__param(0, Request()),
|
|
169
189
|
__param(1, Query()),
|
|
170
190
|
__param(2, Query()),
|
|
@@ -175,9 +195,20 @@ __decorate([
|
|
|
175
195
|
__decorate([
|
|
176
196
|
Example(vbd),
|
|
177
197
|
Get('{id}'),
|
|
198
|
+
Middlewares(acl({ resource: 'vbd', action: 'read', objectId: 'params.id' })),
|
|
199
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
178
200
|
Response(notFoundResp.status, notFoundResp.description),
|
|
179
201
|
__param(0, Path())
|
|
180
202
|
], VbdController.prototype, "getVbd", null);
|
|
203
|
+
__decorate([
|
|
204
|
+
Example(vbdId),
|
|
205
|
+
Post(''),
|
|
206
|
+
Middlewares(json()),
|
|
207
|
+
SuccessResponse(createdResp.status, createdResp.description),
|
|
208
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
209
|
+
Response(invalidParameters.status, invalidParameters.description),
|
|
210
|
+
__param(0, Body())
|
|
211
|
+
], VbdController.prototype, "createVbd", null);
|
|
181
212
|
__decorate([
|
|
182
213
|
Delete('{id}'),
|
|
183
214
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
@@ -187,6 +218,7 @@ __decorate([
|
|
|
187
218
|
__decorate([
|
|
188
219
|
Example(genericAlarmsExample),
|
|
189
220
|
Get('{id}/alarms'),
|
|
221
|
+
Security('*', ['acl']),
|
|
190
222
|
Tags('alarms'),
|
|
191
223
|
Response(notFoundResp.status, notFoundResp.description),
|
|
192
224
|
__param(0, Request()),
|
|
@@ -201,6 +233,7 @@ __decorate([
|
|
|
201
233
|
Example(messageIds),
|
|
202
234
|
Example(partialMessages),
|
|
203
235
|
Get('{id}/messages'),
|
|
236
|
+
Security('*', ['acl']),
|
|
204
237
|
Tags('messages'),
|
|
205
238
|
Response(notFoundResp.status, notFoundResp.description),
|
|
206
239
|
__param(0, Request()),
|
|
@@ -215,6 +248,7 @@ __decorate([
|
|
|
215
248
|
Example(taskIds),
|
|
216
249
|
Example(partialTasks),
|
|
217
250
|
Get('{id}/tasks'),
|
|
251
|
+
Security('*', ['acl']),
|
|
218
252
|
Tags('tasks'),
|
|
219
253
|
Response(notFoundResp.status, notFoundResp.description),
|
|
220
254
|
__param(0, Request()),
|
|
@@ -29,12 +29,18 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
|
|
|
29
29
|
this.#vdiService = vdiService;
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
+
* Returns all VDI snapshots that match the following privilege:
|
|
33
|
+
* - resource: vdi-snapshot, action: read
|
|
34
|
+
*
|
|
32
35
|
* @example fields "uuid,snapshot_time,$snapshot_of"
|
|
33
36
|
* @example filter "snapshot_time:>1725020038"
|
|
34
37
|
* @example limit 42
|
|
35
38
|
*/
|
|
36
39
|
getVdiSnapshots(req, fields, ndjson, markdown, filter, limit) {
|
|
37
|
-
return this.sendObjects(Object.values(this.getObjects({ filter
|
|
40
|
+
return this.sendObjects(Object.values(this.getObjects({ filter })), req, {
|
|
41
|
+
limit,
|
|
42
|
+
privilege: { action: 'read', resource: 'vdi-snapshot' },
|
|
43
|
+
});
|
|
38
44
|
}
|
|
39
45
|
/**
|
|
40
46
|
*
|
|
@@ -59,6 +65,9 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
|
|
|
59
65
|
return this.getObject(id);
|
|
60
66
|
}
|
|
61
67
|
/**
|
|
68
|
+
* Returns all alarms that match the following privilege:
|
|
69
|
+
* - resource: alarm, action: read
|
|
70
|
+
*
|
|
62
71
|
* @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
|
|
63
72
|
* @example fields "id,time"
|
|
64
73
|
* @example filter "time:>1747053793"
|
|
@@ -68,9 +77,12 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
|
|
|
68
77
|
const vdiSnapshot = this.getObject(id);
|
|
69
78
|
const alarms = this.#alarmService.getAlarms({
|
|
70
79
|
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${vdiSnapshot.uuid}`,
|
|
80
|
+
});
|
|
81
|
+
return this.sendObjects(Object.values(alarms), req, {
|
|
82
|
+
path: 'alarms',
|
|
71
83
|
limit,
|
|
84
|
+
privilege: { action: 'read', resource: 'alarm' },
|
|
72
85
|
});
|
|
73
|
-
return this.sendObjects(Object.values(alarms), req, 'alarms');
|
|
74
86
|
}
|
|
75
87
|
/**
|
|
76
88
|
* @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
|
|
@@ -80,24 +92,38 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
|
|
|
80
92
|
await xapiVdiSnapshot.$xapi.VDI_destroy(xapiVdiSnapshot.$ref);
|
|
81
93
|
}
|
|
82
94
|
/**
|
|
95
|
+
* Returns all messages that match the following privilege:
|
|
96
|
+
* - resource: message, action: read
|
|
97
|
+
*
|
|
83
98
|
* @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
|
|
84
99
|
* @example fields "name,id,$object"
|
|
85
100
|
* @example filter "name:VM_STARTED"
|
|
86
101
|
* @example limit 42
|
|
87
102
|
*/
|
|
88
103
|
getVdiSnapshotMessages(req, id, fields, ndjson, markdown, filter, limit) {
|
|
89
|
-
const messages = this.getMessagesForObject(id, { filter
|
|
90
|
-
return this.sendObjects(Object.values(messages), req,
|
|
104
|
+
const messages = this.getMessagesForObject(id, { filter });
|
|
105
|
+
return this.sendObjects(Object.values(messages), req, {
|
|
106
|
+
path: 'messages',
|
|
107
|
+
limit,
|
|
108
|
+
privilege: { action: 'read', resource: 'message' },
|
|
109
|
+
});
|
|
91
110
|
}
|
|
92
111
|
/**
|
|
112
|
+
* Returns all tasks that match the following privilege:
|
|
113
|
+
* - resource: task, action: read
|
|
114
|
+
*
|
|
93
115
|
* @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
|
|
94
116
|
* @example fields "id,status,properties"
|
|
95
117
|
* @example filter "status:failure"
|
|
96
118
|
* @example limit 42
|
|
97
119
|
*/
|
|
98
120
|
async getVdiSnapshotTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
99
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
100
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
121
|
+
const tasks = await this.getTasksForObject(id, { filter });
|
|
122
|
+
return this.sendObjects(Object.values(tasks), req, {
|
|
123
|
+
path: 'tasks',
|
|
124
|
+
limit,
|
|
125
|
+
privilege: { action: 'read', resource: 'task' },
|
|
126
|
+
});
|
|
101
127
|
}
|
|
102
128
|
/**
|
|
103
129
|
* @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
|
|
@@ -120,6 +146,7 @@ __decorate([
|
|
|
120
146
|
Example(vdiSnapshotIds),
|
|
121
147
|
Example(partialVdiSnapshots),
|
|
122
148
|
Get(''),
|
|
149
|
+
Security('*', ['acl']),
|
|
123
150
|
__param(0, Request()),
|
|
124
151
|
__param(1, Query()),
|
|
125
152
|
__param(2, Query()),
|
|
@@ -145,6 +172,7 @@ __decorate([
|
|
|
145
172
|
__decorate([
|
|
146
173
|
Example(genericAlarmsExample),
|
|
147
174
|
Get('{id}/alarms'),
|
|
175
|
+
Security('*', ['acl']),
|
|
148
176
|
Tags('alarms'),
|
|
149
177
|
Response(notFoundResp.status, notFoundResp.description),
|
|
150
178
|
__param(0, Request()),
|
|
@@ -165,6 +193,7 @@ __decorate([
|
|
|
165
193
|
Example(messageIds),
|
|
166
194
|
Example(partialMessages),
|
|
167
195
|
Get('{id}/messages'),
|
|
196
|
+
Security('*', ['acl']),
|
|
168
197
|
Tags('messages'),
|
|
169
198
|
Response(notFoundResp.status, notFoundResp.description),
|
|
170
199
|
__param(0, Request()),
|
|
@@ -179,6 +208,7 @@ __decorate([
|
|
|
179
208
|
Example(taskIds),
|
|
180
209
|
Example(partialTasks),
|
|
181
210
|
Get('{id}/tasks'),
|
|
211
|
+
Security('*', ['acl']),
|
|
182
212
|
Tags('tasks'),
|
|
183
213
|
Response(notFoundResp.status, notFoundResp.description),
|
|
184
214
|
__param(0, Request()),
|