-
Notifications
You must be signed in to change notification settings - Fork 255
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(xo-server): extract vmware import method to its own mixin
- Loading branch information
1 parent
2de0a2b
commit acc7b3a
Showing
4 changed files
with
271 additions
and
244 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
packages/xo-server/src/xo-mixins/vmware/buildChainByNode.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
export function buildDiskChainByNode(disks, snapshots) { | ||
let chain = [] | ||
if (snapshots && snapshots.current) { | ||
const currentSnapshotId = snapshots.current | ||
|
||
let currentSnapshot = snapshots.snapshots.find(({ uid }) => uid === currentSnapshotId) | ||
|
||
chain = [currentSnapshot.disks] | ||
while ((currentSnapshot = snapshots.snapshots.find(({ uid }) => uid === currentSnapshot.parent))) { | ||
chain.push(currentSnapshot.disks) | ||
} | ||
chain.reverse() | ||
} | ||
|
||
chain.push(disks) | ||
|
||
for (const disk of chain) { | ||
if (disk.capacity > 2 * 1024 * 1024 * 1024 * 1024) { | ||
/* 2TO */ | ||
throw new Error("Can't migrate disks larger than 2TiB") | ||
} | ||
} | ||
|
||
const chainsByNodes = {} | ||
chain.forEach(disks => { | ||
disks.forEach(disk => { | ||
chainsByNodes[disk.node] = chainsByNodes[disk.node] || [] | ||
chainsByNodes[disk.node].push(disk) | ||
}) | ||
}) | ||
|
||
return chainsByNodes | ||
} |
90 changes: 90 additions & 0 deletions
90
packages/xo-server/src/xo-mixins/vmware/importDisksfromDatastore.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { Task } from '@xen-orchestra/mixins/Tasks.mjs' | ||
import { VDI_FORMAT_VHD } from '@xen-orchestra/xapi' | ||
import openDeltaVmdkasVhd from '@xen-orchestra/vmware-explorer/openDeltaVmdkAsVhd.mjs' | ||
import VhdEsxiRaw from '@xen-orchestra/vmware-explorer/VhdEsxiRaw.mjs' | ||
import { importVdi as importVdiThroughXva } from '@xen-orchestra/xva/importVdi.mjs' | ||
import { defer } from 'golike-defer' | ||
|
||
async function _importDiskChain( | ||
$defer, | ||
{ esxi, dataStoreToHandlers, sr, vm, chainByNode, vdi, parentVhd, userdevice } | ||
) { | ||
let vhd | ||
if (chainByNode.length === 0) { | ||
return { vhd, vdi } | ||
} | ||
const isFullImport = chainByNode[0].isFull | ||
for (let diskIndex = 0; diskIndex < chainByNode.length; diskIndex++) { | ||
// the first one is a RAW disk ( full ) | ||
const disk = chainByNode[diskIndex] | ||
const { fileName, path, datastore: datastoreName, isFull } = disk | ||
if (isFull) { | ||
vhd = await VhdEsxiRaw.open(datastoreName, path + '/' + fileName, { | ||
thin: false, | ||
esxi, | ||
dataStoreToHandlers, | ||
}) | ||
} else { | ||
if (parentVhd === undefined) { | ||
throw new Error(`Can't import delta of a running VM without its parent VHD`) | ||
} | ||
vhd = await openDeltaVmdkasVhd(datastoreName, path + '/' + fileName, parentVhd, { | ||
lookMissingBlockInParent: isFullImport, // only look to missing block on full import | ||
esxi, | ||
dataStoreToHandlers, | ||
}) | ||
} | ||
vhd.label = fileName | ||
parentVhd = vhd | ||
} | ||
if (isFullImport) { | ||
const { capacity, descriptionLabel, nameLabel } = chainByNode[chainByNode.length - 1] | ||
// we don't need to read the BAT with the importVdiThroughXva process | ||
const vdiMetadata = { | ||
name_description: 'fromESXI' + descriptionLabel, | ||
name_label: '[ESXI]' + nameLabel, | ||
SR: sr.$ref, | ||
virtual_size: capacity, | ||
} | ||
vdi = await importVdiThroughXva(vdiMetadata, vhd, sr.$xapi, sr) | ||
|
||
// it can fail before the vdi is connected to the vm | ||
$defer.onFailure.call(sr.$xapi, 'VDI_destroy', vdi.$ref) | ||
|
||
await sr.$xapi.VBD_create({ | ||
VDI: vdi.$ref, | ||
VM: vm.$ref, | ||
device: `xvd${String.fromCharCode('a'.charCodeAt(0) + userdevice)}`, | ||
userdevice: String(userdevice < 3 ? userdevice : userdevice + 1), | ||
}) | ||
|
||
return { vdi, vhd } | ||
} else { | ||
// delta mode works only in vhd mode for now | ||
const stream = vhd.stream() | ||
await vhd.readBlockAllocationTable() | ||
await vdi.$importContent(stream, { format: VDI_FORMAT_VHD }) | ||
} | ||
return { vdi, vhd } | ||
} | ||
|
||
const importDiskChain = defer(_importDiskChain) | ||
|
||
export const importDisksFromDatastore = async function importDisksFromDatastore({ | ||
esxi, | ||
dataStoreToHandlers, | ||
vm, | ||
chainsByNodes, | ||
sr, | ||
vhds = [], | ||
}) { | ||
return await Promise.all( | ||
Object.keys(chainsByNodes).map(async (node, userdevice) => | ||
Task.run({ properties: { name: `Cold import of disks ${node}` } }, async () => { | ||
const chainByNode = chainsByNodes[node] | ||
const { vdi, vhd: parentVhd } = vhds[userdevice] ?? {} | ||
return importDiskChain({ esxi, dataStoreToHandlers, vm, chainByNode, userdevice, sr, parentVhd, vdi }) | ||
}) | ||
) | ||
) | ||
} |
Oops, something went wrong.