@xen-orchestra/rest-api 0.27.0 → 0.28.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.
@@ -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
- constructor(restApi, vmService, poolService, alarmService) {
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 xapiPool = this.getXapiObject(poolId);
68
- const xapiNetwork = await xapiPool.$xapi.createNetwork({ pifId: pif, ...rest });
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'),
@@ -86,7 +86,7 @@ export class VmService {
86
86
  nSuspended++;
87
87
  break;
88
88
  default:
89
- log.warn('Invalid VM power_state', vm.id, vm.power_state);
89
+ log.warn('Invalid VM power_state', { vmId: vm.id, vmPowerState: vm.power_state });
90
90
  nUnknown++;
91
91
  break;
92
92
  }
@@ -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, isSrWritableOrIso, promiseWriteInStream, vmContainsNoBakTag } from '../helpers/utils.helper.mjs';
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: isSrWritableOrIso,
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: isSrWritableOrIso,
246
+ filter: isSrWritable,
247
247
  });
248
248
  const srs = Object.values(writableSrs);
249
249
  if (srs.length === 0) {