@xen-orchestra/rest-api 0.11.0 → 0.12.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.
Files changed (30) hide show
  1. package/dist/abstract-classes/base-controller.mjs +2 -2
  2. package/dist/alarms/alarm.controller.mjs +10 -60
  3. package/dist/alarms/alarm.service.mjs +67 -0
  4. package/dist/backup-repositories/backup-repositories.controller.mjs +61 -0
  5. package/dist/groups/group.controller.mjs +15 -2
  6. package/dist/helpers/object-wrapper.helper.mjs +8 -1
  7. package/dist/helpers/utils.helper.mjs +74 -1
  8. package/dist/hosts/host.controller.mjs +57 -2
  9. package/dist/hosts/host.service.mjs +78 -0
  10. package/dist/ioc/ioc.mjs +25 -1
  11. package/dist/messages/message.controller.mjs +1 -1
  12. package/dist/networks/network.controller.mjs +34 -2
  13. package/dist/open-api/oa-examples/alarm.oa-example.mjs +12 -0
  14. package/dist/open-api/oa-examples/backup-repository.oa-example.mjs +31 -0
  15. package/dist/open-api/oa-examples/pool.oa-example.mjs +201 -0
  16. package/dist/open-api/oa-examples/user.oa-example.mjs +1 -0
  17. package/dist/open-api/routes/routes.js +585 -76
  18. package/dist/pifs/pif.controller.mjs +34 -2
  19. package/dist/pools/pool.controller.mjs +70 -3
  20. package/dist/pools/pool.service.mjs +212 -0
  21. package/dist/rest-api/rest-api.mjs +6 -1
  22. package/dist/srs/sr.controller.mjs +34 -2
  23. package/dist/users/user.controller.mjs +32 -3
  24. package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +34 -2
  25. package/dist/vdis/vdi.controller.mjs +34 -2
  26. package/dist/vm-templates/vm-template.controller.mjs +34 -2
  27. package/dist/vms/vm.service.mjs +40 -0
  28. package/dist/xoa/xoa.service.mjs +96 -110
  29. package/open-api/spec/swagger.json +3248 -1133
  30. package/package.json +3 -3
@@ -10,13 +10,18 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
+ import { AlarmService } from '../alarms/alarm.service.mjs';
14
+ import { escapeUnsafeComplexMatcher } from '../helpers/utils.helper.mjs';
15
+ import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
13
16
  import { notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
14
17
  import { partialPifs, pif, pifIds } from '../open-api/oa-examples/pif.oa-example.mjs';
15
18
  import { RestApi } from '../rest-api/rest-api.mjs';
16
19
  import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
17
20
  let PifController = class PifController extends XapiXoController {
18
- constructor(restApi) {
21
+ #alarmService;
22
+ constructor(restApi, alarmService) {
19
23
  super('PIF', restApi);
24
+ this.#alarmService = alarmService;
20
25
  }
21
26
  /**
22
27
  * @example fields "attached,device,deviceName,id"
@@ -32,6 +37,20 @@ let PifController = class PifController extends XapiXoController {
32
37
  getPif(id) {
33
38
  return this.getObject(id);
34
39
  }
40
+ /**
41
+ * @example id "d9e42451-3794-089f-de81-4ee0e6137bee"
42
+ * @example fields "id,time"
43
+ * @example filter "time:>1747053793"
44
+ * @example limit 42
45
+ */
46
+ getPifAlarms(req, id, fields, ndjson, filter, limit) {
47
+ const pif = this.getObject(id);
48
+ const alarms = this.#alarmService.getAlarms({
49
+ filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${pif.uuid}`,
50
+ limit,
51
+ });
52
+ return this.sendObjects(Object.values(alarms), req, 'alarms');
53
+ }
35
54
  };
36
55
  __decorate([
37
56
  Example(pifIds),
@@ -49,12 +68,25 @@ __decorate([
49
68
  Response(notFoundResp.status, notFoundResp.description),
50
69
  __param(0, Path())
51
70
  ], PifController.prototype, "getPif", null);
71
+ __decorate([
72
+ Example(genericAlarmsExample),
73
+ Get('{id}/alarms'),
74
+ Tags('alarms'),
75
+ Response(notFoundResp.status, notFoundResp.description),
76
+ __param(0, Request()),
77
+ __param(1, Path()),
78
+ __param(2, Query()),
79
+ __param(3, Query()),
80
+ __param(4, Query()),
81
+ __param(5, Query())
82
+ ], PifController.prototype, "getPifAlarms", null);
52
83
  PifController = __decorate([
53
84
  Route('pifs'),
54
85
  Security('*'),
55
86
  Response(unauthorizedResp.status, unauthorizedResp.description),
56
87
  Tags('pifs'),
57
88
  provide(PifController),
58
- __param(0, inject(RestApi))
89
+ __param(0, inject(RestApi)),
90
+ __param(1, inject(AlarmService))
59
91
  ], PifController);
60
92
  export { PifController };
@@ -9,21 +9,30 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
9
9
  };
10
10
  import { Example, Get, Path, Query, Response, Request, Route, Security, Tags, Post, Middlewares, Body, SuccessResponse, } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
+ import { PassThrough } from 'node:stream';
12
13
  import { provide } from 'inversify-binding-decorators';
13
14
  import { json } from 'express';
14
15
  import { RestApi } from '../rest-api/rest-api.mjs';
15
16
  import { asynchronousActionResp, createdResp, featureUnauthorized, internalServerErrorResp, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
16
17
  import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
17
- import { createVm, importVm, partialPools, pool, poolIds, poolStats } from '../open-api/oa-examples/pool.oa-example.mjs';
18
+ import { AlarmService } from '../alarms/alarm.service.mjs';
19
+ import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
20
+ import { createVm, importVm, partialPools, pool, poolDashboard, poolIds, poolStats, } from '../open-api/oa-examples/pool.oa-example.mjs';
18
21
  import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs';
19
22
  import { createNetwork } from '../open-api/oa-examples/schedule.oa-example.mjs';
20
23
  import { BASE_URL } from '../index.mjs';
21
24
  import { VmService } from '../vms/vm.service.mjs';
25
+ import { PoolService } from './pool.service.mjs';
26
+ import { escapeUnsafeComplexMatcher, NDJSON_CONTENT_TYPE } from '../helpers/utils.helper.mjs';
22
27
  let PoolController = class PoolController extends XapiXoController {
23
28
  #vmService;
24
- constructor(restApi, vmService) {
29
+ #poolService;
30
+ #alarmService;
31
+ constructor(restApi, vmService, poolService, alarmService) {
25
32
  super('pool', restApi);
26
33
  this.#vmService = vmService;
34
+ this.#poolService = poolService;
35
+ this.#alarmService = alarmService;
27
36
  }
28
37
  /**
29
38
  *
@@ -176,6 +185,42 @@ let PoolController = class PoolController extends XapiXoController {
176
185
  getStats(id, granularity) {
177
186
  return this.restApi.xoApp.getXapiPoolStats(id, granularity);
178
187
  }
188
+ /**
189
+ * @example id "355ee47d-ff4c-4924-3db2-fd86ae629677"
190
+ */
191
+ async getPoolDashboard(req, id, ndjson) {
192
+ const poolId = id;
193
+ // throw if pool not found
194
+ this.getObject(poolId);
195
+ const stream = ndjson ? new PassThrough() : undefined;
196
+ const isStream = ndjson && stream !== undefined;
197
+ if (isStream) {
198
+ const res = req.res;
199
+ res.setHeader('Content-Type', NDJSON_CONTENT_TYPE);
200
+ stream.pipe(res);
201
+ }
202
+ const dashboard = await this.#poolService.getDashboard(poolId, { stream });
203
+ if (isStream) {
204
+ stream.end();
205
+ }
206
+ else {
207
+ return dashboard;
208
+ }
209
+ }
210
+ /**
211
+ * @example id "355ee47d-ff4c-4924-3db2-fd86ae629676"
212
+ * @example fields "id,time"
213
+ * @example filter "time:>1747053793"
214
+ * @example limit 42
215
+ */
216
+ getPoolAlarms(req, id, fields, ndjson, filter, limit) {
217
+ const pool = this.getObject(id);
218
+ const alarms = this.#alarmService.getAlarms({
219
+ filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${pool.uuid}`,
220
+ limit,
221
+ });
222
+ return this.sendObjects(Object.values(alarms), req, 'alarms');
223
+ }
179
224
  };
180
225
  __decorate([
181
226
  Example(poolIds),
@@ -270,6 +315,26 @@ __decorate([
270
315
  __param(0, Path()),
271
316
  __param(1, Query())
272
317
  ], PoolController.prototype, "getStats", null);
318
+ __decorate([
319
+ Example(poolDashboard),
320
+ Get('{id}/dashboard'),
321
+ Response(notFoundResp.status, notFoundResp.description),
322
+ __param(0, Request()),
323
+ __param(1, Path()),
324
+ __param(2, Query())
325
+ ], PoolController.prototype, "getPoolDashboard", null);
326
+ __decorate([
327
+ Example(genericAlarmsExample),
328
+ Get('{id}/alarms'),
329
+ Tags('alarms'),
330
+ Response(notFoundResp.status, notFoundResp.description),
331
+ __param(0, Request()),
332
+ __param(1, Path()),
333
+ __param(2, Query()),
334
+ __param(3, Query()),
335
+ __param(4, Query()),
336
+ __param(5, Query())
337
+ ], PoolController.prototype, "getPoolAlarms", null);
273
338
  PoolController = __decorate([
274
339
  Route('pools'),
275
340
  Security('*'),
@@ -277,6 +342,8 @@ PoolController = __decorate([
277
342
  Tags('pools'),
278
343
  provide(PoolController),
279
344
  __param(0, inject(RestApi)),
280
- __param(1, inject(VmService))
345
+ __param(1, inject(VmService)),
346
+ __param(2, inject(PoolService)),
347
+ __param(3, inject(AlarmService))
281
348
  ], PoolController);
282
349
  export { PoolController };
@@ -0,0 +1,212 @@
1
+ import { createLogger } from '@xen-orchestra/log';
2
+ import { HOST_POWER_STATE, VM_POWER_STATE, } from '@vates/types';
3
+ import { HostService } from '../hosts/host.service.mjs';
4
+ import { VmService } from '../vms/vm.service.mjs';
5
+ import { AlarmService } from '../alarms/alarm.service.mjs';
6
+ import { getTopPerProperty, isSrWritableOrIso, promiseWriteInStream } from '../helpers/utils.helper.mjs';
7
+ import { getFromAsyncCache } from '../helpers/cache.helper.mjs';
8
+ const log = createLogger('xo:rest-api:pool-service');
9
+ export class PoolService {
10
+ #restApi;
11
+ #hostService;
12
+ #vmService;
13
+ #alarmService;
14
+ #dashboardAsyncCache = new Map();
15
+ #dashboardCacheOpts;
16
+ constructor(restApi) {
17
+ this.#restApi = restApi;
18
+ this.#hostService = this.#restApi.ioc.get(HostService);
19
+ this.#vmService = this.#restApi.ioc.get(VmService);
20
+ this.#alarmService = this.#restApi.ioc.get(AlarmService);
21
+ this.#dashboardCacheOpts = {
22
+ timeout: this.#restApi.xoApp.config.getOptionalDuration('rest-api.dashboardCacheTimeout') ?? 60000,
23
+ expiresIn: this.#restApi.xoApp.config.getOptionalDuration('rest-api.dashboardCacheExpiresIn'),
24
+ };
25
+ }
26
+ #getHostsStatus(poolId) {
27
+ const { running, disabled, halted, total } = this.#hostService.getHostsStatus({
28
+ filter: host => host.$pool === poolId,
29
+ });
30
+ return { running, disabled, halted, total };
31
+ }
32
+ #getVmsStatus(poolId) {
33
+ const { running, halted, paused, total, suspended } = this.#vmService.getVmsStatus({
34
+ filter: vm => vm.$pool === poolId,
35
+ });
36
+ return {
37
+ running,
38
+ halted,
39
+ paused,
40
+ total,
41
+ suspended,
42
+ };
43
+ }
44
+ #getAlarms(poolId) {
45
+ const alarms = this.#alarmService.getAlarms({ filter: alarm => alarm.$pool === poolId });
46
+ return Object.keys(alarms);
47
+ }
48
+ async #getMissingPatches(poolId) {
49
+ const missingPatchesInfo = await this.#hostService.getMissingPatchesInfo({ filter: host => host.$pool === poolId });
50
+ if (!missingPatchesInfo.hasAuthorization) {
51
+ return {
52
+ hasAuthorization: false,
53
+ };
54
+ }
55
+ const { hasAuthorization, missingPatches } = missingPatchesInfo;
56
+ return {
57
+ hasAuthorization,
58
+ missingPatches,
59
+ };
60
+ }
61
+ #getTopFiveSrsUsage(poolId) {
62
+ const srs = Object.values(this.#restApi.getObjectsByType('SR', {
63
+ filter: sr => sr.$pool === poolId && isSrWritableOrIso(sr),
64
+ }));
65
+ const topFive = getTopPerProperty(srs.map(({ name_label, id, physical_usage, size }) => ({
66
+ name_label,
67
+ id,
68
+ percent: (physical_usage / size) * 100,
69
+ physical_usage,
70
+ size,
71
+ })), { prop: 'percent', length: 5 });
72
+ return topFive;
73
+ }
74
+ #getTopFiveHostsRamUsage(poolId) {
75
+ const hosts = Object.values(this.#restApi.getObjectsByType('host', {
76
+ filter: host => host.$pool === poolId && host.power_state === HOST_POWER_STATE.RUNNING,
77
+ }));
78
+ const topFive = getTopPerProperty(hosts.map(({ name_label, id, memory: { size, usage } }) => ({
79
+ name_label,
80
+ id,
81
+ size,
82
+ usage,
83
+ percent: (usage / size) * 100,
84
+ })), { length: 5, prop: 'percent' });
85
+ return topFive;
86
+ }
87
+ #getVmWithLastRamInfo(vm, stats) {
88
+ const memory = stats.stats.memory?.pop() ?? 0;
89
+ const memoryFree = stats.stats.memoryFree?.pop() ?? 0;
90
+ const usage = memory - memoryFree;
91
+ return { ...vm, memoryStats: { memory, memoryFree, usage } };
92
+ }
93
+ #getVmWithLastCpuInfo(vm, stats) {
94
+ const cpusStats = Object.values(stats.stats.cpus ?? {});
95
+ const usage = cpusStats.reduce((total, cpuStats, index) => {
96
+ const lastCpuStat = cpuStats.pop();
97
+ if (lastCpuStat == null) {
98
+ log.warn(`cpu#${index} is null. vm:`, vm.id);
99
+ }
100
+ total += lastCpuStat ?? 0;
101
+ return total;
102
+ }, 0) / cpusStats.length;
103
+ return { ...vm, usage };
104
+ }
105
+ async #getTopFiveVmsRamCpuUsage(poolId) {
106
+ const vmsUsageResult = await getFromAsyncCache(this.#dashboardAsyncCache, 'vmsRamCpuUsage', async () => {
107
+ const vms = this.#restApi.getObjectsByType('VM', {
108
+ filter: vm => vm.$pool === poolId &&
109
+ (vm.power_state === VM_POWER_STATE.RUNNING || vm.power_state === VM_POWER_STATE.PAUSED),
110
+ });
111
+ const vmsWithRamInfo = [];
112
+ const vmsWithCpuInfo = [];
113
+ for (const id in vms) {
114
+ const vm = vms[id];
115
+ const stats = await this.#restApi.xoApp.getXapiVmStats(vm.id);
116
+ if (vm.managementAgentDetected) {
117
+ const { memoryStats: { memory, memoryFree, usage }, } = this.#getVmWithLastRamInfo(vm, stats);
118
+ vmsWithRamInfo.push({
119
+ id: vm.id,
120
+ name_label: vm.name_label,
121
+ memory,
122
+ memoryFree,
123
+ percent: (usage / memory) * 100,
124
+ });
125
+ }
126
+ const { usage: cpuUsage } = this.#getVmWithLastCpuInfo(vm, stats);
127
+ vmsWithCpuInfo.push({ id: vm.id, name_label: vm.name_label, percent: cpuUsage });
128
+ }
129
+ const topFiveRamUsage = getTopPerProperty(vmsWithRamInfo, { prop: 'percent', length: 5 });
130
+ const topFiveCpuUsage = getTopPerProperty(vmsWithCpuInfo, { prop: 'percent', length: 5 });
131
+ return {
132
+ ram: topFiveRamUsage,
133
+ cpu: topFiveCpuUsage,
134
+ };
135
+ }, this.#dashboardCacheOpts);
136
+ if (vmsUsageResult?.value !== undefined) {
137
+ return { ...vmsUsageResult.value, isExpired: vmsUsageResult.isExpired };
138
+ }
139
+ }
140
+ async #getTopFiveHostsCpuUsage(poolId) {
141
+ const hosts = this.#restApi.getObjectsByType('host', {
142
+ filter: host => host.$pool === poolId && host.power_state === HOST_POWER_STATE.RUNNING,
143
+ });
144
+ const hostsWithPercent = [];
145
+ for (const id in hosts) {
146
+ const host = hosts[id];
147
+ const stats = await this.#restApi.xoApp.getXapiHostStats(host.id, 'seconds');
148
+ const cpusStats = Object.values(stats.stats.cpus ?? {});
149
+ const percent = cpusStats.reduce((total, cpuStats, index) => {
150
+ const lastCpuStat = cpuStats.pop();
151
+ if (lastCpuStat == null) {
152
+ log.warn(`cpu#${index} is null. host:`, host.id);
153
+ }
154
+ total += lastCpuStat ?? 0;
155
+ return total;
156
+ }, 0) / cpusStats.length;
157
+ hostsWithPercent.push({ percent, id: host.id, name_label: host.name_label });
158
+ }
159
+ const topFive = getTopPerProperty(hostsWithPercent, { prop: 'percent', length: 5 });
160
+ return topFive;
161
+ }
162
+ #getCpuProvisioning(poolId) {
163
+ const pool = this.#restApi.getObject(poolId, 'pool');
164
+ const vms = this.#restApi.getObjectsByType('VM', {
165
+ filter: vm => vm.$pool === poolId && (vm.power_state === VM_POWER_STATE.RUNNING || vm.power_state === VM_POWER_STATE.PAUSED),
166
+ });
167
+ let assignedVcpu = 0;
168
+ for (const id in vms) {
169
+ const vm = vms[id];
170
+ assignedVcpu += vm.CPUs.number;
171
+ }
172
+ const total = pool.cpus.cores ?? 0;
173
+ const percent = total === 0 ? 0 : (assignedVcpu * 100) / total;
174
+ return {
175
+ total,
176
+ assigned: assignedVcpu,
177
+ percent,
178
+ };
179
+ }
180
+ async getDashboard(id, { stream } = {}) {
181
+ const [hostStatus, vmsStatus, alarms, missingPatches, storageUsage, hostsRamUsage, hostsCpuUsage, cpuProvisioning, vmsUsage,] = await Promise.all([
182
+ promiseWriteInStream({ maybePromise: this.#getHostsStatus(id), path: 'hosts.status', stream }),
183
+ promiseWriteInStream({ maybePromise: this.#getVmsStatus(id), path: 'vms.status', stream }),
184
+ promiseWriteInStream({ maybePromise: this.#getAlarms(id), path: 'alarms', stream }),
185
+ promiseWriteInStream({ maybePromise: this.#getMissingPatches(id), path: 'hosts.missingPatches', stream }),
186
+ promiseWriteInStream({ maybePromise: this.#getTopFiveSrsUsage(id), path: 'srs.topFiveUsage', stream }),
187
+ promiseWriteInStream({ maybePromise: this.#getTopFiveHostsRamUsage(id), path: 'hosts.topFiveUsage.ram', stream }),
188
+ promiseWriteInStream({ maybePromise: this.#getTopFiveHostsCpuUsage(id), path: 'hosts.topFiveUsage.cpu', stream }),
189
+ promiseWriteInStream({ maybePromise: this.#getCpuProvisioning(id), path: 'cpuProvisioning', stream }),
190
+ promiseWriteInStream({ maybePromise: this.#getTopFiveVmsRamCpuUsage(id), path: 'vms.topFiveUsage', stream }),
191
+ ]);
192
+ return {
193
+ hosts: {
194
+ status: hostStatus,
195
+ topFiveUsage: {
196
+ ram: hostsRamUsage,
197
+ cpu: hostsCpuUsage,
198
+ },
199
+ missingPatches,
200
+ },
201
+ vms: {
202
+ status: vmsStatus,
203
+ topFiveUsage: vmsUsage,
204
+ },
205
+ srs: {
206
+ topFiveUsage: storageUsage,
207
+ },
208
+ alarms,
209
+ cpuProvisioning,
210
+ };
211
+ }
212
+ }
@@ -1,7 +1,9 @@
1
1
  export class RestApi {
2
+ #ioc;
2
3
  #xoApp;
3
- constructor(xoApp) {
4
+ constructor(xoApp, iocContainer) {
4
5
  this.#xoApp = xoApp;
6
+ this.#ioc = iocContainer;
5
7
  }
6
8
  get tasks() {
7
9
  return this.#xoApp.tasks;
@@ -9,6 +11,9 @@ export class RestApi {
9
11
  get xoApp() {
10
12
  return this.#xoApp;
11
13
  }
14
+ get ioc() {
15
+ return this.#ioc;
16
+ }
12
17
  authenticateUser(...args) {
13
18
  return this.#xoApp.authenticateUser(...args);
14
19
  }
@@ -10,13 +10,18 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
+ import { AlarmService } from '../alarms/alarm.service.mjs';
14
+ import { escapeUnsafeComplexMatcher } from '../helpers/utils.helper.mjs';
15
+ import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
13
16
  import { notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
14
17
  import { partialSrs, sr, srIds } from '../open-api/oa-examples/sr.oa-example.mjs';
15
18
  import { RestApi } from '../rest-api/rest-api.mjs';
16
19
  import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
17
20
  let SrController = class SrController extends XapiXoController {
18
- constructor(restApi) {
21
+ #alarmService;
22
+ constructor(restApi, alarmService) {
19
23
  super('SR', restApi);
24
+ this.#alarmService = alarmService;
20
25
  }
21
26
  /**
22
27
  * @example fields "uuid,name_label,allocationStrategy"
@@ -32,6 +37,20 @@ let SrController = class SrController extends XapiXoController {
32
37
  getSr(id) {
33
38
  return this.getObject(id);
34
39
  }
40
+ /**
41
+ * @example id "c4284e12-37c9-7967-b9e8-83ef229c3e03"
42
+ * @example fields "id,time"
43
+ * @example filter "time:>1747053793"
44
+ * @example limit 42
45
+ */
46
+ getSrAlarms(req, id, fields, ndjson, filter, limit) {
47
+ const sr = this.getObject(id);
48
+ const alarms = this.#alarmService.getAlarms({
49
+ filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${sr.uuid}`,
50
+ limit,
51
+ });
52
+ return this.sendObjects(Object.values(alarms), req, 'alarms');
53
+ }
35
54
  };
36
55
  __decorate([
37
56
  Example(srIds),
@@ -49,12 +68,25 @@ __decorate([
49
68
  Response(notFoundResp.status, notFoundResp.description),
50
69
  __param(0, Path())
51
70
  ], SrController.prototype, "getSr", null);
71
+ __decorate([
72
+ Example(genericAlarmsExample),
73
+ Get('{id}/alarms'),
74
+ Tags('alarms'),
75
+ Response(notFoundResp.status, notFoundResp.description),
76
+ __param(0, Request()),
77
+ __param(1, Path()),
78
+ __param(2, Query()),
79
+ __param(3, Query()),
80
+ __param(4, Query()),
81
+ __param(5, Query())
82
+ ], SrController.prototype, "getSrAlarms", null);
52
83
  SrController = __decorate([
53
84
  Route('srs'),
54
85
  Security('*'),
55
86
  Response(unauthorizedResp.status, unauthorizedResp.description),
56
87
  Tags('srs'),
57
88
  provide(SrController),
58
- __param(0, inject(RestApi))
89
+ __param(0, inject(RestApi)),
90
+ __param(1, inject(AlarmService))
59
91
  ], SrController);
60
92
  export { SrController };
@@ -7,10 +7,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __param = (this && this.__param) || function (paramIndex, decorator) {
8
8
  return function (target, key) { decorator(target, key, paramIndex); }
9
9
  };
10
- import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
10
+ import { Body, Delete, Example, Get, Middlewares, Path, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags, } from 'tsoa';
11
+ import { json } from 'express';
11
12
  import { provide } from 'inversify-binding-decorators';
12
- import { notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
13
- import { partialUsers, user, userIds } from '../open-api/oa-examples/user.oa-example.mjs';
13
+ import { createdResp, invalidParameters, noContentResp, notFoundResp, unauthorizedResp, } from '../open-api/common/response.common.mjs';
14
+ import { partialUsers, user, userId, userIds } from '../open-api/oa-examples/user.oa-example.mjs';
14
15
  import { XoController } from '../abstract-classes/xo-controller.mjs';
15
16
  let UserController = class UserController extends XoController {
16
17
  // --- abstract methods
@@ -44,6 +45,19 @@ let UserController = class UserController extends XoController {
44
45
  getUser(id) {
45
46
  return this.getObject(id);
46
47
  }
48
+ /**
49
+ * @example body { "name": "new user", "password": "password", "permission": "none" }
50
+ */
51
+ async createUser(body) {
52
+ const user = await this.restApi.xoApp.createUser(body);
53
+ return { id: user.id };
54
+ }
55
+ /**
56
+ * @example id "722d17b9-699b-49d2-8193-be1ac573d3de"
57
+ */
58
+ async deleteUser(id) {
59
+ await this.restApi.xoApp.deleteUser(id);
60
+ }
47
61
  };
48
62
  __decorate([
49
63
  Example(userIds),
@@ -61,6 +75,21 @@ __decorate([
61
75
  Response(notFoundResp.status, notFoundResp.description),
62
76
  __param(0, Path())
63
77
  ], UserController.prototype, "getUser", null);
78
+ __decorate([
79
+ Example(userId),
80
+ Post(''),
81
+ Middlewares(json()),
82
+ SuccessResponse(createdResp.status, createdResp.description),
83
+ Response(unauthorizedResp.status, unauthorizedResp.description),
84
+ Response(invalidParameters.status, invalidParameters.description),
85
+ __param(0, Body())
86
+ ], UserController.prototype, "createUser", null);
87
+ __decorate([
88
+ Delete('{id}'),
89
+ SuccessResponse(noContentResp.status, noContentResp.description),
90
+ Response(notFoundResp.status, notFoundResp.description),
91
+ __param(0, Path())
92
+ ], UserController.prototype, "deleteUser", null);
64
93
  UserController = __decorate([
65
94
  Route('users'),
66
95
  Security('*'),
@@ -10,13 +10,18 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
+ import { escapeUnsafeComplexMatcher } from '../helpers/utils.helper.mjs';
13
14
  import { notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
14
15
  import { RestApi } from '../rest-api/rest-api.mjs';
15
16
  import { partialVdiSnapshots, vdiSnapshot, vdiSnapshotIds } from '../open-api/oa-examples/vdi-snapshot.oa-example.mjs';
16
17
  import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
18
+ import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
19
+ import { AlarmService } from '../alarms/alarm.service.mjs';
17
20
  let VdiSnapshotController = class VdiSnapshotController extends XapiXoController {
18
- constructor(restApi) {
21
+ #alarmService;
22
+ constructor(restApi, alarmService) {
19
23
  super('VDI-snapshot', restApi);
24
+ this.#alarmService = alarmService;
20
25
  }
21
26
  /**
22
27
  * @example fields "uuid,snapshot_time,$snapshot_of"
@@ -32,6 +37,20 @@ let VdiSnapshotController = class VdiSnapshotController extends XapiXoController
32
37
  getVdiSnapshot(id) {
33
38
  return this.getObject(id);
34
39
  }
40
+ /**
41
+ * @example id "d2727772-735b-478f-b6f9-11e7db56dfd0"
42
+ * @example fields "id,time"
43
+ * @example filter "time:>1747053793"
44
+ * @example limit 42
45
+ */
46
+ getVdiSnapshotAlarms(req, id, fields, ndjson, filter, limit) {
47
+ const vdiSnapshot = this.getObject(id);
48
+ const alarms = this.#alarmService.getAlarms({
49
+ filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${vdiSnapshot.uuid}`,
50
+ limit,
51
+ });
52
+ return this.sendObjects(Object.values(alarms), req, 'alarms');
53
+ }
35
54
  };
36
55
  __decorate([
37
56
  Example(vdiSnapshotIds),
@@ -49,12 +68,25 @@ __decorate([
49
68
  Response(notFoundResp.status, notFoundResp.description),
50
69
  __param(0, Path())
51
70
  ], VdiSnapshotController.prototype, "getVdiSnapshot", null);
71
+ __decorate([
72
+ Example(genericAlarmsExample),
73
+ Get('{id}/alarms'),
74
+ Tags('alarms'),
75
+ Response(notFoundResp.status, notFoundResp.description),
76
+ __param(0, Request()),
77
+ __param(1, Path()),
78
+ __param(2, Query()),
79
+ __param(3, Query()),
80
+ __param(4, Query()),
81
+ __param(5, Query())
82
+ ], VdiSnapshotController.prototype, "getVdiSnapshotAlarms", null);
52
83
  VdiSnapshotController = __decorate([
53
84
  Route('vdi-snapshots'),
54
85
  Security('*'),
55
86
  Response(unauthorizedResp.status, unauthorizedResp.description),
56
87
  Tags('vdis'),
57
88
  provide(VdiSnapshotController),
58
- __param(0, inject(RestApi))
89
+ __param(0, inject(RestApi)),
90
+ __param(1, inject(AlarmService))
59
91
  ], VdiSnapshotController);
60
92
  export { VdiSnapshotController };
@@ -10,13 +10,18 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
10
10
  import { Example, Get, Path, Query, Request, Response, Route, Security, Tags } from 'tsoa';
11
11
  import { inject } from 'inversify';
12
12
  import { provide } from 'inversify-binding-decorators';
13
+ import { AlarmService } from '../alarms/alarm.service.mjs';
14
+ import { escapeUnsafeComplexMatcher } from '../helpers/utils.helper.mjs';
15
+ import { genericAlarmsExample } from '../open-api/oa-examples/alarm.oa-example.mjs';
13
16
  import { notFoundResp, unauthorizedResp } from '../open-api/common/response.common.mjs';
14
17
  import { RestApi } from '../rest-api/rest-api.mjs';
15
18
  import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
16
19
  import { partialVdis, vdi, vdiIds } from '../open-api/oa-examples/vdi.oa-example.mjs';
17
20
  let VdiController = class VdiController extends XapiXoController {
18
- constructor(restApi) {
21
+ #alarmService;
22
+ constructor(restApi, alarmService) {
19
23
  super('VDI', restApi);
24
+ this.#alarmService = alarmService;
20
25
  }
21
26
  /**
22
27
  * @example fields "*"
@@ -32,6 +37,20 @@ let VdiController = class VdiController extends XapiXoController {
32
37
  getVdi(id) {
33
38
  return this.getObject(id);
34
39
  }
40
+ /**
41
+ * @example id "c77f9955-c1d2-4b39-aa1c-73cdb2dacb7e"
42
+ * @example fields "id,time"
43
+ * @example filter "time:>1747053793"
44
+ * @example limit 42
45
+ */
46
+ getVdiAlarms(req, id, fields, ndjson, filter, limit) {
47
+ const vdi = this.getObject(id);
48
+ const alarms = this.#alarmService.getAlarms({
49
+ filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${vdi.uuid}`,
50
+ limit,
51
+ });
52
+ return this.sendObjects(Object.values(alarms), req, 'alarms');
53
+ }
35
54
  };
36
55
  __decorate([
37
56
  Example(vdiIds),
@@ -49,12 +68,25 @@ __decorate([
49
68
  Response(notFoundResp.status, notFoundResp.description),
50
69
  __param(0, Path())
51
70
  ], VdiController.prototype, "getVdi", null);
71
+ __decorate([
72
+ Example(genericAlarmsExample),
73
+ Get('{id}/alarms'),
74
+ Tags('alarms'),
75
+ Response(notFoundResp.status, notFoundResp.description),
76
+ __param(0, Request()),
77
+ __param(1, Path()),
78
+ __param(2, Query()),
79
+ __param(3, Query()),
80
+ __param(4, Query()),
81
+ __param(5, Query())
82
+ ], VdiController.prototype, "getVdiAlarms", null);
52
83
  VdiController = __decorate([
53
84
  Route('vdis'),
54
85
  Security('*'),
55
86
  Response(unauthorizedResp.status, unauthorizedResp.description),
56
87
  Tags('vdis'),
57
88
  provide(VdiController),
58
- __param(0, inject(RestApi))
89
+ __param(0, inject(RestApi)),
90
+ __param(1, inject(AlarmService))
59
91
  ], VdiController);
60
92
  export { VdiController };