feat(xo-web/vm/disk): notify user before breaking action (#4035)

See #3911

- New disk: warning if the selected SR is local to another host than another VDI
- Migrate VDI (row action only): warning if the selected SR is local to another host than another VDI
This commit is contained in:
Rajaa.BARHTAOUI
2019-04-16 11:04:12 +02:00
committed by Pierre Donias
parent d82c951db6
commit f27170ff0e
3 changed files with 82 additions and 9 deletions

View File

@@ -4,6 +4,7 @@
- [Self/New VM] Display confirmation modal when user will use a large amount of resources [#4044](https://github.com/vatesfr/xen-orchestra/issues/4044) (PR [#4127](https://github.com/vatesfr/xen-orchestra/pull/4127))
- [Home] No more false positives when select Tag on Home page [#4087](https://github.com/vatesfr/xen-orchestra/issues/4087) (PR [#4112](https://github.com/vatesfr/xen-orchestra/pull/4112))
- [VDI migration, New disk] Warning when SR host is different from the other disks [#3911](https://github.com/vatesfr/xen-orchestra/issues/3911) (PR [#4035](https://github.com/vatesfr/xen-orchestra/pull/4035))
### Bug fixes

View File

@@ -1051,12 +1051,12 @@ const messages = {
importVdi: 'Import VDI content',
importVdiNoFile: 'No file selected',
selectVdiMessage: 'Drop VHD file here',
srsNotOnSameHost:
'The SRs must either be shared or on the same host for the VM to be able to start.',
useQuotaWarning:
'Creating this disk will use the disk space quota from the resource set {resourceSet} ({spaceLeft} left)',
notEnoughSpaceInResourceSet:
'Not enough space in resource set {resourceSet} ({spaceLeft} left)',
warningVdiSr:
"The VDIs' SRs must either be shared or on the same host for the VM to be able to start.",
// ----- VM network tab -----
vifCreateDeviceButton: 'New device',

View File

@@ -257,6 +257,7 @@ const parseBootOrder = bootOrder => {
})
class NewDisk extends Component {
static propTypes = {
checkSr: PropTypes.func.isRequired,
onClose: PropTypes.func,
vm: PropTypes.object.isRequired,
}
@@ -299,6 +300,12 @@ class NewDisk extends Component {
resourceSet => get(resourceSet, 'limits.disk.available')
)
_checkSr = createSelector(
() => this.props.checkSr,
() => this.state.sr,
(check, sr) => check(sr)
)
render() {
const { vm, isAdmin } = this.props
const { formatMessage } = this.props.intl
@@ -370,6 +377,13 @@ class NewDisk extends Component {
</ActionButton>
</span>
</fieldset>
{!this._checkSr() && (
<div>
<span className='text-danger'>
<Icon icon='alarm' /> {_('warningVdiSr')}
</span>
</div>
)}
{resourceSet != null &&
diskLimit != null &&
(diskLimit < size ? (
@@ -609,6 +623,7 @@ class BootOrder extends Component {
class MigrateVdiModalBody extends Component {
static propTypes = {
checkSr: PropTypes.func.isRequired,
pool: PropTypes.string.isRequired,
}
@@ -621,6 +636,12 @@ class MigrateVdiModalBody extends Component {
poolId => createCompareContainers(poolId)
)
_checkSr = createSelector(
() => this.props.checkSr,
() => this.state.sr,
(check, sr) => check(sr)
)
render() {
return (
<Container>
@@ -643,6 +664,15 @@ class MigrateVdiModalBody extends Component {
</label>
</Col>
</SingleLineRow>
{!this._checkSr() && (
<SingleLineRow>
<Col>
<span className='text-danger'>
<Icon icon='alarm' /> {_('warningVdiSr')}
</span>
</Col>
</SingleLineRow>
)}
</Container>
)
}
@@ -663,11 +693,13 @@ export default class TabDisks extends Component {
}
}
_getVdiSrs = createSelector(
() => this.props.vdis,
createCollectionWrapper(vdis => sortedUniq(map(vdis, '$SR').sort()))
)
_areSrsOnSameHost = createSelector(
createSelector(
() => this.props.vdis,
createCollectionWrapper(vdis => sortedUniq(map(vdis, '$SR').sort()))
),
this._getVdiSrs,
() => this.props.srs,
(vdiSrs, srs) => {
if (some(vdiSrs, srId => srs[srId] === undefined)) {
@@ -711,7 +743,12 @@ export default class TabDisks extends Component {
_migrateVdi = vdi => {
return confirm({
title: _('vdiMigrate'),
body: <MigrateVdiModalBody pool={this.props.vm.$pool} />,
body: (
<MigrateVdiModalBody
checkSr={this._getCheckSr()}
pool={this.props.vm.$pool}
/>
),
}).then(({ sr, migrateAll }) => {
if (!sr) {
return error(_('vdiMigrateNoSr'), _('vdiMigrateNoSrMessage'))
@@ -736,6 +773,37 @@ export default class TabDisks extends Component {
isAdmin || (resourceSet == null && isVmAdmin)
)
_getRequiredHost = createSelector(
this._areSrsOnSameHost,
this._getVdiSrs,
() => this.props.srs,
(areSrsOnSameHost, vdiSrs, srs) => {
if (!areSrsOnSameHost) {
return
}
let container
let sr
forEach(vdiSrs, srId => {
sr = srs[srId]
if (sr !== undefined && !isSrShared(sr)) {
container = sr.$container
return false
}
})
return container
}
)
_getCheckSr = createSelector(
this._getRequiredHost,
requiredHost => sr =>
sr === undefined ||
isSrShared(sr) ||
requiredHost === undefined ||
sr.$container === requiredHost
)
_getVbdsByVdi = createSelector(
() => this.props.vdis,
() => this.props.vbds,
@@ -817,7 +885,11 @@ export default class TabDisks extends Component {
<Col>
{newDisk && (
<div>
<NewDisk vm={vm} onClose={this._toggleNewDisk} />
<NewDisk
checkSr={this._getCheckSr()}
vm={vm}
onClose={this._toggleNewDisk}
/>
<hr />
</div>
)}
@@ -843,7 +915,7 @@ export default class TabDisks extends Component {
{!this._areSrsOnSameHost() && (
<div>
<span className='text-danger'>
<Icon icon='alarm' /> {_('srsNotOnSameHost')}
<Icon icon='alarm' /> {_('warningVdiSr')}
</span>
</div>
)}