@xen-orchestra/rest-api 0.28.2 → 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 +28 -3
- package/dist/abstract-classes/listener.mjs +124 -15
- 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 +25 -11
- package/dist/alarms/alarm.service.mjs +8 -0
- package/dist/backup-archives/backup-archive.controller.mjs +33 -23
- package/dist/backup-archives/backup-archive.service.mjs +21 -0
- package/dist/backup-jobs/backup-job.controller.mjs +74 -25
- package/dist/backup-jobs/backup-job.service.mjs +7 -0
- package/dist/backup-logs/backup-log.controller.mjs +28 -13
- package/dist/backup-logs/backup-log.service.mjs +19 -0
- package/dist/backup-repositories/backup-repositories.controller.mjs +24 -5
- package/dist/events/event.class.mjs +36 -18
- package/dist/events/event.controller.mjs +3 -0
- package/dist/events/event.service.mjs +4 -4
- package/dist/groups/group.controller.mjs +99 -12
- package/dist/helpers/markdown.helper.mjs +20 -0
- package/dist/helpers/object-wrapper.helper.mjs +3 -3
- package/dist/hosts/host.controller.mjs +90 -15
- package/dist/ioc/ioc.mjs +13 -4
- package/dist/messages/message.controller.mjs +32 -10
- 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 +72 -17
- 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 +856 -172
- package/dist/pbds/pbd.controller.mjs +20 -5
- package/dist/pcis/pci.controller.mjs +19 -5
- package/dist/pgpus/pgpu.controller.mjs +19 -5
- package/dist/pifs/pif.controller.mjs +56 -16
- package/dist/pools/pool.controller.mjs +166 -17
- package/dist/proxies/proxy.controller.mjs +25 -6
- package/dist/restore-logs/restore-log.controller.mjs +42 -23
- package/dist/schedules/schedule.controller.mjs +36 -5
- package/dist/servers/server.controller.mjs +71 -9
- package/dist/sms/sm.controller.mjs +17 -4
- package/dist/srs/sr.controller.mjs +74 -18
- package/dist/tasks/task.controller.mjs +74 -13
- package/dist/users/user.controller.mjs +124 -22
- package/dist/vbds/vbd.controller.mjs +76 -38
- package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +48 -14
- package/dist/vdis/vdi.controller.mjs +81 -16
- package/dist/vifs/vif.controller.mjs +118 -16
- package/dist/vm-controller/vm-controller.controller.mjs +77 -19
- package/dist/vm-snapshots/vm-snapshot.controller.mjs +85 -18
- package/dist/vm-templates/vm-template.controller.mjs +86 -18
- package/dist/vms/vm.controller.mjs +182 -24
- package/open-api/spec/swagger.json +12112 -3537
- package/package.json +12 -11
|
@@ -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
|
-
async getGroups(req, fields, ndjson, filter, limit) {
|
|
42
|
-
return this.sendObjects(Object.values(await this.getObjects({ filter
|
|
45
|
+
async getGroups(req, fields, ndjson, markdown, filter, limit) {
|
|
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,46 +129,77 @@ 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"
|
|
103
138
|
* @example limit 42
|
|
104
139
|
*/
|
|
105
|
-
async getGroupUsers(req, id, fields, ndjson, filter, limit) {
|
|
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
|
-
async getGroupTasks(req, id, fields, ndjson, filter, limit) {
|
|
117
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
118
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
158
|
+
async getGroupTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
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()),
|
|
128
175
|
__param(3, Query()),
|
|
129
|
-
__param(4, Query())
|
|
176
|
+
__param(4, Query()),
|
|
177
|
+
__param(5, Query())
|
|
130
178
|
], GroupController.prototype, "getGroups", null);
|
|
131
179
|
__decorate([
|
|
132
180
|
Example(group),
|
|
133
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),
|
|
134
189
|
Response(notFoundResp.status, notFoundResp.description),
|
|
135
190
|
__param(0, Path())
|
|
136
191
|
], GroupController.prototype, "getGroup", null);
|
|
137
192
|
__decorate([
|
|
138
193
|
Patch('{id}'),
|
|
139
|
-
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
|
+
]),
|
|
140
203
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
141
204
|
Response(notFoundResp.status, notFoundResp.description),
|
|
142
205
|
Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
|
|
@@ -147,20 +210,34 @@ __decorate([
|
|
|
147
210
|
__decorate([
|
|
148
211
|
Example(groupId),
|
|
149
212
|
Post(''),
|
|
150
|
-
Middlewares(json()),
|
|
213
|
+
Middlewares([json(), acl({ resource: 'group', action: 'create', object: ({ req }) => req.body })]),
|
|
151
214
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
215
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
152
216
|
Response(invalidParameters.status, invalidParameters.description),
|
|
153
217
|
Response(resourceAlreadyExists.status, resourceAlreadyExists.description),
|
|
154
218
|
__param(0, Body())
|
|
155
219
|
], GroupController.prototype, "createGroup", null);
|
|
156
220
|
__decorate([
|
|
157
221
|
Delete('{id}'),
|
|
222
|
+
Middlewares(acl({
|
|
223
|
+
resource: 'group',
|
|
224
|
+
action: 'delete',
|
|
225
|
+
objectId: 'params.id',
|
|
226
|
+
getObject: ({ restApi }) => restApi.xoApp.getGroup,
|
|
227
|
+
})),
|
|
158
228
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
229
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
159
230
|
Response(notFoundResp.status, notFoundResp.description),
|
|
160
231
|
__param(0, Path())
|
|
161
232
|
], GroupController.prototype, "deleteGroup", null);
|
|
162
233
|
__decorate([
|
|
163
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
|
+
})),
|
|
164
241
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
165
242
|
Response(notFoundResp.status, notFoundResp.description),
|
|
166
243
|
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
@@ -169,6 +246,12 @@ __decorate([
|
|
|
169
246
|
], GroupController.prototype, "removeUserFromGroup", null);
|
|
170
247
|
__decorate([
|
|
171
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
|
+
})),
|
|
172
255
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
173
256
|
Response(notFoundResp.status, notFoundResp.description),
|
|
174
257
|
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
@@ -179,6 +262,7 @@ __decorate([
|
|
|
179
262
|
Example(userIds),
|
|
180
263
|
Example(partialUsers),
|
|
181
264
|
Get('{id}/users'),
|
|
265
|
+
Security('*', ['acl']),
|
|
182
266
|
Tags('users'),
|
|
183
267
|
Response(notFoundResp.status, notFoundResp.description),
|
|
184
268
|
__param(0, Request()),
|
|
@@ -186,12 +270,14 @@ __decorate([
|
|
|
186
270
|
__param(2, Query()),
|
|
187
271
|
__param(3, Query()),
|
|
188
272
|
__param(4, Query()),
|
|
189
|
-
__param(5, Query())
|
|
273
|
+
__param(5, Query()),
|
|
274
|
+
__param(6, Query())
|
|
190
275
|
], GroupController.prototype, "getGroupUsers", null);
|
|
191
276
|
__decorate([
|
|
192
277
|
Example(taskIds),
|
|
193
278
|
Example(partialTasks),
|
|
194
279
|
Get('{id}/tasks'),
|
|
280
|
+
Security('*', ['acl']),
|
|
195
281
|
Tags('tasks'),
|
|
196
282
|
Response(notFoundResp.status, notFoundResp.description),
|
|
197
283
|
__param(0, Request()),
|
|
@@ -199,7 +285,8 @@ __decorate([
|
|
|
199
285
|
__param(2, Query()),
|
|
200
286
|
__param(3, Query()),
|
|
201
287
|
__param(4, Query()),
|
|
202
|
-
__param(5, Query())
|
|
288
|
+
__param(5, Query()),
|
|
289
|
+
__param(6, Query())
|
|
203
290
|
], GroupController.prototype, "getGroupTasks", null);
|
|
204
291
|
GroupController = __decorate([
|
|
205
292
|
Route('groups'),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const escapeCell = (value) => {
|
|
2
|
+
if (value == null)
|
|
3
|
+
return '';
|
|
4
|
+
const text = typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
5
|
+
return text.replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
|
6
|
+
};
|
|
7
|
+
export function makeMarkdownTable(objects) {
|
|
8
|
+
if (objects.length === 0) {
|
|
9
|
+
return 'No results.';
|
|
10
|
+
}
|
|
11
|
+
if (typeof objects[0] === 'string') {
|
|
12
|
+
return objects.join('\n');
|
|
13
|
+
}
|
|
14
|
+
const records = objects;
|
|
15
|
+
const headers = Object.keys(records[0]).filter(key => key !== 'href');
|
|
16
|
+
const headerRow = '| ' + headers.join(' | ') + ' |';
|
|
17
|
+
const separatorRow = '| ' + headers.map(() => '---').join(' | ') + ' |';
|
|
18
|
+
const dataRows = records.map(obj => '| ' + headers.map(header => escapeCell(obj[header])).join(' | ') + ' |');
|
|
19
|
+
return [headerRow, separatorRow, ...dataRows].join('\n');
|
|
20
|
+
}
|
|
@@ -11,11 +11,11 @@ export function makeObjectMapper(req, path) {
|
|
|
11
11
|
if (tmpPath.startsWith('/')) {
|
|
12
12
|
tmpPath = tmpPath.slice(1);
|
|
13
13
|
}
|
|
14
|
-
if (tmpPath.endsWith('/')) {
|
|
15
|
-
tmpPath = tmpPath.slice(0, -1);
|
|
16
|
-
}
|
|
17
14
|
_path = `${BASE_URL}/${tmpPath}`;
|
|
18
15
|
}
|
|
16
|
+
if (_path.endsWith('/')) {
|
|
17
|
+
_path = _path.slice(0, -1);
|
|
18
|
+
}
|
|
19
19
|
return `${_path}/${String(obj.id)}`;
|
|
20
20
|
};
|
|
21
21
|
let objectMapper;
|
|
@@ -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
|
-
getHosts(req, fields, ndjson, filter, limit) {
|
|
42
|
-
return this.sendObjects(Object.values(this.getObjects({ filter
|
|
45
|
+
getHosts(req, fields, ndjson, markdown, filter, limit) {
|
|
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,20 +109,29 @@ 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"
|
|
96
118
|
* @example limit 42
|
|
97
119
|
*/
|
|
98
|
-
getHostAlarms(req, id, fields, ndjson, filter, limit) {
|
|
120
|
+
getHostAlarms(req, id, fields, ndjson, markdown, filter, limit) {
|
|
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
|
-
getHostMessages(req, id, fields, ndjson, filter, limit) {
|
|
133
|
-
const messages = this.getMessagesForObject(id, { filter
|
|
134
|
-
return this.sendObjects(Object.values(messages), req,
|
|
166
|
+
getHostMessages(req, id, fields, ndjson, markdown, filter, limit) {
|
|
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
|
-
async getHostTasks(req, id, fields, ndjson, filter, limit) {
|
|
143
|
-
const tasks = await this.getTasksForObject(id, { filter
|
|
144
|
-
return this.sendObjects(Object.values(tasks), req,
|
|
183
|
+
async getHostTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
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,21 +308,27 @@ __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()),
|
|
263
315
|
__param(3, Query()),
|
|
264
|
-
__param(4, Query())
|
|
316
|
+
__param(4, Query()),
|
|
317
|
+
__param(5, Query())
|
|
265
318
|
], HostController.prototype, "getHosts", null);
|
|
266
319
|
__decorate([
|
|
267
320
|
Example(host),
|
|
268
321
|
Get('{id}'),
|
|
322
|
+
Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
|
|
323
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
269
324
|
Response(notFoundResp.status, notFoundResp.description),
|
|
270
325
|
__param(0, Path())
|
|
271
326
|
], HostController.prototype, "getHost", null);
|
|
272
327
|
__decorate([
|
|
273
328
|
Example(hostStats),
|
|
274
329
|
Get('{id}/stats'),
|
|
330
|
+
Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
|
|
331
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
275
332
|
Response(notFoundResp.status, notFoundResp.description),
|
|
276
333
|
Response(422, 'Invalid granularity'),
|
|
277
334
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
@@ -280,7 +337,9 @@ __decorate([
|
|
|
280
337
|
], HostController.prototype, "getHostStats", null);
|
|
281
338
|
__decorate([
|
|
282
339
|
Get('{id}/audit.txt'),
|
|
340
|
+
Middlewares(acl({ resource: 'host', action: 'export:logs', objectId: 'params.id' })),
|
|
283
341
|
SuccessResponse(200, 'Download started', 'application/octet-stream'),
|
|
342
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
284
343
|
Response(notFoundResp.status, notFoundResp.description),
|
|
285
344
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
286
345
|
__param(0, Request()),
|
|
@@ -288,7 +347,9 @@ __decorate([
|
|
|
288
347
|
], HostController.prototype, "getAuditLog", null);
|
|
289
348
|
__decorate([
|
|
290
349
|
Get('{id}/logs.tgz'),
|
|
350
|
+
Middlewares(acl({ resource: 'host', action: 'export:logs', objectId: 'params.id' })),
|
|
291
351
|
SuccessResponse(200, 'Download started', 'application/gzip'),
|
|
352
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
292
353
|
Response(notFoundResp.status, notFoundResp.description),
|
|
293
354
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
294
355
|
__param(0, Request()),
|
|
@@ -297,6 +358,7 @@ __decorate([
|
|
|
297
358
|
__decorate([
|
|
298
359
|
Example(genericAlarmsExample),
|
|
299
360
|
Get('{id}/alarms'),
|
|
361
|
+
Security('*', ['acl']),
|
|
300
362
|
Tags('alarms'),
|
|
301
363
|
Response(notFoundResp.status, notFoundResp.description),
|
|
302
364
|
__param(0, Request()),
|
|
@@ -304,11 +366,14 @@ __decorate([
|
|
|
304
366
|
__param(2, Query()),
|
|
305
367
|
__param(3, Query()),
|
|
306
368
|
__param(4, Query()),
|
|
307
|
-
__param(5, Query())
|
|
369
|
+
__param(5, Query()),
|
|
370
|
+
__param(6, Query())
|
|
308
371
|
], HostController.prototype, "getHostAlarms", null);
|
|
309
372
|
__decorate([
|
|
310
373
|
Example(hostSmt),
|
|
311
374
|
Get('{id}/smt'),
|
|
375
|
+
Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
|
|
376
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
312
377
|
Response(notFoundResp.status, notFoundResp.description),
|
|
313
378
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
314
379
|
__param(0, Path())
|
|
@@ -316,6 +381,8 @@ __decorate([
|
|
|
316
381
|
__decorate([
|
|
317
382
|
Example(hostMissingPatches),
|
|
318
383
|
Get('{id}/missing_patches'),
|
|
384
|
+
Middlewares(acl({ resource: 'host', action: 'read', objectId: 'params.id' })),
|
|
385
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
319
386
|
Response(notFoundResp.status, notFoundResp.description),
|
|
320
387
|
Response(featureUnauthorized.status, featureUnauthorized.description),
|
|
321
388
|
__param(0, Path())
|
|
@@ -324,6 +391,7 @@ __decorate([
|
|
|
324
391
|
Example(messageIds),
|
|
325
392
|
Example(partialMessages),
|
|
326
393
|
Get('{id}/messages'),
|
|
394
|
+
Security('*', ['acl']),
|
|
327
395
|
Tags('messages'),
|
|
328
396
|
Response(notFoundResp.status, notFoundResp.description),
|
|
329
397
|
__param(0, Request()),
|
|
@@ -331,12 +399,14 @@ __decorate([
|
|
|
331
399
|
__param(2, Query()),
|
|
332
400
|
__param(3, Query()),
|
|
333
401
|
__param(4, Query()),
|
|
334
|
-
__param(5, Query())
|
|
402
|
+
__param(5, Query()),
|
|
403
|
+
__param(6, Query())
|
|
335
404
|
], HostController.prototype, "getHostMessages", null);
|
|
336
405
|
__decorate([
|
|
337
406
|
Example(taskIds),
|
|
338
407
|
Example(partialTasks),
|
|
339
408
|
Get('{id}/tasks'),
|
|
409
|
+
Security('*', ['acl']),
|
|
340
410
|
Tags('tasks'),
|
|
341
411
|
Response(notFoundResp.status, notFoundResp.description),
|
|
342
412
|
__param(0, Request()),
|
|
@@ -344,18 +414,23 @@ __decorate([
|
|
|
344
414
|
__param(2, Query()),
|
|
345
415
|
__param(3, Query()),
|
|
346
416
|
__param(4, Query()),
|
|
347
|
-
__param(5, Query())
|
|
417
|
+
__param(5, Query()),
|
|
418
|
+
__param(6, Query())
|
|
348
419
|
], HostController.prototype, "getHostTasks", null);
|
|
349
420
|
__decorate([
|
|
350
421
|
Put('{id}/tags/{tag}'),
|
|
422
|
+
Middlewares(acl({ resource: 'host', action: 'update:tags', objectId: 'params.id' })),
|
|
351
423
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
424
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
352
425
|
Response(notFoundResp.status, notFoundResp.description),
|
|
353
426
|
__param(0, Path()),
|
|
354
427
|
__param(1, Path())
|
|
355
428
|
], HostController.prototype, "putHostTag", null);
|
|
356
429
|
__decorate([
|
|
357
430
|
Delete('{id}/tags/{tag}'),
|
|
431
|
+
Middlewares(acl({ resource: 'host', action: 'update:tags', objectId: 'params.id' })),
|
|
358
432
|
SuccessResponse(noContentResp.status, noContentResp.description),
|
|
433
|
+
Response(forbiddenOperationResp.status, forbiddenOperationResp.description),
|
|
359
434
|
Response(notFoundResp.status, notFoundResp.description),
|
|
360
435
|
__param(0, Path()),
|
|
361
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 };
|