Skip to content

Commit

Permalink
feat(backups, xo-web/backup/restore): ability to choose SR for each V…
Browse files Browse the repository at this point in the history
…M VDIs

fixes#4605
fixes#4016
  • Loading branch information
Rajaa-BARHTAOUI committed Feb 17, 2022
1 parent 902abd5 commit d8f0c8f
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 29 deletions.
4 changes: 2 additions & 2 deletions @xen-orchestra/backups/ImportVmBackup.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const { Task } = require('./Task.js')
const { watchStreamSize } = require('./_watchStreamSize.js')

exports.ImportVmBackup = class ImportVmBackup {
constructor({ adapter, metadata, srUuid, xapi, settings: { newMacAddresses } = {} }) {
constructor({ adapter, metadata, srUuid, xapi, settings: { newMacAddresses, mapVdisSrs } = {} }) {
this._adapter = adapter
this._importDeltaVmSettings = { newMacAddresses }
this._importDeltaVmSettings = { newMacAddresses, mapVdisSrs }
this._metadata = metadata
this._srUuid = srUuid
this._xapi = xapi
Expand Down
8 changes: 8 additions & 0 deletions @xen-orchestra/backups/_deltaVm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const compareVersions = require('compare-versions')
const find = require('lodash/find.js')
const groupBy = require('lodash/groupBy.js')
const ignoreErrors = require('promise-toolbox/ignoreErrors.js')
const isEmpty = require('lodash/isEmpty.js')
const omit = require('lodash/omit.js')
const { asyncMap } = require('@xen-orchestra/async-map')
const { CancelToken } = require('promise-toolbox')
Expand Down Expand Up @@ -165,6 +166,12 @@ exports.importDeltaVm = defer(async function importDeltaVm(
}
}

if (!isEmpty(mapVdisSrs)) {
for (const [vdiUuid, srId] of Object.entries(mapVdisSrs)) {
mapVdisSrs[vdiUuid] = xapi.getObject(srId, 'SR')._xapiRef
}
}

const baseVdis = {}
baseVm &&
baseVm.$VBDs.forEach(vbd => {
Expand Down Expand Up @@ -239,6 +246,7 @@ exports.importDeltaVm = defer(async function importDeltaVm(
}

newVdi = await xapi.getRecord('VDI', await baseVdi.$clone())

$defer.onFailure(() => newVdi.$destroy())

await newVdi.update_other_config(TAG_COPY_SRC, vdi.uuid)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Collapse from 'collapse'
import Component from 'base-component'
import PropTypes from 'prop-types'
import React from 'react'
import { map } from 'lodash'
import { isEmpty, map } from 'lodash'
import { Vdi } from 'render-xo-item'

import _ from '../../intl'
Expand Down Expand Up @@ -54,21 +54,23 @@ export default class ChooseSrForEachVdisModal extends Component {
const { props } = this
const {
mainSrPredicate = isSrWritable,
placeholder,
srPredicate = mainSrPredicate,
value: { mainSr, mapVdisSrs },
vdis,
} = props

return (
<div>
<SelectSr
onChange={this._onChangeMainSr}
placeholder={_('chooseSrForEachVdisModalMainSr')}
placeholder={placeholder !== undefined ? placeholder : 'chooseSrForEachVdisModalMainSr'}
predicate={mainSrPredicate}
required
value={mainSr}
/>
<br />
{props.vdis != null && mainSr != null && (
{!isEmpty(vdis) && mainSr != null && (
<Collapsible buttonText={_('chooseSrForEachVdisModalSelectSr')} collapsible size='small'>
<br />
<Container>
Expand All @@ -80,11 +82,9 @@ export default class ChooseSrForEachVdisModal extends Component {
<strong>{_('chooseSrForEachVdisModalSrLabel')}</strong>
</Col>
</SingleLineRow>
{map(props.vdis, vdi => (
{map(vdis, vdi => (
<SingleLineRow key={vdi.uuid}>
<Col size={6}>
<Vdi id={vdi.id} showSize />
</Col>
<Col size={6}>{vdi.name !== undefined ? vdi.name : <Vdi id={vdi.id} showSize />}</Col>
<Col size={6}>
<SelectSr
onChange={sr =>
Expand Down
8 changes: 6 additions & 2 deletions packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2205,10 +2205,14 @@ export const runBackupNgJob = ({ force, ...params }) => {

export const listVmBackups = remotes => _call('backupNg.listVmBackups', { remotes: resolveIds(remotes) })

export const restoreBackup = (backup, sr, { generateNewMacAddresses = false, startOnRestore = false } = {}) => {
export const restoreBackup = (
backup,
sr,
{ generateNewMacAddresses = false, mapVdisSrs = {}, startOnRestore = false } = {}
) => {
const promise = _call('backupNg.importVmBackup', {
id: resolveId(backup),
settings: { newMacAddresses: generateNewMacAddresses },
settings: { mapVdisSrs: resolveIds(mapVdisSrs), newMacAddresses: generateNewMacAddresses },
sr: resolveId(sr),
})

Expand Down
10 changes: 7 additions & 3 deletions packages/xo-web/src/xo-app/backup/restore/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,17 @@ export default class Restore extends Component {
body: <RestoreBackupsModalBody data={data} />,
icon: 'restore',
})
.then(({ backup, generateNewMacAddresses, sr, start }) => {
if (backup == null || sr == null) {
.then(({ backup, generateNewMacAddresses, targetSrs: { mainSr, mapVdisSrs }, start }) => {
if (backup == null || mainSr == null) {
error(_('backupRestoreErrorTitle'), _('backupRestoreErrorMessage'))
return
}

return restoreBackup(backup, sr, { generateNewMacAddresses, startOnRestore: start })
return restoreBackup(backup, mainSr, {
generateNewMacAddresses,
mapVdisSrs,
startOnRestore: start,
})
}, noop)
.then(() => this._refreshBackupList())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ import { getRenderXoItemOfType } from 'render-xo-item'
import { Select, Toggle } from 'form'
import { SelectSr } from 'select-objects'

import ChooseSrForEachVdisModal from '../../../common/xo/choose-sr-for-each-vdis-modal'

const BACKUP_RENDERER = getRenderXoItemOfType('backup')

export default class RestoreBackupsModalBody extends Component {
state = { generateNewMacAddresses: false }
state = { generateNewMacAddresses: false, targetSrs: { mainSr: undefined, mapVdisSrs: undefined } }

get value() {
return this.state
}

_getDisks = backup =>
backup !== undefined ? backup.disks.reduce((vdis, vdi) => ({ ...vdis, [vdi.uuid]: vdi }), {}) : {}

render() {
return (
<div>
Expand All @@ -25,20 +31,30 @@ export default class RestoreBackupsModalBody extends Component {
placeholder={_('importBackupModalSelectBackup')}
/>
</div>
<div className='mb-1'>
<SelectSr onChange={this.linkState('sr')} placeholder={_('importBackupModalSelectSr')} />
</div>
<div>
<Toggle iconSize={1} onChange={this.linkState('start')} /> {_('restoreVmBackupsStart', { nVms: 1 })}
</div>
<div>
<Toggle
iconSize={1}
value={this.state.generateNewMacAddresses}
onChange={this.toggleState('generateNewMacAddresses')}
/>{' '}
{_('generateNewMacAddress')}
</div>
{this.state.backup != null && (
<div>
<div className='mb-1'>
<ChooseSrForEachVdisModal
onChange={this.linkState('targetSrs')}
placeholder={_('importBackupModalSelectSr')}
required
value={this.state.targetSrs}
vdis={this._getDisks(this.state.backup)}
/>
</div>
<div>
<Toggle iconSize={1} onChange={this.linkState('start')} /> {_('restoreVmBackupsStart', { nVms: 1 })}
</div>
<div>
<Toggle
iconSize={1}
value={this.state.generateNewMacAddresses}
onChange={this.toggleState('generateNewMacAddresses')}
/>{' '}
{_('generateNewMacAddress')}
</div>
</div>
)}
</div>
)
}
Expand Down

0 comments on commit d8f0c8f

Please sign in to comment.