Skip to content

Commit

Permalink
feat(xo-web/host): ask for confirmation to reboot the updated slave h…
Browse files Browse the repository at this point in the history
…ost if the master is not (#7293)

Fixes #7059

In case a slave host requires a reboot to apply updates and the master is using
the same version as the slave host, a confirmation modal is triggered.
  • Loading branch information
MathieuRA committed Jan 19, 2024
1 parent f024238 commit 85ec261
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- [Pool/Host] Add a warning if hosts do not have the same version within a pool [#7059](https://github.com/vatesfr/xen-orchestra/issues/7059) (PR [#7280](https://github.com/vatesfr/xen-orchestra/pull/7280))
- [Plugins] Loading, or unloading, will respectively enable, or disable, _Auto-load at server start_, this should lead to least surprising behaviors (PR [#7317](https://github.com/vatesfr/xen-orchestra/pull/7317))
- [VM/Advanced] Admin can change VM creator [Forum#7313](https://xcp-ng.org/forum/topic/7313/change-created-by-and-date-information) (PR [#7276](https://github.com/vatesfr/xen-orchestra/pull/7276))
- [Host/Reboot] Confirmation modal to reboot an updated slave host if the master is not [#7059](https://github.com/vatesfr/xen-orchestra/issues/7059) (PR [#7293](https://github.com/vatesfr/xen-orchestra/pull/7293))

### Bug fixes

Expand Down
22 changes: 22 additions & 0 deletions packages/xo-server/src/api/host.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,25 @@ export async function restart({

bypassBlockedSuspend = force,
bypassCurrentVmCheck = force,
bypassVersionCheck = force,
}) {

if (bypassVersionCheck) {
log.warn('host.restart with argument "bypassVersionCheck" set to true', { hostId: host.id })
} else {
const pool = this.getObject(host.$poolId, 'pool')
const master = this.getObject(pool.master, 'host')
const hostRebootRequired = host.rebootRequired
if (hostRebootRequired && host.id !== master.id && host.version === master.version) {
throw incorrectState({
actual: hostRebootRequired,
expected: false,
object: master.id,
property: 'rebootRequired',
})
}
}

if (bypassBackupCheck) {
log.warn('host.restart with argument "bypassBackupCheck" set to true', { hostId: host.id })
} else {
Expand Down Expand Up @@ -165,6 +183,10 @@ restart.params = {
type: 'boolean',
default: false,
},
bypassVersionCheck: {
type: 'boolean',
optional: true,
},
}

restart.resolve = {
Expand Down
3 changes: 3 additions & 0 deletions packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,8 @@ const messages = {
// ----- Host actions ------
disableMaintenanceMode: 'Disable maintenance mode',
enableMaintenanceMode: 'Enable maintenance mode',
slaveHostMoreUpToDateThanMasterAfterRestart:
'It appears that this host will be more up-to-date than the master ({master}) after the restart. This will result in the slave being unable to contact the pool master. Please update and restart your master node first.',
startHostLabel: 'Start',
stopHostLabel: 'Stop',
enableHostLabel: 'Enable',
Expand All @@ -979,6 +981,7 @@ const messages = {
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?',
restartAnyway: 'Restart anyway',
rebootHostLabel: 'Reboot',
noHostsAvailableErrorTitle: 'Error while restarting host',
noHostsAvailableErrorMessage:
Expand Down
26 changes: 25 additions & 1 deletion packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import Icon from '../icon'
import logError from '../log-error'
import NewAuthTokenModal from './new-auth-token-modal'
import RegisterProxyModal from './register-proxy-modal'
import renderXoItem, { renderXoItemFromId, Vm } from '../render-xo-item'
import renderXoItem, { Host, renderXoItemFromId, Vm } from '../render-xo-item'
import store from 'store'
import WarmMigrationModal from './warm-migration-modal'
import { alert, chooseAction, confirm } from '../modal'
Expand Down Expand Up @@ -900,6 +900,24 @@ const _restartHost = async ({ host, ...opts }) => {
return _restartHost({ ...opts, host, bypassBackupCheck: true })
}

if (masterNeedsUpdate(error)) {
const state = store.getState()
const master = getObject(state, getObject(state, host.$pool).master)
await chooseAction({
body: (
<p>
<Icon icon='alarm' />{' '}
{_('slaveHostMoreUpToDateThanMasterAfterRestart', { master: <Host id={master.id} link /> })}
</p>
),
buttons: [{ label: _('restartAnyway'), btnStyle: 'danger' }],
icon: 'alarm',
title: _('restartHostModalTitle'),
})

return _restartHost({ ...opts, host, bypassVersionCheck: true })
}

if (noHostsAvailableErrCheck(error)) {
alert(_('noHostsAvailableErrorTitle'), _('noHostsAvailableErrorMessage'))
}
Expand All @@ -926,6 +944,12 @@ const backupIsRunning = (err, poolId) =>
forbiddenOperation.is(err, {
reason: `A backup is running on the pool: ${poolId}`,
}))
const masterNeedsUpdate = err =>
err !== undefined &&
incorrectState.is(err, {
property: 'rebootRequired',
})

const noHostsAvailableErrCheck = err => err !== undefined && noHostsAvailable.is(err)

export const restartHosts = (hosts, force = false) => {
Expand Down

0 comments on commit 85ec261

Please sign in to comment.