Skip to content

Commit

Permalink
feat(backup): add sanity check of aliases in cleanVm
Browse files Browse the repository at this point in the history
  • Loading branch information
fbeauchamp committed Jan 10, 2022
1 parent 7ec9c07 commit 58cd8b3
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 5 deletions.
21 changes: 21 additions & 0 deletions @xen-orchestra/backups/_cleanVm.integ.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const crypto = require('crypto')
const { RemoteAdapter } = require('./RemoteAdapter')
const { VHDFOOTER, VHDHEADER } = require('./tests.fixtures.js')
const { VhdFile, Constants, VhdDirectory, VhdAbstract } = require('vhd-lib')
const { checkAliases } = require('./_cleanVm')
const { dirname, basename } = require('path')

let tempDir, adapter, handler, jobId, vdiId, basePath
Expand Down Expand Up @@ -406,3 +407,23 @@ describe('tests multiple combination ', () => {
}
}
})

test('check Aliases should work alone', async () => {
await handler.mkdir('vhds')
await handler.mkdir('vhds/data')
await generateVhd(`vhds/data/ok.vhd`)
await VhdAbstract.createAlias(handler, 'vhds/ok.alias.vhd', 'vhds/data/ok.vhd')

await VhdAbstract.createAlias(handler, 'vhds/missingData.alias.vhd', 'vhds/data/nonexistent.vhd')

await generateVhd(`vhds/data/missingalias.vhd`)

await checkAliases(['vhds/missingData.alias.vhd', 'vhds/ok.alias.vhd'], 'vhds/data', { remove: true, handler })

// only ok have suvived
const alias = (await handler.list('vhds')).filter(f => f.endsWith('.vhd'))
expect(alias.length).toEqual(1)

const data = await handler.list('vhds/data')
expect(data.length).toEqual(1)
})
62 changes: 57 additions & 5 deletions @xen-orchestra/backups/_cleanVm.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const assert = require('assert')
const sum = require('lodash/sum')
const { asyncMap } = require('@xen-orchestra/async-map')
const { Constants, mergeVhd, openVhd, VhdAbstract, VhdFile } = require('vhd-lib')
const { Constants, isVhdAlias, mergeVhd, openVhd, VhdAbstract, VhdFile, resolveAlias } = require('vhd-lib')
const { dirname, resolve } = require('path')
const { DISK_TYPES } = Constants
const { isMetadataFile, isVhdFile, isXvaFile, isXvaSumFile } = require('./_backupType.js')
Expand Down Expand Up @@ -82,6 +82,7 @@ async function mergeVhdChain(chain, { handler, onLog, remove, merge }) {
)

clearInterval(handle)
onLog(`merging ${child} into ${parent} done`)

await Promise.all([
VhdAbstract.rename(handler, parent, child),
Expand All @@ -103,6 +104,7 @@ const noop = Function.prototype
const INTERRUPTED_VHDS_REG = /^(?:(.+)\/)?\.(.+)\.merge.json$/
const listVhds = async (handler, vmDir) => {
const vhds = []
const aliases = {}
const interruptedVhds = new Set()

await asyncMap(
Expand All @@ -120,7 +122,7 @@ const listVhds = async (handler, vmDir) => {
filter: file => isVhdFile(file) || INTERRUPTED_VHDS_REG.test(file),
prependDir: true,
})

aliases[vdiDir] = list.filter(vhd => isVhdAlias(vhd))
list.forEach(file => {
const res = INTERRUPTED_VHDS_REG.exec(file)
if (res === null) {
Expand All @@ -134,8 +136,54 @@ const listVhds = async (handler, vmDir) => {
)
)

return { vhds, interruptedVhds }
return { vhds, interruptedVhds, aliases }
}

async function checkAliases(aliasPaths, targetDataRepository, { handler, onLog = noop, remove = false }) {
const aliasFound = []
for (const path of aliasPaths) {
const target = await resolveAlias(handler, path)

if (!isVhdFile(target)) {
onLog(`Alias ${path} references a non vhd target: ${target}`)
if (remove) {
await handler.unlink(target)
await handler.unlink(path)
}
continue
}

try {
const { dispose } = await openVhd(handler, target)
dispose()
} catch (e) {
onLog(`target ${target} of alias ${path} is missing or broken`)
if (remove) {
try {
await VhdAbstract.unlink(handler, path)
} catch(e){}
}
continue
}

aliasFound.push(resolve('/', target))
}

const entries = await handler.list(targetDataRepository, {
ignoreMissing: true,
prependDir: true,
})

entries.forEach(async entry => {
if (!aliasFound.includes(entry)) {
onLog(`the Vhd ${entry} is not referenced by a an alias`)
if (remove) {
await VhdAbstract.unlink(handler, entry)
}
}
})
}
exports.checkAliases = checkAliases

const defaultMergeLimiter = limitConcurrency(1)

Expand Down Expand Up @@ -180,8 +228,12 @@ exports.cleanVm = async function cleanVm(
}
}
})

// @todo : add check for data folder of alias not referenced in a valid alias
// check if alias are correct
// check if all vhd in data subfolder have a corresponding alias
await asyncMap(Object.keys(vhdsList.aliases), async dir => {
const aliases = vhdsList.aliases[dir]
await checkAliases(aliases, `${dir}/data`, { handler, onLog, remove })
})

// remove VHDs with missing ancestors
{
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

> Users must be able to say: “Nice enhancement, I'm eager to test it”
- [Backup] Add sanity check of alias after backup. PR [6043](https://github.com/vatesfr/xen-orchestra/pull/6043)

### Bug fixes

> Users must be able to say: “I had this issue, happy to know it's fixed”
Expand Down

0 comments on commit 58cd8b3

Please sign in to comment.