feat(@xen-orchestra/rest-api): expose vm snapshot action (#8622)

This commit is contained in:
Mathieu
2025-05-27 13:50:51 +02:00
committed by GitHub
parent dfbc578dfa
commit b8f9be6553
5 changed files with 55 additions and 3 deletions

View File

@@ -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]>
}
}

View File

@@ -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',

View File

@@ -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,
},
})
}
}

View File

@@ -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))

View File

@@ -620,6 +620,7 @@ export default class RestApi {
hard_shutdown: true,
clean_reboot: true,
hard_reboot: true,
snapshot: true,
},
},
'vm-controllers': {},