Fix snapshot deletion after VM export.

This commit is contained in:
Julien Fontanet 2015-05-25 12:51:42 +02:00
parent 9ab110277a
commit 9bcb2ac094
3 changed files with 51 additions and 27 deletions

View File

@ -239,28 +239,8 @@ exports.create = create
#---------------------------------------------------------------------
delete_ = $coroutine ({vm, delete_disks: deleteDisks}) ->
if $isVMRunning vm
@throw 'INVALID_PARAMS', 'The VM can only be deleted when halted'
xapi = @getXAPI vm
if deleteDisks
$forEach vm.$VBDs, (ref) =>
try
VBD = @getObject ref, 'VBD'
catch e
return
return if VBD.read_only or not VBD.VDI?
$wait xapi.call 'VDI.destroy', VBD.VDI
return
$wait xapi.call 'VM.destroy', vm.ref
return true
delete_ = ({vm, delete_disks: deleteDisks}) ->
return @getXAPI(vm).deleteVm(vm.id, deleteDisks)
delete_.params = {
id: { type: 'string' }
@ -819,17 +799,19 @@ export_ = $coroutine ({vm, compress}) ->
)
pFinally(
xapi._watchTask(task)
.then (result) ->
.then((result) ->
$debug 'export succeeded'
return
.catch (error) ->
)
.catch((error) ->
$debug 'export failed: %j', error
return
)
,
$coroutine =>
->
if snapshotRef?
$debug 'deleting temp snapshot...'
$wait exports.delete.call this, id: snapshotRef, delete_disks: true
xapi.deleteVm(snapshotRef, true)
return
)

View File

@ -68,6 +68,13 @@ export const parseXml = (function () {
// -------------------------------------------------------------------
// This function does nothing and returns undefined.
//
// It is often used to swallow promise's errors.
export function noop () {}
// -------------------------------------------------------------------
// Ponyfill for Promise.finally(cb)
export const pFinally = (promise, cb) => {
return promise.then(

View File

@ -9,7 +9,7 @@ import {promisify} from 'bluebird'
import {Xapi as XapiBase} from 'xen-api'
import {debounce} from './decorators'
import {ensureArray, parseXml, pFinally} from './utils'
import {ensureArray, noop, parseXml, pFinally} from './utils'
import {JsonRpcError} from './api-errors'
const debug = createDebug('xo:xapi')
@ -61,6 +61,14 @@ const getNamespaceForType = (type) => typeToNamespace[type] || type
// ===================================================================
const VM_RUNNING_POWER_STATES = {
Running: true,
Paused: true
}
const isVmRunning = (vm) => VM_RUNNING_POWER_STATES[vm.power_state]
// ===================================================================
export default class Xapi extends XapiBase {
constructor (...args) {
super(...args)
@ -454,6 +462,33 @@ export default class Xapi extends XapiBase {
// =================================================================
async _deleteVdi (vdiId) {
const vdi = this.getObject(vdiId)
await this.call('VDI.destroy', vdi.$ref)
}
async deleteVm (vmId, deleteDisks = false) {
const vm = this.getObject(vmId)
if (isVmRunning(vm)) {
throw new Error('running VMs cannot be deleted')
}
if (deleteDisks) {
// TODO: simplify when we start to use xen-api >= 0.5
await Promise.all(map(vm.VBDs, ref => {
try {
return this._deleteVdi(this.getObject(ref).VDI).catch(noop)
} catch (_) {}
}))
}
await this.call('VM.destroy', vm.$ref)
}
// =================================================================
async _doDockerAction (vmId, action, containerId) {
const vm = this.getObject(vmId)
const host = this.getObject(vm.resident_on)