@xen-orchestra/backups 0.61.0 → 0.61.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.
@@ -168,13 +168,13 @@ export class ImportVmBackup {
168
168
  vdis[vdiRef].baseVdi = snapshotCandidate
169
169
  } catch (error) {
170
170
  // can be a broken VHD chain, a vhd chain with a key backup, ....
171
- // not an irrecuperable error, don't dispose parentVhd, and fallback to full restore
171
+ // not an irrecuperable error, don't dispose parentVhd, and fall back to full restore
172
172
  warn(`can't use differential restore`, { error })
173
173
  descendant?.close()
174
174
  negativeDisk?.close()
175
175
  }
176
176
  }
177
- // didn't make a negative stream : fallback to classic stream
177
+ // didn't make a negative stream : fall back to classic stream
178
178
  if (disk === undefined) {
179
179
  debug('use legacy restore')
180
180
  disk = parent
package/RemoteAdapter.mjs CHANGED
@@ -205,7 +205,7 @@ export class RemoteAdapter {
205
205
  })
206
206
  }
207
207
 
208
- // check if we will be allowed to merge a a vhd created in this adapter
208
+ // check if we will be allowed to merge a vhd created in this adapter
209
209
  // with the vhd at path `path`
210
210
  async isMergeableParent(packedParentUid, path) {
211
211
  return await Disposable.use(VhdSynthetic.fromVhdChain(this.handler, path), vhd => {
@@ -776,7 +776,7 @@ export class RemoteAdapter {
776
776
  let json
777
777
  let isImmutable = false
778
778
  let remoteIsImmutable = false
779
- // if the remote is immutable, check if this metadatas are also immutables
779
+ // if the remote is immutable, check if this metadata is also immutable
780
780
  try {
781
781
  // this file is not encrypted
782
782
  await this._handler._readFile(IMMUTABILTY_METADATA_FILENAME)
@@ -792,7 +792,7 @@ export class RemoteAdapter {
792
792
  json = await this.handler.readFile(path, { flag: 'r+' })
793
793
  // s3 handler don't respect flags
794
794
  } catch (err) {
795
- // retry without triggerring immutbaility check ,only on immutable remote
795
+ // retry without triggering immutability check ,only on immutable remote
796
796
  if (err.code === 'EPERM' && remoteIsImmutable) {
797
797
  isImmutable = true
798
798
  json = await this._handler.readFile(path, { flag: 'r' })
@@ -24,7 +24,7 @@ export class RestoreMetadataBackup {
24
24
  const dataFileName = resolve('/', backupId, metadata.data ?? 'data.json').slice(1)
25
25
  const data = await handler.readFile(dataFileName)
26
26
 
27
- // if data is JSON, sent it as a plain string, otherwise, consider the data as binary and encode it
27
+ // if data is JSON, sent it as a plain string; otherwise, consider the data as binary and encode it
28
28
  const isJson = dataFileName.endsWith('.json')
29
29
  return isJson ? data.toString() : { encoding: 'base64', data: data.toString('base64') }
30
30
  }
package/_cleanVm.mjs CHANGED
@@ -512,7 +512,7 @@ export async function cleanVm(
512
512
  remove,
513
513
  mergeBlockConcurrency,
514
514
  })
515
- const metadataPath = vhdsToJSons[chain[chain.length - 1]] // all the chain should have the same metada file
515
+ const metadataPath = vhdsToJSons[chain[chain.length - 1]] // all the chain should have the same metadata file
516
516
  metadataWithMergedVhd[metadataPath] = (metadataWithMergedVhd[metadataPath] ?? 0) + finalVhdSize
517
517
  })
518
518
  }
@@ -26,7 +26,7 @@ const LTR_DEFINITIONS = {
26
26
 
27
27
  copy.date(date.date() - firstDayOfWeek)
28
28
  // warning, the year in term of week may different from YYYY
29
- // since the computation of the first week of a year is timezone dependant
29
+ // since the computation of the first week of a year is timezone dependent
30
30
  return copy.format('gggg-ww')
31
31
  }
32
32
  },
@@ -59,7 +59,7 @@ const LTR_DEFINITIONS = {
59
59
  * return the entries too old to be kept
60
60
  * if multiple entries are i the same time bucket : keep only the most recent one
61
61
  * if an entry is valid in any of the bucket OR the minRetentionCount : keep it
62
- * if a bucket is completly empty : it does not count as one, thus it may extend the retention
62
+ * if a bucket is completely empty : it does not count as one, thus it may extend the retention
63
63
  * @returns Array<Backup>
64
64
  */
65
65
  export function getOldEntries(minRetentionCount, entries, { longTermRetention = {}, timezone } = {}) {
@@ -231,7 +231,7 @@ export const importIncrementalVm = defer(async function importIncrementalVm(
231
231
  cancelableMap(cancelToken, Object.entries(newVdis), async (cancelToken, [id, vdi]) => {
232
232
  for (const disk of ensureArray(disks[id])) {
233
233
  if (disk === null) {
234
- // we restore a backup and reuse completly a local snapshot
234
+ // we restore a backup and reuse completely a local snapshot
235
235
  continue
236
236
  }
237
237
  await xapi.setField('VDI', vdi.$ref, 'name_label', `[Importing] ${vdiRecords[id].name_label}`)
package/_isValidXva.mjs CHANGED
@@ -44,7 +44,7 @@ const isValidTar = async (handler, size, fd) => {
44
44
  return buf.every(_ => _ === 0)
45
45
  }
46
46
 
47
- // TODO: find an heuristic for compressed files
47
+ // TODO: find a heuristic for compressed files
48
48
  export async function isValidXva(path) {
49
49
  const handler = this._handler
50
50
 
package/_otherConfig.mjs CHANGED
@@ -43,7 +43,7 @@ async function getDeltaChainLength(xapi, type, ref) {
43
43
  }
44
44
 
45
45
  /**
46
- * set the delta chain lenght ( number of delta since last base backup) to a VM and its associated VDIs
46
+ * set the delta chain length ( number of delta since last base backup) to a VM and its associated VDIs
47
47
  *
48
48
  * @param {Xapi} xapi
49
49
  * @param {String} vmRef
@@ -58,7 +58,7 @@ export async function setVmDeltaChainLength(xapi, vmRef, length) {
58
58
 
59
59
  /**
60
60
  * Compute the delta chain length of a VM and its associated VDIs
61
- * if there is a discrependcy, use, the highest value
61
+ * if there is a discrepancy, use, the highest value
62
62
  * @param {Xapi} xapi
63
63
  * @param {String} vmRef
64
64
  * @returns {Promise}
@@ -92,7 +92,7 @@ export function resetVmOtherConfig(xapi, vmRef) {
92
92
 
93
93
  /**
94
94
  *
95
- * used to ensure compatibiliy with the previous snapshots that were having the config stored only into VM
95
+ * used to ensure compatibility with the previous snapshots that were having the config stored only into VM
96
96
  *
97
97
  * @param {Xapi} xapi
98
98
  * @param {String} vmRef
@@ -152,7 +152,7 @@ export async function setVmOtherConfig(xapi, vmRef, { timestamp, jobId, schedule
152
152
  }
153
153
  /**
154
154
  *
155
- * mark the export of he VM and its VDIs as successfull
155
+ * mark the export of he VM and its VDIs as successful
156
156
  *
157
157
  * @param {Xapi} xapi
158
158
  * @param {String} vmRef
@@ -24,7 +24,7 @@ export const FullRemote = class FullRemoteVmBackupRunner extends AbstractRemote
24
24
  writer =>
25
25
  writer.run({
26
26
  stream: forkStreamUnpipe(stream),
27
- // stream will be forked and transformed, it's not safe to attach additionnal properties to it
27
+ // stream will be forked and transformed, it's not safe to attach additional properties to it
28
28
  streamLength: stream.length,
29
29
  maxStreamLength: stream.maxStreamLength, // on encrypted source
30
30
  timestamp: metadata.timestamp,
@@ -45,8 +45,8 @@ export const FullXapi = class FullXapiVmBackupRunner extends AbstractXapi {
45
45
  for (const vdiRef of vdis) {
46
46
  const vdi = await this._xapi.getRecord('VDI', vdiRef)
47
47
 
48
- // the size a of fully allocated vdi will be virtual_size exaclty, it's a gross over evaluation
49
- // of the real stream size in general, since a disk is never completly full
48
+ // the size a of fully allocated vdi will be virtual_size exactly, it's a gross over evaluation
49
+ // of the real stream size in general, since a disk is never completely full
50
50
  // vdi.physical_size seems to underevaluate a lot the real disk usage of a VDI, as of 2023-10-30
51
51
  maxStreamLength += vdi.virtual_size
52
52
  }
@@ -5,6 +5,7 @@ import assert from 'node:assert'
5
5
  import * as UUID from 'uuid'
6
6
 
7
7
  import { AbstractRemote } from './_AbstractRemote.mjs'
8
+ import { forkDeltaExport } from './_forkDeltaExport.mjs'
8
9
  import { IncrementalRemoteWriter } from '../_writers/IncrementalRemoteWriter.mjs'
9
10
  import { Disposable } from 'promise-toolbox'
10
11
  import { openVhd } from 'vhd-lib'
@@ -17,7 +18,7 @@ class IncrementalRemoteVmBackupRunner extends AbstractRemote {
17
18
  return IncrementalRemoteWriter
18
19
  }
19
20
 
20
- // we'll transfer the full list if at least one backup should be transfered
21
+ // we'll transfer the full list if at least one backup should be transferred
21
22
  // to ensure we don't cut the delta chain
22
23
  _filterTransferList(transferList) {
23
24
  if (transferList.some(vmBackupMetadata => this._filterPredicate(vmBackupMetadata))) {
@@ -88,18 +89,10 @@ class IncrementalRemoteVmBackupRunner extends AbstractRemote {
88
89
  await this._selectBaseVm(metadata)
89
90
  await this._callWriters(writer => writer.prepare({ isBase: metadata.isBase }), 'writer.prepare()')
90
91
 
91
- function fork(incrementalExport, label) {
92
- const { disks, ...forked } = incrementalExport
93
- forked.disks = {}
94
- for (const key in disks) {
95
- forked.disks[key] = disks[key].fork(label)
96
- }
97
- return forked
98
- }
99
92
  await this._callWriters(
100
93
  writer =>
101
94
  writer.transfer({
102
- deltaExport: fork(incrementalExport, writer.constructor.name + ' ' + Math.random()),
95
+ deltaExport: forkDeltaExport(incrementalExport, writer.constructor.name),
103
96
  isVhdDifferencing,
104
97
  timestamp: metadata.timestamp,
105
98
  vm: metadata.vm,
@@ -2,6 +2,7 @@ import { createLogger } from '@xen-orchestra/log'
2
2
  import keyBy from 'lodash/keyBy.js'
3
3
 
4
4
  import { AbstractXapi } from './_AbstractXapi.mjs'
5
+ import { forkDeltaExport } from './_forkDeltaExport.mjs'
5
6
  import { exportIncrementalVm } from '../../_incrementalVm.mjs'
6
7
  import { IncrementalRemoteWriter } from '../_writers/IncrementalRemoteWriter.mjs'
7
8
  import { IncrementalXapiWriter } from '../_writers/IncrementalXapiWriter.mjs'
@@ -50,21 +51,14 @@ export const IncrementalXapi = class IncrementalXapiVmBackupRunner extends Abstr
50
51
  if (useNbd) {
51
52
  Task.info('Transfer data using NBD')
52
53
  }
53
- function fork(deltaExport, label) {
54
- const { disks, ...forked } = deltaExport
55
- forked.disks = {}
56
- for (const key in disks) {
57
- forked.disks[key] = disks[key].fork(label)
58
- }
59
- return forked
60
- }
61
54
 
62
- // @todo : reimplement throttle,nbsource: d use
55
+ // @todo : reimplement throttle
56
+
63
57
  const timestamp = Date.now()
64
58
  await this._callWriters(
65
59
  writer =>
66
60
  writer.transfer({
67
- deltaExport: fork(deltaExport, writer.constructor.name + ' ' + Math.random()),
61
+ deltaExport: forkDeltaExport(deltaExport, writer.constructor.name),
68
62
  isVhdDifferencing,
69
63
  timestamp,
70
64
  vm,
@@ -90,7 +90,7 @@ export const AbstractRemote = class AbstractRemoteVmBackupRunner extends Abstrac
90
90
  for (const timestamp of timestamps) {
91
91
  if (remoteMetadatas[timestamp] !== nbRemotes) {
92
92
  // this backup is not present in all the remote
93
- // should be retransfered if not found later
93
+ // should be retransferred if not found later
94
94
  transferList.push(localMetada.get(timestamp))
95
95
  } else {
96
96
  // backup is present in local and remote : the chain has already been transferred
@@ -195,7 +195,7 @@ export const AbstractXapi = class AbstractXapiVmBackupRunner extends Abstract {
195
195
  }
196
196
  })
197
197
  await Promise.all(vmSnapshots.map(snapshot => populateVdisOtherConfig(xapi, snapshot.$ref)))
198
- // end of compatibiliy handling
198
+ // end of compatibility handling
199
199
 
200
200
  // handle snapshot by VDI
201
201
  this._jobSnapshotVdis = []
@@ -298,7 +298,7 @@ export const AbstractXapi = class AbstractXapiVmBackupRunner extends Abstract {
298
298
  // preferNbd is not a guarantee that the backup used NBD, depending on the network configuration,
299
299
  // in that case next runs will be full, but there is not an easy way to prevent that
300
300
  this._settings.preferNbd &&
301
- // only delete snapshost data if the config allows it
301
+ // only delete snapshot data if the config allows it
302
302
  this._settings.cbtDestroySnapshotData
303
303
  ) {
304
304
  Task.info('will delete snapshot data')
@@ -0,0 +1,16 @@
1
+ import { SynchronizedDisk } from '@xen-orchestra/disk-transform'
2
+ import cloneDeep from 'lodash/cloneDeep.js'
3
+
4
+ export function forkDeltaExport(deltaExport, label) {
5
+ label += ' ' + Math.random()
6
+ const { disks, ...rest } = deltaExport
7
+ const fork = cloneDeep(rest)
8
+ fork.disks = {}
9
+ for (const [key, disk] of Object.entries(disks)) {
10
+ if (!(disk instanceof SynchronizedDisk)) {
11
+ throw new Error('Can only fork synchronized disks ')
12
+ }
13
+ fork.disks[key] = disk.fork(label)
14
+ }
15
+ return fork
16
+ }
@@ -230,7 +230,7 @@ export class IncrementalRemoteWriter extends MixinRemoteWriter(AbstractIncrement
230
230
  const path = `${this._vmBackupDir}/${vhds[diskRef]}`
231
231
  await adapter.writeVhd(path, disk, {
232
232
  // no checksum for VHDs, because they will be invalidated by
233
- // merges and chainings
233
+ // merges and chains
234
234
  checksum: false,
235
235
  validator: tmpPath => checkVhd(handler, tmpPath),
236
236
  writeBlockConcurrency: this._config.writeBlockConcurrency,
@@ -21,7 +21,7 @@ export class IncrementalXapiWriter extends MixinXapiWriter(AbstractIncrementalWr
21
21
  }
22
22
 
23
23
  // @todo use an index if possible
24
- // @todo : this seems similare to decorateVmMetadata
24
+ // @todo : this seems similar to decorateVmMetadata
25
25
  const replicatedVdis = sr.$VDIs
26
26
  .filter(vdi => {
27
27
  // REPLICATED_TO_SR_UUID is not used here since we are already filtering from sr.$VDIs
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.61.0",
11
+ "version": "0.61.1",
12
12
  "engines": {
13
13
  "node": ">=14.18"
14
14
  },
@@ -25,7 +25,7 @@
25
25
  "@vates/decorate-with": "^2.1.0",
26
26
  "@vates/disposable": "^0.1.6",
27
27
  "@vates/fuse-vhd": "^2.1.2",
28
- "@vates/generator-toolbox": "^1.0.2",
28
+ "@vates/generator-toolbox": "^1.0.3",
29
29
  "@vates/nbd-client": "^3.1.3",
30
30
  "@vates/parse-duration": "^0.1.1",
31
31
  "@xen-orchestra/async-map": "^0.1.2",