feat(xo-web/pool): ability to do a rolling pool reboot (#7243)
Fixes #6885 See #7242
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
- [Tags] Admin can create colored tags (PR [#7262](https://github.com/vatesfr/xen-orchestra/pull/7262))
|
||||
- [Tags] Add tooltips on `xo:no-bak` and `xo:notify-on-snapshot` tags (PR [#7335](https://github.com/vatesfr/xen-orchestra/pull/7335))
|
||||
- [VM] Custom notes [#5792](https://github.com/vatesfr/xen-orchestra/issues/5792) (PR [#7322](https://github.com/vatesfr/xen-orchestra/pull/7322))
|
||||
- [Pool/Advanced] Ability to do a `Rolling Pool Reboot` (Enterprise plans) [#6885](https://github.com/vatesfr/xen-orchestra/issues/6885) (PRs [#7243](https://github.com/vatesfr/xen-orchestra/pull/7243), [#7242](https://github.com/vatesfr/xen-orchestra/pull/7242))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
||||
@@ -912,6 +912,13 @@ const messages = {
|
||||
poolSupportSourceUsers: 'XCP-ng Pro Support not available for source users',
|
||||
poolSupportXcpngOnly: 'Only available for pool of XCP-ng hosts',
|
||||
poolLicenseAlreadyFullySupported: 'The pool is already fully supported',
|
||||
rollingPoolReboot: 'Rolling Pool Reboot',
|
||||
rollingPoolRebootHaWarning: 'High Availability is enabled. This will automatically disable it during the reboot.',
|
||||
rollingPoolRebootLoadBalancerWarning:
|
||||
'Load Balancer plugin is running. This will automatically pause it during the reboot.',
|
||||
rollingPoolRebootMessage:
|
||||
'Are you sure you want to start a Rolling Pool Reboot? Running VMs will be migrated back and forth and this can take a while. Scheduled backups that may concern this pool will be disabled.',
|
||||
|
||||
setpoolMaster: 'Master',
|
||||
syslogRemoteHost: 'Remote syslog host',
|
||||
defaultMigrationNetwork: 'Default migration network',
|
||||
@@ -2684,6 +2691,9 @@ const messages = {
|
||||
proxyMultipleLicenses: 'This proxy has more than 1 license!',
|
||||
proxyUnknownVm: 'Unknown proxy VM.',
|
||||
|
||||
// ----- plan -----
|
||||
onlyAvailableToEnterprise: 'Only available to Enterprise users',
|
||||
|
||||
// ----- proxies -----
|
||||
forgetProxyApplianceTitle: 'Forget prox{n, plural, one {y} other {ies}}',
|
||||
forgetProxyApplianceMessage: 'Are you sure you want to forget {n, number} prox{n, plural, one {y} other {ies}}?',
|
||||
|
||||
@@ -48,6 +48,7 @@ import {
|
||||
} from '../store/actions'
|
||||
|
||||
import parseNdJson from './_parseNdJson'
|
||||
import RollingPoolRebootModal from './rolling-pool-reboot-modal'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
@@ -816,6 +817,32 @@ export const setPoolMaster = host =>
|
||||
}),
|
||||
}).then(() => _call('pool.setPoolMaster', { host: resolveId(host) }), noop)
|
||||
|
||||
export const rollingPoolReboot = async pool => {
|
||||
const poolId = resolveId(pool)
|
||||
await confirm({
|
||||
body: <RollingPoolRebootModal pool={poolId} />,
|
||||
title: _('rollingPoolReboot'),
|
||||
icon: 'pool-rolling-reboot',
|
||||
})
|
||||
try {
|
||||
return await _call('pool.rollingReboot', { pool: poolId })
|
||||
} catch (error) {
|
||||
if (!forbiddenOperation.is(error)) {
|
||||
throw error
|
||||
}
|
||||
await confirm({
|
||||
body: (
|
||||
<p className='text-warning'>
|
||||
<Icon icon='alarm' /> {_('bypassBackupPoolModalMessage')}
|
||||
</p>
|
||||
),
|
||||
title: _('rollingPoolReboot'),
|
||||
icon: 'pool-rolling-reboot',
|
||||
})
|
||||
return _call('pool.rollingReboot', { pool: poolId, bypassBackupCheck: true })
|
||||
}
|
||||
}
|
||||
|
||||
// Host --------------------------------------------------------------
|
||||
|
||||
export const setSchedulerGranularity = (host, schedulerGranularity) =>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import _ from 'intl'
|
||||
import addSubscriptions from 'add-subscriptions'
|
||||
import BaseComponent from 'base-component'
|
||||
import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import { connectStore } from 'utils'
|
||||
import { createGetObjectsOfType } from 'selectors'
|
||||
|
||||
import { subscribePlugins } from '../'
|
||||
|
||||
@addSubscriptions(() => ({
|
||||
plugins: subscribePlugins,
|
||||
}))
|
||||
@connectStore(
|
||||
{
|
||||
pools: createGetObjectsOfType('pool'),
|
||||
},
|
||||
{ withRef: true }
|
||||
)
|
||||
export default class RollingPoolRebootModal extends BaseComponent {
|
||||
render() {
|
||||
const pool = this.props.pools[this.props.pool]
|
||||
const loadBalancerPlugin =
|
||||
this.props.plugins !== undefined && this.props.plugins.find(plugin => plugin.name === 'load-balancer')
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>{_('rollingPoolRebootMessage')}</p>
|
||||
{pool.HA_enabled && (
|
||||
<p>
|
||||
<em className='text-warning'>
|
||||
<Icon icon='alarm' /> {_('rollingPoolRebootHaWarning')}
|
||||
</em>
|
||||
</p>
|
||||
)}
|
||||
{loadBalancerPlugin !== undefined && loadBalancerPlugin.loaded && (
|
||||
<p>
|
||||
<em className='text-warning'>
|
||||
<Icon icon='alarm' /> {_('rollingPoolRebootLoadBalancerWarning')}
|
||||
</em>
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -695,6 +695,10 @@
|
||||
@extend .fa;
|
||||
@extend .fa-angle-double-down;
|
||||
}
|
||||
&-rolling-reboot {
|
||||
@extend .fa;
|
||||
@extend .fa-circle-o-notch;
|
||||
}
|
||||
}
|
||||
|
||||
&-vif {
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
editPool,
|
||||
installSupplementalPackOnAllHosts,
|
||||
isSrWritable,
|
||||
rollingPoolReboot,
|
||||
setHostsMultipathing,
|
||||
setPoolMaster,
|
||||
setRemoteSyslogHost,
|
||||
@@ -45,7 +46,7 @@ import { confirm } from '../../common/modal'
|
||||
import { error } from '../../common/notification'
|
||||
import { Host, Pool } from '../../common/render-xo-item'
|
||||
import { isAdmin } from '../../common/selectors'
|
||||
import { SOURCES, getXoaPlan } from '../../common/xoa-plans'
|
||||
import { ENTERPRISE, SOURCES, getXoaPlan } from '../../common/xoa-plans'
|
||||
|
||||
const BindLicensesButton = decorate([
|
||||
addSubscriptions({
|
||||
@@ -266,12 +267,23 @@ export default class TabAdvanced extends Component {
|
||||
const { enabled: hostsEnabledMultipathing, disabled: hostsDisabledMultipathing } = hostsByMultipathing
|
||||
const { crashDumpSr } = pool
|
||||
const crashDumpSrPredicate = this._getCrashDumpSrPredicate()
|
||||
const isEnterprisePlan = getXoaPlan().value >= ENTERPRISE.value
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Container>
|
||||
{this._isNetboxPluginLoaded() && (
|
||||
<Row>
|
||||
<Col className='text-xs-right'>
|
||||
<Row>
|
||||
<Col className='text-xs-right'>
|
||||
<TabButton
|
||||
btnStyle='warning'
|
||||
handler={rollingPoolReboot}
|
||||
handlerParam={pool}
|
||||
icon='pool-rolling-reboot'
|
||||
labelId='rollingPoolReboot'
|
||||
disabled={!isEnterprisePlan}
|
||||
tooltip={!isEnterprisePlan ? _('onlyAvailableToEnterprise') : undefined}
|
||||
/>
|
||||
{this._isNetboxPluginLoaded() && (
|
||||
<TabButton
|
||||
btnStyle='primary'
|
||||
handler={synchronizeNetbox}
|
||||
@@ -279,9 +291,9 @@ export default class TabAdvanced extends Component {
|
||||
icon='refresh'
|
||||
labelId='syncNetbox'
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<h3>{_('xenSettingsLabel')}</h3>
|
||||
|
||||
Reference in New Issue
Block a user