@xen-orchestra/rest-api 0.1.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/README.md ADDED
@@ -0,0 +1,74 @@
1
+ <!-- DO NOT EDIT MANUALLY, THIS FILE HAS BEEN GENERATED -->
2
+
3
+ # @xen-orchestra/rest-api
4
+
5
+ [![Package Version](https://badgen.net/npm/v/@xen-orchestra/rest-api)](https://npmjs.org/package/@xen-orchestra/rest-api) ![License](https://badgen.net/npm/license/@xen-orchestra/rest-api) [![PackagePhobia](https://badgen.net/bundlephobia/minzip/@xen-orchestra/rest-api)](https://bundlephobia.com/result?p=@xen-orchestra/rest-api) [![Node compatibility](https://badgen.net/npm/node/@xen-orchestra/rest-api)](https://npmjs.org/package/@xen-orchestra/rest-api)
6
+
7
+ > REST API to manage your XOA
8
+
9
+ ## Install
10
+
11
+ Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/rest-api):
12
+
13
+ ```sh
14
+ npm install --save @xen-orchestra/rest-api
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ # @xen-orchestra/rest-api
20
+
21
+ ## Rules
22
+
23
+ The REST API is based on the `TSOA` framework and therefore we use decorators a lot to define the behavior of a route or a group of routes. To keep things easily visible, it is best to always use the decorators in the same order.
24
+
25
+ ### Class decorator
26
+
27
+ ```ts
28
+ @Routes('foo')
29
+ @Security('*')
30
+ @Response(401)
31
+ @provide(Foo)
32
+ class Foo extends Controller {}
33
+ ```
34
+
35
+ ### Methods decorator
36
+
37
+ ```ts
38
+ @Routes('foo')
39
+ ...
40
+ class Foo extends Controller {
41
+
42
+
43
+ /**
44
+ * any jsdoc anotations
45
+ * @example id 1234
46
+ */
47
+ @Example(['foo', 'bar'])
48
+ @Get('{id}')
49
+ @Security('*')
50
+ @Response(404)
51
+ getFoo(@Path() id: string) {
52
+ return this.getFoo(id)
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### Examples
58
+
59
+ In order not to pollute important decorators, all example structures should be in a separate file. `src/open-api/examples/<resource>.example.mts`
60
+
61
+ ## Contributions
62
+
63
+ Contributions are _very_ welcomed, either on the documentation or on
64
+ the code.
65
+
66
+ You may:
67
+
68
+ - report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
69
+ you've encountered;
70
+ - fork and create a pull request.
71
+
72
+ ## License
73
+
74
+ [AGPL-3.0-or-later](https://spdx.org/licenses/AGPL-3.0-or-later) © [Vates SAS](https://vates.fr)
@@ -0,0 +1,26 @@
1
+ import * as CM from 'complex-matcher';
2
+ import { Controller } from 'tsoa';
3
+ import { makeObjectMapper } from '../helpers/object-wrapper.helper.mjs';
4
+ export class XapiXoController extends Controller {
5
+ #type;
6
+ restApi;
7
+ constructor(type, restApi) {
8
+ super();
9
+ this.#type = type;
10
+ this.restApi = restApi;
11
+ }
12
+ getObjects({ filter, limit } = {}) {
13
+ if (filter !== undefined) {
14
+ filter = CM.parse(filter).createPredicate();
15
+ }
16
+ return this.restApi.getObjectsByType(this.#type, { filter, limit });
17
+ }
18
+ getObject(id) {
19
+ return this.restApi.getObject(id, this.#type);
20
+ }
21
+ sendObjects(objects, req) {
22
+ const mapper = makeObjectMapper(req);
23
+ const mappedObjects = objects.map(mapper);
24
+ return mappedObjects;
25
+ }
26
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import path from 'node:path';
2
+ import pick from 'lodash/pick.js';
3
+ const { join } = path.posix;
4
+ export function makeObjectMapper(req, path = req.path) {
5
+ const makeUrl = ({ id }) => join(baseUrl, path, typeof id === 'number' ? String(id) : id);
6
+ let objectMapper;
7
+ const { query, baseUrl } = req;
8
+ const { fields } = query;
9
+ if (fields === '*') {
10
+ objectMapper = object => ({
11
+ ...object,
12
+ href: makeUrl(object),
13
+ });
14
+ }
15
+ else if (typeof fields === 'string') {
16
+ const _fields = fields.split(',');
17
+ objectMapper = object => {
18
+ const url = makeUrl(object);
19
+ return { ...pick(object, _fields), href: url };
20
+ };
21
+ }
22
+ else {
23
+ objectMapper = makeUrl;
24
+ }
25
+ return function (obj) {
26
+ return objectMapper(obj);
27
+ };
28
+ }
package/dist/index.mjs ADDED
@@ -0,0 +1,20 @@
1
+ import * as swaggerUi from 'swagger-ui-express';
2
+ import { createRequire } from 'module';
3
+ import genericErrorHandler from './middlewares/generic-error-handler.middleware.mjs';
4
+ import tsoaToXoErrorHandler from './middlewares/tsoa-to-xo-error.middleware.mjs';
5
+ import { RegisterRoutes } from './open-api/routes/routes.js';
6
+ import { setupContainer } from './ioc/ioc.mjs';
7
+ // Avoid using "import from" to import a json file as this requires assert/with and will break compatibility with recent node versions
8
+ // https://github.com/nodejs/node/issues/51622
9
+ const require = createRequire(import.meta.url);
10
+ const swaggerOpenApiSpec = require('../open-api/spec/swagger.json');
11
+ export default function setupRestApi(express, xoApp) {
12
+ setupContainer(xoApp);
13
+ RegisterRoutes(express);
14
+ // do not register the doc at the root level, or it may lead to unwated behaviour
15
+ // uncomment when all endpoints are migrated to this API
16
+ // express.get('/rest/v0', (_req, res) => res.redirect('/rest/v0/docs'))
17
+ express.use('/rest/v0/docs', swaggerUi.serve, swaggerUi.setup(swaggerOpenApiSpec));
18
+ express.use('/rest/v0', tsoaToXoErrorHandler);
19
+ express.use('/rest/v0', genericErrorHandler);
20
+ }
@@ -0,0 +1,17 @@
1
+ import { buildProviderModule } from 'inversify-binding-decorators';
2
+ import { Container, decorate, injectable } from 'inversify';
3
+ import { Controller } from 'tsoa';
4
+ import { RestApi } from '../rest-api/rest-api.mjs';
5
+ const iocContainer = new Container();
6
+ decorate(injectable(), Controller);
7
+ iocContainer.load(buildProviderModule());
8
+ export function setupContainer(xoApp) {
9
+ if (iocContainer.isBound(RestApi)) {
10
+ iocContainer.unbind(RestApi);
11
+ }
12
+ iocContainer
13
+ .bind(RestApi)
14
+ .toDynamicValue(() => new RestApi(xoApp))
15
+ .inSingletonScope();
16
+ }
17
+ export { iocContainer };
@@ -0,0 +1,34 @@
1
+ import { createLogger } from '@xen-orchestra/log';
2
+ import { invalidCredentials, notImplemented, unauthorized } from 'xo-common/api-errors.js';
3
+ import { iocContainer } from '../ioc/ioc.mjs';
4
+ import { RestApi } from '../rest-api/rest-api.mjs';
5
+ const noop = () => { };
6
+ const log = createLogger('xo:rest-api:authentication');
7
+ function getCredentials(securityName, req) {
8
+ const token = req.cookies.token ?? req.cookies.authenticationToken;
9
+ if (securityName === '*' || securityName === 'token') {
10
+ if (token !== undefined) {
11
+ return { token };
12
+ }
13
+ return;
14
+ }
15
+ log.error(`${securityName} not implemented.`);
16
+ throw notImplemented();
17
+ }
18
+ // TODO: correctly handle ACL/Resource set users
19
+ // for now only support "xoa-admin"
20
+ export async function expressAuthentication(req, securityName) {
21
+ const restApi = iocContainer.get(RestApi);
22
+ const ip = req.ip;
23
+ const credentials = getCredentials(securityName, req);
24
+ if (credentials === undefined) {
25
+ throw invalidCredentials();
26
+ }
27
+ const { user } = await restApi.authenticateUser(credentials, { ip });
28
+ if (user.permission !== 'admin') {
29
+ log.error(`The REST API can only be used by 'xoa-admin' users for now. Your permission: ${user.permission}`);
30
+ throw unauthorized();
31
+ }
32
+ await restApi.runWithApiContext(user, noop);
33
+ Promise.resolve(user);
34
+ }
@@ -0,0 +1,33 @@
1
+ import { createLogger } from '@xen-orchestra/log';
2
+ import { featureUnauthorized, forbiddenOperation, invalidCredentials, invalidParameters, noSuchObject, notImplemented, unauthorized, } from 'xo-common/api-errors.js';
3
+ const log = createLogger('xo:rest-api:error-handler');
4
+ // must have 4 parameters to be recognized as an error middleware by express
5
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
+ export default function genericErrorHandler(error, req, res, _next) {
7
+ if (!(error instanceof Error)) {
8
+ log.error(error);
9
+ res.status(500).json({ error });
10
+ return;
11
+ }
12
+ if (noSuchObject.is(error)) {
13
+ res.status(404);
14
+ }
15
+ else if (unauthorized.is(error) || forbiddenOperation.is(error) || featureUnauthorized.is(error)) {
16
+ res.status(403);
17
+ }
18
+ else if (invalidCredentials.is(error)) {
19
+ res.status(401);
20
+ }
21
+ else if (invalidParameters.is(error)) {
22
+ res.status(422);
23
+ }
24
+ else if (notImplemented.is(error)) {
25
+ res.status(501);
26
+ }
27
+ else {
28
+ res.status(500);
29
+ log.error(error);
30
+ }
31
+ log.info(`[${req.method}] ${req.path} (${res.statusCode})`);
32
+ res.json({ error: error.message });
33
+ }
@@ -0,0 +1,8 @@
1
+ import { invalidParameters } from 'xo-common/api-errors.js';
2
+ import { ValidateError } from 'tsoa';
3
+ export default function tsoaToXoErrorHandler(error, _req, _res, next) {
4
+ if (error instanceof ValidateError) {
5
+ /* throw */ invalidParameters(error.fields);
6
+ }
7
+ return next(error);
8
+ }
@@ -0,0 +1,181 @@
1
+ import { fetchMiddlewares, ExpressTemplateService } from '@tsoa/runtime';
2
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
3
+ import { VmController } from './../../vms/vm.controller.mjs';
4
+ import { expressAuthentication } from './../../middlewares/authentication.middleware.mjs';
5
+ // @ts-ignore - no great way to install types from subpackage
6
+ import { iocContainer } from './../../ioc/ioc.mjs';
7
+ const expressAuthenticationRecasted = expressAuthentication;
8
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
9
+ const models = {
10
+ "Record_string.string_": {
11
+ "dataType": "refAlias",
12
+ "type": { "dataType": "nestedObjectLiteral", "nestedProperties": {}, "additionalProperties": { "dataType": "string" }, "validators": {} },
13
+ },
14
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
15
+ "Record_VM_OPERATIONS.string_": {
16
+ "dataType": "refAlias",
17
+ "type": { "dataType": "nestedObjectLiteral", "nestedProperties": { "assert_operation_valid": { "dataType": "string", "required": true }, "awaiting_memory_live": { "dataType": "string", "required": true }, "call_plugin": { "dataType": "string", "required": true }, "changing_dynamic_range": { "dataType": "string", "required": true }, "changing_memory_limits": { "dataType": "string", "required": true }, "changing_memory_live": { "dataType": "string", "required": true }, "changing_NVRAM": { "dataType": "string", "required": true }, "changing_shadow_memory": { "dataType": "string", "required": true }, "changing_shadow_memory_live": { "dataType": "string", "required": true }, "changing_static_range": { "dataType": "string", "required": true }, "changing_VCPUs": { "dataType": "string", "required": true }, "changing_VCPUs_live": { "dataType": "string", "required": true }, "checkpoint": { "dataType": "string", "required": true }, "clean_reboot": { "dataType": "string", "required": true }, "clean_shutdown": { "dataType": "string", "required": true }, "clone": { "dataType": "string", "required": true }, "copy": { "dataType": "string", "required": true }, "create_template": { "dataType": "string", "required": true }, "create_vtpm": { "dataType": "string", "required": true }, "csvm": { "dataType": "string", "required": true }, "data_source_op": { "dataType": "string", "required": true }, "destroy": { "dataType": "string", "required": true }, "export": { "dataType": "string", "required": true }, "get_boot_record": { "dataType": "string", "required": true }, "hard_reboot": { "dataType": "string", "required": true }, "hard_shutdown": { "dataType": "string", "required": true }, "import": { "dataType": "string", "required": true }, "make_into_template": { "dataType": "string", "required": true }, "metadata_export": { "dataType": "string", "required": true }, "migrate_send": { "dataType": "string", "required": true }, "pause": { "dataType": "string", "required": true }, "pool_migrate": { "dataType": "string", "required": true }, "power_state_reset": { "dataType": "string", "required": true }, "provision": { "dataType": "string", "required": true }, "query_services": { "dataType": "string", "required": true }, "resume": { "dataType": "string", "required": true }, "resume_on": { "dataType": "string", "required": true }, "revert": { "dataType": "string", "required": true }, "reverting": { "dataType": "string", "required": true }, "send_sysrq": { "dataType": "string", "required": true }, "send_trigger": { "dataType": "string", "required": true }, "shutdown": { "dataType": "string", "required": true }, "snapshot": { "dataType": "string", "required": true }, "snapshot_with_quiesce": { "dataType": "string", "required": true }, "start": { "dataType": "string", "required": true }, "start_on": { "dataType": "string", "required": true }, "suspend": { "dataType": "string", "required": true }, "unpause": { "dataType": "string", "required": true }, "update_allowed_operations": { "dataType": "string", "required": true } }, "validators": {} },
18
+ },
19
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
20
+ "VM_OPERATIONS": {
21
+ "dataType": "refAlias",
22
+ "type": { "dataType": "union", "subSchemas": [{ "dataType": "enum", "enums": ["assert_operation_valid"] }, { "dataType": "enum", "enums": ["awaiting_memory_live"] }, { "dataType": "enum", "enums": ["call_plugin"] }, { "dataType": "enum", "enums": ["changing_dynamic_range"] }, { "dataType": "enum", "enums": ["changing_memory_limits"] }, { "dataType": "enum", "enums": ["changing_memory_live"] }, { "dataType": "enum", "enums": ["changing_NVRAM"] }, { "dataType": "enum", "enums": ["changing_shadow_memory"] }, { "dataType": "enum", "enums": ["changing_shadow_memory_live"] }, { "dataType": "enum", "enums": ["changing_static_range"] }, { "dataType": "enum", "enums": ["changing_VCPUs"] }, { "dataType": "enum", "enums": ["changing_VCPUs_live"] }, { "dataType": "enum", "enums": ["checkpoint"] }, { "dataType": "enum", "enums": ["clean_reboot"] }, { "dataType": "enum", "enums": ["clean_shutdown"] }, { "dataType": "enum", "enums": ["clone"] }, { "dataType": "enum", "enums": ["copy"] }, { "dataType": "enum", "enums": ["create_template"] }, { "dataType": "enum", "enums": ["create_vtpm"] }, { "dataType": "enum", "enums": ["csvm"] }, { "dataType": "enum", "enums": ["data_source_op"] }, { "dataType": "enum", "enums": ["destroy"] }, { "dataType": "enum", "enums": ["export"] }, { "dataType": "enum", "enums": ["get_boot_record"] }, { "dataType": "enum", "enums": ["hard_reboot"] }, { "dataType": "enum", "enums": ["hard_shutdown"] }, { "dataType": "enum", "enums": ["import"] }, { "dataType": "enum", "enums": ["make_into_template"] }, { "dataType": "enum", "enums": ["metadata_export"] }, { "dataType": "enum", "enums": ["migrate_send"] }, { "dataType": "enum", "enums": ["pause"] }, { "dataType": "enum", "enums": ["pool_migrate"] }, { "dataType": "enum", "enums": ["power_state_reset"] }, { "dataType": "enum", "enums": ["provision"] }, { "dataType": "enum", "enums": ["query_services"] }, { "dataType": "enum", "enums": ["resume"] }, { "dataType": "enum", "enums": ["resume_on"] }, { "dataType": "enum", "enums": ["revert"] }, { "dataType": "enum", "enums": ["reverting"] }, { "dataType": "enum", "enums": ["send_sysrq"] }, { "dataType": "enum", "enums": ["send_trigger"] }, { "dataType": "enum", "enums": ["shutdown"] }, { "dataType": "enum", "enums": ["snapshot"] }, { "dataType": "enum", "enums": ["snapshot_with_quiesce"] }, { "dataType": "enum", "enums": ["start"] }, { "dataType": "enum", "enums": ["start_on"] }, { "dataType": "enum", "enums": ["suspend"] }, { "dataType": "enum", "enums": ["unpause"] }, { "dataType": "enum", "enums": ["update_allowed_operations"] }], "validators": {} },
23
+ },
24
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
25
+ "Record_string.VM_OPERATIONS_": {
26
+ "dataType": "refAlias",
27
+ "type": { "dataType": "nestedObjectLiteral", "nestedProperties": {}, "additionalProperties": { "ref": "VM_OPERATIONS" }, "validators": {} },
28
+ },
29
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
30
+ "VM_POWER_STATE": {
31
+ "dataType": "refAlias",
32
+ "type": { "dataType": "union", "subSchemas": [{ "dataType": "enum", "enums": ["Halted"] }, { "dataType": "enum", "enums": ["Paused"] }, { "dataType": "enum", "enums": ["Running"] }, { "dataType": "enum", "enums": ["Suspended"] }], "validators": {} },
33
+ },
34
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
35
+ "DOMAIN_TYPE": {
36
+ "dataType": "refAlias",
37
+ "type": { "dataType": "union", "subSchemas": [{ "dataType": "enum", "enums": ["hvm"] }, { "dataType": "enum", "enums": ["pv"] }, { "dataType": "enum", "enums": ["pvh"] }, { "dataType": "enum", "enums": ["pv_in_pvh"] }, { "dataType": "enum", "enums": ["unspecified"] }], "validators": {} },
38
+ },
39
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
40
+ "Unbrand_XoVm_": {
41
+ "dataType": "refAlias",
42
+ "type": { "dataType": "nestedObjectLiteral", "nestedProperties": { "$VBDs": { "dataType": "array", "array": { "dataType": "string" }, "required": true }, "$VGPUs": { "dataType": "array", "array": { "dataType": "string" }, "required": true }, "$container": { "dataType": "string", "required": true }, "$pool": { "dataType": "string", "required": true }, "$poolId": { "dataType": "string", "required": true }, "_xapiRef": { "dataType": "string", "required": true }, "CPUs": { "dataType": "nestedObjectLiteral", "nestedProperties": { "number": { "dataType": "double", "required": true }, "max": { "dataType": "double", "required": true } }, "required": true }, "PV_args": { "dataType": "string" }, "VGPUs": { "dataType": "array", "array": { "dataType": "string" }, "required": true }, "VIFs": { "dataType": "array", "array": { "dataType": "string" }, "required": true }, "VTPMs": { "dataType": "array", "array": { "dataType": "string" }, "required": true }, "addresses": { "ref": "Record_string.string_", "required": true }, "affinityHost": { "dataType": "string" }, "attachedPcis": { "dataType": "array", "array": { "dataType": "string" } }, "auto_poweron": { "dataType": "boolean", "required": true }, "bios_strings": { "ref": "Record_string.string_", "required": true }, "blockedOperations": { "ref": "Record_VM_OPERATIONS.string_", "required": true }, "boot": { "ref": "Record_string.string_", "required": true }, "coresPerSocket": { "dataType": "double" }, "cpuCap": { "dataType": "double" }, "cpuMask": { "dataType": "array", "array": { "dataType": "double" } }, "cpuWeight": { "dataType": "double" }, "creation": { "ref": "Record_string.string_", "required": true }, "current_operations": { "ref": "Record_string.VM_OPERATIONS_", "required": true }, "docker": { "dataType": "nestedObjectLiteral", "nestedProperties": { "version": { "dataType": "string" }, "process": { "dataType": "string" }, "info": { "dataType": "string" }, "enabled": { "dataType": "boolean", "required": true }, "containers": { "dataType": "array", "array": { "dataType": "string" } } } }, "expNestedHvm": { "dataType": "boolean", "required": true }, "hasVendorDevice": { "dataType": "boolean", "required": true }, "high_availability": { "dataType": "string", "required": true }, "installTime": { "dataType": "double" }, "isFirmwareSupported": { "dataType": "boolean", "required": true }, "memory": { "dataType": "nestedObjectLiteral", "nestedProperties": { "usage": { "dataType": "double" }, "static": { "dataType": "array", "array": { "dataType": "double" }, "required": true }, "size": { "dataType": "double", "required": true }, "dynamic": { "dataType": "array", "array": { "dataType": "double" }, "required": true } }, "required": true }, "mainIpAddress": { "dataType": "string" }, "managementAgentDetected": { "dataType": "boolean" }, "name_description": { "dataType": "string", "required": true }, "name_label": { "dataType": "string", "required": true }, "needsVtpm": { "dataType": "boolean", "required": true }, "nicType": { "dataType": "string" }, "notes": { "dataType": "string" }, "os_version": { "ref": "Record_string.string_", "required": true }, "other": { "ref": "Record_string.string_", "required": true }, "parent": { "dataType": "string" }, "power_state": { "ref": "VM_POWER_STATE", "required": true }, "pvDriversDetected": { "dataType": "boolean" }, "pvDriversUpToDate": { "dataType": "boolean" }, "pvDriversVersion": { "dataType": "string" }, "resourceSet": { "dataType": "string" }, "secureBoot": { "dataType": "boolean", "required": true }, "snapshots": { "dataType": "array", "array": { "dataType": "string" }, "required": true }, "startDelay": { "dataType": "double", "required": true }, "startTime": { "dataType": "double" }, "suspendSr": { "dataType": "string" }, "tags": { "dataType": "array", "array": { "dataType": "string" }, "required": true }, "vga": { "dataType": "string" }, "videoram": { "dataType": "double" }, "viridian": { "dataType": "boolean", "required": true }, "virtualizationMode": { "ref": "DOMAIN_TYPE", "required": true }, "xenStoreData": { "ref": "Record_string.string_", "required": true }, "xentools": { "dataType": "union", "subSchemas": [{ "dataType": "enum", "enums": [false] }, { "dataType": "nestedObjectLiteral", "nestedProperties": { "version": { "dataType": "string", "required": true }, "minor": { "dataType": "double", "required": true }, "major": { "dataType": "double", "required": true } } }] }, "id": { "dataType": "string", "required": true }, "type": { "dataType": "enum", "enums": ["VM"], "required": true } }, "validators": {} },
43
+ },
44
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
45
+ "WithHref_Unbrand_XoVm__": {
46
+ "dataType": "refAlias",
47
+ "type": { "dataType": "intersection", "subSchemas": [{ "ref": "Unbrand_XoVm_" }, { "dataType": "nestedObjectLiteral", "nestedProperties": { "href": { "dataType": "string", "required": true } } }], "validators": {} },
48
+ },
49
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
50
+ "Partial_Unbrand_XoVm__": {
51
+ "dataType": "refAlias",
52
+ "type": { "dataType": "nestedObjectLiteral", "nestedProperties": { "$VBDs": { "dataType": "array", "array": { "dataType": "string" } }, "$VGPUs": { "dataType": "array", "array": { "dataType": "string" } }, "$container": { "dataType": "string" }, "$pool": { "dataType": "string" }, "$poolId": { "dataType": "string" }, "_xapiRef": { "dataType": "string" }, "CPUs": { "dataType": "nestedObjectLiteral", "nestedProperties": { "number": { "dataType": "double", "required": true }, "max": { "dataType": "double", "required": true } } }, "PV_args": { "dataType": "string" }, "VGPUs": { "dataType": "array", "array": { "dataType": "string" } }, "VIFs": { "dataType": "array", "array": { "dataType": "string" } }, "VTPMs": { "dataType": "array", "array": { "dataType": "string" } }, "addresses": { "ref": "Record_string.string_" }, "affinityHost": { "dataType": "string" }, "attachedPcis": { "dataType": "array", "array": { "dataType": "string" } }, "auto_poweron": { "dataType": "boolean" }, "bios_strings": { "ref": "Record_string.string_" }, "blockedOperations": { "ref": "Record_VM_OPERATIONS.string_" }, "boot": { "ref": "Record_string.string_" }, "coresPerSocket": { "dataType": "double" }, "cpuCap": { "dataType": "double" }, "cpuMask": { "dataType": "array", "array": { "dataType": "double" } }, "cpuWeight": { "dataType": "double" }, "creation": { "ref": "Record_string.string_" }, "current_operations": { "ref": "Record_string.VM_OPERATIONS_" }, "docker": { "dataType": "nestedObjectLiteral", "nestedProperties": { "version": { "dataType": "string" }, "process": { "dataType": "string" }, "info": { "dataType": "string" }, "enabled": { "dataType": "boolean", "required": true }, "containers": { "dataType": "array", "array": { "dataType": "string" } } } }, "expNestedHvm": { "dataType": "boolean" }, "hasVendorDevice": { "dataType": "boolean" }, "high_availability": { "dataType": "string" }, "installTime": { "dataType": "double" }, "isFirmwareSupported": { "dataType": "boolean" }, "memory": { "dataType": "nestedObjectLiteral", "nestedProperties": { "usage": { "dataType": "double" }, "static": { "dataType": "array", "array": { "dataType": "double" }, "required": true }, "size": { "dataType": "double", "required": true }, "dynamic": { "dataType": "array", "array": { "dataType": "double" }, "required": true } } }, "mainIpAddress": { "dataType": "string" }, "managementAgentDetected": { "dataType": "boolean" }, "name_description": { "dataType": "string" }, "name_label": { "dataType": "string" }, "needsVtpm": { "dataType": "boolean" }, "nicType": { "dataType": "string" }, "notes": { "dataType": "string" }, "os_version": { "ref": "Record_string.string_" }, "other": { "ref": "Record_string.string_" }, "parent": { "dataType": "string" }, "power_state": { "ref": "VM_POWER_STATE" }, "pvDriversDetected": { "dataType": "boolean" }, "pvDriversUpToDate": { "dataType": "boolean" }, "pvDriversVersion": { "dataType": "string" }, "resourceSet": { "dataType": "string" }, "secureBoot": { "dataType": "boolean" }, "snapshots": { "dataType": "array", "array": { "dataType": "string" } }, "startDelay": { "dataType": "double" }, "startTime": { "dataType": "double" }, "suspendSr": { "dataType": "string" }, "tags": { "dataType": "array", "array": { "dataType": "string" } }, "vga": { "dataType": "string" }, "videoram": { "dataType": "double" }, "viridian": { "dataType": "boolean" }, "virtualizationMode": { "ref": "DOMAIN_TYPE" }, "xenStoreData": { "ref": "Record_string.string_" }, "xentools": { "dataType": "union", "subSchemas": [{ "dataType": "enum", "enums": [false] }, { "dataType": "nestedObjectLiteral", "nestedProperties": { "version": { "dataType": "string", "required": true }, "minor": { "dataType": "double", "required": true }, "major": { "dataType": "double", "required": true } } }] }, "id": { "dataType": "string" }, "type": { "dataType": "enum", "enums": ["VM"] } }, "validators": {} },
53
+ },
54
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
55
+ "WithHref_Partial_Unbrand_XoVm___": {
56
+ "dataType": "refAlias",
57
+ "type": { "dataType": "intersection", "subSchemas": [{ "ref": "Partial_Unbrand_XoVm__" }, { "dataType": "nestedObjectLiteral", "nestedProperties": { "href": { "dataType": "string", "required": true } } }], "validators": {} },
58
+ },
59
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
60
+ };
61
+ const templateService = new ExpressTemplateService(models, { "noImplicitAdditionalProperties": "throw-on-extras", "bodyCoercion": true });
62
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
63
+ export function RegisterRoutes(app) {
64
+ // ###########################################################################################################
65
+ // NOTE: If you do not see routes for all of your controllers in this file, then you might not have informed tsoa of where to look
66
+ // Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa
67
+ // ###########################################################################################################
68
+ const argsVmController_getVms = {
69
+ req: { "in": "request", "name": "req", "required": true, "dataType": "object" },
70
+ fields: { "in": "query", "name": "fields", "dataType": "string" },
71
+ filter: { "in": "query", "name": "filter", "dataType": "string" },
72
+ limit: { "in": "query", "name": "limit", "dataType": "double" },
73
+ };
74
+ app.get('/rest/v0/vms', authenticateMiddleware([{ "*": [] }]), ...(fetchMiddlewares(VmController)), ...(fetchMiddlewares(VmController.prototype.getVms)), async function VmController_getVms(request, response, next) {
75
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
76
+ let validatedArgs = [];
77
+ try {
78
+ validatedArgs = templateService.getValidatedArgs({ args: argsVmController_getVms, request, response });
79
+ const container = typeof iocContainer === 'function' ? iocContainer(request) : iocContainer;
80
+ const controller = await container.get(VmController);
81
+ if (typeof controller['setStatus'] === 'function') {
82
+ controller.setStatus(undefined);
83
+ }
84
+ await templateService.apiHandler({
85
+ methodName: 'getVms',
86
+ controller,
87
+ response,
88
+ next,
89
+ validatedArgs,
90
+ successStatus: undefined,
91
+ });
92
+ }
93
+ catch (err) {
94
+ return next(err);
95
+ }
96
+ });
97
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
98
+ const argsVmController_getVm = {
99
+ id: { "in": "path", "name": "id", "required": true, "dataType": "string" },
100
+ };
101
+ app.get('/rest/v0/vms/:id', authenticateMiddleware([{ "*": [] }]), ...(fetchMiddlewares(VmController)), ...(fetchMiddlewares(VmController.prototype.getVm)), async function VmController_getVm(request, response, next) {
102
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
103
+ let validatedArgs = [];
104
+ try {
105
+ validatedArgs = templateService.getValidatedArgs({ args: argsVmController_getVm, request, response });
106
+ const container = typeof iocContainer === 'function' ? iocContainer(request) : iocContainer;
107
+ const controller = await container.get(VmController);
108
+ if (typeof controller['setStatus'] === 'function') {
109
+ controller.setStatus(undefined);
110
+ }
111
+ await templateService.apiHandler({
112
+ methodName: 'getVm',
113
+ controller,
114
+ response,
115
+ next,
116
+ validatedArgs,
117
+ successStatus: undefined,
118
+ });
119
+ }
120
+ catch (err) {
121
+ return next(err);
122
+ }
123
+ });
124
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
125
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
126
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
127
+ function authenticateMiddleware(security = []) {
128
+ return async function runAuthenticationMiddleware(request, response, next) {
129
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
130
+ // keep track of failed auth attempts so we can hand back the most
131
+ // recent one. This behavior was previously existing so preserving it
132
+ // here
133
+ const failedAttempts = [];
134
+ const pushAndRethrow = (error) => {
135
+ failedAttempts.push(error);
136
+ throw error;
137
+ };
138
+ const secMethodOrPromises = [];
139
+ for (const secMethod of security) {
140
+ if (Object.keys(secMethod).length > 1) {
141
+ const secMethodAndPromises = [];
142
+ for (const name in secMethod) {
143
+ secMethodAndPromises.push(expressAuthenticationRecasted(request, name, secMethod[name], response)
144
+ .catch(pushAndRethrow));
145
+ }
146
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
147
+ secMethodOrPromises.push(Promise.all(secMethodAndPromises)
148
+ .then(users => { return users[0]; }));
149
+ }
150
+ else {
151
+ for (const name in secMethod) {
152
+ secMethodOrPromises.push(expressAuthenticationRecasted(request, name, secMethod[name], response)
153
+ .catch(pushAndRethrow));
154
+ }
155
+ }
156
+ }
157
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
158
+ try {
159
+ request['user'] = await Promise.any(secMethodOrPromises);
160
+ // Response was sent in middleware, abort
161
+ if (response.writableEnded) {
162
+ return;
163
+ }
164
+ next();
165
+ }
166
+ catch (err) {
167
+ // Show most recent error as response
168
+ const error = failedAttempts.pop();
169
+ error.status = error.status || 401;
170
+ // Response was sent in middleware, abort
171
+ if (response.writableEnded) {
172
+ return;
173
+ }
174
+ next(error);
175
+ }
176
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
177
+ };
178
+ }
179
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
180
+ }
181
+ // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
@@ -0,0 +1,18 @@
1
+ export class RestApi {
2
+ #xoApp;
3
+ constructor(xoApp) {
4
+ this.#xoApp = xoApp;
5
+ }
6
+ authenticateUser(...args) {
7
+ return this.#xoApp.authenticateUser(...args);
8
+ }
9
+ getObject(id, type) {
10
+ return this.#xoApp.getObject(id, type);
11
+ }
12
+ getObjectsByType(type, opts) {
13
+ return this.#xoApp.getObjectsByType(type, opts);
14
+ }
15
+ runWithApiContext(...args) {
16
+ return this.#xoApp.runWithApiContext(...args);
17
+ }
18
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { Example, Get, Path, Query, Request, Response, Route, Security } from 'tsoa';
11
+ import { inject } from 'inversify';
12
+ import { provide } from 'inversify-binding-decorators';
13
+ import { partialVms, vm, vmIds } from '../open-api/examples/vm.example.mjs';
14
+ import { RestApi } from '../rest-api/rest-api.mjs';
15
+ import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs';
16
+ let VmController = class VmController extends XapiXoController {
17
+ constructor(restApi) {
18
+ super('VM', restApi);
19
+ }
20
+ /**
21
+ *
22
+ * @example fields "name_label,power_state,uuid"
23
+ * @example filter "power_state:Running"
24
+ * @example limit 42
25
+ */
26
+ getVms(req, fields, filter, limit) {
27
+ return this.sendObjects(Object.values(this.getObjects({ filter, limit })), req);
28
+ }
29
+ /**
30
+ *
31
+ * @example id "f07ab729-c0e8-721c-45ec-f11276377030"
32
+ */
33
+ getVm(id) {
34
+ return this.getObject(id);
35
+ }
36
+ };
37
+ __decorate([
38
+ Example(vmIds),
39
+ Example(partialVms),
40
+ Get(''),
41
+ __param(0, Request()),
42
+ __param(1, Query()),
43
+ __param(2, Query()),
44
+ __param(3, Query())
45
+ ], VmController.prototype, "getVms", null);
46
+ __decorate([
47
+ Example(vm),
48
+ Get('{id}'),
49
+ Response(404),
50
+ __param(0, Path())
51
+ ], VmController.prototype, "getVm", null);
52
+ VmController = __decorate([
53
+ Route('vms'),
54
+ Security('*'),
55
+ Response(401)
56
+ // the `provide` decorator is mandatory on class that injects/receives dependencies.
57
+ // It automatically bind the class to the IOC container that handles dependency injection
58
+ ,
59
+ provide(VmController),
60
+ __param(0, inject(RestApi))
61
+ ], VmController);
62
+ export { VmController };