feat(xo-web/pool): ability to do a rolling pool reboot (#7243)

Fixes #6885
See #7242
This commit is contained in:
Mathieu
2024-01-26 17:08:52 +01:00
committed by GitHub
parent c250cd9b89
commit 0c0251082d
6 changed files with 107 additions and 7 deletions

View File

@@ -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

View File

@@ -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}}?',

View File

@@ -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) =>

View File

@@ -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>
)
}
}

View File

@@ -695,6 +695,10 @@
@extend .fa;
@extend .fa-angle-double-down;
}
&-rolling-reboot {
@extend .fa;
@extend .fa-circle-o-notch;
}
}
&-vif {

View File

@@ -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>