@xen-orchestra/backups 0.25.0 → 0.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/RemoteAdapter.js CHANGED
@@ -15,7 +15,7 @@ const { deduped } = require('@vates/disposable/deduped.js')
15
15
  const { decorateMethodsWith } = require('@vates/decorate-with')
16
16
  const { compose } = require('@vates/compose')
17
17
  const { execFile } = require('child_process')
18
- const { readdir, stat } = require('fs-extra')
18
+ const { readdir, lstat } = require('fs-extra')
19
19
  const { v4: uuidv4 } = require('uuid')
20
20
  const { ZipFile } = require('yazl')
21
21
  const zlib = require('zlib')
@@ -47,13 +47,12 @@ const resolveSubpath = (root, path) => resolve(root, `.${resolve('/', path)}`)
47
47
  const RE_VHDI = /^vhdi(\d+)$/
48
48
 
49
49
  async function addDirectory(files, realPath, metadataPath) {
50
- try {
51
- const subFiles = await readdir(realPath)
52
- await asyncMap(subFiles, file => addDirectory(files, realPath + '/' + file, metadataPath + '/' + file))
53
- } catch (error) {
54
- if (error == null || error.code !== 'ENOTDIR') {
55
- throw error
56
- }
50
+ const stats = await lstat(realPath)
51
+ if (stats.isDirectory()) {
52
+ await asyncMap(await readdir(realPath), file =>
53
+ addDirectory(files, realPath + '/' + file, metadataPath + '/' + file)
54
+ )
55
+ } else if (stats.isFile()) {
57
56
  files.push({
58
57
  realPath,
59
58
  metadataPath,
@@ -292,7 +291,7 @@ class RemoteAdapter {
292
291
  }
293
292
 
294
293
  #useVhdDirectory() {
295
- return this.handler.type === 's3'
294
+ return this.handler.useVhdDirectory()
296
295
  }
297
296
 
298
297
  #useAlias() {
@@ -383,8 +382,12 @@ class RemoteAdapter {
383
382
  const entriesMap = {}
384
383
  await asyncMap(await readdir(path), async name => {
385
384
  try {
386
- const stats = await stat(`${path}/${name}`)
387
- entriesMap[stats.isDirectory() ? `${name}/` : name] = {}
385
+ const stats = await lstat(`${path}/${name}`)
386
+ if (stats.isDirectory()) {
387
+ entriesMap[name + '/'] = {}
388
+ } else if (stats.isFile()) {
389
+ entriesMap[name] = {}
390
+ }
388
391
  } catch (error) {
389
392
  if (error == null || error.code !== 'ENOENT') {
390
393
  throw error
package/_cleanVm.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  const assert = require('assert')
4
4
  const sum = require('lodash/sum')
5
+ const UUID = require('uuid')
5
6
  const { asyncMap } = require('@xen-orchestra/async-map')
6
7
  const { Constants, mergeVhd, openVhd, VhdAbstract, VhdFile } = require('vhd-lib')
7
8
  const { isVhdAlias, resolveVhdAlias } = require('vhd-lib/aliases')
@@ -50,7 +51,7 @@ const computeVhdsSize = (handler, vhdPaths) =>
50
51
  async function mergeVhdChain(chain, { handler, logInfo, remove, merge }) {
51
52
  assert(chain.length >= 2)
52
53
  const chainCopy = [...chain]
53
- const parent = chainCopy.pop()
54
+ const parent = chainCopy.shift()
54
55
  const children = chainCopy
55
56
 
56
57
  if (merge) {
@@ -59,30 +60,20 @@ async function mergeVhdChain(chain, { handler, logInfo, remove, merge }) {
59
60
  let done, total
60
61
  const handle = setInterval(() => {
61
62
  if (done !== undefined) {
62
- logInfo(`merging children in progress`, { children, parent, doneCount: done, totalCount: total})
63
+ logInfo(`merging children in progress`, { children, parent, doneCount: done, totalCount: total })
63
64
  }
64
65
  }, 10e3)
65
66
 
66
67
  const mergedSize = await mergeVhd(handler, parent, handler, children, {
68
+ logInfo,
67
69
  onProgress({ done: d, total: t }) {
68
70
  done = d
69
71
  total = t
70
72
  },
73
+ remove,
71
74
  })
72
75
 
73
76
  clearInterval(handle)
74
- const mergeTargetChild = children.shift()
75
- await Promise.all([
76
- VhdAbstract.rename(handler, parent, mergeTargetChild),
77
- asyncMap(children, child => {
78
- logInfo(`the VHD child is already merged`, { child })
79
- if (remove) {
80
- logInfo(`deleting merged VHD child`, { child })
81
- return VhdAbstract.unlink(handler, child)
82
- }
83
- }),
84
- ])
85
-
86
77
  return mergedSize
87
78
  }
88
79
  }
@@ -197,6 +188,7 @@ exports.cleanVm = async function cleanVm(
197
188
  const handler = this._handler
198
189
 
199
190
  const vhdsToJSons = new Set()
191
+ const vhdById = new Map()
200
192
  const vhdParents = { __proto__: null }
201
193
  const vhdChildren = { __proto__: null }
202
194
 
@@ -218,6 +210,27 @@ exports.cleanVm = async function cleanVm(
218
210
  }
219
211
  vhdChildren[parent] = path
220
212
  }
213
+ // Detect VHDs with the same UUIDs
214
+ //
215
+ // Due to a bug introduced in a1bcd35e2
216
+ const duplicate = vhdById.get(UUID.stringify(vhd.footer.uuid))
217
+ let vhdKept = vhd
218
+ if (duplicate !== undefined) {
219
+ logWarn('uuid is duplicated', { uuid: UUID.stringify(vhd.footer.uuid) })
220
+ if (duplicate.containsAllDataOf(vhd)) {
221
+ logWarn(`should delete ${path}`)
222
+ vhdKept = duplicate
223
+ vhds.delete(path)
224
+ } else if (vhd.containsAllDataOf(duplicate)) {
225
+ logWarn(`should delete ${duplicate._path}`)
226
+ vhds.delete(duplicate._path)
227
+ } else {
228
+ logWarn(`same ids but different content`)
229
+ }
230
+ } else {
231
+ logInfo('not duplicate', UUID.stringify(vhd.footer.uuid), path)
232
+ }
233
+ vhdById.set(UUID.stringify(vhdKept.footer.uuid), vhdKept)
221
234
  })
222
235
  } catch (error) {
223
236
  vhds.delete(path)
@@ -372,7 +385,7 @@ exports.cleanVm = async function cleanVm(
372
385
  const unusedVhdsDeletion = []
373
386
  const toMerge = []
374
387
  {
375
- // VHD chains (as list from child to ancestor) to merge indexed by last
388
+ // VHD chains (as list from oldest to most recent) to merge indexed by most recent
376
389
  // ancestor
377
390
  const vhdChainsToMerge = { __proto__: null }
378
391
 
@@ -396,7 +409,7 @@ exports.cleanVm = async function cleanVm(
396
409
  if (child !== undefined) {
397
410
  const chain = getUsedChildChainOrDelete(child)
398
411
  if (chain !== undefined) {
399
- chain.push(vhd)
412
+ chain.unshift(vhd)
400
413
  return chain
401
414
  }
402
415
  }
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/vatesfr/xen-orchestra.git"
10
10
  },
11
- "version": "0.25.0",
11
+ "version": "0.27.1",
12
12
  "engines": {
13
13
  "node": ">=14.6"
14
14
  },
@@ -22,7 +22,7 @@
22
22
  "@vates/disposable": "^0.1.1",
23
23
  "@vates/parse-duration": "^0.1.1",
24
24
  "@xen-orchestra/async-map": "^0.1.2",
25
- "@xen-orchestra/fs": "^1.0.3",
25
+ "@xen-orchestra/fs": "^2.0.0",
26
26
  "@xen-orchestra/log": "^0.3.0",
27
27
  "@xen-orchestra/template": "^0.1.0",
28
28
  "compare-versions": "^4.0.1",
@@ -38,7 +38,7 @@
38
38
  "promise-toolbox": "^0.21.0",
39
39
  "proper-lockfile": "^4.1.2",
40
40
  "uuid": "^8.3.2",
41
- "vhd-lib": "^3.2.0",
41
+ "vhd-lib": "^3.3.2",
42
42
  "yazl": "^2.5.1"
43
43
  },
44
44
  "devDependencies": {
@@ -46,7 +46,7 @@
46
46
  "tmp": "^0.2.1"
47
47
  },
48
48
  "peerDependencies": {
49
- "@xen-orchestra/xapi": "^1.1.0"
49
+ "@xen-orchestra/xapi": "^1.4.0"
50
50
  },
51
51
  "license": "AGPL-3.0-or-later",
52
52
  "author": {