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:
commit
a5590b090c
@ -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
|
||||||
|
96
src/xapi.js
96
src/xapi.js
@ -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, {
|
||||||
|
Loading…
Reference in New Issue
Block a user