From 1bead03151937b8e5355197aa52ae3d7ca33af21 Mon Sep 17 00:00:00 2001 From: badrAZ Date: Fri, 26 May 2017 13:18:07 +0200 Subject: [PATCH] feat(vm.rollingDrCopy): previous backups can be removed first (#553) See vatesfr/xo-web#2157 --- src/api/vm.coffee | 5 +++-- src/xapi/index.js | 4 +++- src/xo-mixins/backups.js | 28 +++++++++++++++++++++------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/api/vm.coffee b/src/api/vm.coffee index c3fcf568d..b4163d28e 100644 --- a/src/api/vm.coffee +++ b/src/api/vm.coffee @@ -858,7 +858,7 @@ exports.rollingBackup = rollingBackup #--------------------------------------------------------------------- -rollingDrCopy = ({vm, pool, sr, tag, depth, retention = depth}) -> +rollingDrCopy = ({vm, pool, sr, tag, depth, retention = depth, deleteOldBackupsFirst}) -> unless sr unless pool throw invalidParameters('either pool or sr param should be specified') @@ -868,7 +868,7 @@ rollingDrCopy = ({vm, pool, sr, tag, depth, retention = depth}) -> sr = @getObject(pool.default_SR, 'SR') - return @rollingDrCopyVm({vm, sr, tag, retention}) + return @rollingDrCopyVm({vm, sr, tag, retention, deleteOldBackupsFirst}) rollingDrCopy.params = { retention: { type: 'number', optional: true } @@ -878,6 +878,7 @@ rollingDrCopy.params = { pool: { type: 'string', optional: true } sr: { type: 'string', optional: true } tag: { type: 'string'} + deleteOldBackupsFirst: {type: 'boolean', optional: true} } rollingDrCopy.resolve = { diff --git a/src/xapi/index.js b/src/xapi/index.js index 36bc8d40a..9cef44c79 100644 --- a/src/xapi/index.js +++ b/src/xapi/index.js @@ -555,7 +555,9 @@ export default class Xapi extends XapiBase { } = {}) { // Fall back on local copy if possible. if (targetXapi === this) { - return this.copyVm(vmId, targetSrId, { nameLabel }) + return { + vm: await this.copyVm(vmId, targetSrId, { nameLabel }) + } } const sr = targetXapi.getObject(targetSrId) diff --git a/src/xo-mixins/backups.js b/src/xo-mixins/backups.js index 401da496d..3932caf2c 100644 --- a/src/xo-mixins/backups.js +++ b/src/xo-mixins/backups.js @@ -998,7 +998,14 @@ export default class { await Promise.all(promises) } - async rollingDrCopyVm ({vm, sr, tag, retention}) { + _removeVms (xapi, vms) { + return Promise.all(mapToArray(vms, vm => + // Do not consider a failure to delete an old copy as a fatal error. + xapi.deleteVm(vm.$id)::pCatch(noop) + )) + } + + async rollingDrCopyVm ({vm, sr, tag, retention, deleteOldBackupsFirst}) { tag = 'DR_' + tag const reg = new RegExp('^' + escapeStringRegexp(`${vm.name_label}_${tag}_`) + '[0-9]{8}T[0-9]{6}Z$') @@ -1015,7 +1022,16 @@ export default class { vms[vm.$id] = vm } }) - const olderCopies = sortBy(vms, 'name_label') + + let vmsToRemove = sortBy(vms, 'name_label') + + if (retention > 1) { + vmsToRemove = vmsToRemove.slice(0, 1 - retention) + } + + if (deleteOldBackupsFirst) { + await this._removeVms(targetXapi, vmsToRemove) + } const copyName = `${vm.name_label}_${tag}_${safeDateFormat(new Date())}` const data = await sourceXapi.remoteCopyVm(vm.$id, targetXapi, sr.$id, { @@ -1024,11 +1040,9 @@ export default class { await targetXapi.addTag(data.vm.$id, 'Disaster Recovery') - const n = 1 - retention - await Promise.all(mapToArray(n ? olderCopies.slice(0, n) : olderCopies, vm => - // Do not consider a failure to delete an old copy as a fatal error. - targetXapi.deleteVm(vm.$id)::pCatch(noop) - )) + if (!deleteOldBackupsFirst) { + await this._removeVms(targetXapi, vmsToRemove) + } return { size: data.size