@@ -7,6 +7,7 @@
|
||||
- [Perf alert] Ability to trigger an alarm if a host/VM/SR usage value is below the threshold [#3612](https://github.com/vatesfr/xen-orchestra/issues/3612) (PR [#3675](https://github.com/vatesfr/xen-orchestra/pull/3675))
|
||||
- [Home/VMs] Display pool's name [#2226](https://github.com/vatesfr/xen-orchestra/issues/2226) (PR [#3709](https://github.com/vatesfr/xen-orchestra/pull/3709))
|
||||
- [Servers] Prevent new connection if pool is already connected [#2238](https://github.com/vatesfr/xen-orchestra/issues/2238) (PR [#3724](https://github.com/vatesfr/xen-orchestra/pull/3724))
|
||||
- [VM] Pause (like Suspend but doesn't copy RAM on disk) [#3727](https://github.com/vatesfr/xen-orchestra/issues/3727) (PR [#3731](https://github.com/vatesfr/xen-orchestra/pull/3731))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
||||
@@ -1080,6 +1080,20 @@ suspend.resolve = {
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
export async function pause({ vm }) {
|
||||
await this.getXapi(vm).call('VM.pause', vm._xapiRef)
|
||||
}
|
||||
|
||||
pause.params = {
|
||||
id: { type: 'string' },
|
||||
}
|
||||
|
||||
pause.resolve = {
|
||||
vm: ['id', 'VM', 'operate'],
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
export function resume({ vm }) {
|
||||
return this.getXapi(vm).resumeVm(vm._xapiId)
|
||||
}
|
||||
|
||||
@@ -1596,7 +1596,9 @@ export default class Xapi extends XapiBase {
|
||||
throw forbiddenOperation('Start', e.params[1])
|
||||
}
|
||||
if (e.code === 'VM_BAD_POWER_STATE') {
|
||||
return this.resumeVm(vmId)
|
||||
return e.params[2] === 'paused'
|
||||
? this.unpauseVm(vmId)
|
||||
: this.resumeVm(vmId)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
@@ -449,7 +449,7 @@ export default {
|
||||
}
|
||||
await this.call('VM.revert', snapshot.$ref)
|
||||
if (snapshot.snapshot_info['power-state-at-snapshot'] === 'Running') {
|
||||
const vm = snapshot.$snapshot_of
|
||||
const vm = await this.barrier(snapshot.snapshot_of)
|
||||
if (vm.power_state === 'Halted') {
|
||||
this.startVm(vm.$id)::ignoreErrors()
|
||||
} else if (vm.power_state === 'Suspended') {
|
||||
@@ -463,6 +463,10 @@ export default {
|
||||
return this.call('VM.resume', this.getObject(vmId).$ref, false, true)
|
||||
},
|
||||
|
||||
async unpauseVm(vmId) {
|
||||
return this.call('VM.unpause', this.getObject(vmId).$ref)
|
||||
},
|
||||
|
||||
shutdownVm(vmId, { hard = false } = {}) {
|
||||
return this.call(
|
||||
`VM.${hard ? 'hard' : 'clean'}_shutdown`,
|
||||
|
||||
@@ -618,6 +618,7 @@ const messages = {
|
||||
startVmOnMissingHostMessage: 'You must select a host',
|
||||
recoveryModeLabel: 'Recovery start',
|
||||
suspendVmLabel: 'Suspend',
|
||||
pauseVmLabel: 'Pause',
|
||||
stopVmLabel: 'Stop',
|
||||
forceShutdownVmLabel: 'Force shutdown',
|
||||
rebootVmLabel: 'Reboot',
|
||||
@@ -871,6 +872,7 @@ const messages = {
|
||||
powerStateHalted: 'halted',
|
||||
powerStateRunning: 'running',
|
||||
powerStateSuspended: 'suspended',
|
||||
powerStatePaused: 'paused',
|
||||
|
||||
// ----- VM home -----
|
||||
vmCurrentStatus: 'Current status:',
|
||||
@@ -1459,6 +1461,9 @@ const messages = {
|
||||
suspendVmsModalTitle: 'Suspend VM{vms, plural, one {} other {s}}',
|
||||
suspendVmsModalMessage:
|
||||
'Are you sure you want to suspend {vms, number} VM{vms, plural, one {} other {s}}?',
|
||||
pauseVmsModalTitle: 'Pause VM{vms, plural, one {} other {s}}',
|
||||
pauseVmsModalMessage:
|
||||
'Are you sure you want to pause {vms, number} VM{vms, plural, one {} other {s}}?',
|
||||
restartVmsModalTitle: 'Restart VM{vms, plural, one {} other {s}}',
|
||||
restartVmsModalMessage:
|
||||
'Are you sure you want to restart {vms, number} VM{vms, plural, one {} other {s}}?',
|
||||
@@ -2075,7 +2080,7 @@ const messages = {
|
||||
durationFormat:
|
||||
'{days, plural, =0 {} one {# day } other {# days }}{hours, plural, =0 {} one {# hour } other {# hours }}{minutes, plural, =0 {} one {# minute } other {# minutes }}{seconds, plural, =0 {} one {# second} other {# seconds}}',
|
||||
}
|
||||
forEach(messages, function (message, id) {
|
||||
forEach(messages, function(message, id) {
|
||||
if (isString(message)) {
|
||||
messages[id] = {
|
||||
id,
|
||||
|
||||
@@ -946,15 +946,21 @@ export const suspendVm = vm => _call('vm.suspend', { id: resolveId(vm) })
|
||||
|
||||
export const suspendVms = vms =>
|
||||
confirm({
|
||||
title: _('suspendVmsModalTitle', { nVms: vms.length }),
|
||||
body: _('suspendVmsModalMessage', { nVms: vms.length }),
|
||||
title: _('suspendVmsModalTitle', { vms: vms.length }),
|
||||
body: _('suspendVmsModalMessage', { vms: vms.length }),
|
||||
}).then(
|
||||
() =>
|
||||
Promise.all(map(vms, vm => _call('vm.suspend', { id: resolveId(vm) }))),
|
||||
noop
|
||||
)
|
||||
|
||||
export const resumeVm = vm => _call('vm.resume', { id: resolveId(vm) })
|
||||
export const pauseVm = vm => _call('vm.pause', { id: resolveId(vm) })
|
||||
|
||||
export const pauseVms = vms =>
|
||||
confirm({
|
||||
title: _('pauseVmsModalTitle', { vms: vms.length }),
|
||||
body: _('pauseVmsModalMessage', { vms: vms.length }),
|
||||
}).then(() => Promise.all(map(vms, pauseVm)), noop)
|
||||
|
||||
export const recoveryStartVm = vm =>
|
||||
_call('vm.recoveryStart', { id: resolveId(vm) })
|
||||
|
||||
@@ -323,6 +323,11 @@
|
||||
@extend .fa-desktop;
|
||||
@extend .text-primary;
|
||||
}
|
||||
&-paused {
|
||||
@extend .fa;
|
||||
@extend .fa-desktop;
|
||||
@extend .text-muted;
|
||||
}
|
||||
&-halted {
|
||||
@extend .fa;
|
||||
@extend .fa-desktop;
|
||||
@@ -364,6 +369,10 @@
|
||||
@extend .fa-copy;
|
||||
}
|
||||
&-suspend {
|
||||
@extend .fa;
|
||||
@extend .fa-power-off;
|
||||
}
|
||||
&-pause {
|
||||
@extend .fa;
|
||||
@extend .fa-pause;
|
||||
}
|
||||
@@ -377,7 +386,7 @@
|
||||
}
|
||||
&-force-shutdown {
|
||||
@extend .fa;
|
||||
@extend .fa-power-off;
|
||||
@extend .fa-plug;
|
||||
}
|
||||
&-docker {
|
||||
@extend .fa;
|
||||
@@ -418,7 +427,7 @@
|
||||
&-paused {
|
||||
@extend .fa;
|
||||
@extend .fa-circle;
|
||||
@extend .xo-status-suspended;
|
||||
@extend .xo-status-paused;
|
||||
}
|
||||
|
||||
&-unknown {
|
||||
|
||||
@@ -45,6 +45,7 @@ import {
|
||||
forgetSrs,
|
||||
isSrShared,
|
||||
migrateVms,
|
||||
pauseVms,
|
||||
reconnectAllHostsSrs,
|
||||
rescanSrs,
|
||||
restartHosts,
|
||||
@@ -149,6 +150,11 @@ const OPTIONS = {
|
||||
{ handler: copyVms, icon: 'vm-copy', tooltip: _('copyVmLabel') },
|
||||
],
|
||||
otherActions: [
|
||||
{
|
||||
handler: pauseVms,
|
||||
icon: 'vm-pause',
|
||||
labelId: 'pauseVmLabel',
|
||||
},
|
||||
{
|
||||
handler: suspendVms,
|
||||
icon: 'vm-suspend',
|
||||
|
||||
@@ -190,8 +190,8 @@ export default class Jobs extends Component {
|
||||
'vm.delete',
|
||||
'vm.migrate',
|
||||
'vm.migrate',
|
||||
'vm.pause',
|
||||
'vm.restart',
|
||||
'vm.resume',
|
||||
'vm.revert',
|
||||
'vm.rollingBackup',
|
||||
'vm.rollingDrCopy',
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
exportVm,
|
||||
migrateVm,
|
||||
restartVm,
|
||||
resumeVm,
|
||||
snapshotVm,
|
||||
startVm,
|
||||
stopVm,
|
||||
@@ -125,7 +124,7 @@ const vmActionBarByState = {
|
||||
Suspended: ({ vm, isSelfUser, canAdministrate }) => (
|
||||
<ActionBar display='icon' handlerParam={vm}>
|
||||
<Action
|
||||
handler={resumeVm}
|
||||
handler={startVm}
|
||||
icon='vm-start'
|
||||
label={_('resumeVmLabel')}
|
||||
pending={includes(vm.current_operations, 'start')}
|
||||
@@ -156,6 +155,24 @@ const vmActionBarByState = {
|
||||
)}
|
||||
</ActionBar>
|
||||
),
|
||||
Paused: ({ vm, isSelfUser }) => (
|
||||
<ActionBar display='icon' handlerParam={vm}>
|
||||
<Action
|
||||
handler={startVm}
|
||||
icon='vm-start'
|
||||
label={_('resumeVmLabel')}
|
||||
pending={includes(vm.current_operations, 'unpause')}
|
||||
/>
|
||||
{!isSelfUser && (
|
||||
<Action
|
||||
handler={snapshotVm}
|
||||
icon='vm-snapshot'
|
||||
label={_('snapshotVmLabel')}
|
||||
pending={includes(vm.current_operations, 'snapshot')}
|
||||
/>
|
||||
)}
|
||||
</ActionBar>
|
||||
),
|
||||
}
|
||||
|
||||
const VmActionBar = addSubscriptions(() => ({
|
||||
@@ -163,7 +180,10 @@ const VmActionBar = addSubscriptions(() => ({
|
||||
}))(
|
||||
connectStore(() => ({
|
||||
checkPermissions: getCheckPermissions,
|
||||
userId: createSelector(getUser, user => user.id),
|
||||
userId: createSelector(
|
||||
getUser,
|
||||
user => user.id
|
||||
),
|
||||
}))(({ checkPermissions, vm, userId, resourceSets }) => {
|
||||
// Is the user in the same resource set as the VM
|
||||
const _getIsSelfUser = createSelector(
|
||||
|
||||
@@ -32,9 +32,9 @@ import {
|
||||
editVm,
|
||||
getVmsHaValues,
|
||||
isVmRunning,
|
||||
pauseVm,
|
||||
recoveryStartVm,
|
||||
restartVm,
|
||||
resumeVm,
|
||||
shareVm,
|
||||
startVm,
|
||||
stopVm,
|
||||
@@ -330,6 +330,13 @@ export default class TabAdvanced extends Component {
|
||||
<Col className='text-xs-right'>
|
||||
{vm.power_state === 'Running' && (
|
||||
<span>
|
||||
<TabButton
|
||||
btnStyle='primary'
|
||||
handler={pauseVm}
|
||||
handlerParam={vm}
|
||||
icon='vm-pause'
|
||||
labelId='pauseVmLabel'
|
||||
/>
|
||||
<TabButton
|
||||
btnStyle='primary'
|
||||
handler={suspendVm}
|
||||
@@ -381,7 +388,7 @@ export default class TabAdvanced extends Component {
|
||||
<span>
|
||||
<TabButton
|
||||
btnStyle='primary'
|
||||
handler={resumeVm}
|
||||
handler={startVm}
|
||||
handlerParam={vm}
|
||||
icon='vm-start'
|
||||
labelId='resumeVmLabel'
|
||||
@@ -395,6 +402,31 @@ export default class TabAdvanced extends Component {
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
{vm.power_state === 'Paused' && (
|
||||
<span>
|
||||
<TabButton
|
||||
btnStyle='primary'
|
||||
handler={startVm}
|
||||
handlerParam={vm}
|
||||
icon='vm-start'
|
||||
labelId='resumeVmLabel'
|
||||
/>
|
||||
<TabButton
|
||||
btnStyle='warning'
|
||||
handler={forceReboot}
|
||||
handlerParam={vm}
|
||||
icon='vm-force-reboot'
|
||||
labelId='forceRebootVmLabel'
|
||||
/>
|
||||
<TabButton
|
||||
btnStyle='warning'
|
||||
handler={forceShutdown}
|
||||
handlerParam={vm}
|
||||
icon='vm-force-shutdown'
|
||||
labelId='forceShutdownVmLabel'
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
<TabButton
|
||||
btnStyle='danger'
|
||||
disabled={vm.power_state !== 'Halted'}
|
||||
|
||||
Reference in New Issue
Block a user