mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-11-09 17:06:13 -06:00
feat(rest): add revert snapshot route (#9788)
This commit is contained in:
@@ -37,6 +37,7 @@ import type {
|
||||
XoVm,
|
||||
XoVmTemplate,
|
||||
XoVif,
|
||||
XoVmSnapshot,
|
||||
} from '../xo.mjs'
|
||||
|
||||
export type XcpPatches = {
|
||||
@@ -129,6 +130,7 @@ export interface Xapi {
|
||||
listMissingPatches(host: XoHost['id']): Promise<XcpPatches[] | XsPatches[]>
|
||||
pool_emergencyShutdown(): Promise<void>
|
||||
resumeVm(id: XoVm['id']): Promise<void>
|
||||
revertVm(snapshotId: XoVmSnapshot['id']): Promise<void>
|
||||
unpauseVm(id: XoVm['id']): Promise<void>
|
||||
cloneVm(
|
||||
vmId: XoVm['id'],
|
||||
|
||||
@@ -8,6 +8,7 @@ export default {
|
||||
hard: true,
|
||||
},
|
||||
resume: true,
|
||||
'revert-snapshot': true,
|
||||
shutdown: {
|
||||
clean: true,
|
||||
hard: true,
|
||||
|
||||
@@ -129,7 +129,7 @@ export class GroupController extends XoController<XoGroup> {
|
||||
json(),
|
||||
acl({
|
||||
resource: 'group',
|
||||
action: actionFromBody('update:name'),
|
||||
action: actionFromBody<'group'>('update:name'),
|
||||
objectId: 'params.id',
|
||||
getObject: ({ restApi }) => restApi.xoApp.getGroup,
|
||||
}),
|
||||
|
||||
@@ -72,7 +72,7 @@ export type AclEntry = {
|
||||
| {
|
||||
action:
|
||||
| SupportedActions<Resource>
|
||||
| ((opts: { req: AuthenticatedRequest; restApi: RestApi }) => SupportedActions<Resource>)
|
||||
| ((opts: { req: AuthenticatedRequest; restApi: RestApi }) => SupportedActions<Resource> | undefined)
|
||||
actions?: never
|
||||
}
|
||||
| {
|
||||
|
||||
@@ -67,6 +67,7 @@ import { partialVmBackupJobs, vmBackupJobIds } from '../open-api/oa-examples/bac
|
||||
import { messageIds, partialMessages } from '../open-api/oa-examples/message.oa-example.mjs'
|
||||
import type { UnbrandedVmDashboard } from './vm.type.mjs'
|
||||
import type { CreateActionReturnType } from '../abstract-classes/base-controller.mjs'
|
||||
import { Task } from '@vates/task'
|
||||
|
||||
const IGNORED_VDIS_TAG = '[NOSNAP]'
|
||||
|
||||
@@ -571,6 +572,71 @@ export class VmController extends XapiXoController<XoVm> {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Required privilege:
|
||||
* - resource: vm, action: revert-snapshot
|
||||
* - resource: vm, action: snapshot (if `snapshotBefore: true`)
|
||||
*
|
||||
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
||||
* @example body { "snapshotId": "f07ab729-c0e8-721c-45ec-f11276377030", "snapshotBefore": true }
|
||||
*/
|
||||
@Example(taskLocation)
|
||||
@Post('{id}/actions/revert_snapshot')
|
||||
@Middlewares([
|
||||
json(),
|
||||
acl([
|
||||
{ resource: 'vm', action: 'revert-snapshot', objectId: 'params.id' },
|
||||
{
|
||||
resource: 'vm',
|
||||
action: ({ req }) => (req.body.snapshotBefore ? 'snapshot' : undefined),
|
||||
objectId: 'params.id',
|
||||
},
|
||||
]),
|
||||
])
|
||||
@SuccessResponse(asynchronousActionResp.status, asynchronousActionResp.description)
|
||||
@Response(noContentResp.status, noContentResp.description)
|
||||
@Response(forbiddenOperationResp.status, forbiddenOperationResp.description)
|
||||
@Response(notFoundResp.status, notFoundResp.description)
|
||||
@Response(invalidParametersResp.status, invalidParametersResp.description)
|
||||
@Response(internalServerErrorResp.status, internalServerErrorResp.description)
|
||||
async revertSnapshotVm(
|
||||
@Path() id: string,
|
||||
@Body() body: { snapshotId: string; snapshotBefore?: boolean },
|
||||
@Query() sync?: boolean
|
||||
): CreateActionReturnType<void> {
|
||||
const vmId = id as XoVm['id']
|
||||
const action = async () => {
|
||||
const snapshotId = body.snapshotId as XoVmSnapshot['id']
|
||||
|
||||
// Ensure the snapshot belongs to this VM
|
||||
const vm = this.getObject(vmId)
|
||||
if (!vm.snapshots.includes(snapshotId)) {
|
||||
throw invalidParameters(`snapshot ${snapshotId} does not belong to VM ${vmId}`)
|
||||
}
|
||||
|
||||
if (body.snapshotBefore) {
|
||||
await Task.run({ properties: { name: 'snapshot VM', objectId: vmId, objectType: 'VM' } }, () =>
|
||||
this.getXapiObject(vmId).$snapshot({ ignoredVdisTag: IGNORED_VDIS_TAG })
|
||||
)
|
||||
|
||||
await Task.run({ properties: { name: 'revert snapshot', objectId: vmId, objectType: 'VM' } }, () =>
|
||||
this.getXapi(vmId).revertVm(snapshotId)
|
||||
)
|
||||
} else {
|
||||
await this.getXapi(vmId).revertVm(snapshotId)
|
||||
}
|
||||
}
|
||||
|
||||
return this.createAction<void>(action, {
|
||||
sync,
|
||||
statusCode: noContentResp.status,
|
||||
taskProperties: {
|
||||
name: 'revert VM snapshot',
|
||||
objectId: vmId,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Required privilege:
|
||||
* - resource: vm, action: snapshot
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
- [xo-server] support qcow2 format in `disk.importContent` and `disk.import` jsonRPC api (PR [#9817](https://github.com/vatesfr/xen-orchestra/pull/9817))
|
||||
- [web-core] Update `UiTag` and parse tag for detecting tags with `=` (PR [#9811](https://github.com/vatesfr/xen-orchestra/pull/9811))
|
||||
- [Encryption] Implement encryption and decryption feature for redis (PR [#9735](https://github.com/vatesfr/xen-orchestra/pull/9735))
|
||||
- [REST API] Add `vms/:id/actions/revert_snapshot` REST route (PR [#9788](https://github.com/vatesfr/xen-orchestra/pull/9788))
|
||||
- **XO 5**:
|
||||
- [Export config] Hide passphrase by default (PR [#9824](https://github.com/vatesfr/xen-orchestra/pull/9824))
|
||||
- [Backups] Refactor clean phase for incremental and full backups ([#9765](https://github.com/vatesfr/xen-orchestra/pull/9765))
|
||||
|
||||
@@ -105,7 +105,7 @@ Actions are written using the exact string you pass in a privilege. A parent act
|
||||
|
||||
| Resource | Available actions |
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `vm` | `read`, `delete`, `export`, `pause`, `start`, `resume`, `snapshot`, `suspend`, `unpause`, `reboot:clean`, `reboot:hard`, `shutdown:clean`, `shutdown:hard`, `update:datasources`, `update:tags` |
|
||||
| `vm` | `read`, `delete`, `export`, `pause`, `start`, `resume`, `revert-snapshot`, `snapshot`, `suspend`, `unpause`, `reboot:clean`, `reboot:hard`, `shutdown:clean`, `shutdown:hard`, `update:datasources`, `update:tags` |
|
||||
| `vm-snapshot` | `read`, `delete`, `export`, `update:tags` |
|
||||
| `vm-template` | `read`, `delete`, `export`, `instantiate`, `update:tags` |
|
||||
| `vm-controller` | `read`, `update:tags` |
|
||||
|
||||
Reference in New Issue
Block a user