fix(vm.import{,Delta}Backup): make restored VMs identifiable
Their names is prefixed with the exported date and they have a specific tag (*restored from backup*). Fixes vatesfr/xo-web#1719
This commit is contained in:
parent
79b80dcd07
commit
5870769e7d
10
src/utils.js
10
src/utils.js
@ -19,7 +19,10 @@ import xml2js from 'xml2js'
|
||||
// does not implement `guess` function for example.
|
||||
import 'moment-timezone'
|
||||
|
||||
import through2 from 'through2'
|
||||
import { CronJob } from 'cron'
|
||||
import { Readable } from 'stream'
|
||||
import { utcFormat, utcParse } from 'd3-time-format'
|
||||
import {
|
||||
all as pAll,
|
||||
defer,
|
||||
@ -30,9 +33,6 @@ import {
|
||||
createHash,
|
||||
randomBytes
|
||||
} from 'crypto'
|
||||
import { Readable } from 'stream'
|
||||
import through2 from 'through2'
|
||||
import {utcFormat as d3TimeFormat} from 'd3-time-format'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
@ -391,7 +391,9 @@ export const popProperty = obj => {
|
||||
|
||||
// Format a date in ISO 8601 in a safe way to be used in filenames
|
||||
// (even on Windows).
|
||||
export const safeDateFormat = d3TimeFormat('%Y%m%dT%H%M%SZ')
|
||||
export const safeDateFormat = utcFormat('%Y%m%dT%H%M%SZ')
|
||||
|
||||
export const safeDateParse = utcParse('%Y%m%dT%H%M%SZ')
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
dirname
|
||||
} from 'path'
|
||||
import { satisfies as versionSatisfies } from 'semver'
|
||||
import { utcFormat } from 'd3-time-format'
|
||||
|
||||
import vhdMerge, { chainVhd } from '../vhd-merge'
|
||||
import xapiObjectToXo from '../xapi-object-to-xo'
|
||||
@ -23,7 +24,8 @@ import {
|
||||
noop,
|
||||
pCatch,
|
||||
pSettle,
|
||||
safeDateFormat
|
||||
safeDateFormat,
|
||||
safeDateParse
|
||||
} from '../utils'
|
||||
import {
|
||||
VDI_FORMAT_VHD
|
||||
@ -34,6 +36,8 @@ import {
|
||||
const DELTA_BACKUP_EXT = '.json'
|
||||
const DELTA_BACKUP_EXT_LENGTH = DELTA_BACKUP_EXT.length
|
||||
|
||||
const shortDate = utcFormat('%Y-%m-%d')
|
||||
|
||||
// Test if a file is a vdi backup. (full or delta)
|
||||
const isVdiBackup = name => /^\d+T\d+Z_(?:full|delta)\.vhd$/.test(name)
|
||||
|
||||
@ -41,6 +45,37 @@ const isVdiBackup = name => /^\d+T\d+Z_(?:full|delta)\.vhd$/.test(name)
|
||||
const isDeltaVdiBackup = name => /^\d+T\d+Z_delta\.vhd$/.test(name)
|
||||
const isFullVdiBackup = name => /^\d+T\d+Z_full\.vhd$/.test(name)
|
||||
|
||||
const parseVmBackupPath = name => {
|
||||
const base = basename(name)
|
||||
let baseMatches
|
||||
|
||||
baseMatches = /^([^_]+)_([^_]+)_(.+)\.xva$/.exec(base)
|
||||
if (baseMatches) {
|
||||
return {
|
||||
datetime: safeDateParse(baseMatches[1]),
|
||||
name: baseMatches[3],
|
||||
tag: baseMatches[2],
|
||||
type: 'xva'
|
||||
}
|
||||
}
|
||||
|
||||
let dirMatches
|
||||
if (
|
||||
(baseMatches = /^([^_]+)_(.+)\.json$/.exec(base)) &&
|
||||
(dirMatches = /^vm_delta_([^_]+)_(.+)$/.exec(basename(dirname(name))))
|
||||
) {
|
||||
return {
|
||||
datetime: safeDateParse(baseMatches[1]),
|
||||
name: baseMatches[2],
|
||||
uuid: dirMatches[2],
|
||||
tag: dirMatches[1],
|
||||
type: 'delta'
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('invalid VM backup filename')
|
||||
}
|
||||
|
||||
// Get the timestamp of a vdi backup. (full or delta)
|
||||
const getVdiTimestamp = name => {
|
||||
const arr = /^(\d+T\d+Z)_(?:full|delta)\.vhd$/.exec(name)
|
||||
@ -114,6 +149,15 @@ export default class {
|
||||
const xapi = this._xo.getXapi(sr)
|
||||
|
||||
const vm = await xapi.importVm(stream, { srId: sr._xapiId })
|
||||
|
||||
const { datetime } = parseVmBackupPath(file)
|
||||
await Promise.all([
|
||||
xapi.addTag(vm.$id, 'restored from backup'),
|
||||
xapi.editVm(vm.$id, {
|
||||
name_label: `${vm.name_label} (${shortDate(datetime)})`
|
||||
})
|
||||
])
|
||||
|
||||
return xapiObjectToXo(vm).id
|
||||
}
|
||||
|
||||
@ -590,10 +634,13 @@ export default class {
|
||||
}
|
||||
|
||||
async importDeltaVmBackup ({sr, remoteId, filePath}) {
|
||||
filePath = `${filePath}${DELTA_BACKUP_EXT}`
|
||||
const { datetime } = parseVmBackupPath(filePath)
|
||||
|
||||
const handler = await this._xo.getRemoteHandler(remoteId)
|
||||
const xapi = this._xo.getXapi(sr)
|
||||
|
||||
const delta = JSON.parse(await handler.readFile(`${filePath}${DELTA_BACKUP_EXT}`))
|
||||
const delta = JSON.parse(await handler.readFile(filePath))
|
||||
let vm
|
||||
const { version } = delta
|
||||
|
||||
@ -620,9 +667,12 @@ export default class {
|
||||
)
|
||||
)
|
||||
|
||||
delta.vm.name_label += ` (${shortDate(datetime)})`
|
||||
delta.vm.tags.push('restored from backup')
|
||||
|
||||
vm = await xapi.importDeltaVm(delta, {
|
||||
srId: sr._xapiId,
|
||||
disableStartAfterImport: false
|
||||
disableStartAfterImport: false,
|
||||
srId: sr._xapiId
|
||||
})
|
||||
} else {
|
||||
throw new Error(`Unsupported delta backup version: ${version}`)
|
||||
|
Loading…
Reference in New Issue
Block a user