From 71ca51dc1a88262304c402f79fef0493b7a4e91d Mon Sep 17 00:00:00 2001 From: Fabrice Marsaud Date: Fri, 6 Nov 2015 17:07:18 +0100 Subject: [PATCH] Disaster recovery feature --- src/api/vm.coffee | 23 +++++++++++++++++++++++ src/xo.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/api/vm.coffee b/src/api/vm.coffee index a7e59acef..fc01ea904 100644 --- a/src/api/vm.coffee +++ b/src/api/vm.coffee @@ -541,6 +541,29 @@ exports.rollingBackup = rollingBackup #--------------------------------------------------------------------- +rollingDrCopy = ({vm, pool, tag, depth}) -> + if vm.$poolId is pool.id + throw new JsonRpcError('Disaster Recovery attempts to copy on the same pool') + return @rollingDrCopyVm({vm, sr: @getObject(pool.default_SR, 'SR'), tag, depth}) + +rollingDrCopy.params = { + id: { type: 'string' } + pool: { type: 'string' } + tag: { type: 'string'} + depth: { type: 'number' } +} + +rollingDrCopy.resolve = { + vm: ['id', ['VM', 'VM-snapshot'], 'administrate'], + pool: ['pool', 'pool', 'administrate'] +} + +rollingDrCopy.description = 'Copies a VM to a different pool, with a tagged name, and removes the oldest VM with the same tag from this pool, according to depth' + +exports.rollingDrCopy = rollingDrCopy + +#--------------------------------------------------------------------- + start = $coroutine ({vm}) -> yield @getXAPI(vm).call( 'VM.start', vm.ref diff --git a/src/xo.js b/src/xo.js index 8fc691877..fefba3a0f 100644 --- a/src/xo.js +++ b/src/xo.js @@ -836,6 +836,37 @@ export default class Xo extends EventEmitter { await Promise.all(promises) } + async rollingDrCopyVm ({vm, sr, tag, depth}) { + tag = 'DR_' + tag + const reg = new RegExp('^' + escapeStringRegexp(`${vm.name_label}_${tag}_`) + '[0-9]{8}T[0-9]{6}Z$') + + const targetXapi = this.getXAPI(sr) + sr = targetXapi.getObject(sr.id) + const sourceXapi = this.getXAPI(vm) + vm = sourceXapi.getObject(vm.id) + + const vms = [] + forEach(sr.$VDIs, vdi => { + const vbds = vdi.$VBDs + const vm = vbds && vbds[0] && vbds[0].$VM + if (vm && reg.test(vm.name_label)) { + vms.push(vm) + } + }) + const olderCopies = sortBy(vms, 'name_label') + + const copyName = `${vm.name_label}_${tag}_${safeDateFormat(new Date())}` + const drCopy = await sourceXapi.remoteCopyVm(vm.$id, targetXapi, sr.$id, copyName) + await targetXapi.addTag(drCopy.$id, 'Disaster Recovery') + + const promises = [] + for (let surplus = olderCopies.length - (depth - 1); surplus > 0; surplus--) { + const oldDRVm = olderCopies.shift() + promises.push(targetXapi.deleteVm(oldDRVm.$id, true)) + } + await Promise.all(promises) + } + // ----------------------------------------------------------------- async createAuthenticationToken ({userId}) {