feat(xo-server,xo-web/snapshot): ability to snapshot the VM memory (#3812)
Fixes #3795
This commit is contained in:
parent
b459f74a8c
commit
b8a3d00343
@ -7,6 +7,7 @@
|
||||
- [Backup NG] Restore logs moved to restore tab [#3772](https://github.com/vatesfr/xen-orchestra/issues/3772) (PR [#3802](https://github.com/vatesfr/xen-orchestra/pull/3802))
|
||||
- [Remotes] New SMB implementation that provides better stability and performance [#2257](https://github.com/vatesfr/xen-orchestra/issues/2257) (PR [#3708](https://github.com/vatesfr/xen-orchestra/pull/3708))
|
||||
- [VM/advanced] ACL management from VM view [#3040](https://github.com/vatesfr/xen-orchestra/issues/3727) (PR [#3040](https://github.com/vatesfr/xen-orchestra/pull/3774))
|
||||
- [VM / snapshots] Ability to save the VM memory [#3795](https://github.com/vatesfr/xen-orchestra/issues/3795) (PR [#3812](https://github.com/vatesfr/xen-orchestra/pull/3812))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
@ -20,12 +20,19 @@ export default {
|
||||
// https://xapi-project.github.io/xen-api/classes/vm.html#checkpoint
|
||||
async checkpointVm(vmId, nameLabel) {
|
||||
const vm = this.getObject(vmId)
|
||||
const ref = await this.callAsync(
|
||||
'VM.checkpoint',
|
||||
vm.$ref,
|
||||
nameLabel != null ? nameLabel : vm.name_label
|
||||
).then(extractOpaqueRef)
|
||||
return this.barrier(ref)
|
||||
try {
|
||||
const ref = await this.callAsync(
|
||||
'VM.checkpoint',
|
||||
vm.$ref,
|
||||
nameLabel != null ? nameLabel : vm.name_label
|
||||
).then(extractOpaqueRef)
|
||||
return this.barrier(ref)
|
||||
} catch (error) {
|
||||
if (error.code === 'VM_BAD_POWER_STATE') {
|
||||
return this._snapshotVm(vm, nameLabel)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: clean up on error.
|
||||
|
@ -1001,6 +1001,8 @@ const messages = {
|
||||
|
||||
// ----- VM snapshot tab -----
|
||||
noSnapshots: 'No snapshots',
|
||||
newSnapshotWithMemory: 'New snapshot with memory',
|
||||
snapshotMemorySaved: 'memory saved',
|
||||
snapshotCreateButton: 'New snapshot',
|
||||
tipCreateSnapshotLabel: 'Just click on the snapshot button to create one!',
|
||||
revertSnapshot: 'Revert VM to this snapshot',
|
||||
@ -1477,9 +1479,8 @@ const messages = {
|
||||
restartVmsModalTitle: 'Restart VM{vms, plural, one {} other {s}}',
|
||||
restartVmsModalMessage:
|
||||
'Are you sure you want to restart {vms, number} VM{vms, plural, one {} other {s}}?',
|
||||
snapshotSaveMemory: 'save memory',
|
||||
snapshotVmsModalTitle: 'Snapshot VM{vms, plural, one {} other {s}}',
|
||||
snapshotVmsModalMessage:
|
||||
'Are you sure you want to snapshot {vms, number} VM{vms, plural, one {} other {s}}?',
|
||||
deleteVmsModalTitle: 'Delete VM{vms, plural, one {} other {s}}',
|
||||
deleteVmsModalMessage:
|
||||
'Are you sure you want to delete {vms, number} VM{vms, plural, one {} other {s}}? ALL VM DISKS WILL BE REMOVED',
|
||||
|
@ -1116,13 +1116,19 @@ export const deleteTemplates = templates =>
|
||||
}, noop)
|
||||
}, noop)
|
||||
|
||||
export const snapshotVm = vm => _call('vm.snapshot', { id: resolveId(vm) })
|
||||
export const snapshotVm = (vm, saveMemory) =>
|
||||
_call('vm.snapshot', { id: resolveId(vm), saveMemory })
|
||||
|
||||
import SnapshotVmModalBody from './snapshot-vm-modal' // eslint-disable-line import/first
|
||||
export const snapshotVms = vms =>
|
||||
confirm({
|
||||
icon: 'memory',
|
||||
title: _('snapshotVmsModalTitle', { vms: vms.length }),
|
||||
body: _('snapshotVmsModalMessage', { vms: vms.length }),
|
||||
}).then(() => map(vms, vmId => snapshotVm({ id: vmId })), noop)
|
||||
body: <SnapshotVmModalBody />,
|
||||
}).then(
|
||||
saveMemory => Promise.all(map(vms, vm => snapshotVm(vm, saveMemory))),
|
||||
noop
|
||||
)
|
||||
|
||||
export const deleteSnapshot = vm =>
|
||||
confirm({
|
||||
|
23
packages/xo-web/src/common/xo/snapshot-vm-modal/index.js
Normal file
23
packages/xo-web/src/common/xo/snapshot-vm-modal/index.js
Normal file
@ -0,0 +1,23 @@
|
||||
import Component from 'base-component'
|
||||
import React from 'react'
|
||||
|
||||
import _ from '../../intl'
|
||||
|
||||
export default class SnapshotVmModalBody extends Component {
|
||||
get value() {
|
||||
return this.state.saveMemory
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<label>
|
||||
<input
|
||||
type='checkbox'
|
||||
onChange={this.linkState('saveMemory')}
|
||||
checked={this.state.saveMemory}
|
||||
/>{' '}
|
||||
{_('snapshotSaveMemory')}
|
||||
</label>
|
||||
)
|
||||
}
|
||||
}
|
@ -48,10 +48,18 @@ const COLUMNS = [
|
||||
},
|
||||
{
|
||||
itemRenderer: snapshot => (
|
||||
<Text
|
||||
onChange={value => editVm(snapshot, { name_label: value })}
|
||||
value={snapshot.name_label}
|
||||
/>
|
||||
<div>
|
||||
<Text
|
||||
onChange={value => editVm(snapshot, { name_label: value })}
|
||||
value={snapshot.name_label}
|
||||
/>{' '}
|
||||
{/* checkpoint snapshots are in a Suspended state */}
|
||||
{snapshot.power_state === 'Suspended' && (
|
||||
<Tooltip content={_('snapshotMemorySaved')}>
|
||||
<Icon icon='memory' color='text-success' />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
name: _('snapshotName'),
|
||||
sortCriteria: _ => _.name_label,
|
||||
@ -107,6 +115,8 @@ const INDIVIDUAL_ACTIONS = [
|
||||
},
|
||||
]
|
||||
|
||||
const _snapshotVmWithMemory = vm => snapshotVm(vm, true)
|
||||
|
||||
@connectStore(() => ({
|
||||
snapshots: createGetObjectsOfType('VM-snapshot')
|
||||
.pick((_, props) => props.vm.snapshots)
|
||||
@ -119,6 +129,16 @@ export default class TabSnapshot extends Component {
|
||||
<Container>
|
||||
<Row>
|
||||
<Col className='text-xs-right'>
|
||||
{vm.power_state !== 'Halted' && (
|
||||
<TabButton
|
||||
btnStyle='primary'
|
||||
handler={_snapshotVmWithMemory}
|
||||
handlerParam={vm}
|
||||
icon='memory'
|
||||
labelId='newSnapshotWithMemory'
|
||||
pending={includes(vm.current_operations, 'checkpoint')}
|
||||
/>
|
||||
)}
|
||||
<TabButton
|
||||
btnStyle='primary'
|
||||
handler={snapshotVm}
|
||||
|
Loading…
Reference in New Issue
Block a user