mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-09-11 06:29:51 -05:00
feat(@xen-orchestra/rest-api): expose vm snapshot action (#8622)
This commit is contained in:
@@ -77,9 +77,16 @@ type WrapperXenApi<T, Type extends string, Fn = { (): void }> = T & {
|
||||
$call: Fn
|
||||
$callAsync: Fn
|
||||
$type: Type
|
||||
$snapshot(params: {
|
||||
cancelToken?: unknown
|
||||
ignoredVdisTag?: string
|
||||
name_label?: string
|
||||
unplugVusbs?: boolean
|
||||
}): Promise<XenApiVm['$ref']>
|
||||
$xapi: {
|
||||
call: <ReturnType>(...args: unknown[]) => Promise<ReturnType>
|
||||
callAsync: <ReturnType>(...args: unknown[]) => Promise<ReturnType>
|
||||
getField<T extends XenApiRecord, K extends keyof T>(type: Type, ref: T['$ref'], field: K): Promise<T[K]>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ export type Unbrand<T> = {
|
||||
export const createdResp = {
|
||||
status: 201,
|
||||
description: 'Resource created',
|
||||
}
|
||||
} as const
|
||||
|
||||
export const actionAsyncroneResp = {
|
||||
status: 202,
|
||||
description: 'Action executed asynchronously',
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
import { Example, Get, Path, Post, Query, Request, Response, Route, Security, Tags, SuccessResponse } from 'tsoa'
|
||||
import { Example, Get, Path, Post, Query, Request, Response, Route, Security, Tags, SuccessResponse, Body } from 'tsoa'
|
||||
import { Request as ExRequest } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { incorrectState, invalidParameters } from 'xo-common/api-errors.js'
|
||||
import { provide } from 'inversify-binding-decorators'
|
||||
import type { XapiStatsGranularity, XapiVmStats, XoVm } from '@vates/types'
|
||||
import type { XapiStatsGranularity, XapiVmStats, XenApiVm, XoVm, XoVmSnapshot } from '@vates/types'
|
||||
|
||||
import {
|
||||
actionAsyncroneResp,
|
||||
createdResp,
|
||||
internalServerErrorResp,
|
||||
noContentResp,
|
||||
notFoundResp,
|
||||
unauthorizedResp,
|
||||
type Unbrand,
|
||||
} from '../open-api/common/response.common.mjs'
|
||||
import { BASE_URL } from '../index.mjs'
|
||||
import { partialVms, vm, vmIds, vmStatsExample } from '../open-api/oa-examples/vm.oa-example.mjs'
|
||||
import { RestApi } from '../rest-api/rest-api.mjs'
|
||||
import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs'
|
||||
import type { WithHref } from '../helpers/helper.type.mjs'
|
||||
import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs'
|
||||
|
||||
const IGNORED_VDIS_TAG = '[NOSNAP]'
|
||||
|
||||
@Route('vms')
|
||||
@Security('*')
|
||||
@Response(unauthorizedResp.status, unauthorizedResp.description)
|
||||
@@ -205,4 +209,42 @@ export class VmController extends XapiXoController<XoVm> {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
||||
* @example body { "name_label": "my_awesome_snapshot" }
|
||||
*/
|
||||
@Example(taskLocation)
|
||||
@Post('{id}/actions/snapshot')
|
||||
@SuccessResponse(actionAsyncroneResp.status, actionAsyncroneResp.description, actionAsyncroneResp.produce)
|
||||
@Response(createdResp.status, 'Snapshot created')
|
||||
@Response(notFoundResp.status, notFoundResp.description)
|
||||
@Response(internalServerErrorResp.status, internalServerErrorResp.description)
|
||||
async snapshotVm(
|
||||
@Path() id: string,
|
||||
@Body() body?: { name_label?: XoVmSnapshot['name_label'] },
|
||||
@Query() sync?: boolean
|
||||
): Promise<string | { id: XenApiVm['uuid'] }> {
|
||||
const vmId = id as XoVm['id']
|
||||
const action = async () => {
|
||||
const xapiVm = this.getXapiObject(vmId)
|
||||
const ref = await xapiVm.$snapshot({ ignoredVdisTag: IGNORED_VDIS_TAG, name_label: body?.name_label })
|
||||
const snapshotId = await xapiVm.$xapi.getField<XenApiVm, 'uuid'>('VM', ref, 'uuid')
|
||||
|
||||
if (sync) {
|
||||
this.setHeader('Location', `${BASE_URL}/vm-snapshots/${snapshotId}`)
|
||||
}
|
||||
|
||||
return { id: snapshotId }
|
||||
}
|
||||
|
||||
return this.createAction<Promise<{ id: XenApiVm['uuid'] }>>(action, {
|
||||
sync,
|
||||
statusCode: createdResp.status,
|
||||
taskProperties: {
|
||||
name: 'snapshot VM',
|
||||
objectId: vmId,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
- **Migrated REST API endpoints**:
|
||||
- `/rest/v0/pifs` (PR [#8569](https://github.com/vatesfr/xen-orchestra/pull/8569))
|
||||
- `/rest/v0/pifs/<pif-id>` (PR [#8569](https://github.com/vatesfr/xen-orchestra/pull/8569))
|
||||
- `/rest/v0/vms/<vm-id>/actions/snapshot` (PR [#8622](https://github.com/vatesfr/xen-orchestra/pull/8622))
|
||||
- **XO 6:**
|
||||
- [i18n] Update Czech, German, Spanish, Dutch, Russian and Swedish translations (PR [#8534](https://github.com/vatesfr/xen-orchestra/pull/8534))
|
||||
|
||||
|
||||
@@ -620,6 +620,7 @@ export default class RestApi {
|
||||
hard_shutdown: true,
|
||||
clean_reboot: true,
|
||||
hard_reboot: true,
|
||||
snapshot: true,
|
||||
},
|
||||
},
|
||||
'vm-controllers': {},
|
||||
|
||||
Reference in New Issue
Block a user