feat(xo-server,xo-web/SR): display maintenance mode button (#6308)

Fixes #6215
This commit is contained in:
Mathieu 2022-06-30 15:31:28 +02:00 committed by GitHub
parent 50ec614b2a
commit 16b1935f12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 2 deletions

View File

@ -9,6 +9,7 @@
- [Restore backup] Clearer error message when importing a VM backup requires restoration of CH >= 8.1 (PR [#6304](https://github.com/vatesfr/xen-orchestra/pull/6304))
- [Backup] Users can use VHD directory on any remote type (PR [#6273](https://github.com/vatesfr/xen-orchestra/pull/6273))
- [SR/advanced] Ability to enable/disable a maintenance mode for an SR [#6215](https://github.com/vatesfr/xen-orchestra/issues/6215) (PRs [#6308](https://github.com/vatesfr/xen-orchestra/pull/6308), [#6297](https://github.com/vatesfr/xen-orchestra/pull/6297))
### Bug fixes
@ -33,6 +34,7 @@
- @xen-orchestra/xapi minor
- vhd-lib patch
- xo-remote-parser patch
- xo-server minor
- xo-web minor
<!--packages-end-->

View File

@ -539,6 +539,7 @@ const TRANSFORMS = {
allocationStrategy: ALLOCATION_BY_TYPE[srType],
current_operations: obj.current_operations,
inMaintenanceMode: obj.other_config['xo:maintenanceState'] !== undefined,
name_description: obj.name_description,
name_label: obj.name_label,
size: +obj.physical_size,

View File

@ -2208,6 +2208,7 @@ const messages = {
downloadConfig: 'Download current config',
// ----- SR -----
andNMore: 'and {n} more',
disabledVdiMigrateTooltip: "Snapshots and base copies can't be migrated individually",
srReconnectAllModalTitle: 'Reconnect all hosts',
srReconnectAllModalMessage: 'This will reconnect this SR to all its hosts.',
@ -2223,6 +2224,9 @@ const messages = {
srAllDisconnected: 'Disconnected',
srSomeConnected: 'Partially connected',
srAllConnected: 'Connected',
maintenanceSrModalBody:
'In order to put this SR in maintenance mode, the following VM{n, plural, one {} other {s}} will be shut down. Are you sure you want to continue?',
maintenanceMode: 'Maintenance mode',
migrateSelectedVdis: 'Migrate selected VDIs',
migrateVdiMessage:
'All the VDIs attached to a VM must either be on a shared SR or on the same host (local SR) for the VM to be able to start.',

View File

@ -20,7 +20,7 @@ import invoke from '../invoke'
import Icon from '../icon'
import logError from '../log-error'
import NewAuthTokenModal from './new-auth-token-modal'
import renderXoItem, { renderXoItemFromId } from '../render-xo-item'
import renderXoItem, { renderXoItemFromId, Vm } from '../render-xo-item'
import store from 'store'
import { alert, chooseAction, confirm } from '../modal'
import { error, info, success } from '../notification'
@ -40,6 +40,10 @@ import parseNdJson from './_parseNdJson'
// ===================================================================
const MAX_VMS = 30
// ===================================================================
export const ITEMS_PER_PAGE_OPTIONS = [10, 20, 50, 100]
export const VDIS_TO_COALESCE_LIMIT = 10
@ -2108,6 +2112,41 @@ export const editSr = (sr, { nameDescription, nameLabel }) =>
export const rescanSr = sr => _call('sr.scan', { id: resolveId(sr) })
export const rescanSrs = srs => Promise.all(map(resolveIds(srs), id => _call('sr.scan', { id })))
export const toggleSrMaintenanceMode = sr => {
const id = resolveId(sr)
const method = sr.inMaintenanceMode ? 'disableMaintenanceMode' : 'enableMaintenanceMode'
return _call(`sr.${method}`, { id }).catch(async err => {
if (
incorrectState.is(err, {
property: 'vmsToShutdown',
})
) {
const vmIds = err.data.expected
const nVms = vmIds.length
await confirm({
title: _('maintenanceMode'),
body: (
<div>
{_('maintenanceSrModalBody', { n: nVms })}
<ul>
{vmIds.slice(0, MAX_VMS).map(id => (
<li key={id}>
<Vm id={id} />
</li>
))}
</ul>
{nVms > MAX_VMS && _('andNMore', { n: nVms - MAX_VMS })}
</div>
),
})
return _call(`sr.${method}`, { id, vmsToShutdown: vmIds })
} else {
throw err
}
})
}
// PBDs --------------------------------------------------------------
export const connectPbd = pbd => _call('pbd.connect', { id: resolveId(pbd) })

View File

@ -583,6 +583,14 @@
// SR
&-sr,
&-vdi {
&-disable {
@extend .fa;
@extend .fa-times-circle;
}
&-enable {
@extend .fa;
@extend .fa-wrench;
}
&-reconnect-all {
@extend .fa;
@extend .fa-retweet;

View File

@ -113,6 +113,7 @@ export default class SrItem extends Component {
<Text value={sr.name_label} onChange={this._setNameLabel} useLongClick />
</Ellipsis>
{isDefaultSr && <span className='tag tag-pill tag-info ml-1'>{_('defaultSr')}</span>}
{sr.inMaintenanceMode && <span className='tag tag-pill tag-warning ml-1'>{_('maintenanceMode')}</span>}
</EllipsisContainer>
</Col>
<Col largeSize={1} className='hidden-md-down'>

View File

@ -9,7 +9,7 @@ import { Container, Row, Col } from 'grid'
import { CustomFields } from 'custom-fields'
import { createGetObjectsOfType } from 'selectors'
import { createSelector } from 'reselect'
import { createSrUnhealthyVdiChainsLengthSubscription, deleteSr } from 'xo'
import { createSrUnhealthyVdiChainsLengthSubscription, deleteSr, toggleSrMaintenanceMode } from 'xo'
import { flowRight, isEmpty, keys, sum, values } from 'lodash'
// ===================================================================
@ -59,6 +59,23 @@ export default ({ sr }) => (
<Row>
<Col className='text-xs-right'>
<TabButton btnStyle='danger' handler={deleteSr} handlerParam={sr} icon='sr-remove' labelId='srRemoveButton' />
{sr.inMaintenanceMode ? (
<TabButton
btnStyle='warning'
handler={toggleSrMaintenanceMode}
handlerParam={sr}
icon='sr-disable'
labelId='disableMaintenanceMode'
/>
) : (
<TabButton
btnStyle='warning'
handler={toggleSrMaintenanceMode}
handlerParam={sr}
icon='sr-enable'
labelId='enableMaintenanceMode'
/>
)}
</Col>
</Row>
<Row>