feat(xo-web/host): ask for confirmation to reboot the updated slave host 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.
This commit is contained in:
@@ -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))
|
- [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))
|
- [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))
|
- [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
|
### Bug fixes
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,25 @@ export async function restart({
|
|||||||
|
|
||||||
bypassBlockedSuspend = force,
|
bypassBlockedSuspend = force,
|
||||||
bypassCurrentVmCheck = 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) {
|
if (bypassBackupCheck) {
|
||||||
log.warn('host.restart with argument "bypassBackupCheck" set to true', { hostId: host.id })
|
log.warn('host.restart with argument "bypassBackupCheck" set to true', { hostId: host.id })
|
||||||
} else {
|
} else {
|
||||||
@@ -165,6 +183,10 @@ restart.params = {
|
|||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
bypassVersionCheck: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
restart.resolve = {
|
restart.resolve = {
|
||||||
|
|||||||
@@ -967,6 +967,8 @@ const messages = {
|
|||||||
// ----- Host actions ------
|
// ----- Host actions ------
|
||||||
disableMaintenanceMode: 'Disable maintenance mode',
|
disableMaintenanceMode: 'Disable maintenance mode',
|
||||||
enableMaintenanceMode: 'Enable 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',
|
startHostLabel: 'Start',
|
||||||
stopHostLabel: 'Stop',
|
stopHostLabel: 'Stop',
|
||||||
enableHostLabel: 'Enable',
|
enableHostLabel: 'Enable',
|
||||||
@@ -979,6 +981,7 @@ const messages = {
|
|||||||
forceRebootHostLabel: 'Force reboot',
|
forceRebootHostLabel: 'Force reboot',
|
||||||
forceSmartRebootHost:
|
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?',
|
'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',
|
rebootHostLabel: 'Reboot',
|
||||||
noHostsAvailableErrorTitle: 'Error while restarting host',
|
noHostsAvailableErrorTitle: 'Error while restarting host',
|
||||||
noHostsAvailableErrorMessage:
|
noHostsAvailableErrorMessage:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import Icon from '../icon'
|
|||||||
import logError from '../log-error'
|
import logError from '../log-error'
|
||||||
import NewAuthTokenModal from './new-auth-token-modal'
|
import NewAuthTokenModal from './new-auth-token-modal'
|
||||||
import RegisterProxyModal from './register-proxy-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 store from 'store'
|
||||||
import WarmMigrationModal from './warm-migration-modal'
|
import WarmMigrationModal from './warm-migration-modal'
|
||||||
import { alert, chooseAction, confirm } from '../modal'
|
import { alert, chooseAction, confirm } from '../modal'
|
||||||
@@ -900,6 +900,24 @@ const _restartHost = async ({ host, ...opts }) => {
|
|||||||
return _restartHost({ ...opts, host, bypassBackupCheck: true })
|
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)) {
|
if (noHostsAvailableErrCheck(error)) {
|
||||||
alert(_('noHostsAvailableErrorTitle'), _('noHostsAvailableErrorMessage'))
|
alert(_('noHostsAvailableErrorTitle'), _('noHostsAvailableErrorMessage'))
|
||||||
}
|
}
|
||||||
@@ -926,6 +944,12 @@ const backupIsRunning = (err, poolId) =>
|
|||||||
forbiddenOperation.is(err, {
|
forbiddenOperation.is(err, {
|
||||||
reason: `A backup is running on the pool: ${poolId}`,
|
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)
|
const noHostsAvailableErrCheck = err => err !== undefined && noHostsAvailable.is(err)
|
||||||
|
|
||||||
export const restartHosts = (hosts, force = false) => {
|
export const restartHosts = (hosts, force = false) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user