Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(xo-web/backup/restore): ability to ignore VDIs #6143

Merged
merged 2 commits into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion @xen-orchestra/backups/ImportVmBackup.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ exports.ImportVmBackup = class ImportVmBackup {
} else {
assert.strictEqual(metadata.mode, 'delta')

backup = await adapter.readDeltaVmBackup(metadata)
const ignoredVdis = new Set(
Object.entries(this._importDeltaVmSettings.mapVdisSrs)
.filter(([_, srUuid]) => srUuid === null)
.map(([vdiUuid]) => vdiUuid)
)
backup = await adapter.readDeltaVmBackup(metadata, ignoredVdis)
Object.values(backup.streams).forEach(stream => watchStreamSize(stream, sizeContainer))
}

Expand Down
10 changes: 6 additions & 4 deletions @xen-orchestra/backups/RemoteAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const fromCallback = require('promise-toolbox/fromCallback')
const fromEvent = require('promise-toolbox/fromEvent')
const pDefer = require('promise-toolbox/defer')
const groupBy = require('lodash/groupBy.js')
const pickBy = require('lodash/pickBy.js')
const { dirname, join, normalize, resolve } = require('path')
const { createLogger } = require('@xen-orchestra/log')
const { Constants, createVhdDirectoryFromStream, openVhd, VhdAbstract, VhdDirectory, VhdSynthetic } = require('vhd-lib')
Expand Down Expand Up @@ -576,14 +577,15 @@ class RemoteAdapter {
return stream
}

async readDeltaVmBackup(metadata) {
async readDeltaVmBackup(metadata, ignoredVdis) {
const handler = this._handler
const { vbds, vdis, vhds, vifs, vm } = metadata
const { vbds, vhds, vifs, vm } = metadata
const dir = dirname(metadata._filename)
const vdis = ignoredVdis === undefined ? metadata.vdis : pickBy(metadata.vdis, vdi => !ignoredVdis.has(vdi.uuid))

const streams = {}
await asyncMapSettled(Object.keys(vdis), async id => {
streams[`${id}.vhd`] = await this._createSyntheticStream(handler, join(dir, vhds[id]))
await asyncMapSettled(Object.keys(vdis), async ref => {
streams[`${ref}.vhd`] = await this._createSyntheticStream(handler, join(dir, vhds[ref]))
julien-f marked this conversation as resolved.
Show resolved Hide resolved
})

return {
Expand Down
3 changes: 3 additions & 0 deletions @xen-orchestra/backups/_deltaVm.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ exports.TAG_COPY_SRC = TAG_COPY_SRC

const ensureArray = value => (value === undefined ? [] : Array.isArray(value) ? value : [value])
const resolveUuid = async (xapi, cache, uuid, type) => {
if (uuid == null) {
return uuid
}
let ref = cache.get(uuid)
if (ref === undefined) {
ref = await xapi.call(`${type}.get_by_uuid`, uuid)
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [REST API] Expose networks, VBDs, VDIs and VIFs
- [Console] Supports host and VM consoles behind HTTP proxies [#6133](https://github.com/vatesfr/xen-orchestra/pull/6133)
- [Install patches] Disable patch installation when `High Availability` is enabled (PR [#6145](https://github.com/vatesfr/xen-orchestra/pull/6145))
- [Delta Backup/Restore] Ability to ignore some VDIs (PR [#6143](https://github.com/vatesfr/xen-orchestra/pull/6143))

### Bug fixes

Expand Down Expand Up @@ -44,5 +45,5 @@
- vhd-cli minor
- @xen-orchestra/backups minor
- @xen-orchestra/proxy minor
- xo-server patch
- xo-server minor
- xo-web minor
julien-f marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -1826,6 +1826,7 @@ const messages = {
'This VM contains a duplicate MAC address or has the same MAC address as another running VM. Do you want to continue?',
vmsWithDuplicatedMacAddressesMessage:
'{nVms, number} VM{nVms, plural, one {} other {s}} contain{nVms, plural, one {s} other {}} duplicate MAC addresses or {nVms, plural, one {has} other {have}} the same MAC addresses as other running VMs. Do you want to continue?',
ignoreVdi: 'Ignore this VDI',

// ----- Servers -----
enableServerErrorTitle: 'Enable server',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import Collapse from 'collapse'
import Component from 'base-component'
import Icon from 'icon'
import PropTypes from 'prop-types'
import React from 'react'
import Tooltip from 'tooltip'
import { Container, Col } from 'grid'
import { isEmpty, map } from 'lodash'
import { isSrWritable } from 'xo'
import { Vdi } from 'render-xo-item'

import _ from '../../intl'
import SingleLineRow from '../../single-line-row'
import { Container, Col } from 'grid'
import { isSrWritable } from 'xo'
import { SelectSr } from '../../select-objects'

const Collapsible = ({ collapsible, children, ...props }) =>
Expand All @@ -29,6 +31,7 @@ Collapsible.propTypes = {

export default class ChooseSrForEachVdisModal extends Component {
static propTypes = {
ignorableVdis: PropTypes.bool,
mainSrPredicate: PropTypes.func,
onChange: PropTypes.func.isRequired,
srPredicate: PropTypes.func,
Expand All @@ -53,6 +56,7 @@ export default class ChooseSrForEachVdisModal extends Component {
render() {
const { props } = this
const {
ignorableVdis = false,
mainSrPredicate = isSrWritable,
placeholder,
srPredicate = mainSrPredicate,
Expand All @@ -64,7 +68,7 @@ export default class ChooseSrForEachVdisModal extends Component {
<div>
<SelectSr
onChange={this._onChangeMainSr}
placeholder={placeholder !== undefined ? placeholder : 'chooseSrForEachVdisModalMainSr'}
placeholder={placeholder !== undefined ? placeholder : _('chooseSrForEachVdisModalMainSr')}
predicate={mainSrPredicate}
required
value={mainSr}
Expand All @@ -84,7 +88,9 @@ export default class ChooseSrForEachVdisModal extends Component {
</SingleLineRow>
{map(vdis, vdi => (
<SingleLineRow key={vdi.uuid}>
<Col size={6}>{vdi.name !== undefined ? vdi.name : <Vdi id={vdi.id} showSize />}</Col>
<Col size={ignorableVdis ? 5 : 6}>
{vdi.name !== undefined ? vdi.name : <Vdi id={vdi.id} showSize />}
</Col>
<Col size={6}>
<SelectSr
onChange={sr =>
Expand All @@ -96,6 +102,22 @@ export default class ChooseSrForEachVdisModal extends Component {
value={mapVdisSrs !== undefined && mapVdisSrs[vdi.uuid]}
/>
</Col>
{ignorableVdis && (
<Col size={1}>
<Tooltip content={_('ignoreVdi')}>
<a
role='button'
onClick={() =>
this._onChange({
mapVdisSrs: { ...mapVdisSrs, [vdi.uuid]: null },
})
}
>
<Icon icon='remove' />
</a>
</Tooltip>
</Col>
)}
</SingleLineRow>
))}
<i>{_('optionalEntry')}</i>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ export default class RestoreBackupsModalBody extends Component {

_getDisks = createSelector(
() => this.state.backup,
backup =>
() => this.state.targetSrs.mapVdisSrs,
(backup, mapVdisSrs) =>
backup !== undefined && backup.mode === 'delta'
? backup.disks.reduce((vdis, vdi) => ({ ...vdis, [vdi.uuid]: vdi }), {})
? backup.disks.reduce(
(vdis, vdi) =>
mapVdisSrs !== undefined && mapVdisSrs[vdi.uuid] === null ? vdis : { ...vdis, [vdi.uuid]: vdi },
{}
)
: {}
)

Expand All @@ -40,6 +45,7 @@ export default class RestoreBackupsModalBody extends Component {
<div>
<div className='mb-1'>
<ChooseSrForEachVdisModal
ignorableVdis
onChange={this.linkState('targetSrs')}
placeholder={_('importBackupModalSelectSr')}
required
Expand Down