feat(vm.importDeltaBackup): custom VDI→SR mapping (#567)

See vatesfr/xo-web#2070
This commit is contained in:
badrAZ 2017-06-30 15:52:12 +02:00 committed by Julien Fontanet
parent 9df1716480
commit d4f8d98d2b
4 changed files with 46 additions and 17 deletions

View File

@ -422,6 +422,7 @@ exports.insertCd = insertCd
migrate = $coroutine ({ migrate = $coroutine ({
vm, vm,
host, host,
sr,
mapVdisSrs, mapVdisSrs,
mapVifsNetworks, mapVifsNetworks,
migrationNetwork migrationNetwork
@ -452,6 +453,7 @@ migrate = $coroutine ({
throw unauthorized() throw unauthorized()
yield @getXapi(vm).migrateVm(vm._xapiId, @getXapi(host), host._xapiId, { yield @getXapi(vm).migrateVm(vm._xapiId, @getXapi(host), host._xapiId, {
sr: @getObject(sr, 'SR')._xapiId
migrationNetworkId: migrationNetwork?._xapiId migrationNetworkId: migrationNetwork?._xapiId
mapVifsNetworks: mapVifsNetworksXapi, mapVifsNetworks: mapVifsNetworksXapi,
mapVdisSrs: mapVdisSrsXapi, mapVdisSrs: mapVdisSrsXapi,
@ -466,6 +468,9 @@ migrate.params = {
# Identifier of the host to migrate to. # Identifier of the host to migrate to.
targetHost: { type: 'string' } targetHost: { type: 'string' }
# Identifier of the default SR to migrate to.
sr: { type: 'string', optional: true }
# Map VDIs IDs --> SRs IDs # Map VDIs IDs --> SRs IDs
mapVdisSrs: { type: 'object', optional: true } mapVdisSrs: { type: 'object', optional: true }
@ -722,13 +727,20 @@ exports.rollingDeltaBackup = rollingDeltaBackup
#--------------------------------------------------------------------- #---------------------------------------------------------------------
importDeltaBackup = ({sr, remote, filePath}) -> importDeltaBackup = ({sr, remote, filePath, mapVdisSrs}) ->
return @importDeltaVmBackup({sr, remoteId: remote, filePath}) mapVdisSrsXapi = {}
forEach mapVdisSrs, (srId, vdiId) =>
mapVdisSrsXapi[vdiId] = @getObject(srId, 'SR')._xapiId
return @importDeltaVmBackup({sr, remoteId: remote, filePath, mapVdisSrs: mapVdisSrsXapi})
importDeltaBackup.params = { importDeltaBackup.params = {
sr: { type: 'string' } sr: { type: 'string' }
remote: { type: 'string' } remote: { type: 'string' }
filePath: { type: 'string' } filePath: { type: 'string' }
# Map VDIs UUIDs --> SRs IDs
mapVdisSrs: { type: 'object', optional: true }
} }
importDeltaBackup.resolve = { importDeltaBackup.resolve = {

View File

@ -597,3 +597,13 @@ export const splitFirst = (string, separator) => {
string.slice(i + separator.length) string.slice(i + separator.length)
] ]
} }
// -------------------------------------------------------------------
export const getFirstPropertyName = object => {
for (const key in object) {
if (Object.prototype.hasOwnProperty.call(object, key)) {
return key
}
}
}

View File

@ -891,9 +891,10 @@ export default class Xapi extends XapiBase {
@deferrable.onFailure @deferrable.onFailure
async importDeltaVm ($onFailure, delta, { async importDeltaVm ($onFailure, delta, {
deleteBase = false, deleteBase = false,
disableStartAfterImport = true,
mapVdisSrs = {},
name_label = delta.vm.name_label, name_label = delta.vm.name_label,
srId = this.pool.default_SR, srId = this.pool.default_SR
disableStartAfterImport = true
} = {}) { } = {}) {
const { version } = delta const { version } = delta
@ -914,8 +915,6 @@ export default class Xapi extends XapiBase {
} }
} }
const sr = this.getObject(srId)
const baseVdis = {} const baseVdis = {}
baseVm && forEach(baseVm.$VBDs, vbd => { baseVm && forEach(baseVm.$VBDs, vbd => {
baseVdis[vbd.VDI] = vbd.$VDI baseVdis[vbd.VDI] = vbd.$VDI
@ -962,7 +961,7 @@ export default class Xapi extends XapiBase {
[TAG_BASE_DELTA]: undefined, [TAG_BASE_DELTA]: undefined,
[TAG_COPY_SRC]: vdi.uuid [TAG_COPY_SRC]: vdi.uuid
}, },
sr: sr.$id sr: mapVdisSrs[vdi.uuid] || srId
}) })
$onFailure(() => this._deleteVdi(newVdi)) $onFailure(() => this._deleteVdi(newVdi))
@ -1056,6 +1055,7 @@ export default class Xapi extends XapiBase {
async _migrateVmWithStorageMotion (vm, hostXapi, host, { async _migrateVmWithStorageMotion (vm, hostXapi, host, {
migrationNetwork = find(host.$PIFs, pif => pif.management).$network, // TODO: handle not found migrationNetwork = find(host.$PIFs, pif => pif.management).$network, // TODO: handle not found
sr,
mapVdisSrs, mapVdisSrs,
mapVifsNetworks mapVifsNetworks
}) { }) {
@ -1067,7 +1067,9 @@ export default class Xapi extends XapiBase {
if (vbd.type === 'Disk') { if (vbd.type === 'Disk') {
vdis[vdi.$ref] = mapVdisSrs && mapVdisSrs[vdi.$id] vdis[vdi.$ref] = mapVdisSrs && mapVdisSrs[vdi.$id]
? hostXapi.getObject(mapVdisSrs[vdi.$id]).$ref ? hostXapi.getObject(mapVdisSrs[vdi.$id]).$ref
: defaultSr.$ref // Will error if there are no default SR. : sr !== undefined
? hostXapi.getObject(sr).$ref
: defaultSr.$ref // Will error if there are no default SR.
} }
} }
@ -1325,6 +1327,7 @@ export default class Xapi extends XapiBase {
} }
async migrateVm (vmId, hostXapi, hostId, { async migrateVm (vmId, hostXapi, hostId, {
sr,
migrationNetworkId, migrationNetworkId,
mapVifsNetworks, mapVifsNetworks,
mapVdisSrs mapVdisSrs
@ -1335,14 +1338,16 @@ export default class Xapi extends XapiBase {
const accrossPools = vm.$pool !== host.$pool const accrossPools = vm.$pool !== host.$pool
const useStorageMotion = ( const useStorageMotion = (
accrossPools || accrossPools ||
migrationNetworkId || sr !== undefined ||
mapVifsNetworks || migrationNetworkId !== undefined ||
mapVdisSrs !isEmpty(mapVifsNetworks) ||
!isEmpty(mapVdisSrs)
) )
if (useStorageMotion) { if (useStorageMotion) {
await this._migrateVmWithStorageMotion(vm, hostXapi, host, { await this._migrateVmWithStorageMotion(vm, hostXapi, host, {
migrationNetwork: migrationNetworkId && hostXapi.getObject(migrationNetworkId), migrationNetwork: migrationNetworkId && hostXapi.getObject(migrationNetworkId),
sr,
mapVdisSrs, mapVdisSrs,
mapVifsNetworks mapVifsNetworks
}) })

View File

@ -32,6 +32,7 @@ import { lvs, pvs } from '../lvm'
import { import {
asyncMap, asyncMap,
forEach, forEach,
getFirstPropertyName,
mapFilter, mapFilter,
mapToArray, mapToArray,
noop, noop,
@ -506,7 +507,7 @@ export default class {
return vdiId return vdiId
} }
async _legacyImportDeltaVmBackup (xapi, { remoteId, handler, filePath, info, sr }) { async _legacyImportDeltaVmBackup (xapi, { remoteId, handler, filePath, info, sr, mapVdisSrs = {} }) {
// Import vm metadata. // Import vm metadata.
const vm = await (async () => { const vm = await (async () => {
const stream = await handler.createReadStream(`${filePath}.xva`) const stream = await handler.createReadStream(`${filePath}.xva`)
@ -532,7 +533,7 @@ export default class {
mapToArray( mapToArray(
info.vdis, info.vdis,
async vdiInfo => { async vdiInfo => {
vdiInfo.sr = sr._xapiId vdiInfo.sr = mapVdisSrs[vdiInfo.uuid] || sr._xapiId
const vdiId = await this._legacyImportDeltaVdiBackup(xapi, { vmId: vm.$id, handler, dir, vdiInfo }) const vdiId = await this._legacyImportDeltaVdiBackup(xapi, { vmId: vm.$id, handler, dir, vdiInfo })
vdiIds[vdiInfo.uuid] = vdiId vdiIds[vdiInfo.uuid] = vdiId
@ -868,12 +869,12 @@ export default class {
} }
} }
async importDeltaVmBackup ({sr, remoteId, filePath}) { async importDeltaVmBackup ({sr, remoteId, filePath, mapVdisSrs = {}}) {
filePath = `${filePath}${DELTA_BACKUP_EXT}` filePath = `${filePath}${DELTA_BACKUP_EXT}`
const { datetime } = parseVmBackupPath(filePath) const { datetime } = parseVmBackupPath(filePath)
const handler = await this._xo.getRemoteHandler(remoteId) const handler = await this._xo.getRemoteHandler(remoteId)
const xapi = this._xo.getXapi(sr) const xapi = this._xo.getXapi(sr || mapVdisSrs[getFirstPropertyName(mapVdisSrs)])
const delta = JSON.parse(await handler.readFile(filePath)) const delta = JSON.parse(await handler.readFile(filePath))
let vm let vm
@ -882,7 +883,7 @@ export default class {
if (!version) { if (!version) {
// Legacy import. (Version 0.0.0) // Legacy import. (Version 0.0.0)
vm = await this._legacyImportDeltaVmBackup(xapi, { vm = await this._legacyImportDeltaVmBackup(xapi, {
remoteId, handler, filePath, info: delta, sr remoteId, handler, filePath, info: delta, sr, mapVdisSrs
}) })
} else if (versionSatisfies(delta.version, '^1')) { } else if (versionSatisfies(delta.version, '^1')) {
const basePath = dirname(filePath) const basePath = dirname(filePath)
@ -907,7 +908,8 @@ export default class {
vm = await xapi.importDeltaVm(delta, { vm = await xapi.importDeltaVm(delta, {
disableStartAfterImport: false, disableStartAfterImport: false,
srId: sr._xapiId srId: sr !== undefined && sr._xapiId,
mapVdisSrs
}) })
} else { } else {
throw new Error(`Unsupported delta backup version: ${version}`) throw new Error(`Unsupported delta backup version: ${version}`)