@xen-orchestra/backups 0.73.1 → 0.73.2

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.mjs CHANGED
@@ -300,7 +300,20 @@ export class RemoteAdapter {
300
300
  async deleteFullVmBackups(backups) {
301
301
  const handler = this._handler
302
302
  await asyncMapSettled(backups, ({ _filename, xva }) =>
303
- Promise.all([handler.unlink(_filename), handler.unlink(resolveRelativeFromFile(_filename, xva))])
303
+ Promise.all([
304
+ handler.unlink(_filename).catch(error => {
305
+ warn('error while removing full vm backup metadata', { error, filename: _filename })
306
+ if (error.code !== 'ENOENT') throw error
307
+ }),
308
+ handler.unlink(resolveRelativeFromFile(_filename, xva)).catch(error => {
309
+ warn('error while removing full vm backup file', { error, filename: _filename })
310
+ if (error.code !== 'ENOENT') throw error
311
+ }),
312
+ handler.unlink(resolveRelativeFromFile(_filename, `${xva}.checksum`)).catch(error => {
313
+ // checksum can be missing , it's not an issue
314
+ if (error.code !== 'ENOENT') throw error
315
+ }),
316
+ ])
304
317
  )
305
318
 
306
319
  await this.#removeVmBackupsFromCache(backups)
@@ -311,18 +324,46 @@ export class RemoteAdapter {
311
324
  }
312
325
 
313
326
  async deleteVmBackups(files) {
314
- const metadata = await asyncMap(files, file => this.readVmBackupMetadata(file))
315
- const { delta, full, ...others } = groupBy(metadata, 'mode')
327
+ const metadataOrNull = await asyncMap(files, async file => {
328
+ try {
329
+ return await this.readVmBackupMetadata(file)
330
+ } catch (error) {
331
+ if (error.code === 'ENOENT') {
332
+ // File was already removed (e.g. by coalescing); clean the stale cache entry
333
+ warn('backup metadata not found, removing stale cache entry', { file })
334
+ return null
335
+ }
336
+ throw error
337
+ }
338
+ })
339
+
340
+ const presentMetadata = []
341
+ const missingFiles = []
342
+ for (let i = 0; i < files.length; i++) {
343
+ if (metadataOrNull[i] === null) {
344
+ missingFiles.push({ _filename: files[i] })
345
+ } else {
346
+ presentMetadata.push(metadataOrNull[i])
347
+ }
348
+ }
349
+
350
+ const { delta, full, ...others } = groupBy(presentMetadata, 'mode')
316
351
 
317
352
  const unsupportedModes = Object.keys(others)
318
353
  if (unsupportedModes.length !== 0) {
319
354
  throw new Error('no deleter for backup modes: ' + unsupportedModes.join(', '))
320
355
  }
321
-
322
- await Promise.all([
323
- delta !== undefined && this.deleteDeltaVmBackups(delta),
324
- full !== undefined && this.deleteFullVmBackups(full),
325
- ])
356
+ const promises = []
357
+ if (delta !== undefined) {
358
+ promises.push(this.deleteDeltaVmBackups(delta))
359
+ }
360
+ if (full !== undefined) {
361
+ promises.push(this.deleteFullVmBackups(full))
362
+ }
363
+ if (missingFiles.length) {
364
+ promises.push(this.#removeVmBackupsFromCache(missingFiles))
365
+ }
366
+ await Promise.all(promises)
326
367
 
327
368
  await asyncMap(new Set(files.map(file => dirname(file))), dir =>
328
369
  // - don't merge in main process, unused VHDs will be merged in the next backup run
@@ -229,13 +229,14 @@ export class IncrementalRemoteWriter extends MixinRemoteWriter(AbstractIncrement
229
229
  Object.entries(deltaExport.disks),
230
230
  async ([diskRef, disk]) => {
231
231
  const path = `${this._vmBackupDir}/${vhds[diskRef]}`
232
- size += await adapter.writeVhd(path, disk, {
232
+ const transferred = await adapter.writeVhd(path, disk, {
233
233
  // no checksum for VHDs, because they will be invalidated by
234
234
  // merges and chains
235
235
  checksum: false,
236
236
  validator: tmpPath => checkVhd(handler, tmpPath),
237
237
  writeBlockConcurrency: this._config.writeBlockConcurrency,
238
238
  })
239
+ size += transferred
239
240
  },
240
241
  {
241
242
  concurrency: settings.diskPerVmConcurrency,
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.73.1",
11
+ "version": "0.73.2",
12
12
  "engines": {
13
13
  "node": ">=14.18"
14
14
  },
@@ -30,14 +30,14 @@
30
30
  "@vates/nbd-client": "^3.4.0",
31
31
  "@vates/parse-duration": "^0.1.1",
32
32
  "@vates/task": "^0.7.0",
33
- "@vates/types": "^1.25.0",
33
+ "@vates/types": "^1.26.0",
34
34
  "@xen-orchestra/async-map": "^0.1.3",
35
35
  "@xen-orchestra/disk-transform": "^1.3.0",
36
36
  "@xen-orchestra/fs": "^4.9.0",
37
37
  "@xen-orchestra/log": "^0.7.2",
38
38
  "@xen-orchestra/qcow2": "^1.3.0",
39
39
  "@xen-orchestra/template": "^0.1.1",
40
- "@xen-orchestra/backup-archive": "^1.0.0",
40
+ "@xen-orchestra/backup-archive": "^1.0.1",
41
41
  "app-conf": "^3.0.0",
42
42
  "compare-versions": "^6.0.0",
43
43
  "d3-time-format": "^4.1.0",