Merge pull request #116 from vatesfr/julien-f-vm-copy

vm.copy() can a copy a VM on a remote or local SR.
This commit is contained in:
Julien Fontanet 2015-11-09 15:14:04 +01:00
commit a5590b090c
2 changed files with 106 additions and 28 deletions

View File

@ -390,15 +390,11 @@ exports.restart = restart
#--------------------------------------------------------------------- #---------------------------------------------------------------------
clone = $coroutine ({vm, name, full_copy}) -> clone = ({vm, name, full_copy}) ->
xapi = @getXAPI(vm) return @getXAPI(vm).cloneVm(vm.ref, {
nameLabel: name,
newVm = yield if full_copy fast: not full_copy
xapi.copyVm(vm.ref, null, name) }).then(vm -> vm.$id)
else
xapi.cloneVm(vm.ref, name)
return newVm.$id
clone.params = { clone.params = {
id: { type: 'string' } id: { type: 'string' }
@ -415,6 +411,30 @@ exports.clone = clone
#--------------------------------------------------------------------- #---------------------------------------------------------------------
copy = ({ vm, sr, name }) ->
if vm.$poolId == sr.$poolId
return @getXAPI(vm).copyVm(vm.id, sr.id, name).then((vm) -> vm.$id)
return @getXAPI(vm).remoteCopyVm(vm.id, @getXAPI(sr), sr.id, name).then((vm) -> vm.$id)
copy.params = {
name: {
type: 'string',
optional: true
}
vm: { type: 'string' },
sr: { type: 'string' }
}
copy.resolve = {
vm: [ 'vm', 'VM', 'administrate' ]
sr: [ 'sr', 'SR', 'operate' ]
}
exports.copy = copy
#---------------------------------------------------------------------
# TODO: rename convertToTemplate() # TODO: rename convertToTemplate()
convert = $coroutine ({vm}) -> convert = $coroutine ({vm}) ->
yield @getXAPI(vm).call 'VM.set_is_a_template', vm.ref, true yield @getXAPI(vm).call 'VM.set_is_a_template', vm.ref, true

View File

@ -555,10 +555,20 @@ export default class Xapi extends XapiBase {
// ================================================================= // =================================================================
// Clone a VM: make a fast copy by fast copying each of its VDIs
// (using snapshots where possible) on the same SRs.
async _cloneVm (vm, nameLabel = vm.name_label) { async _cloneVm (vm, nameLabel = vm.name_label) {
return await this.call('VM.clone', vm.$ref, nameLabel) return await this.call('VM.clone', vm.$ref, nameLabel)
} }
// Copy a VM: make a normal copy of a VM and all its VDIs.
//
// If a SR is specified, it will contains the copies of the VDIs,
// otherwise they will use the SRs they are on.
async _copyVm (vm, nameLabel = vm.nameLabel, sr = undefined) {
return await this.call('VM.copy', nameLabel, sr ? sr.$ref : '')
}
async _snapshotVm (vm, nameLabel = vm.name_label) { async _snapshotVm (vm, nameLabel = vm.name_label) {
const ref = await this.call('VM.snapshot', vm.$ref, nameLabel) const ref = await this.call('VM.snapshot', vm.$ref, nameLabel)
@ -568,21 +578,46 @@ export default class Xapi extends XapiBase {
return ref return ref
} }
async cloneVm (vmId, nameLabel = undefined) { async cloneVm (vmId, {
return this._getOrWaitObject( nameLabel = undefined,
await this._cloneVm(this.getObject(vmId), nameLabel) fast = true
} = {}) {
const vm = this.getObject(vmId)
const cloneRef = await (
fast
? this._cloneVm(vm, nameLabel)
: this._copyVm(vm, nameLabel)
)
return await this._getOrWaitObject(cloneRef)
}
async copyVm (vmId, srId, nameLabel = undefined) {
return await this._getOrWaitObject(
await this._copyVm(
this.getObject(vmId),
nameLabel,
this.getObject(srId)
)
) )
} }
async copyVm (vmId, srId = null, nameLabel = undefined) { async remoteCopyVm (vmId, targetXapi, targetSrId, nameLabel = undefined) {
const vm = this.getObject(vmId) const sr = targetXapi.getObject(targetSrId)
const srRef = (srId == null) const stream = await this.exportVm(vmId)
? ''
: this.getObject(srId).$ref
return await this._getOrWaitObject( const vm = await targetXapi._getOrWaitObject(
await this.call('VM.copy', vm.$ref, nameLabel || vm.nameLabel, srRef) await targetXapi._importVm(stream, stream.length, sr)
) )
if (nameLabel !== undefined) {
await targetXapi._setObjectProperties(vm, {
nameLabel
})
}
return vm
} }
// TODO: clean up on error. // TODO: clean up on error.
@ -784,7 +819,17 @@ export default class Xapi extends XapiBase {
} }
}) })
stream.response = await eventToPromise(stream, 'response') const response = await eventToPromise(stream, 'response')
const { headers: {
'content-length': length
} } = response
if (length) {
stream.length = length
}
// TODO: remove when no longer used.
stream.response = response
return stream return stream
} }
@ -838,23 +883,25 @@ export default class Xapi extends XapiBase {
request.abort() request.abort()
} }
// TODO: an XVA can contain multiple VMs async _importVm (stream, length, sr) {
async importVm (stream, length, {
srId
} = {}) {
const taskRef = await this._createTask('VM import') const taskRef = await this._createTask('VM import')
const query = { const query = {
session_id: this.sessionId, session_id: this.sessionId,
task_id: taskRef task_id: taskRef
} }
if (srId) {
query.sr_id = this.getObject(srId).$ref let host
if (sr) {
host = sr.$PBDs[0].$host
query.sr_id = sr.$ref
} else {
host = this.pool.$master
} }
const upload = length const upload = length
? got.put({ ? got.put({
hostname: this.pool.$master.address, hostname: host.address,
path: '/import/' path: '/import/'
}, { }, {
body: stream, body: stream,
@ -868,7 +915,18 @@ export default class Xapi extends XapiBase {
this._watchTask(taskRef).then(extractOpaqueRef) this._watchTask(taskRef).then(extractOpaqueRef)
]) ])
return this._getOrWaitObject(vmRef) return vmRef
}
// TODO: an XVA can contain multiple VMs
async importVm (stream, length, {
srId
} = {}) {
return await this._getOrWaitObject(await this._importVm(
stream,
length,
srId && this.getObject(srId)
))
} }
async migrateVm (vmId, hostXapi, hostId, { async migrateVm (vmId, hostXapi, hostId, {