parent
84d7ba5758
commit
5e11e87a0c
@ -755,12 +755,13 @@ exports.importDeltaBackup = importDeltaBackup
|
|||||||
|
|
||||||
#---------------------------------------------------------------------
|
#---------------------------------------------------------------------
|
||||||
|
|
||||||
deltaCopy = ({ force, vm, sr }) -> @deltaCopyVm(vm, sr, force)
|
deltaCopy = ({ force, vm, retention, sr }) -> @deltaCopyVm(vm, sr, force, retention)
|
||||||
|
|
||||||
deltaCopy.params = {
|
deltaCopy.params = {
|
||||||
|
force: { type: 'boolean', optional: true },
|
||||||
id: { type: 'string' },
|
id: { type: 'string' },
|
||||||
sr: { type: 'string' },
|
retention: { type: 'number', optional: true },
|
||||||
force: { type: 'boolean', optional: true }
|
sr: { type: 'string' }
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaCopy.resolve = {
|
deltaCopy.resolve = {
|
||||||
|
@ -894,18 +894,15 @@ export default class Xapi extends XapiBase {
|
|||||||
vbds,
|
vbds,
|
||||||
vdis,
|
vdis,
|
||||||
vifs,
|
vifs,
|
||||||
vm: baseVm && !disableBaseTags
|
vm: {
|
||||||
? {
|
...vm,
|
||||||
...vm,
|
other_config: baseVm && !disableBaseTags
|
||||||
other_config: {
|
? {
|
||||||
...vm.other_config,
|
...vm.other_config,
|
||||||
[TAG_BASE_DELTA]: baseVm.uuid
|
[TAG_BASE_DELTA]: baseVm.uuid
|
||||||
}
|
}
|
||||||
}
|
: omit(vm.other_config, TAG_BASE_DELTA)
|
||||||
: {
|
}
|
||||||
...vm,
|
|
||||||
other_config: omit(vm.other_config, TAG_BASE_DELTA)
|
|
||||||
}
|
|
||||||
}, 'streams', {
|
}, 'streams', {
|
||||||
value: await streams::pAll()
|
value: await streams::pAll()
|
||||||
})
|
})
|
||||||
|
@ -51,6 +51,8 @@ import {
|
|||||||
|
|
||||||
const DELTA_BACKUP_EXT = '.json'
|
const DELTA_BACKUP_EXT = '.json'
|
||||||
const DELTA_BACKUP_EXT_LENGTH = DELTA_BACKUP_EXT.length
|
const DELTA_BACKUP_EXT_LENGTH = DELTA_BACKUP_EXT.length
|
||||||
|
const TAG_SOURCE_VM = 'xo:source_vm'
|
||||||
|
const TAG_EXPORT_TIME = 'xo:export_time'
|
||||||
|
|
||||||
const shortDate = utcFormat('%Y-%m-%d')
|
const shortDate = utcFormat('%Y-%m-%d')
|
||||||
|
|
||||||
@ -398,12 +400,12 @@ export default class {
|
|||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
@deferrable.onFailure
|
@deferrable.onFailure
|
||||||
async deltaCopyVm ($onFailure, srcVm, targetSr, force = false) {
|
async deltaCopyVm ($onFailure, srcVm, targetSr, force = false, retention = 1) {
|
||||||
const srcXapi = this._xo.getXapi(srcVm)
|
const srcXapi = this._xo.getXapi(srcVm)
|
||||||
const targetXapi = this._xo.getXapi(targetSr)
|
const targetXapi = this._xo.getXapi(targetSr)
|
||||||
|
|
||||||
// Get Xen objects from XO objects.
|
// Get Xen objects from XO objects.
|
||||||
srcVm = srcXapi.getObject(srcVm._xapiId)
|
const { uuid } = srcVm = srcXapi.getObject(srcVm._xapiId)
|
||||||
targetSr = targetXapi.getObject(targetSr._xapiId)
|
targetSr = targetXapi.getObject(targetSr._xapiId)
|
||||||
|
|
||||||
// 1. Find the local base for this SR (if any).
|
// 1. Find the local base for this SR (if any).
|
||||||
@ -426,7 +428,10 @@ export default class {
|
|||||||
$onFailure(() => srcXapi.deleteVm(delta.vm.uuid))
|
$onFailure(() => srcXapi.deleteVm(delta.vm.uuid))
|
||||||
$onFailure(cancel)
|
$onFailure(cancel)
|
||||||
|
|
||||||
delta.vm.name_label += ` (${shortDate(Date.now())})`
|
const now = Date.now()
|
||||||
|
delta.vm.name_label += ` (${shortDate(now)})`
|
||||||
|
delta.vm.other_config[TAG_SOURCE_VM] = uuid
|
||||||
|
delta.vm.other_config[TAG_EXPORT_TIME] = safeDateFormat(now)
|
||||||
|
|
||||||
forEach(delta.vdis, (vdi, key) => {
|
forEach(delta.vdis, (vdi, key) => {
|
||||||
const id = `${key}.vhd`
|
const id = `${key}.vhd`
|
||||||
@ -436,10 +441,19 @@ export default class {
|
|||||||
delta.streams[id] = delta.streams[id].pipe(sizeStream)
|
delta.streams[id] = delta.streams[id].pipe(sizeStream)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let toRemove = filter(targetXapi.objects.all, obj =>
|
||||||
|
obj.$type === 'vm' &&
|
||||||
|
obj.other_config[TAG_SOURCE_VM] === uuid
|
||||||
|
)
|
||||||
|
const n = toRemove.length - retention + 1 // take into account the future copy
|
||||||
|
toRemove = n > 0
|
||||||
|
? sortBy(toRemove, _ => _.other_config[TAG_EXPORT_TIME]).slice(0, n)
|
||||||
|
: undefined
|
||||||
|
|
||||||
const promise = targetXapi.importDeltaVm(
|
const promise = targetXapi.importDeltaVm(
|
||||||
delta,
|
delta,
|
||||||
{
|
{
|
||||||
deleteBase: true, // Remove the remote base.
|
deleteBase: toRemove.length === 0, // old replications are not captured in toRemove
|
||||||
srId: targetSr.$id
|
srId: targetSr.$id
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -450,6 +464,12 @@ export default class {
|
|||||||
promise.then(() => srcXapi.deleteVm(localBaseUuid))::ignoreErrors()
|
promise.then(() => srcXapi.deleteVm(localBaseUuid))::ignoreErrors()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toRemove !== undefined) {
|
||||||
|
promise.then(() => asyncMap(toRemove, _ =>
|
||||||
|
targetXapi.deleteVm(_.$id))
|
||||||
|
)::ignoreErrors()
|
||||||
|
}
|
||||||
|
|
||||||
// (Asynchronously) Identify snapshot as future base.
|
// (Asynchronously) Identify snapshot as future base.
|
||||||
promise.then(() => {
|
promise.then(() => {
|
||||||
return srcXapi._updateObjectMapProperty(srcVm, 'other_config', {
|
return srcXapi._updateObjectMapProperty(srcVm, 'other_config', {
|
||||||
|
Loading…
Reference in New Issue
Block a user