@xen-orchestra/rest-api 0.28.1 → 0.29.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/dist/abstract-classes/base-controller.mjs +10 -0
- package/dist/abstract-classes/listener.mjs +8 -3
- package/dist/alarms/alarm.controller.mjs +3 -2
- package/dist/backup-archives/backup-archive.controller.mjs +3 -2
- package/dist/backup-jobs/backup-job.controller.mjs +15 -10
- package/dist/backup-logs/backup-log.controller.mjs +3 -2
- package/dist/backup-repositories/backup-repositories.controller.mjs +3 -2
- package/dist/events/event.class.mjs +12 -9
- package/dist/events/event.service.mjs +2 -3
- package/dist/groups/group.controller.mjs +9 -6
- package/dist/helpers/markdown.helper.mjs +20 -0
- package/dist/helpers/object-wrapper.helper.mjs +3 -3
- package/dist/hosts/host.controller.mjs +12 -8
- package/dist/messages/message.controller.mjs +3 -2
- package/dist/networks/network.controller.mjs +12 -8
- package/dist/open-api/routes/routes.js +182 -42
- package/dist/pbds/pbd.controller.mjs +3 -2
- package/dist/pcis/pci.controller.mjs +3 -2
- package/dist/pgpus/pgpu.controller.mjs +3 -2
- package/dist/pifs/pif.controller.mjs +12 -8
- package/dist/pools/pool.controller.mjs +12 -8
- package/dist/proxies/proxy.controller.mjs +3 -2
- package/dist/restore-logs/restore-log.controller.mjs +6 -4
- package/dist/schedules/schedule.controller.mjs +3 -2
- package/dist/servers/server.controller.mjs +6 -4
- package/dist/sms/sm.controller.mjs +3 -2
- package/dist/srs/sr.controller.mjs +12 -8
- package/dist/tasks/task.controller.mjs +3 -2
- package/dist/users/user.controller.mjs +9 -6
- package/dist/vbds/vbd.controller.mjs +12 -8
- package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +12 -8
- package/dist/vdis/vdi.controller.mjs +12 -8
- package/dist/vifs/vif.controller.mjs +76 -10
- package/dist/vm-controller/vm-controller.controller.mjs +15 -10
- package/dist/vm-snapshots/vm-snapshot.controller.mjs +15 -10
- package/dist/vm-templates/vm-template.controller.mjs +15 -10
- package/dist/vms/vm.controller.mjs +18 -12
- package/dist/vms/vm.service.mjs +7 -2
- package/open-api/spec/swagger.json +1164 -231
- package/package.json +11 -11
|
@@ -3,8 +3,10 @@ import { createGzip } from 'node:zlib';
|
|
|
3
3
|
import { pipeline } from 'node:stream/promises';
|
|
4
4
|
import { Readable } from 'node:stream';
|
|
5
5
|
import { BASE_URL } from '../index.mjs';
|
|
6
|
+
import { makeMarkdownTable } from '../helpers/markdown.helper.mjs';
|
|
6
7
|
import { makeNdJsonStream } from '../helpers/stream.helper.mjs';
|
|
7
8
|
import { makeObjectMapper } from '../helpers/object-wrapper.helper.mjs';
|
|
9
|
+
import { invalidParameters } from 'xo-common/api-errors.js';
|
|
8
10
|
import { NDJSON_CONTENT_TYPE, safeParseComplexMatcher } from '../helpers/utils.helper.mjs';
|
|
9
11
|
const noop = () => { };
|
|
10
12
|
export class BaseController extends Controller {
|
|
@@ -18,12 +20,20 @@ export class BaseController extends Controller {
|
|
|
18
20
|
sendObjects(objects, req, path) {
|
|
19
21
|
const mapper = makeObjectMapper(req, path);
|
|
20
22
|
const mappedObjects = objects.map(mapper);
|
|
23
|
+
if (req.query.ndjson === 'true' && req.query.markdown === 'true') {
|
|
24
|
+
throw invalidParameters('Cannot use both ndjson and markdown output formats simultaneously');
|
|
25
|
+
}
|
|
21
26
|
if (req.query.ndjson === 'true') {
|
|
22
27
|
const res = req.res;
|
|
23
28
|
res.setHeader('Content-Type', NDJSON_CONTENT_TYPE);
|
|
24
29
|
const stream = Readable.from(makeNdJsonStream(mappedObjects));
|
|
25
30
|
return stream;
|
|
26
31
|
}
|
|
32
|
+
else if (req.query.markdown === 'true') {
|
|
33
|
+
const res = req.res;
|
|
34
|
+
res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
|
|
35
|
+
return Readable.from([makeMarkdownTable(mappedObjects)]);
|
|
36
|
+
}
|
|
27
37
|
else {
|
|
28
38
|
return mappedObjects;
|
|
29
39
|
}
|
|
@@ -14,12 +14,18 @@ export class Listener {
|
|
|
14
14
|
return this.#eventEmitter;
|
|
15
15
|
}
|
|
16
16
|
addSubscriber(subscriber, fields = '*') {
|
|
17
|
-
this
|
|
17
|
+
const unregisterOnClear = subscriber.onClear(() => this.removeSubscriber(subscriber.id));
|
|
18
|
+
this.#subscribers.set(subscriber.id, { fields, subscriber, unregisterOnClear });
|
|
18
19
|
if (this.#subscribers.size === 1) {
|
|
19
20
|
this.#watchedEvent.forEach(event => this.#addEventListener(event));
|
|
20
21
|
}
|
|
21
22
|
}
|
|
22
23
|
removeSubscriber(subscriberId) {
|
|
24
|
+
const subscriberWithConf = this.#subscribers.get(subscriberId);
|
|
25
|
+
if (subscriberWithConf === undefined) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
subscriberWithConf.unregisterOnClear();
|
|
23
29
|
this.#subscribers.delete(subscriberId);
|
|
24
30
|
if (this.#subscribers.size === 0) {
|
|
25
31
|
this.removeAllEventListeners();
|
|
@@ -32,8 +38,7 @@ export class Listener {
|
|
|
32
38
|
this.#eventCallbacks.clear();
|
|
33
39
|
}
|
|
34
40
|
clear() {
|
|
35
|
-
this.
|
|
36
|
-
this.#subscribers.clear();
|
|
41
|
+
this.#subscribers.forEach(({ subscriber }) => this.removeSubscriber(subscriber.id));
|
|
37
42
|
this.#watchedEvent = [];
|
|
38
43
|
}
|
|
39
44
|
#addEventListener(event) {
|
|
@@ -43,7 +43,7 @@ let AlarmController = class AlarmController extends XapiXoController {
|
|
|
43
43
|
* @example filter "body:name:physical_utilisation"
|
|
44
44
|
* @example limit 42
|
|
45
45
|
*/
|
|
46
|
-
getAlarms(req, fields, ndjson, filter, limit) {
|
|
46
|
+
getAlarms(req, fields, ndjson, markdown, filter, limit) {
|
|
47
47
|
return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
@@ -61,7 +61,8 @@ __decorate([
|
|
|
61
61
|
__param(1, Query()),
|
|
62
62
|
__param(2, Query()),
|
|
63
63
|
__param(3, Query()),
|
|
64
|
-
__param(4, Query())
|
|
64
|
+
__param(4, Query()),
|
|
65
|
+
__param(5, Query())
|
|
65
66
|
], AlarmController.prototype, "getAlarms", null);
|
|
66
67
|
__decorate([
|
|
67
68
|
Example(alarm),
|
|
@@ -61,7 +61,7 @@ let BackupArchiveController = class BackupArchiveController extends XoController
|
|
|
61
61
|
* @example filter "disks:length:>0"
|
|
62
62
|
* @example limit 42
|
|
63
63
|
*/
|
|
64
|
-
async getBackupArchives(req, backupRepositories, fields, ndjson, filter, limit) {
|
|
64
|
+
async getBackupArchives(req, backupRepositories, fields, ndjson, markdown, filter, limit) {
|
|
65
65
|
const backupArchives = await this.getObjects({ backupRepositories, filter, limit });
|
|
66
66
|
return this.sendObjects(Object.values(backupArchives), req);
|
|
67
67
|
}
|
|
@@ -83,7 +83,8 @@ __decorate([
|
|
|
83
83
|
__param(2, Query()),
|
|
84
84
|
__param(3, Query()),
|
|
85
85
|
__param(4, Query()),
|
|
86
|
-
__param(5, Query())
|
|
86
|
+
__param(5, Query()),
|
|
87
|
+
__param(6, Query())
|
|
87
88
|
], BackupArchiveController.prototype, "getBackupArchives", null);
|
|
88
89
|
__decorate([
|
|
89
90
|
Example(backupArchive),
|
|
@@ -46,7 +46,7 @@ let BackupJobController = class BackupJobController extends XoController {
|
|
|
46
46
|
* @example filter "type:backup"
|
|
47
47
|
* @example limit 42
|
|
48
48
|
*/
|
|
49
|
-
async getBackupJobs(req, fields, ndjson, filter, limit) {
|
|
49
|
+
async getBackupJobs(req, fields, ndjson, markdown, filter, limit) {
|
|
50
50
|
const backupJobs = await this.getObjects({ filter, limit });
|
|
51
51
|
return this.sendObjects(Object.values(backupJobs), req, 'backup-jobs');
|
|
52
52
|
}
|
|
@@ -65,7 +65,8 @@ __decorate([
|
|
|
65
65
|
__param(1, Query()),
|
|
66
66
|
__param(2, Query()),
|
|
67
67
|
__param(3, Query()),
|
|
68
|
-
__param(4, Query())
|
|
68
|
+
__param(4, Query()),
|
|
69
|
+
__param(5, Query())
|
|
69
70
|
], BackupJobController.prototype, "getBackupJobs", null);
|
|
70
71
|
__decorate([
|
|
71
72
|
Example(vmBackupJob),
|
|
@@ -117,7 +118,7 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
|
|
|
117
118
|
* @example filter "mode:delta"
|
|
118
119
|
* @example limit 42
|
|
119
120
|
*/
|
|
120
|
-
async getVmBackupJobs(req, fields, ndjson, filter, limit) {
|
|
121
|
+
async getVmBackupJobs(req, fields, ndjson, markdown, filter, limit) {
|
|
121
122
|
const vmBackupJobs = await this.restApi.xoApp.getAllJobs('backup');
|
|
122
123
|
return this.sendObjects(limitAndFilterArray(vmBackupJobs, { filter, limit }), req, 'backup-jobs');
|
|
123
124
|
}
|
|
@@ -138,7 +139,7 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
|
|
|
138
139
|
* @example filter "xoMetadata?"
|
|
139
140
|
* @example limit 42
|
|
140
141
|
*/
|
|
141
|
-
async getMetadataBackupJobs(req, fields, ndjson, filter, limit) {
|
|
142
|
+
async getMetadataBackupJobs(req, fields, ndjson, markdown, filter, limit) {
|
|
142
143
|
const metadataBackupJobs = await this.restApi.xoApp.getAllJobs('metadataBackup');
|
|
143
144
|
return this.sendObjects(limitAndFilterArray(metadataBackupJobs, { filter, limit }), req, 'backup-jobs');
|
|
144
145
|
}
|
|
@@ -154,7 +155,7 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
|
|
|
154
155
|
* @example filter "mode:delta"
|
|
155
156
|
* @example limit 42
|
|
156
157
|
*/
|
|
157
|
-
async getMirrorBackupJobs(req, fields, ndjson, filter, limit) {
|
|
158
|
+
async getMirrorBackupJobs(req, fields, ndjson, markdown, filter, limit) {
|
|
158
159
|
const mirrorBackupJobs = await this.restApi.xoApp.getAllJobs('mirrorBackup');
|
|
159
160
|
return this.sendObjects(limitAndFilterArray(mirrorBackupJobs, { filter, limit }), req, 'backup-jobs');
|
|
160
161
|
}
|
|
@@ -169,7 +170,7 @@ let DeprecatedBackupController = class DeprecatedBackupController extends XoCont
|
|
|
169
170
|
* @example filter "status:success"
|
|
170
171
|
* @example limit 42
|
|
171
172
|
*/
|
|
172
|
-
async getDeprecatedBackupLogs(req, fields, ndjson, filter, limit) {
|
|
173
|
+
async getDeprecatedBackupLogs(req, fields, ndjson, markdown, filter, limit) {
|
|
173
174
|
const userFilter = filter === undefined ? () => true : safeParseComplexMatcher(filter).createPredicate();
|
|
174
175
|
const predicate = (log) => {
|
|
175
176
|
if (!this.#backupLogService.isBackupLog(log)) {
|
|
@@ -201,7 +202,8 @@ __decorate([
|
|
|
201
202
|
__param(1, Query()),
|
|
202
203
|
__param(2, Query()),
|
|
203
204
|
__param(3, Query()),
|
|
204
|
-
__param(4, Query())
|
|
205
|
+
__param(4, Query()),
|
|
206
|
+
__param(5, Query())
|
|
205
207
|
], DeprecatedBackupController.prototype, "getVmBackupJobs", null);
|
|
206
208
|
__decorate([
|
|
207
209
|
Hidden(),
|
|
@@ -228,7 +230,8 @@ __decorate([
|
|
|
228
230
|
__param(1, Query()),
|
|
229
231
|
__param(2, Query()),
|
|
230
232
|
__param(3, Query()),
|
|
231
|
-
__param(4, Query())
|
|
233
|
+
__param(4, Query()),
|
|
234
|
+
__param(5, Query())
|
|
232
235
|
], DeprecatedBackupController.prototype, "getMetadataBackupJobs", null);
|
|
233
236
|
__decorate([
|
|
234
237
|
Example(metadataBackupJob),
|
|
@@ -248,7 +251,8 @@ __decorate([
|
|
|
248
251
|
__param(1, Query()),
|
|
249
252
|
__param(2, Query()),
|
|
250
253
|
__param(3, Query()),
|
|
251
|
-
__param(4, Query())
|
|
254
|
+
__param(4, Query()),
|
|
255
|
+
__param(5, Query())
|
|
252
256
|
], DeprecatedBackupController.prototype, "getMirrorBackupJobs", null);
|
|
253
257
|
__decorate([
|
|
254
258
|
Example(mirrorBackupJob),
|
|
@@ -268,7 +272,8 @@ __decorate([
|
|
|
268
272
|
__param(1, Query()),
|
|
269
273
|
__param(2, Query()),
|
|
270
274
|
__param(3, Query()),
|
|
271
|
-
__param(4, Query())
|
|
275
|
+
__param(4, Query()),
|
|
276
|
+
__param(5, Query())
|
|
272
277
|
], DeprecatedBackupController.prototype, "getDeprecatedBackupLogs", null);
|
|
273
278
|
__decorate([
|
|
274
279
|
Example(backupLog),
|
|
@@ -37,7 +37,7 @@ let BackupLogController = class BackupLogController extends XoController {
|
|
|
37
37
|
* @example filter "status:success"
|
|
38
38
|
* @example limit 42
|
|
39
39
|
*/
|
|
40
|
-
async getBackupLogs(req, fields, ndjson, filter, limit) {
|
|
40
|
+
async getBackupLogs(req, fields, ndjson, markdown, filter, limit) {
|
|
41
41
|
const backupLogs = await this.getObjects({ filter, limit });
|
|
42
42
|
return this.sendObjects(Object.values(backupLogs), req);
|
|
43
43
|
}
|
|
@@ -56,7 +56,8 @@ __decorate([
|
|
|
56
56
|
__param(1, Query()),
|
|
57
57
|
__param(2, Query()),
|
|
58
58
|
__param(3, Query()),
|
|
59
|
-
__param(4, Query())
|
|
59
|
+
__param(4, Query()),
|
|
60
|
+
__param(5, Query())
|
|
60
61
|
], BackupLogController.prototype, "getBackupLogs", null);
|
|
61
62
|
__decorate([
|
|
62
63
|
Example(backupLog),
|
|
@@ -30,7 +30,7 @@ let BackupRepositoryController = class BackupRepositoryController extends XoCont
|
|
|
30
30
|
* @example filter "enabled?"
|
|
31
31
|
* @example limit 42
|
|
32
32
|
*/
|
|
33
|
-
async getRepositories(req, fields, ndjson, filter, limit) {
|
|
33
|
+
async getRepositories(req, fields, ndjson, markdown, filter, limit) {
|
|
34
34
|
return this.sendObjects(Object.values(await this.getObjects({ filter, limit })), req);
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
@@ -48,7 +48,8 @@ __decorate([
|
|
|
48
48
|
__param(1, Query()),
|
|
49
49
|
__param(2, Query()),
|
|
50
50
|
__param(3, Query()),
|
|
51
|
-
__param(4, Query())
|
|
51
|
+
__param(4, Query()),
|
|
52
|
+
__param(5, Query())
|
|
52
53
|
], BackupRepositoryController.prototype, "getRepositories", null);
|
|
53
54
|
__decorate([
|
|
54
55
|
Example(backupRepository),
|
|
@@ -10,6 +10,7 @@ export class Subscriber {
|
|
|
10
10
|
#manager;
|
|
11
11
|
#connection;
|
|
12
12
|
#isAlive;
|
|
13
|
+
#cleanupCallbacks = new Set();
|
|
13
14
|
get id() {
|
|
14
15
|
return this.#id;
|
|
15
16
|
}
|
|
@@ -34,6 +35,10 @@ export class Subscriber {
|
|
|
34
35
|
this.clear();
|
|
35
36
|
}
|
|
36
37
|
}
|
|
38
|
+
onClear(callback) {
|
|
39
|
+
this.#cleanupCallbacks.add(callback);
|
|
40
|
+
return () => this.#cleanupCallbacks.delete(callback);
|
|
41
|
+
}
|
|
37
42
|
broadcast(event, data) {
|
|
38
43
|
if (!this.#isAlive) {
|
|
39
44
|
log.warn('broadcast called on a subscriber that is not alive, but still in memory! Force clear and do nothing');
|
|
@@ -44,10 +49,13 @@ export class Subscriber {
|
|
|
44
49
|
this.#safeWrite(payload);
|
|
45
50
|
}
|
|
46
51
|
clear() {
|
|
47
|
-
this.#isAlive
|
|
48
|
-
|
|
49
|
-
this.#connection.destroy();
|
|
52
|
+
if (!this.#isAlive) {
|
|
53
|
+
return;
|
|
50
54
|
}
|
|
55
|
+
this.#isAlive = false;
|
|
56
|
+
this.#connection.destroy();
|
|
57
|
+
this.#cleanupCallbacks.forEach(cb => cb());
|
|
58
|
+
this.#cleanupCallbacks.clear();
|
|
51
59
|
this.#manager.removeSubscriber(this.id);
|
|
52
60
|
}
|
|
53
61
|
}
|
|
@@ -132,11 +140,6 @@ export class SubscriberManager {
|
|
|
132
140
|
this.#subscribers.delete(id);
|
|
133
141
|
}
|
|
134
142
|
clear() {
|
|
135
|
-
this.#subscribers.forEach(subscriber =>
|
|
136
|
-
if (!subscriber.connection.closed) {
|
|
137
|
-
subscriber.connection.destroy();
|
|
138
|
-
}
|
|
139
|
-
this.#subscribers.delete(subscriber.id);
|
|
140
|
-
});
|
|
143
|
+
this.#subscribers.forEach(subscriber => subscriber.clear());
|
|
141
144
|
}
|
|
142
145
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
1
|
import { createLogger } from '@xen-orchestra/log';
|
|
3
2
|
import { PassThrough, pipeline } from 'node:stream';
|
|
4
3
|
import { PingListener, Subscriber, SubscriberManager, XoListener } from './event.class.mjs';
|
|
@@ -50,9 +49,9 @@ export class EventService {
|
|
|
50
49
|
'Cache-Control': 'no-cache, no-transform',
|
|
51
50
|
});
|
|
52
51
|
res.setHeaders(headers);
|
|
53
|
-
const maxRam = this.#restApi.xoApp.config.get('rest-api.
|
|
52
|
+
const maxRam = this.#restApi.xoApp.config.get('rest-api.maxRamAllocatedPerSseClient');
|
|
54
53
|
const connection = new PassThrough({
|
|
55
|
-
highWaterMark: Math.round(
|
|
54
|
+
highWaterMark: Math.round(1024 * 1024 * maxRam),
|
|
56
55
|
});
|
|
57
56
|
pipeline(connection, res, error => {
|
|
58
57
|
if (error?.code !== 'ERR_STREAM_PREMATURE_CLOSE') {
|
|
@@ -38,7 +38,7 @@ let GroupController = class GroupController extends XoController {
|
|
|
38
38
|
* @example filter "users:length:>0"
|
|
39
39
|
* @example limit 42
|
|
40
40
|
*/
|
|
41
|
-
async getGroups(req, fields, ndjson, filter, limit) {
|
|
41
|
+
async getGroups(req, fields, ndjson, markdown, filter, limit) {
|
|
42
42
|
return this.sendObjects(Object.values(await this.getObjects({ filter, limit })), req);
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
@@ -102,7 +102,7 @@ let GroupController = class GroupController extends XoController {
|
|
|
102
102
|
* @example filter "permission:none"
|
|
103
103
|
* @example limit 42
|
|
104
104
|
*/
|
|
105
|
-
async getGroupUsers(req, id, fields, ndjson, filter, limit) {
|
|
105
|
+
async getGroupUsers(req, id, fields, ndjson, markdown, filter, limit) {
|
|
106
106
|
const group = await this.getObject(id);
|
|
107
107
|
const users = await Promise.all(group.users.map(id => this.#userService.getUser(id)));
|
|
108
108
|
return this.sendObjects(limitAndFilterArray(users, { filter, limit }), req, 'users');
|
|
@@ -113,7 +113,7 @@ let GroupController = class GroupController extends XoController {
|
|
|
113
113
|
* @example filter "status:failure"
|
|
114
114
|
* @example limit 42
|
|
115
115
|
*/
|
|
116
|
-
async getGroupTasks(req, id, fields, ndjson, filter, limit) {
|
|
116
|
+
async getGroupTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
117
117
|
const tasks = await this.getTasksForObject(id, { filter, limit });
|
|
118
118
|
return this.sendObjects(Object.values(tasks), req, 'tasks');
|
|
119
119
|
}
|
|
@@ -126,7 +126,8 @@ __decorate([
|
|
|
126
126
|
__param(1, Query()),
|
|
127
127
|
__param(2, Query()),
|
|
128
128
|
__param(3, Query()),
|
|
129
|
-
__param(4, Query())
|
|
129
|
+
__param(4, Query()),
|
|
130
|
+
__param(5, Query())
|
|
130
131
|
], GroupController.prototype, "getGroups", null);
|
|
131
132
|
__decorate([
|
|
132
133
|
Example(group),
|
|
@@ -186,7 +187,8 @@ __decorate([
|
|
|
186
187
|
__param(2, Query()),
|
|
187
188
|
__param(3, Query()),
|
|
188
189
|
__param(4, Query()),
|
|
189
|
-
__param(5, Query())
|
|
190
|
+
__param(5, Query()),
|
|
191
|
+
__param(6, Query())
|
|
190
192
|
], GroupController.prototype, "getGroupUsers", null);
|
|
191
193
|
__decorate([
|
|
192
194
|
Example(taskIds),
|
|
@@ -199,7 +201,8 @@ __decorate([
|
|
|
199
201
|
__param(2, Query()),
|
|
200
202
|
__param(3, Query()),
|
|
201
203
|
__param(4, Query()),
|
|
202
|
-
__param(5, Query())
|
|
204
|
+
__param(5, Query()),
|
|
205
|
+
__param(6, Query())
|
|
203
206
|
], GroupController.prototype, "getGroupTasks", null);
|
|
204
207
|
GroupController = __decorate([
|
|
205
208
|
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;
|
|
@@ -38,7 +38,7 @@ let HostController = class HostController extends XapiXoController {
|
|
|
38
38
|
* @example filter "productBrand:XCP-ng"
|
|
39
39
|
* @example limit 42
|
|
40
40
|
*/
|
|
41
|
-
getHosts(req, fields, ndjson, filter, limit) {
|
|
41
|
+
getHosts(req, fields, ndjson, markdown, filter, limit) {
|
|
42
42
|
return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
@@ -95,7 +95,7 @@ let HostController = class HostController extends XapiXoController {
|
|
|
95
95
|
* @example filter "time:>1747053793"
|
|
96
96
|
* @example limit 42
|
|
97
97
|
*/
|
|
98
|
-
getHostAlarms(req, id, fields, ndjson, filter, limit) {
|
|
98
|
+
getHostAlarms(req, id, fields, ndjson, markdown, filter, limit) {
|
|
99
99
|
const host = this.getObject(id);
|
|
100
100
|
const alarms = this.#alarmService.getAlarms({
|
|
101
101
|
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${host.uuid}`,
|
|
@@ -129,7 +129,7 @@ let HostController = class HostController extends XapiXoController {
|
|
|
129
129
|
* @example filter "name:PBD_PLUG_FAILED_ON_SERVER_START"
|
|
130
130
|
* @example limit 42
|
|
131
131
|
*/
|
|
132
|
-
getHostMessages(req, id, fields, ndjson, filter, limit) {
|
|
132
|
+
getHostMessages(req, id, fields, ndjson, markdown, filter, limit) {
|
|
133
133
|
const messages = this.getMessagesForObject(id, { filter, limit });
|
|
134
134
|
return this.sendObjects(Object.values(messages), req, 'messages');
|
|
135
135
|
}
|
|
@@ -139,7 +139,7 @@ let HostController = class HostController extends XapiXoController {
|
|
|
139
139
|
* @example filter "status:failure"
|
|
140
140
|
* @example limit 42
|
|
141
141
|
*/
|
|
142
|
-
async getHostTasks(req, id, fields, ndjson, filter, limit) {
|
|
142
|
+
async getHostTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
143
143
|
const tasks = await this.getTasksForObject(id, { filter, limit });
|
|
144
144
|
return this.sendObjects(Object.values(tasks), req, 'tasks');
|
|
145
145
|
}
|
|
@@ -261,7 +261,8 @@ __decorate([
|
|
|
261
261
|
__param(1, Query()),
|
|
262
262
|
__param(2, Query()),
|
|
263
263
|
__param(3, Query()),
|
|
264
|
-
__param(4, Query())
|
|
264
|
+
__param(4, Query()),
|
|
265
|
+
__param(5, Query())
|
|
265
266
|
], HostController.prototype, "getHosts", null);
|
|
266
267
|
__decorate([
|
|
267
268
|
Example(host),
|
|
@@ -304,7 +305,8 @@ __decorate([
|
|
|
304
305
|
__param(2, Query()),
|
|
305
306
|
__param(3, Query()),
|
|
306
307
|
__param(4, Query()),
|
|
307
|
-
__param(5, Query())
|
|
308
|
+
__param(5, Query()),
|
|
309
|
+
__param(6, Query())
|
|
308
310
|
], HostController.prototype, "getHostAlarms", null);
|
|
309
311
|
__decorate([
|
|
310
312
|
Example(hostSmt),
|
|
@@ -331,7 +333,8 @@ __decorate([
|
|
|
331
333
|
__param(2, Query()),
|
|
332
334
|
__param(3, Query()),
|
|
333
335
|
__param(4, Query()),
|
|
334
|
-
__param(5, Query())
|
|
336
|
+
__param(5, Query()),
|
|
337
|
+
__param(6, Query())
|
|
335
338
|
], HostController.prototype, "getHostMessages", null);
|
|
336
339
|
__decorate([
|
|
337
340
|
Example(taskIds),
|
|
@@ -344,7 +347,8 @@ __decorate([
|
|
|
344
347
|
__param(2, Query()),
|
|
345
348
|
__param(3, Query()),
|
|
346
349
|
__param(4, Query()),
|
|
347
|
-
__param(5, Query())
|
|
350
|
+
__param(5, Query()),
|
|
351
|
+
__param(6, Query())
|
|
348
352
|
], HostController.prototype, "getHostTasks", null);
|
|
349
353
|
__decorate([
|
|
350
354
|
Put('{id}/tags/{tag}'),
|
|
@@ -47,7 +47,7 @@ let MessageController = class MessageController extends XapiXoController {
|
|
|
47
47
|
* @example filter "name:VM_STARTED"
|
|
48
48
|
* @example limit 42
|
|
49
49
|
*/
|
|
50
|
-
getMessages(req, fields, ndjson, filter, limit) {
|
|
50
|
+
getMessages(req, fields, ndjson, markdown, filter, limit) {
|
|
51
51
|
return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
@@ -65,7 +65,8 @@ __decorate([
|
|
|
65
65
|
__param(1, Query()),
|
|
66
66
|
__param(2, Query()),
|
|
67
67
|
__param(3, Query()),
|
|
68
|
-
__param(4, Query())
|
|
68
|
+
__param(4, Query()),
|
|
69
|
+
__param(5, Query())
|
|
69
70
|
], MessageController.prototype, "getMessages", null);
|
|
70
71
|
__decorate([
|
|
71
72
|
Example(message),
|
|
@@ -30,7 +30,7 @@ let NetworkController = class NetworkController extends XapiXoController {
|
|
|
30
30
|
* @example filter "nbd?"
|
|
31
31
|
* @example limit 42
|
|
32
32
|
*/
|
|
33
|
-
getNetworks(req, fields, ndjson, filter, limit) {
|
|
33
|
+
getNetworks(req, fields, ndjson, markdown, filter, limit) {
|
|
34
34
|
return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
@@ -52,7 +52,7 @@ let NetworkController = class NetworkController extends XapiXoController {
|
|
|
52
52
|
* @example filter "time:>1747053793"
|
|
53
53
|
* @example limit 42
|
|
54
54
|
*/
|
|
55
|
-
getNetworkAlarms(req, id, fields, ndjson, filter, limit) {
|
|
55
|
+
getNetworkAlarms(req, id, fields, ndjson, markdown, filter, limit) {
|
|
56
56
|
const network = this.getObject(id);
|
|
57
57
|
const alarms = this.#alarmService.getAlarms({
|
|
58
58
|
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${network.uuid}`,
|
|
@@ -66,7 +66,7 @@ let NetworkController = class NetworkController extends XapiXoController {
|
|
|
66
66
|
* @example filter "name:VM_STARTED"
|
|
67
67
|
* @example limit 42
|
|
68
68
|
*/
|
|
69
|
-
getNetworkMessages(req, id, fields, ndjson, filter, limit) {
|
|
69
|
+
getNetworkMessages(req, id, fields, ndjson, markdown, filter, limit) {
|
|
70
70
|
const messages = this.getMessagesForObject(id, { filter, limit });
|
|
71
71
|
return this.sendObjects(Object.values(messages), req, 'messages');
|
|
72
72
|
}
|
|
@@ -76,7 +76,7 @@ let NetworkController = class NetworkController extends XapiXoController {
|
|
|
76
76
|
* @example filter "status:failure"
|
|
77
77
|
* @example limit 42
|
|
78
78
|
*/
|
|
79
|
-
async getNetworkTasks(req, id, fields, ndjson, filter, limit) {
|
|
79
|
+
async getNetworkTasks(req, id, fields, ndjson, markdown, filter, limit) {
|
|
80
80
|
const tasks = await this.getTasksForObject(id, { filter, limit });
|
|
81
81
|
return this.sendObjects(Object.values(tasks), req, 'tasks');
|
|
82
82
|
}
|
|
@@ -105,7 +105,8 @@ __decorate([
|
|
|
105
105
|
__param(1, Query()),
|
|
106
106
|
__param(2, Query()),
|
|
107
107
|
__param(3, Query()),
|
|
108
|
-
__param(4, Query())
|
|
108
|
+
__param(4, Query()),
|
|
109
|
+
__param(5, Query())
|
|
109
110
|
], NetworkController.prototype, "getNetworks", null);
|
|
110
111
|
__decorate([
|
|
111
112
|
Example(network),
|
|
@@ -129,7 +130,8 @@ __decorate([
|
|
|
129
130
|
__param(2, Query()),
|
|
130
131
|
__param(3, Query()),
|
|
131
132
|
__param(4, Query()),
|
|
132
|
-
__param(5, Query())
|
|
133
|
+
__param(5, Query()),
|
|
134
|
+
__param(6, Query())
|
|
133
135
|
], NetworkController.prototype, "getNetworkAlarms", null);
|
|
134
136
|
__decorate([
|
|
135
137
|
Example(messageIds),
|
|
@@ -142,7 +144,8 @@ __decorate([
|
|
|
142
144
|
__param(2, Query()),
|
|
143
145
|
__param(3, Query()),
|
|
144
146
|
__param(4, Query()),
|
|
145
|
-
__param(5, Query())
|
|
147
|
+
__param(5, Query()),
|
|
148
|
+
__param(6, Query())
|
|
146
149
|
], NetworkController.prototype, "getNetworkMessages", null);
|
|
147
150
|
__decorate([
|
|
148
151
|
Example(taskIds),
|
|
@@ -155,7 +158,8 @@ __decorate([
|
|
|
155
158
|
__param(2, Query()),
|
|
156
159
|
__param(3, Query()),
|
|
157
160
|
__param(4, Query()),
|
|
158
|
-
__param(5, Query())
|
|
161
|
+
__param(5, Query()),
|
|
162
|
+
__param(6, Query())
|
|
159
163
|
], NetworkController.prototype, "getNetworkTasks", null);
|
|
160
164
|
__decorate([
|
|
161
165
|
Put('{id}/tags/{tag}'),
|