feat(xo-web/host): allow to force smartReboot
This commit is contained in:
parent
3bf6aae103
commit
549d9b70a9
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
> Users must be able to say: “Nice enhancement, I'm eager to test it”
|
> Users must be able to say: “Nice enhancement, I'm eager to test it”
|
||||||
|
|
||||||
|
- [Host/Advanced] Allow to force _Smart reboot_ if some resident VMs have the suspend operation blocked [Forum#7136](https://xcp-ng.org/forum/topic/7136/suspending-vms-during-host-reboot/23) (PR [#7025](https://github.com/vatesfr/xen-orchestra/pull/7025))
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
|
||||||
> Users must be able to say: “I had this issue, happy to know it's fixed”
|
> Users must be able to say: “I had this issue, happy to know it's fixed”
|
||||||
@ -29,5 +31,6 @@
|
|||||||
|
|
||||||
- @xen-orchestra/xapi minor
|
- @xen-orchestra/xapi minor
|
||||||
- xo-server minor
|
- xo-server minor
|
||||||
|
- xo-web minor
|
||||||
|
|
||||||
<!--packages-end-->
|
<!--packages-end-->
|
||||||
|
@ -963,9 +963,13 @@ const messages = {
|
|||||||
enableHostLabel: 'Enable',
|
enableHostLabel: 'Enable',
|
||||||
disableHostLabel: 'Disable',
|
disableHostLabel: 'Disable',
|
||||||
restartHostAgent: 'Restart toolstack',
|
restartHostAgent: 'Restart toolstack',
|
||||||
|
smartRebootBypassCurrentVmCheck:
|
||||||
|
'As the XOA is hosted on the host that is scheduled for a reboot, it will also be restarted. Consequently, XO won\'t be able to resume VMs, and VMs with the "Protect from accidental shutdown" option enabled will not have this option reactivated automatically.',
|
||||||
smartRebootHostLabel: 'Smart reboot',
|
smartRebootHostLabel: 'Smart reboot',
|
||||||
smartRebootHostTooltip: 'Suspend resident VMs, reboot host and resume VMs automatically',
|
smartRebootHostTooltip: 'Suspend resident VMs, reboot host and resume VMs automatically',
|
||||||
forceRebootHostLabel: 'Force reboot',
|
forceRebootHostLabel: 'Force reboot',
|
||||||
|
forceSmartRebootHost:
|
||||||
|
'Smart Reboot failed because {nVms, number} VM{nVms, plural, one {} other {s}} ha{nVms, plural, one {s} other {ve}} {nVms, plural, one {its} other {their}} Suspend operation blocked. Would you like to force?',
|
||||||
rebootHostLabel: 'Reboot',
|
rebootHostLabel: 'Reboot',
|
||||||
noHostsAvailableErrorTitle: 'Error while restarting host',
|
noHostsAvailableErrorTitle: 'Error while restarting host',
|
||||||
noHostsAvailableErrorMessage:
|
noHostsAvailableErrorMessage:
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
incorrectState,
|
incorrectState,
|
||||||
noHostsAvailable,
|
noHostsAvailable,
|
||||||
operationBlocked,
|
operationBlocked,
|
||||||
|
operationFailed,
|
||||||
vmLacksFeature,
|
vmLacksFeature,
|
||||||
} from 'xo-common/api-errors'
|
} from 'xo-common/api-errors'
|
||||||
|
|
||||||
@ -821,42 +822,89 @@ export const setRemoteSyslogHost = (host, syslogDestination) =>
|
|||||||
export const setRemoteSyslogHosts = (hosts, syslogDestination) =>
|
export const setRemoteSyslogHosts = (hosts, syslogDestination) =>
|
||||||
Promise.all(map(hosts, host => setRemoteSyslogHost(host, syslogDestination)))
|
Promise.all(map(hosts, host => setRemoteSyslogHost(host, syslogDestination)))
|
||||||
|
|
||||||
export const restartHost = (host, force = false, suspendResidentVms = false) =>
|
export const restartHost = async (
|
||||||
confirm({
|
host,
|
||||||
|
force = false,
|
||||||
|
suspendResidentVms = false,
|
||||||
|
bypassBlockedSuspend = false,
|
||||||
|
bypassCurrentVmCheck = false
|
||||||
|
) => {
|
||||||
|
await confirm({
|
||||||
title: _('restartHostModalTitle'),
|
title: _('restartHostModalTitle'),
|
||||||
body: _('restartHostModalMessage'),
|
body: _('restartHostModalMessage'),
|
||||||
}).then(
|
})
|
||||||
() =>
|
return _restartHost({ host, force, suspendResidentVms, bypassBlockedSuspend, bypassCurrentVmCheck })
|
||||||
_call('host.restart', { id: resolveId(host), force, suspendResidentVms })
|
}
|
||||||
.catch(async error => {
|
|
||||||
if (
|
const _restartHost = async ({ host, ...opts }) => {
|
||||||
forbiddenOperation.is(error, {
|
opts = { ...opts, id: resolveId(host) }
|
||||||
reason: `A backup may run on the pool: ${host.$poolId}`,
|
|
||||||
}) ||
|
try {
|
||||||
forbiddenOperation.is(error, {
|
await _call('host.restart', opts)
|
||||||
reason: `A backup is running on the pool: ${host.$poolId}`,
|
} catch (error) {
|
||||||
})
|
if (cantSuspend(error)) {
|
||||||
) {
|
await confirm({
|
||||||
await confirm({
|
body: (
|
||||||
body: (
|
<p>
|
||||||
<p className='text-warning'>
|
<Icon icon='alarm' /> {_('forceSmartRebootHost', { nVms: error.data.actual.length })}
|
||||||
<Icon icon='alarm' /> {_('bypassBackupHostModalMessage')}
|
</p>
|
||||||
</p>
|
),
|
||||||
),
|
title: _('restartHostModalTitle'),
|
||||||
title: _('restartHostModalTitle'),
|
})
|
||||||
})
|
return _restartHost({ ...opts, host, bypassBlockedSuspend: true })
|
||||||
return _call('host.restart', { id: resolveId(host), force, suspendResidentVms, bypassBackupCheck: true })
|
}
|
||||||
}
|
|
||||||
throw error
|
if (xoaOnHost(error)) {
|
||||||
})
|
await confirm({
|
||||||
.catch(error => {
|
body: (
|
||||||
if (noHostsAvailable.is(error)) {
|
<p>
|
||||||
alert(_('noHostsAvailableErrorTitle'), _('noHostsAvailableErrorMessage'))
|
<Icon icon='alarm' /> {_('smartRebootBypassCurrentVmCheck')}
|
||||||
}
|
</p>
|
||||||
throw error
|
),
|
||||||
}),
|
title: _('restartHostModalTitle'),
|
||||||
noop
|
})
|
||||||
)
|
return _restartHost({ ...opts, host, bypassCurrentVmCheck: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backupIsRunning(error, host.$poolId)) {
|
||||||
|
await confirm({
|
||||||
|
body: (
|
||||||
|
<p className='text-warning'>
|
||||||
|
<Icon icon='alarm' /> {_('bypassBackupHostModalMessage')}
|
||||||
|
</p>
|
||||||
|
),
|
||||||
|
title: _('restartHostModalTitle'),
|
||||||
|
})
|
||||||
|
return _restartHost({ ...opts, host, bypassBackupCheck: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noHostsAvailableErrCheck(error)) {
|
||||||
|
alert(_('noHostsAvailableErrorTitle'), _('noHostsAvailableErrorMessage'))
|
||||||
|
}
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Restart Host errors
|
||||||
|
const cantSuspend = err =>
|
||||||
|
err !== undefined &&
|
||||||
|
incorrectState.is(err, {
|
||||||
|
object: 'suspendBlocked',
|
||||||
|
})
|
||||||
|
const xoaOnHost = err =>
|
||||||
|
err !== undefined &&
|
||||||
|
operationFailed.is(err, {
|
||||||
|
code: 'xoaOnHost',
|
||||||
|
})
|
||||||
|
const backupIsRunning = (err, poolId) =>
|
||||||
|
err !== undefined &&
|
||||||
|
(forbiddenOperation.is(err, {
|
||||||
|
reason: `A backup may run on the pool: ${poolId}`,
|
||||||
|
}) ||
|
||||||
|
forbiddenOperation.is(err, {
|
||||||
|
reason: `A backup is running on the pool: ${poolId}`,
|
||||||
|
}))
|
||||||
|
const noHostsAvailableErrCheck = err => err !== undefined && noHostsAvailable.is(err)
|
||||||
|
|
||||||
export const restartHosts = (hosts, force = false) => {
|
export const restartHosts = (hosts, force = false) => {
|
||||||
const nHosts = size(hosts)
|
const nHosts = size(hosts)
|
||||||
|
@ -76,7 +76,7 @@ const downloadLogs = async uuid => {
|
|||||||
const forceReboot = host => restartHost(host, true)
|
const forceReboot = host => restartHost(host, true)
|
||||||
|
|
||||||
const smartReboot = ALLOW_SMART_REBOOT
|
const smartReboot = ALLOW_SMART_REBOOT
|
||||||
? host => restartHost(host, false, true) // don't force, suspend resident VMs
|
? host => restartHost(host, false, true, false, false) // don't force, suspend resident VMs, don't bypass blocked suspend, don't bypass current VM check
|
||||||
: () => {}
|
: () => {}
|
||||||
|
|
||||||
const formatPack = ({ name, author, description, version }, key) => (
|
const formatPack = ({ name, author, description, version }, key) => (
|
||||||
|
Loading…
Reference in New Issue
Block a user