diff --git a/@xen-orchestra/backups-cli/_fs.js b/@xen-orchestra/backups-cli/_fs.js index cdfa4c97e..cebc573b9 100644 --- a/@xen-orchestra/backups-cli/_fs.js +++ b/@xen-orchestra/backups-cli/_fs.js @@ -3,6 +3,17 @@ const { dirname } = require('path') const fs = require('promise-toolbox/promisifyAll')(require('fs')) module.exports = fs +fs.getSize = path => + fs.stat(path).then( + _ => _.size, + error => { + if (error.code === 'ENOENT') { + return 0 + } + throw error + } + ) + fs.mktree = async function mkdirp(path) { try { await fs.mkdir(path) diff --git a/@xen-orchestra/backups-cli/commands/info.js b/@xen-orchestra/backups-cli/commands/info.js new file mode 100644 index 000000000..117ab90bd --- /dev/null +++ b/@xen-orchestra/backups-cli/commands/info.js @@ -0,0 +1,58 @@ +const groupBy = require('lodash/groupBy') +const { createHash } = require('crypto') +const { dirname, resolve } = require('path') + +const asyncMap = require('../_asyncMap') +const { readdir2, readFile, getSize } = require('../_fs') + +const sha512 = str => createHash('sha512').update(str).digest('hex') +const sum = values => values.reduce((a, b) => a + b) + +module.exports = async function info(vmDirs) { + const jsonFiles = ( + await asyncMap(vmDirs, async vmDir => + (await readdir2(vmDir)).filter(_ => _.endsWith('.json')) + ) + ).flat() + + const hashes = { __proto__: null } + + const info = ( + await asyncMap(jsonFiles, async jsonFile => { + try { + const jsonDir = dirname(jsonFile) + const json = await readFile(jsonFile) + + const hash = sha512(json) + if (hash in hashes) { + console.log(jsonFile, 'duplicate of', hashes[hash]) + return + } + hashes[hash] = jsonFile + + const metadata = JSON.parse(json) + + return { + jsonDir, + jsonFile, + metadata, + size: + json.length + + (await (metadata.mode === 'delta' + ? asyncMap(Object.values(metadata.vhds), _ => + getSize(resolve(jsonDir, _)) + ).then(sum) + : getSize(resolve(jsonDir, metadata.xva)))), + } + } catch (error) { + console.error(jsonFile, error) + } + }) + ).filter(_ => _ !== undefined) + const byJobs = groupBy(info, 'metadata.jobId') + Object.keys(byJobs) + .sort() + .forEach(jobId => { + console.log(jobId, sum(byJobs[jobId].map(_ => _.size))) + }) +} diff --git a/@xen-orchestra/backups-cli/index.js b/@xen-orchestra/backups-cli/index.js index 56dd53203..94ec9c976 100755 --- a/@xen-orchestra/backups-cli/index.js +++ b/@xen-orchestra/backups-cli/index.js @@ -13,6 +13,12 @@ require('./_composeCommands')({ }, usage: 'xo-vm-backups ', }, + info: { + get main() { + return require('./commands/info') + }, + usage: 'xo-vm-backups/*', + }, })(process.argv.slice(2), 'xo-backups').catch(error => { console.error('main', error) process.exitCode = 1