@xen-orchestra/rest-api 0.27.0 → 0.28.1
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/backup-logs/backup-log.service.mjs +5 -2
- package/dist/hosts/host.controller.mjs +90 -1
- package/dist/ioc/ioc.mjs +8 -0
- package/dist/middlewares/generic-error-handler.middleware.mjs +1 -1
- package/dist/networks/network.service.mjs +23 -0
- package/dist/open-api/routes/routes.js +204 -19
- package/dist/pools/pool.controller.mjs +88 -6
- package/dist/srs/sr.controller.mjs +29 -0
- package/dist/vms/vm.controller.mjs +58 -0
- package/dist/vms/vm.service.mjs +1 -1
- package/dist/xoa/xoa.service.mjs +3 -3
- package/open-api/spec/swagger.json +649 -18
- package/package.json +5 -5
|
@@ -26,15 +26,18 @@ import { VmService } from '../vms/vm.service.mjs';
|
|
|
26
26
|
import { PoolService } from './pool.service.mjs';
|
|
27
27
|
import { escapeUnsafeComplexMatcher, NDJSON_CONTENT_TYPE } from '../helpers/utils.helper.mjs';
|
|
28
28
|
import { messageIds, partialMessages } from '../open-api/oa-examples/message.oa-example.mjs';
|
|
29
|
+
import { NetworkService } from '../networks/network.service.mjs';
|
|
29
30
|
let PoolController = class PoolController extends XapiXoController {
|
|
30
31
|
#vmService;
|
|
31
32
|
#poolService;
|
|
32
33
|
#alarmService;
|
|
33
|
-
|
|
34
|
+
#networkService;
|
|
35
|
+
constructor(restApi, vmService, poolService, alarmService, networkService) {
|
|
34
36
|
super('pool', restApi);
|
|
35
37
|
this.#vmService = vmService;
|
|
36
38
|
this.#poolService = poolService;
|
|
37
39
|
this.#alarmService = alarmService;
|
|
40
|
+
this.#networkService = networkService;
|
|
38
41
|
}
|
|
39
42
|
/**
|
|
40
43
|
*
|
|
@@ -64,10 +67,8 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
64
67
|
const poolId = id;
|
|
65
68
|
const action = async () => {
|
|
66
69
|
const { pif, ...rest } = body;
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const network = this.restApi.getObject(xapiNetwork.uuid, 'network');
|
|
70
|
-
return { id: network.id };
|
|
70
|
+
const networkId = await this.#networkService.create(poolId, { pifId: pif, ...rest });
|
|
71
|
+
return { id: networkId };
|
|
71
72
|
};
|
|
72
73
|
return this.createAction(action, {
|
|
73
74
|
sync,
|
|
@@ -79,6 +80,55 @@ let PoolController = class PoolController extends XapiXoController {
|
|
|
79
80
|
},
|
|
80
81
|
});
|
|
81
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
85
|
+
* @example body {
|
|
86
|
+
* "name": "awes0me_bonded_network",
|
|
87
|
+
* "description": "random description",
|
|
88
|
+
* "pifIds": ["ad15b2c8-3d9a-194e-c43a-e3dcda74b256", "7b6bed50-26b2-bd27-8f3a-1b5a81989a92"],
|
|
89
|
+
* "bondMode": "lacp"
|
|
90
|
+
* }
|
|
91
|
+
*/
|
|
92
|
+
createBondedNetwork(id, body, sync) {
|
|
93
|
+
const poolId = id;
|
|
94
|
+
const action = async () => {
|
|
95
|
+
const { pifIds, ...rest } = body;
|
|
96
|
+
const networkId = await this.#networkService.create(poolId, { pifIds: pifIds, ...rest });
|
|
97
|
+
return { id: networkId };
|
|
98
|
+
};
|
|
99
|
+
return this.createAction(action, {
|
|
100
|
+
sync,
|
|
101
|
+
statusCode: createdResp.status,
|
|
102
|
+
taskProperties: {
|
|
103
|
+
name: 'create bonded network',
|
|
104
|
+
objectId: poolId,
|
|
105
|
+
args: body,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
|
|
111
|
+
* @example body {
|
|
112
|
+
* "name": "awes0me_internal_network",
|
|
113
|
+
* "description": "random description"
|
|
114
|
+
* }
|
|
115
|
+
*/
|
|
116
|
+
createInternalNetwork(id, body, sync) {
|
|
117
|
+
const poolId = id;
|
|
118
|
+
const action = async () => {
|
|
119
|
+
const networkId = await this.#networkService.create(poolId, body);
|
|
120
|
+
return { id: networkId };
|
|
121
|
+
};
|
|
122
|
+
return this.createAction(action, {
|
|
123
|
+
sync,
|
|
124
|
+
statusCode: createdResp.status,
|
|
125
|
+
taskProperties: {
|
|
126
|
+
name: 'create internal network',
|
|
127
|
+
objectId: poolId,
|
|
128
|
+
args: body,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
82
132
|
/**
|
|
83
133
|
* @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
|
|
84
134
|
*/
|
|
@@ -331,11 +381,42 @@ __decorate([
|
|
|
331
381
|
SuccessResponse(createdResp.status, createdResp.description),
|
|
332
382
|
Response(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
333
383
|
Response(notFoundResp.status, notFoundResp.description),
|
|
384
|
+
Response(invalidParametersResp.status, invalidParametersResp.description),
|
|
334
385
|
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
335
386
|
__param(0, Path()),
|
|
336
387
|
__param(1, Body()),
|
|
337
388
|
__param(2, Query())
|
|
338
389
|
], PoolController.prototype, "createNetwork", null);
|
|
390
|
+
__decorate([
|
|
391
|
+
Example(taskLocation),
|
|
392
|
+
Example(createNetwork),
|
|
393
|
+
Post('{id}/actions/create_bonded_network'),
|
|
394
|
+
Middlewares(json()),
|
|
395
|
+
Tags('networks'),
|
|
396
|
+
SuccessResponse(createdResp.status, createdResp.description),
|
|
397
|
+
Response(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
398
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
399
|
+
Response(invalidParametersResp.status, invalidParametersResp.description),
|
|
400
|
+
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
401
|
+
__param(0, Path()),
|
|
402
|
+
__param(1, Body()),
|
|
403
|
+
__param(2, Query())
|
|
404
|
+
], PoolController.prototype, "createBondedNetwork", null);
|
|
405
|
+
__decorate([
|
|
406
|
+
Example(taskLocation),
|
|
407
|
+
Example(createNetwork),
|
|
408
|
+
Post('{id}/actions/create_internal_network'),
|
|
409
|
+
Middlewares(json()),
|
|
410
|
+
Tags('networks'),
|
|
411
|
+
SuccessResponse(createdResp.status, createdResp.description),
|
|
412
|
+
Response(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
413
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
414
|
+
Response(invalidParametersResp.status, invalidParametersResp.description),
|
|
415
|
+
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
416
|
+
__param(0, Path()),
|
|
417
|
+
__param(1, Body()),
|
|
418
|
+
__param(2, Query())
|
|
419
|
+
], PoolController.prototype, "createInternalNetwork", null);
|
|
339
420
|
__decorate([
|
|
340
421
|
Example(taskLocation),
|
|
341
422
|
Post('{id}/actions/emergency_shutdown'),
|
|
@@ -490,6 +571,7 @@ PoolController = __decorate([
|
|
|
490
571
|
__param(0, inject(RestApi)),
|
|
491
572
|
__param(1, inject(VmService)),
|
|
492
573
|
__param(2, inject(PoolService)),
|
|
493
|
-
__param(3, inject(AlarmService))
|
|
574
|
+
__param(3, inject(AlarmService)),
|
|
575
|
+
__param(4, inject(NetworkService))
|
|
494
576
|
], PoolController);
|
|
495
577
|
export { PoolController };
|
|
@@ -150,6 +150,24 @@ let SrController = class SrController extends XapiXoController {
|
|
|
150
150
|
},
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
|
|
155
|
+
*/
|
|
156
|
+
async forgetSr(id, sync) {
|
|
157
|
+
const srId = id;
|
|
158
|
+
const action = async () => {
|
|
159
|
+
const xapiSr = this.getXapiObject(srId);
|
|
160
|
+
await xapiSr.$xapi.forgetSr(srId);
|
|
161
|
+
};
|
|
162
|
+
return this.createAction(action, {
|
|
163
|
+
sync,
|
|
164
|
+
statusCode: noContentResp.status,
|
|
165
|
+
taskProperties: {
|
|
166
|
+
name: 'forget sr',
|
|
167
|
+
objectId: srId,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
153
171
|
};
|
|
154
172
|
__decorate([
|
|
155
173
|
Example(srIds),
|
|
@@ -253,6 +271,17 @@ __decorate([
|
|
|
253
271
|
__param(0, Path()),
|
|
254
272
|
__param(1, Query())
|
|
255
273
|
], SrController.prototype, "scanSr", null);
|
|
274
|
+
__decorate([
|
|
275
|
+
Example(taskLocation),
|
|
276
|
+
Post('{id}/actions/forget'),
|
|
277
|
+
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
278
|
+
Response(noContentResp.status, noContentResp.description),
|
|
279
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
280
|
+
Response(invalidParametersResp.status, invalidParametersResp.description),
|
|
281
|
+
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
282
|
+
__param(0, Path()),
|
|
283
|
+
__param(1, Query())
|
|
284
|
+
], SrController.prototype, "forgetSr", null);
|
|
256
285
|
SrController = __decorate([
|
|
257
286
|
Route('srs'),
|
|
258
287
|
Security('*'),
|
|
@@ -325,6 +325,51 @@ let VmController = class VmController extends XapiXoController {
|
|
|
325
325
|
},
|
|
326
326
|
});
|
|
327
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
*
|
|
330
|
+
* - For fast clone on the same SR, omit `srId` and set `fast` to `true`.
|
|
331
|
+
* - For full copy on the same SR, omit `srId` and set `fast` to `false`.
|
|
332
|
+
* - To copy the VM to a different SR (always a full copy), provide `srId`. Supports cross-pool copy. Optionally use `compress: "gzip"` or `compress: "zstd"` to compress the export stream during cross-pool copy.
|
|
333
|
+
*
|
|
334
|
+
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
335
|
+
* @example body { "name_label": "cloned_vm", "fast": true }
|
|
336
|
+
*/
|
|
337
|
+
async cloneVm(id, body, sync) {
|
|
338
|
+
const vmId = id;
|
|
339
|
+
const action = async () => {
|
|
340
|
+
const xapi = this.getXapi(vmId);
|
|
341
|
+
let clonedVmUuid;
|
|
342
|
+
if (body !== undefined && 'srId' in body && body.srId !== undefined) {
|
|
343
|
+
const srId = body.srId;
|
|
344
|
+
const vm = this.getObject(vmId);
|
|
345
|
+
const sr = this.restApi.getObject(srId, 'SR');
|
|
346
|
+
if (vm.$pool === sr.$pool) {
|
|
347
|
+
clonedVmUuid = (await xapi.copyVm(vmId, { nameLabel: body.name_label, srOrSrId: srId })).uuid;
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
const targetXapi = this.restApi.xoApp.getXapi(srId);
|
|
351
|
+
clonedVmUuid = (await xapi.remoteCopyVm(vmId, targetXapi, srId, { compress: body.compress, nameLabel: body.name_label })).vm.uuid;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
const fast = body !== undefined && 'fast' in body ? body.fast : undefined;
|
|
356
|
+
clonedVmUuid = (await xapi.cloneVm(vmId, { nameLabel: body?.name_label, fast })).uuid;
|
|
357
|
+
}
|
|
358
|
+
if (sync) {
|
|
359
|
+
this.setHeader('Location', `${BASE_URL}/vms/${clonedVmUuid}`);
|
|
360
|
+
}
|
|
361
|
+
return { id: clonedVmUuid };
|
|
362
|
+
};
|
|
363
|
+
return this.createAction(action, {
|
|
364
|
+
sync,
|
|
365
|
+
statusCode: createdResp.status,
|
|
366
|
+
taskProperties: {
|
|
367
|
+
name: 'clone VM',
|
|
368
|
+
objectId: vmId,
|
|
369
|
+
params: body,
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
}
|
|
328
373
|
/**
|
|
329
374
|
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
|
330
375
|
* @example fields "id,time"
|
|
@@ -604,6 +649,19 @@ __decorate([
|
|
|
604
649
|
__param(1, Body()),
|
|
605
650
|
__param(2, Query())
|
|
606
651
|
], VmController.prototype, "snapshotVm", null);
|
|
652
|
+
__decorate([
|
|
653
|
+
Example(taskLocation),
|
|
654
|
+
Post('{id}/actions/clone'),
|
|
655
|
+
Middlewares(json()),
|
|
656
|
+
SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description),
|
|
657
|
+
Response(createdResp.status, createdResp.description),
|
|
658
|
+
Response(notFoundResp.status, notFoundResp.description),
|
|
659
|
+
Response(internalServerErrorResp.status, internalServerErrorResp.description),
|
|
660
|
+
Response(invalidParametersResp.status, invalidParametersResp.description),
|
|
661
|
+
__param(0, Path()),
|
|
662
|
+
__param(1, Body()),
|
|
663
|
+
__param(2, Query())
|
|
664
|
+
], VmController.prototype, "cloneVm", null);
|
|
607
665
|
__decorate([
|
|
608
666
|
Example(genericAlarmsExample),
|
|
609
667
|
Get('{id}/alarms'),
|
package/dist/vms/vm.service.mjs
CHANGED
package/dist/xoa/xoa.service.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { extractIdsFromSimplePattern } from '@xen-orchestra/backups/extractIdsFr
|
|
|
8
8
|
import { noSuchObject } from 'xo-common/api-errors.js';
|
|
9
9
|
import { parse } from 'xo-remote-parser';
|
|
10
10
|
import { getFromAsyncCache } from '../helpers/cache.helper.mjs';
|
|
11
|
-
import { isReplicaVm,
|
|
11
|
+
import { isReplicaVm, isSrWritable, promiseWriteInStream, vmContainsNoBakTag } from '../helpers/utils.helper.mjs';
|
|
12
12
|
import { HostService } from '../hosts/host.service.mjs';
|
|
13
13
|
import { BackupLogService } from '../backup-logs/backup-log.service.mjs';
|
|
14
14
|
import { VmService } from '../vms/vm.service.mjs';
|
|
@@ -115,7 +115,7 @@ export class XoaService {
|
|
|
115
115
|
const pools = Object.values(this.#restApi.getObjectsByType('pool'));
|
|
116
116
|
const hosts = Object.values(this.#restApi.getObjectsByType('host'));
|
|
117
117
|
const srs = Object.values(this.#restApi.getObjectsByType('SR', {
|
|
118
|
-
filter:
|
|
118
|
+
filter: isSrWritable,
|
|
119
119
|
}));
|
|
120
120
|
if (pools.length === 0 && hosts.length === 0 && srs.length === 0) {
|
|
121
121
|
return { isEmpty: true };
|
|
@@ -243,7 +243,7 @@ export class XoaService {
|
|
|
243
243
|
}
|
|
244
244
|
#getStorageRepositoriesSizeInfo() {
|
|
245
245
|
const writableSrs = this.#restApi.getObjectsByType('SR', {
|
|
246
|
-
filter:
|
|
246
|
+
filter: isSrWritable,
|
|
247
247
|
});
|
|
248
248
|
const srs = Object.values(writableSrs);
|
|
249
249
|
if (srs.length === 0) {
|