feat(xo-web/host): allow to force smartReboot

This commit is contained in:
mathieuRA 2023-09-07 17:00:16 +02:00 committed by Pierre Donias
parent 3bf6aae103
commit 549d9b70a9
4 changed files with 90 additions and 35 deletions

View File

@ -7,6 +7,8 @@
> 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
> Users must be able to say: “I had this issue, happy to know it's fixed”
@ -29,5 +31,6 @@
- @xen-orchestra/xapi minor
- xo-server minor
- xo-web minor
<!--packages-end-->

View File

@ -963,9 +963,13 @@ const messages = {
enableHostLabel: 'Enable',
disableHostLabel: 'Disable',
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',
smartRebootHostTooltip: 'Suspend resident VMs, reboot host and resume VMs automatically',
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',
noHostsAvailableErrorTitle: 'Error while restarting host',
noHostsAvailableErrorMessage:

View File

@ -16,6 +16,7 @@ import {
incorrectState,
noHostsAvailable,
operationBlocked,
operationFailed,
vmLacksFeature,
} from 'xo-common/api-errors'
@ -821,22 +822,51 @@ export const setRemoteSyslogHost = (host, syslogDestination) =>
export const setRemoteSyslogHosts = (hosts, syslogDestination) =>
Promise.all(map(hosts, host => setRemoteSyslogHost(host, syslogDestination)))
export const restartHost = (host, force = false, suspendResidentVms = false) =>
confirm({
export const restartHost = async (
host,
force = false,
suspendResidentVms = false,
bypassBlockedSuspend = false,
bypassCurrentVmCheck = false
) => {
await confirm({
title: _('restartHostModalTitle'),
body: _('restartHostModalMessage'),
}).then(
() =>
_call('host.restart', { id: resolveId(host), force, suspendResidentVms })
.catch(async error => {
if (
forbiddenOperation.is(error, {
reason: `A backup may run on the pool: ${host.$poolId}`,
}) ||
forbiddenOperation.is(error, {
reason: `A backup is running on the pool: ${host.$poolId}`,
})
) {
return _restartHost({ host, force, suspendResidentVms, bypassBlockedSuspend, bypassCurrentVmCheck })
}
const _restartHost = async ({ host, ...opts }) => {
opts = { ...opts, id: resolveId(host) }
try {
await _call('host.restart', opts)
} catch (error) {
if (cantSuspend(error)) {
await confirm({
body: (
<p>
<Icon icon='alarm' /> {_('forceSmartRebootHost', { nVms: error.data.actual.length })}
</p>
),
title: _('restartHostModalTitle'),
})
return _restartHost({ ...opts, host, bypassBlockedSuspend: true })
}
if (xoaOnHost(error)) {
await confirm({
body: (
<p>
<Icon icon='alarm' /> {_('smartRebootBypassCurrentVmCheck')}
</p>
),
title: _('restartHostModalTitle'),
})
return _restartHost({ ...opts, host, bypassCurrentVmCheck: true })
}
if (backupIsRunning(error, host.$poolId)) {
await confirm({
body: (
<p className='text-warning'>
@ -845,18 +875,36 @@ export const restartHost = (host, force = false, suspendResidentVms = false) =>
),
title: _('restartHostModalTitle'),
})
return _call('host.restart', { id: resolveId(host), force, suspendResidentVms, bypassBackupCheck: true })
return _restartHost({ ...opts, host, bypassBackupCheck: true })
}
throw error
})
.catch(error => {
if (noHostsAvailable.is(error)) {
if (noHostsAvailableErrCheck(error)) {
alert(_('noHostsAvailableErrorTitle'), _('noHostsAvailableErrorMessage'))
}
throw error
}),
noop
)
}
}
// ---- 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) => {
const nHosts = size(hosts)

View File

@ -76,7 +76,7 @@ const downloadLogs = async uuid => {
const forceReboot = host => restartHost(host, true)
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) => (