@xen-orchestra/rest-api 0.10.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.
- package/dist/abstract-classes/base-controller.mjs +24 -2
- package/dist/alarms/alarm.controller.mjs +11 -61
- package/dist/alarms/alarm.service.mjs +67 -0
- package/dist/backup-repositories/backup-repositories.controller.mjs +61 -0
- package/dist/groups/group.controller.mjs +15 -2
- package/dist/helpers/object-wrapper.helper.mjs +8 -1
- package/dist/helpers/utils.helper.mjs +74 -1
- package/dist/hosts/host.controller.mjs +87 -3
- package/dist/hosts/host.service.mjs +78 -0
- package/dist/ioc/ioc.mjs +25 -1
- package/dist/messages/message.controller.mjs +2 -2
- package/dist/middlewares/generic-error-handler.middleware.mjs +15 -11
- package/dist/middlewares/tsoa-to-xo-error.middleware.mjs +1 -1
- package/dist/networks/network.controller.mjs +34 -2
- package/dist/open-api/oa-examples/alarm.oa-example.mjs +12 -0
- package/dist/open-api/oa-examples/backup-repository.oa-example.mjs +31 -0
- package/dist/open-api/oa-examples/pool.oa-example.mjs +401 -0
- package/dist/open-api/oa-examples/user.oa-example.mjs +1 -0
- package/dist/open-api/routes/routes.js +708 -113
- package/dist/pifs/pif.controller.mjs +34 -2
- package/dist/pools/pool.controller.mjs +84 -3
- package/dist/pools/pool.service.mjs +212 -0
- package/dist/rest-api/rest-api.mjs +6 -1
- package/dist/srs/sr.controller.mjs +34 -2
- package/dist/users/user.controller.mjs +32 -3
- package/dist/vdi-snapshots/vdi-snapshot.controller.mjs +34 -2
- package/dist/vdis/vdi.controller.mjs +34 -2
- package/dist/vm-templates/vm-template.controller.mjs +34 -2
- package/dist/vms/vm.controller.mjs +1 -1
- package/dist/vms/vm.service.mjs +40 -0
- package/dist/xoa/xoa.service.mjs +96 -110
- package/open-api/spec/swagger.json +6069 -1899
- 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 { 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
|
-
|
|
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 };
|
|
@@ -10,13 +10,18 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
10
10
|
import { Example, Get, Security, Query, Request, Response, Route, Tags, Path } 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 { partialVmTemplates, vmTemplate, vmTemplateIds } from '../open-api/oa-examples/vm-template.oa-example.mjs';
|
|
17
20
|
let VmTemplateController = class VmTemplateController extends XapiXoController {
|
|
18
|
-
|
|
21
|
+
#alarmService;
|
|
22
|
+
constructor(restApi, alarmService) {
|
|
19
23
|
super('VM-template', restApi);
|
|
24
|
+
this.#alarmService = alarmService;
|
|
20
25
|
}
|
|
21
26
|
/**
|
|
22
27
|
* @example fields "id,isDefaultTemplate,name_label"
|
|
@@ -32,6 +37,20 @@ let VmTemplateController = class VmTemplateController extends XapiXoController {
|
|
|
32
37
|
getVmTemplate(id) {
|
|
33
38
|
return this.getObject(id);
|
|
34
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* @example id "b7569d99-30f8-178a-7d94-801de3e29b5b-f873abe0-b138-4995-8f6f-498b423d234d"
|
|
42
|
+
* @example fields "id,time"
|
|
43
|
+
* @example filter "time:>1747053793"
|
|
44
|
+
* @example limit 42
|
|
45
|
+
*/
|
|
46
|
+
getVmTemplateAlarms(req, id, fields, ndjson, filter, limit) {
|
|
47
|
+
const vmTemplate = this.getObject(id);
|
|
48
|
+
const alarms = this.#alarmService.getAlarms({
|
|
49
|
+
filter: `${escapeUnsafeComplexMatcher(filter) ?? ''} object:uuid:${vmTemplate.uuid}`,
|
|
50
|
+
limit,
|
|
51
|
+
});
|
|
52
|
+
return this.sendObjects(Object.values(alarms), req, 'alarms');
|
|
53
|
+
}
|
|
35
54
|
};
|
|
36
55
|
__decorate([
|
|
37
56
|
Example(vmTemplateIds),
|
|
@@ -49,12 +68,25 @@ __decorate([
|
|
|
49
68
|
Response(notFoundResp.status, notFoundResp.description),
|
|
50
69
|
__param(0, Path())
|
|
51
70
|
], VmTemplateController.prototype, "getVmTemplate", 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
|
+
], VmTemplateController.prototype, "getVmTemplateAlarms", null);
|
|
52
83
|
VmTemplateController = __decorate([
|
|
53
84
|
Route('vm-templates'),
|
|
54
85
|
Security('*'),
|
|
55
86
|
Response(unauthorizedResp.status, unauthorizedResp.description),
|
|
56
87
|
Tags('vms'),
|
|
57
88
|
provide(VmTemplateController),
|
|
58
|
-
__param(0, inject(RestApi))
|
|
89
|
+
__param(0, inject(RestApi)),
|
|
90
|
+
__param(1, inject(AlarmService))
|
|
59
91
|
], VmTemplateController);
|
|
60
92
|
export { VmTemplateController };
|
|
@@ -52,7 +52,7 @@ let VmController = class VmController extends XapiXoController {
|
|
|
52
52
|
if (incorrectState.is(error, {
|
|
53
53
|
property: 'resident_on',
|
|
54
54
|
})) {
|
|
55
|
-
|
|
55
|
+
throw invalidParameters(`VM ${id} is halted or host could not be found.`, error);
|
|
56
56
|
}
|
|
57
57
|
throw error;
|
|
58
58
|
}
|
package/dist/vms/vm.service.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createLogger } from '@xen-orchestra/log';
|
|
2
2
|
import { defer } from 'golike-defer';
|
|
3
3
|
import { Task } from '@vates/task';
|
|
4
|
+
import { VM_POWER_STATE, } from '@vates/types';
|
|
4
5
|
const log = createLogger('xo:rest-api:vm-service');
|
|
5
6
|
export class VmService {
|
|
6
7
|
#restApi;
|
|
@@ -44,4 +45,43 @@ export class VmService {
|
|
|
44
45
|
return xoVm.id;
|
|
45
46
|
}
|
|
46
47
|
create = defer(this.#create);
|
|
48
|
+
getVmsStatus(opts) {
|
|
49
|
+
const vms = this.#restApi.getObjectsByType('VM', opts);
|
|
50
|
+
let nRunning = 0;
|
|
51
|
+
let nPaused = 0;
|
|
52
|
+
let nSuspended = 0;
|
|
53
|
+
let nHalted = 0;
|
|
54
|
+
let nUnknown = 0;
|
|
55
|
+
let total = 0;
|
|
56
|
+
for (const id in vms) {
|
|
57
|
+
total++;
|
|
58
|
+
const vm = vms[id];
|
|
59
|
+
switch (vm.power_state) {
|
|
60
|
+
case VM_POWER_STATE.RUNNING:
|
|
61
|
+
nRunning++;
|
|
62
|
+
break;
|
|
63
|
+
case VM_POWER_STATE.HALTED:
|
|
64
|
+
nHalted++;
|
|
65
|
+
break;
|
|
66
|
+
case VM_POWER_STATE.PAUSED:
|
|
67
|
+
nPaused++;
|
|
68
|
+
break;
|
|
69
|
+
case VM_POWER_STATE.SUSPENDED:
|
|
70
|
+
nSuspended++;
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
log.warn('Invalid VM power_state', vm.id, vm.power_state);
|
|
74
|
+
nUnknown++;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
running: nRunning,
|
|
80
|
+
halted: nHalted,
|
|
81
|
+
paused: nPaused,
|
|
82
|
+
suspended: nSuspended,
|
|
83
|
+
unknown: nUnknown,
|
|
84
|
+
total,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
47
87
|
}
|
package/dist/xoa/xoa.service.mjs
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import groupBy from 'lodash/groupBy.js';
|
|
2
2
|
import semver from 'semver';
|
|
3
|
-
import { BACKUP_TYPE,
|
|
4
|
-
import { asyncEach } from '@vates/async-each';
|
|
3
|
+
import { BACKUP_TYPE, VM_POWER_STATE, } from '@vates/types';
|
|
5
4
|
import { createLogger } from '@xen-orchestra/log';
|
|
6
5
|
import { createPredicate } from 'value-matcher';
|
|
7
6
|
import { extractIdsFromSimplePattern } from '@xen-orchestra/backups/extractIdsFromSimplePattern.mjs';
|
|
8
|
-
import { isPromise } from 'node:util/types';
|
|
9
7
|
import { noSuchObject } from 'xo-common/api-errors.js';
|
|
10
8
|
import { parse } from 'xo-remote-parser';
|
|
11
9
|
import { getFromAsyncCache } from '../helpers/cache.helper.mjs';
|
|
12
|
-
import { isReplicaVm,
|
|
10
|
+
import { isReplicaVm, isSrWritableOrIso, promiseWriteInStream, vmContainsNoBakTag } from '../helpers/utils.helper.mjs';
|
|
11
|
+
import { HostService } from '../hosts/host.service.mjs';
|
|
13
12
|
const log = createLogger('xo:rest-api:xoa-service');
|
|
14
13
|
export class XoaService {
|
|
15
14
|
#restApi;
|
|
15
|
+
#hostService;
|
|
16
16
|
#dashboardAsyncCache = new Map();
|
|
17
17
|
#dashboardCacheOpts;
|
|
18
18
|
constructor(restApi) {
|
|
19
19
|
this.#restApi = restApi;
|
|
20
|
+
this.#hostService = restApi.ioc.get(HostService);
|
|
20
21
|
this.#dashboardCacheOpts = {
|
|
21
22
|
timeout: this.#restApi.xoApp.config.getOptionalDuration('rest-api.dashboardCacheTimeout') ?? 60000,
|
|
22
23
|
expiresIn: this.#restApi.xoApp.config.getOptionalDuration('rest-api.dashboardCacheExpiresIn'),
|
|
@@ -25,15 +26,12 @@ export class XoaService {
|
|
|
25
26
|
async #getBackupRepositoriesSizeInfo() {
|
|
26
27
|
const brResult = await getFromAsyncCache(this.#dashboardAsyncCache, 'backupRepositories', async () => {
|
|
27
28
|
const xoApp = this.#restApi.xoApp;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
available: 0,
|
|
31
|
-
backups: 0,
|
|
32
|
-
other: 0,
|
|
33
|
-
total: 0,
|
|
34
|
-
used: 0,
|
|
35
|
-
};
|
|
29
|
+
let s3Brsize;
|
|
30
|
+
let otherBrSize;
|
|
36
31
|
const backupRepositories = await xoApp.getAllRemotes();
|
|
32
|
+
if (backupRepositories.length === 0) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
37
35
|
const backupRepositoriesInfo = await xoApp.getAllRemotesInfo();
|
|
38
36
|
for (const backupRepository of backupRepositories) {
|
|
39
37
|
const { type } = parse(backupRepository.url);
|
|
@@ -44,17 +42,48 @@ export class XoaService {
|
|
|
44
42
|
const totalBackupSize = await xoApp.getTotalBackupSizeOnRemote(backupRepository.id);
|
|
45
43
|
const { available, size, used } = backupRepositoryInfo;
|
|
46
44
|
const isS3 = type === 's3';
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
45
|
+
if (isS3) {
|
|
46
|
+
if (s3Brsize === undefined) {
|
|
47
|
+
s3Brsize = { size: { backups: 0 } };
|
|
48
|
+
}
|
|
49
|
+
s3Brsize.size.backups += totalBackupSize.onDisk;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
if (otherBrSize === undefined) {
|
|
53
|
+
otherBrSize = {
|
|
54
|
+
size: {
|
|
55
|
+
backups: 0,
|
|
56
|
+
available: undefined,
|
|
57
|
+
other: undefined,
|
|
58
|
+
total: undefined,
|
|
59
|
+
used: undefined,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (available === undefined || size === undefined || used === undefined) {
|
|
64
|
+
log.info('#getBackupRepositoriesSizeInfo missing info for BR:', backupRepository.id);
|
|
65
|
+
}
|
|
66
|
+
otherBrSize.size.backups += totalBackupSize.onDisk;
|
|
67
|
+
if (available !== undefined) {
|
|
68
|
+
otherBrSize.size.available = (otherBrSize.size.available ?? 0) + available;
|
|
69
|
+
}
|
|
70
|
+
if (used !== undefined) {
|
|
71
|
+
otherBrSize.size.used = (otherBrSize.size.used ?? 0) + used;
|
|
72
|
+
otherBrSize.size.other = (otherBrSize.size.other ?? 0) + (used - totalBackupSize.onDisk);
|
|
73
|
+
}
|
|
74
|
+
if (size !== undefined) {
|
|
75
|
+
otherBrSize.size.total = (otherBrSize.size.total ?? 0) + size;
|
|
76
|
+
}
|
|
55
77
|
}
|
|
56
78
|
}
|
|
57
|
-
|
|
79
|
+
const result = {};
|
|
80
|
+
if (s3Brsize !== undefined) {
|
|
81
|
+
result.s3 = s3Brsize;
|
|
82
|
+
}
|
|
83
|
+
if (otherBrSize !== undefined) {
|
|
84
|
+
result.other = otherBrSize;
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
58
87
|
}, this.#dashboardCacheOpts);
|
|
59
88
|
if (brResult?.value !== undefined) {
|
|
60
89
|
return { ...brResult.value, isExpired: brResult.isExpired };
|
|
@@ -71,15 +100,15 @@ export class XoaService {
|
|
|
71
100
|
#getResourcesOverview() {
|
|
72
101
|
const pools = Object.values(this.#restApi.getObjectsByType('pool'));
|
|
73
102
|
const hosts = Object.values(this.#restApi.getObjectsByType('host'));
|
|
74
|
-
const
|
|
75
|
-
filter:
|
|
103
|
+
const srs = Object.values(this.#restApi.getObjectsByType('SR', {
|
|
104
|
+
filter: isSrWritableOrIso,
|
|
76
105
|
}));
|
|
77
|
-
const maxLenght = Math.max(hosts.length,
|
|
106
|
+
const maxLenght = Math.max(hosts.length, srs.length);
|
|
78
107
|
const resourcesOverview = { nCpus: 0, memorySize: 0, srSize: 0 };
|
|
79
108
|
for (let index = 0; index < maxLenght; index++) {
|
|
80
109
|
const pool = pools[index];
|
|
81
110
|
const host = hosts[index];
|
|
82
|
-
const sr =
|
|
111
|
+
const sr = srs[index];
|
|
83
112
|
if (pool !== undefined) {
|
|
84
113
|
resourcesOverview.nCpus += pool.cpus.cores ?? 0;
|
|
85
114
|
}
|
|
@@ -139,34 +168,16 @@ export class XoaService {
|
|
|
139
168
|
return nHostsEol;
|
|
140
169
|
}
|
|
141
170
|
async #getMissingPatchesInfo() {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
};
|
|
171
|
+
const missingPatchesInfo = await this.#hostService.getMissingPatchesInfo();
|
|
172
|
+
if (!missingPatchesInfo.hasAuthorization) {
|
|
173
|
+
return { hasAuthorization: false };
|
|
146
174
|
}
|
|
147
|
-
const
|
|
148
|
-
const poolsWithMissingPatches = new Set();
|
|
149
|
-
let nHostsWithMissingPatches = 0;
|
|
150
|
-
let nHostsFailed = 0;
|
|
151
|
-
await asyncEach(hosts, async (host) => {
|
|
152
|
-
const xapi = this.#restApi.xoApp.getXapi(host);
|
|
153
|
-
try {
|
|
154
|
-
const patches = await xapi.listMissingPatches(host.id);
|
|
155
|
-
if (patches.length > 0) {
|
|
156
|
-
nHostsWithMissingPatches++;
|
|
157
|
-
poolsWithMissingPatches.add(host.$pool);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
catch (err) {
|
|
161
|
-
log.error('listMissingPatches failed', err);
|
|
162
|
-
nHostsFailed++;
|
|
163
|
-
}
|
|
164
|
-
});
|
|
175
|
+
const { hasAuthorization, nHostsFailed, nHostsWithMissingPatches, nPoolsWithMissingPatches } = missingPatchesInfo;
|
|
165
176
|
return {
|
|
166
|
-
hasAuthorization
|
|
177
|
+
hasAuthorization,
|
|
167
178
|
nHostsFailed,
|
|
168
179
|
nHostsWithMissingPatches,
|
|
169
|
-
nPoolsWithMissingPatches
|
|
180
|
+
nPoolsWithMissingPatches,
|
|
170
181
|
};
|
|
171
182
|
}
|
|
172
183
|
#isReplicaVmInVdb(vbds) {
|
|
@@ -207,7 +218,7 @@ export class XoaService {
|
|
|
207
218
|
}
|
|
208
219
|
#getStorageRepositoriesSizeInfo() {
|
|
209
220
|
const writableSrs = this.#restApi.getObjectsByType('SR', {
|
|
210
|
-
filter:
|
|
221
|
+
filter: isSrWritableOrIso,
|
|
211
222
|
});
|
|
212
223
|
let replicated = 0;
|
|
213
224
|
let total = 0;
|
|
@@ -374,30 +385,11 @@ export class XoaService {
|
|
|
374
385
|
}
|
|
375
386
|
}
|
|
376
387
|
#getHostsStatus() {
|
|
377
|
-
const
|
|
378
|
-
let nRunning = 0;
|
|
379
|
-
let nHalted = 0;
|
|
380
|
-
let nUnknown = 0;
|
|
381
|
-
let total = 0;
|
|
382
|
-
for (const id in hosts) {
|
|
383
|
-
total++;
|
|
384
|
-
const host = hosts[id];
|
|
385
|
-
switch (host.power_state) {
|
|
386
|
-
case HOST_POWER_STATE.RUNNING:
|
|
387
|
-
nRunning++;
|
|
388
|
-
break;
|
|
389
|
-
case HOST_POWER_STATE.HALTED:
|
|
390
|
-
nHalted++;
|
|
391
|
-
break;
|
|
392
|
-
default:
|
|
393
|
-
nUnknown++;
|
|
394
|
-
break;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
388
|
+
const { running, halted, total, unknown } = this.#hostService.getHostsStatus();
|
|
397
389
|
return {
|
|
398
|
-
running
|
|
399
|
-
halted
|
|
400
|
-
unknown
|
|
390
|
+
running,
|
|
391
|
+
halted,
|
|
392
|
+
unknown,
|
|
401
393
|
total,
|
|
402
394
|
};
|
|
403
395
|
}
|
|
@@ -432,44 +424,38 @@ export class XoaService {
|
|
|
432
424
|
};
|
|
433
425
|
}
|
|
434
426
|
async getDashboard({ stream } = {}) {
|
|
435
|
-
async function promiseWriteInStream(maybePromise, key) {
|
|
436
|
-
let data;
|
|
437
|
-
if (isPromise(maybePromise)) {
|
|
438
|
-
data = await maybePromise;
|
|
439
|
-
}
|
|
440
|
-
else {
|
|
441
|
-
data = maybePromise;
|
|
442
|
-
}
|
|
443
|
-
if (stream !== undefined) {
|
|
444
|
-
if (stream.writableNeedDrain) {
|
|
445
|
-
await new Promise(resolve => stream.once('drain', resolve));
|
|
446
|
-
}
|
|
447
|
-
stream.write(JSON.stringify({ [key]: data }) + '\n');
|
|
448
|
-
}
|
|
449
|
-
return data;
|
|
450
|
-
}
|
|
451
427
|
const [nPools, nHosts, hostsStatus, resourcesOverview, vmsStatus, storageRepositories, poolsStatus, missingPatches, backupRepositories, nHostsEol, backups,] = await Promise.all([
|
|
452
|
-
promiseWriteInStream(this.#getNumberOfPools(), 'nPools'),
|
|
453
|
-
promiseWriteInStream(this.#getNumberOfHosts(), 'nHosts'),
|
|
454
|
-
promiseWriteInStream(this.#getHostsStatus(), 'hostsStatus'),
|
|
455
|
-
promiseWriteInStream(this.#getResourcesOverview(), 'resourcesOverview'),
|
|
456
|
-
promiseWriteInStream(this.#getVmsStatus(), 'vmsStatus'),
|
|
457
|
-
promiseWriteInStream(
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
promiseWriteInStream(
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
428
|
+
promiseWriteInStream({ maybePromise: this.#getNumberOfPools(), path: 'nPools', stream }),
|
|
429
|
+
promiseWriteInStream({ maybePromise: this.#getNumberOfHosts(), path: 'nHosts', stream }),
|
|
430
|
+
promiseWriteInStream({ maybePromise: this.#getHostsStatus(), path: 'hostsStatus', stream }),
|
|
431
|
+
promiseWriteInStream({ maybePromise: this.#getResourcesOverview(), path: 'resourcesOverview', stream }),
|
|
432
|
+
promiseWriteInStream({ maybePromise: this.#getVmsStatus(), path: 'vmsStatus', stream }),
|
|
433
|
+
promiseWriteInStream({
|
|
434
|
+
maybePromise: this.#getStorageRepositoriesSizeInfo(),
|
|
435
|
+
path: 'storageRepositories',
|
|
436
|
+
stream,
|
|
437
|
+
handleError: true,
|
|
438
|
+
}),
|
|
439
|
+
promiseWriteInStream({ maybePromise: this.#getPoolsStatus(), path: 'poolsStatus', stream }),
|
|
440
|
+
promiseWriteInStream({ maybePromise: this.#getMissingPatchesInfo(), path: 'missingPatches', stream }),
|
|
441
|
+
promiseWriteInStream({
|
|
442
|
+
maybePromise: this.#getBackupRepositoriesSizeInfo(),
|
|
443
|
+
path: 'backupRepositories',
|
|
444
|
+
stream,
|
|
445
|
+
handleError: true,
|
|
446
|
+
}),
|
|
447
|
+
promiseWriteInStream({
|
|
448
|
+
maybePromise: this.#getNumberOfEolHosts(),
|
|
449
|
+
path: 'nHostsEol',
|
|
450
|
+
stream,
|
|
451
|
+
handleError: true,
|
|
452
|
+
}),
|
|
453
|
+
promiseWriteInStream({
|
|
454
|
+
maybePromise: this.#getbackupsInfo(),
|
|
455
|
+
path: 'backups',
|
|
456
|
+
stream,
|
|
457
|
+
handleError: true,
|
|
458
|
+
}),
|
|
473
459
|
]);
|
|
474
460
|
return {
|
|
475
461
|
nPools,
|