@xen-orchestra/backups 0.39.0 → 0.41.0
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/{Backup.js → Backup.mjs} +4 -6
- package/{DurablePartition.js → DurablePartition.mjs} +2 -4
- package/{HealthCheckVmBackup.js → HealthCheckVmBackup.mjs} +2 -4
- package/{ImportVmBackup.js → ImportVmBackup.mjs} +6 -8
- package/{RemoteAdapter.js → RemoteAdapter.mjs} +69 -76
- package/RestoreMetadataBackup.mjs +32 -0
- package/{Task.js → Task.mjs} +3 -6
- package/_backupType.mjs +4 -0
- package/{_backupWorker.js → _backupWorker.mjs} +22 -22
- package/{_cancelableMap.js → _cancelableMap.mjs} +3 -5
- package/{_cleanVm.js → _cleanVm.mjs} +16 -19
- package/_filenameDate.mjs +6 -0
- package/{_getOldEntries.js → _getOldEntries.mjs} +1 -3
- package/{_getTmpDir.js → _getTmpDir.mjs} +5 -7
- package/_getVmBackupDir.mjs +5 -0
- package/{_incrementalVm.js → _incrementalVm.mjs} +21 -20
- package/{_isValidXva.js → _isValidXva.mjs} +2 -5
- package/{_listPartitions.js → _listPartitions.mjs} +6 -9
- package/{_lvm.js → _lvm.mjs} +5 -7
- package/_runners/{Metadata.js → Metadata.mjs} +10 -12
- package/_runners/{VmsRemote.js → VmsRemote.mjs} +12 -14
- package/_runners/{VmsXapi.js → VmsXapi.mjs} +13 -15
- package/_runners/{_Abstract.js → _Abstract.mjs} +7 -9
- package/_runners/{_PoolMetadataBackup.js → _PoolMetadataBackup.mjs} +7 -10
- package/_runners/{_RemoteTimeoutError.js → _RemoteTimeoutError.mjs} +1 -3
- package/_runners/{_XoMetadataBackup.js → _XoMetadataBackup.mjs} +14 -10
- package/_runners/{_createStreamThrottle.js → _createStreamThrottle.mjs} +4 -6
- package/_runners/{_forkStreamUnpipe.js → _forkStreamUnpipe.mjs} +4 -5
- package/_runners/{_getAdaptersByRemote.js → _getAdaptersByRemote.mjs} +1 -3
- package/_runners/_runTask.mjs +5 -0
- package/_runners/_vmRunners/{FullRemote.js → FullRemote.mjs} +9 -12
- package/_runners/_vmRunners/{FullXapi.js → FullXapi.mjs} +7 -9
- package/_runners/_vmRunners/{IncrementalRemote.js → IncrementalRemote.mjs} +11 -12
- package/_runners/_vmRunners/{IncrementalXapi.js → IncrementalXapi.mjs} +18 -20
- package/_runners/_vmRunners/{_Abstract.js → _Abstract.mjs} +4 -6
- package/_runners/_vmRunners/{_AbstractRemote.js → _AbstractRemote.mjs} +6 -6
- package/_runners/_vmRunners/{_AbstractXapi.js → _AbstractXapi.mjs} +14 -17
- package/_runners/_vmRunners/_forkDeltaExport.mjs +11 -0
- package/_runners/_writers/{FullRemoteWriter.js → FullRemoteWriter.mjs} +6 -8
- package/_runners/_writers/{FullXapiWriter.js → FullXapiWriter.mjs} +10 -12
- package/_runners/_writers/{IncrementalRemoteWriter.js → IncrementalRemoteWriter.mjs} +22 -24
- package/_runners/_writers/{IncrementalXapiWriter.js → IncrementalXapiWriter.mjs} +11 -13
- package/_runners/_writers/{_AbstractFullWriter.js → _AbstractFullWriter.mjs} +2 -4
- package/_runners/_writers/{_AbstractIncrementalWriter.js → _AbstractIncrementalWriter.mjs} +2 -4
- package/_runners/_writers/{_AbstractWriter.js → _AbstractWriter.mjs} +3 -5
- package/_runners/_writers/{_MixinRemoteWriter.js → _MixinRemoteWriter.mjs} +10 -12
- package/_runners/_writers/{_MixinXapiWriter.js → _MixinXapiWriter.mjs} +6 -8
- package/_runners/_writers/_checkVhd.mjs +6 -0
- package/_runners/_writers/{_listReplicatedVms.js → _listReplicatedVms.mjs} +1 -3
- package/_runners/_writers/{_packUuid.js → _packUuid.mjs} +1 -3
- package/{_watchStreamSize.js → _watchStreamSize.mjs} +1 -3
- package/{extractIdsFromSimplePattern.js → extractIdsFromSimplePattern.mjs} +1 -3
- package/{formatVmBackups.js → formatVmBackups.mjs} +3 -5
- package/merge-worker/cli.mjs +103 -0
- package/merge-worker/config.toml +1 -0
- package/merge-worker/{index.js → index.mjs} +6 -7
- package/package.json +12 -9
- package/{parseMetadataBackupId.js → parseMetadataBackupId.mjs} +2 -4
- package/{runBackupWorker.js → runBackupWorker.mjs} +4 -7
- package/RestoreMetadataBackup.js +0 -29
- package/_backupType.js +0 -6
- package/_filenameDate.js +0 -8
- package/_getVmBackupDir.js +0 -8
- package/_runners/_runTask.js +0 -6
- package/_runners/_vmRunners/_forkDeltaExport.js +0 -12
- package/_runners/_writers/_checkVhd.js +0 -8
- package/merge-worker/cli.js +0 -92
|
@@ -1,29 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const { packUuid } = require('./_packUuid.js')
|
|
22
|
-
const { Disposable } = require('promise-toolbox')
|
|
1
|
+
import assert from 'node:assert'
|
|
2
|
+
import mapValues from 'lodash/mapValues.js'
|
|
3
|
+
import ignoreErrors from 'promise-toolbox/ignoreErrors'
|
|
4
|
+
import { asyncEach } from '@vates/async-each'
|
|
5
|
+
import { asyncMap } from '@xen-orchestra/async-map'
|
|
6
|
+
import { chainVhd, checkVhdChain, openVhd, VhdAbstract } from 'vhd-lib'
|
|
7
|
+
import { createLogger } from '@xen-orchestra/log'
|
|
8
|
+
import { decorateClass } from '@vates/decorate-with'
|
|
9
|
+
import { defer } from 'golike-defer'
|
|
10
|
+
import { dirname } from 'node:path'
|
|
11
|
+
|
|
12
|
+
import { formatFilenameDate } from '../../_filenameDate.mjs'
|
|
13
|
+
import { getOldEntries } from '../../_getOldEntries.mjs'
|
|
14
|
+
import { Task } from '../../Task.mjs'
|
|
15
|
+
|
|
16
|
+
import { MixinRemoteWriter } from './_MixinRemoteWriter.mjs'
|
|
17
|
+
import { AbstractIncrementalWriter } from './_AbstractIncrementalWriter.mjs'
|
|
18
|
+
import { checkVhd } from './_checkVhd.mjs'
|
|
19
|
+
import { packUuid } from './_packUuid.mjs'
|
|
20
|
+
import { Disposable } from 'promise-toolbox'
|
|
23
21
|
|
|
24
22
|
const { warn } = createLogger('xo:backups:DeltaBackupWriter')
|
|
25
23
|
|
|
26
|
-
class IncrementalRemoteWriter extends MixinRemoteWriter(AbstractIncrementalWriter) {
|
|
24
|
+
export class IncrementalRemoteWriter extends MixinRemoteWriter(AbstractIncrementalWriter) {
|
|
27
25
|
async checkBaseVdis(baseUuidToSrcVdi) {
|
|
28
26
|
const { handler } = this._adapter
|
|
29
27
|
const adapter = this._adapter
|
|
@@ -238,6 +236,6 @@ class IncrementalRemoteWriter extends MixinRemoteWriter(AbstractIncrementalWrite
|
|
|
238
236
|
// TODO: run cleanup?
|
|
239
237
|
}
|
|
240
238
|
}
|
|
241
|
-
|
|
239
|
+
decorateClass(IncrementalRemoteWriter, {
|
|
242
240
|
_transfer: defer,
|
|
243
241
|
})
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import { asyncMap, asyncMapSettled } from '@xen-orchestra/async-map'
|
|
2
|
+
import ignoreErrors from 'promise-toolbox/ignoreErrors'
|
|
3
|
+
import { formatDateTime } from '@xen-orchestra/xapi'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
import { formatFilenameDate } from '../../_filenameDate.mjs'
|
|
6
|
+
import { getOldEntries } from '../../_getOldEntries.mjs'
|
|
7
|
+
import { importIncrementalVm, TAG_COPY_SRC } from '../../_incrementalVm.mjs'
|
|
8
|
+
import { Task } from '../../Task.mjs'
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const { Task } = require('../../Task.js')
|
|
10
|
+
import { AbstractIncrementalWriter } from './_AbstractIncrementalWriter.mjs'
|
|
11
|
+
import { MixinXapiWriter } from './_MixinXapiWriter.mjs'
|
|
12
|
+
import { listReplicatedVms } from './_listReplicatedVms.mjs'
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
const { MixinXapiWriter } = require('./_MixinXapiWriter.js')
|
|
14
|
-
const { listReplicatedVms } = require('./_listReplicatedVms.js')
|
|
15
|
-
|
|
16
|
-
exports.IncrementalXapiWriter = class IncrementalXapiWriter extends MixinXapiWriter(AbstractIncrementalWriter) {
|
|
14
|
+
export class IncrementalXapiWriter extends MixinXapiWriter(AbstractIncrementalWriter) {
|
|
17
15
|
async checkBaseVdis(baseUuidToSrcVdi, baseVm) {
|
|
18
16
|
const sr = this._sr
|
|
19
17
|
const replicatedVm = listReplicatedVms(sr.$xapi, this._job.id, sr.uuid, this._vmUuid).find(
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { AbstractWriter } from './_AbstractWriter.mjs'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.AbstractFullWriter = class AbstractFullWriter extends AbstractWriter {
|
|
3
|
+
export class AbstractFullWriter extends AbstractWriter {
|
|
6
4
|
async run({ timestamp, sizeContainer, stream, vm, vmSnapshot }) {
|
|
7
5
|
try {
|
|
8
6
|
return await this._run({ timestamp, sizeContainer, stream, vm, vmSnapshot })
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { AbstractWriter } from './_AbstractWriter.mjs'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.AbstractIncrementalWriter = class AbstractIncrementalWriter extends AbstractWriter {
|
|
3
|
+
export class AbstractIncrementalWriter extends AbstractWriter {
|
|
6
4
|
checkBaseVdis(baseUuidToSrcVdi, baseVm) {
|
|
7
5
|
throw new Error('Not implemented')
|
|
8
6
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { formatFilenameDate } from '../../_filenameDate.mjs'
|
|
2
|
+
import { getVmBackupDir } from '../../_getVmBackupDir.mjs'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const { getVmBackupDir } = require('../../_getVmBackupDir')
|
|
5
|
-
|
|
6
|
-
exports.AbstractWriter = class AbstractWriter {
|
|
4
|
+
export class AbstractWriter {
|
|
7
5
|
constructor({ config, healthCheckSr, job, vmUuid, scheduleId, settings }) {
|
|
8
6
|
this._config = config
|
|
9
7
|
this._healthCheckSr = healthCheckSr
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import { createLogger } from '@xen-orchestra/log'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import assert from 'node:assert'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const { HealthCheckVmBackup } = require('../../HealthCheckVmBackup.js')
|
|
10
|
-
const { ImportVmBackup } = require('../../ImportVmBackup.js')
|
|
11
|
-
const { Task } = require('../../Task.js')
|
|
12
|
-
const MergeWorker = require('../../merge-worker/index.js')
|
|
5
|
+
import { formatFilenameDate } from '../../_filenameDate.mjs'
|
|
6
|
+
import { getVmBackupDir } from '../../_getVmBackupDir.mjs'
|
|
7
|
+
import { HealthCheckVmBackup } from '../../HealthCheckVmBackup.mjs'
|
|
8
|
+
import { ImportVmBackup } from '../../ImportVmBackup.mjs'
|
|
9
|
+
import { Task } from '../../Task.mjs'
|
|
10
|
+
import * as MergeWorker from '../../merge-worker/index.mjs'
|
|
13
11
|
|
|
14
12
|
const { info, warn } = createLogger('xo:backups:MixinBackupWriter')
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
export const MixinRemoteWriter = (BaseClass = Object) =>
|
|
17
15
|
class MixinRemoteWriter extends BaseClass {
|
|
18
16
|
#lock
|
|
19
17
|
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { extractOpaqueRef } from '@xen-orchestra/xapi'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
import { HealthCheckVmBackup } from '../../HealthCheckVmBackup.mjs'
|
|
5
|
+
import { Task } from '../../Task.mjs'
|
|
4
6
|
|
|
5
|
-
const
|
|
6
|
-
const assert = require('node:assert/strict')
|
|
7
|
-
const { HealthCheckVmBackup } = require('../../HealthCheckVmBackup')
|
|
8
|
-
|
|
9
|
-
exports.MixinXapiWriter = (BaseClass = Object) =>
|
|
7
|
+
export const MixinXapiWriter = (BaseClass = Object) =>
|
|
10
8
|
class MixinXapiWriter extends BaseClass {
|
|
11
9
|
constructor({ sr, ...rest }) {
|
|
12
10
|
super(rest)
|
|
@@ -20,7 +18,7 @@ exports.MixinXapiWriter = (BaseClass = Object) =>
|
|
|
20
18
|
const vdiRefs = await xapi.VM_getDisks(baseVm.$ref)
|
|
21
19
|
for (const vdiRef of vdiRefs) {
|
|
22
20
|
const vdi = xapi.getObject(vdiRef)
|
|
23
|
-
if (vdi.$SR.uuid !== this.
|
|
21
|
+
if (vdi.$SR.uuid !== this._healthCheckSr.uuid) {
|
|
24
22
|
return false
|
|
25
23
|
}
|
|
26
24
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
1
|
const getReplicatedVmDatetime = vm => {
|
|
4
2
|
const { 'xo:backup:datetime': datetime = vm.name_label.slice(-17, -1) } = vm.other_config
|
|
5
3
|
return datetime
|
|
@@ -7,7 +5,7 @@ const getReplicatedVmDatetime = vm => {
|
|
|
7
5
|
|
|
8
6
|
const compareReplicatedVmDatetime = (a, b) => (getReplicatedVmDatetime(a) < getReplicatedVmDatetime(b) ? -1 : 1)
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
export function listReplicatedVms(xapi, scheduleOrJobId, srUuid, vmUuid) {
|
|
11
9
|
const { all } = xapi.objects
|
|
12
10
|
const vms = {}
|
|
13
11
|
for (const key in all) {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const mapValues = require('lodash/mapValues.js')
|
|
4
|
-
const { dirname } = require('path')
|
|
1
|
+
import mapValues from 'lodash/mapValues.js'
|
|
2
|
+
import { dirname } from 'node:path'
|
|
5
3
|
|
|
6
4
|
function formatVmBackup(backup) {
|
|
7
5
|
return {
|
|
@@ -31,6 +29,6 @@ function formatVmBackup(backup) {
|
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
// format all backups as returned by RemoteAdapter#listAllVmBackups()
|
|
34
|
-
|
|
32
|
+
export function formatVmBackups(backupsByVM) {
|
|
35
33
|
return mapValues(backupsByVM, backups => backups.map(formatVmBackup))
|
|
36
34
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// eslint-disable-next-line eslint-comments/disable-enable-pair
|
|
3
|
+
/* eslint-disable n/shebang */
|
|
4
|
+
|
|
5
|
+
import { asyncEach } from '@vates/async-each'
|
|
6
|
+
import { catchGlobalErrors } from '@xen-orchestra/log/configure'
|
|
7
|
+
import { createLogger } from '@xen-orchestra/log'
|
|
8
|
+
import { getSyncedHandler } from '@xen-orchestra/fs'
|
|
9
|
+
import { join } from 'node:path'
|
|
10
|
+
import { load as loadConfig } from 'app-conf'
|
|
11
|
+
import Disposable from 'promise-toolbox/Disposable'
|
|
12
|
+
|
|
13
|
+
import { getVmBackupDir } from '../_getVmBackupDir.mjs'
|
|
14
|
+
import { RemoteAdapter } from '../RemoteAdapter.mjs'
|
|
15
|
+
|
|
16
|
+
import { CLEAN_VM_QUEUE } from './index.mjs'
|
|
17
|
+
|
|
18
|
+
const APP_NAME = 'xo-merge-worker'
|
|
19
|
+
const APP_DIR = new URL('.', import.meta.url).pathname
|
|
20
|
+
// -------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
catchGlobalErrors(createLogger('xo:backups:mergeWorker'))
|
|
23
|
+
|
|
24
|
+
const { fatal, info, warn } = createLogger('xo:backups:mergeWorker')
|
|
25
|
+
|
|
26
|
+
// -------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
const main = Disposable.wrap(async function* main(args) {
|
|
29
|
+
const handler = yield getSyncedHandler({ url: 'file://' + process.cwd() })
|
|
30
|
+
|
|
31
|
+
yield handler.lock(CLEAN_VM_QUEUE)
|
|
32
|
+
|
|
33
|
+
const adapter = new RemoteAdapter(handler)
|
|
34
|
+
|
|
35
|
+
const listRetry = async () => {
|
|
36
|
+
const timeoutResolver = resolve => setTimeout(resolve, 10e3)
|
|
37
|
+
for (let i = 0; i < 10; ++i) {
|
|
38
|
+
const entries = await handler.list(CLEAN_VM_QUEUE)
|
|
39
|
+
if (entries.length !== 0) {
|
|
40
|
+
entries.sort()
|
|
41
|
+
return entries
|
|
42
|
+
}
|
|
43
|
+
await new Promise(timeoutResolver)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let taskFiles
|
|
48
|
+
while ((taskFiles = await listRetry()) !== undefined) {
|
|
49
|
+
const { concurrency } = await loadConfig(APP_NAME, {
|
|
50
|
+
appDir: APP_DIR,
|
|
51
|
+
ignoreUnknownFormats: true,
|
|
52
|
+
})
|
|
53
|
+
await asyncEach(
|
|
54
|
+
taskFiles,
|
|
55
|
+
async taskFileBasename => {
|
|
56
|
+
const previousTaskFile = join(CLEAN_VM_QUEUE, taskFileBasename)
|
|
57
|
+
const taskFile = join(CLEAN_VM_QUEUE, '_' + taskFileBasename)
|
|
58
|
+
|
|
59
|
+
// move this task to the end
|
|
60
|
+
try {
|
|
61
|
+
await handler.rename(previousTaskFile, taskFile)
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// this error occurs if the task failed too many times (i.e. too many `_` prefixes)
|
|
64
|
+
// there is nothing more that can be done
|
|
65
|
+
if (error.code === 'ENAMETOOLONG') {
|
|
66
|
+
await handler.unlink(previousTaskFile)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
throw error
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const vmDir = getVmBackupDir(String(await handler.readFile(taskFile)))
|
|
74
|
+
try {
|
|
75
|
+
await adapter.cleanVm(vmDir, { merge: true, logInfo: info, logWarn: warn, remove: true })
|
|
76
|
+
} catch (error) {
|
|
77
|
+
// consider the clean successful if the VM dir is missing
|
|
78
|
+
if (error.code !== 'ENOENT') {
|
|
79
|
+
throw error
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
handler.unlink(taskFile).catch(error => warn('deleting task failure', { error }))
|
|
84
|
+
} catch (error) {
|
|
85
|
+
warn('failure handling task', { error })
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{ concurrency }
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
info('starting')
|
|
94
|
+
main(process.argv.slice(2)).then(
|
|
95
|
+
() => {
|
|
96
|
+
info('bye :-)')
|
|
97
|
+
},
|
|
98
|
+
error => {
|
|
99
|
+
fatal(error)
|
|
100
|
+
|
|
101
|
+
process.exit(1)
|
|
102
|
+
}
|
|
103
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
concurrency = 1
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { spawn } from 'child_process'
|
|
3
|
+
import { check } from 'proper-lockfile'
|
|
2
4
|
|
|
3
|
-
const
|
|
4
|
-
const { spawn } = require('child_process')
|
|
5
|
-
const { check } = require('proper-lockfile')
|
|
5
|
+
export const CLEAN_VM_QUEUE = '/xo-vm-backups/.queue/clean-vm/'
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const CLI_PATH = new URL('cli.mjs', import.meta.url).pathname
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
exports.run = async function runMergeWorker(remotePath) {
|
|
9
|
+
export const run = async function runMergeWorker(remotePath) {
|
|
11
10
|
try {
|
|
12
11
|
// TODO: find a way to pass the acquire the lock and then pass it down the worker
|
|
13
12
|
if (await check(join(remotePath, CLEAN_VM_QUEUE))) {
|
package/package.json
CHANGED
|
@@ -8,32 +8,33 @@
|
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
|
10
10
|
},
|
|
11
|
-
"version": "0.
|
|
11
|
+
"version": "0.41.0",
|
|
12
12
|
"engines": {
|
|
13
13
|
"node": ">=14.18"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"postversion": "npm publish --access public",
|
|
17
|
-
"test-integration": "node--test *.integ.
|
|
17
|
+
"test-integration": "node--test *.integ.mjs"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
+
"@iarna/toml": "^2.2.5",
|
|
20
21
|
"@kldzj/stream-throttle": "^1.1.1",
|
|
21
22
|
"@vates/async-each": "^1.0.0",
|
|
22
23
|
"@vates/cached-dns.lookup": "^1.0.0",
|
|
23
24
|
"@vates/compose": "^2.1.0",
|
|
24
25
|
"@vates/decorate-with": "^2.0.0",
|
|
25
26
|
"@vates/disposable": "^0.1.4",
|
|
26
|
-
"@vates/fuse-vhd": "^
|
|
27
|
-
"@vates/nbd-client": "^
|
|
27
|
+
"@vates/fuse-vhd": "^2.0.0",
|
|
28
|
+
"@vates/nbd-client": "^2.0.0",
|
|
28
29
|
"@vates/parse-duration": "^0.1.1",
|
|
29
30
|
"@xen-orchestra/async-map": "^0.1.2",
|
|
30
31
|
"@xen-orchestra/fs": "^4.0.1",
|
|
31
32
|
"@xen-orchestra/log": "^0.6.0",
|
|
32
33
|
"@xen-orchestra/template": "^0.1.0",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
34
|
+
"app-conf": "^2.3.0",
|
|
35
|
+
"compare-versions": "^6.0.0",
|
|
36
|
+
"d3-time-format": "^4.1.0",
|
|
35
37
|
"decorator-synchronized": "^0.6.0",
|
|
36
|
-
"fs-extra": "^11.1.0",
|
|
37
38
|
"golike-defer": "^0.5.1",
|
|
38
39
|
"limit-concurrency-decorator": "^0.5.0",
|
|
39
40
|
"lodash": "^4.17.20",
|
|
@@ -41,19 +42,21 @@
|
|
|
41
42
|
"parse-pairs": "^2.0.0",
|
|
42
43
|
"promise-toolbox": "^0.21.0",
|
|
43
44
|
"proper-lockfile": "^4.1.2",
|
|
45
|
+
"tar": "^6.1.15",
|
|
44
46
|
"uuid": "^9.0.0",
|
|
45
47
|
"vhd-lib": "^4.5.0",
|
|
46
|
-
"xen-api": "^1.3.
|
|
48
|
+
"xen-api": "^1.3.5",
|
|
47
49
|
"yazl": "^2.5.1"
|
|
48
50
|
},
|
|
49
51
|
"devDependencies": {
|
|
52
|
+
"fs-extra": "^11.1.0",
|
|
50
53
|
"rimraf": "^5.0.1",
|
|
51
54
|
"sinon": "^15.0.1",
|
|
52
55
|
"test": "^3.2.1",
|
|
53
56
|
"tmp": "^0.2.1"
|
|
54
57
|
},
|
|
55
58
|
"peerDependencies": {
|
|
56
|
-
"@xen-orchestra/xapi": "^
|
|
59
|
+
"@xen-orchestra/xapi": "^3.0.1"
|
|
57
60
|
},
|
|
58
61
|
"license": "AGPL-3.0-or-later",
|
|
59
62
|
"author": {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { DIR_XO_CONFIG_BACKUPS, DIR_XO_POOL_METADATA_BACKUPS } from './RemoteAdapter.mjs'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.parseMetadataBackupId = function parseMetadataBackupId(backupId) {
|
|
3
|
+
export function parseMetadataBackupId(backupId) {
|
|
6
4
|
const [dir, ...rest] = backupId.split('/')
|
|
7
5
|
if (dir === DIR_XO_CONFIG_BACKUPS) {
|
|
8
6
|
const [scheduleId, timestamp] = rest
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const { createLogger } = require('@xen-orchestra/log')
|
|
5
|
-
const { fork } = require('child_process')
|
|
1
|
+
import { createLogger } from '@xen-orchestra/log'
|
|
2
|
+
import { fork } from 'child_process'
|
|
6
3
|
|
|
7
4
|
const { warn } = createLogger('xo:backups:backupWorker')
|
|
8
5
|
|
|
9
|
-
const PATH =
|
|
6
|
+
const PATH = new URL('_backupWorker.mjs', import.meta.url).pathname
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
export function runBackupWorker(params, onLog) {
|
|
12
9
|
return new Promise((resolve, reject) => {
|
|
13
10
|
const worker = fork(PATH)
|
|
14
11
|
|
package/RestoreMetadataBackup.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { join, resolve } = require('node:path/posix')
|
|
4
|
-
|
|
5
|
-
const { DIR_XO_POOL_METADATA_BACKUPS } = require('./RemoteAdapter.js')
|
|
6
|
-
const { PATH_DB_DUMP } = require('./_runners/_PoolMetadataBackup.js')
|
|
7
|
-
|
|
8
|
-
exports.RestoreMetadataBackup = class RestoreMetadataBackup {
|
|
9
|
-
constructor({ backupId, handler, xapi }) {
|
|
10
|
-
this._backupId = backupId
|
|
11
|
-
this._handler = handler
|
|
12
|
-
this._xapi = xapi
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async run() {
|
|
16
|
-
const backupId = this._backupId
|
|
17
|
-
const handler = this._handler
|
|
18
|
-
const xapi = this._xapi
|
|
19
|
-
|
|
20
|
-
if (backupId.split('/')[0] === DIR_XO_POOL_METADATA_BACKUPS) {
|
|
21
|
-
return xapi.putResource(await handler.createReadStream(`${backupId}/data`), PATH_DB_DUMP, {
|
|
22
|
-
task: xapi.task_create('Import pool metadata'),
|
|
23
|
-
})
|
|
24
|
-
} else {
|
|
25
|
-
const metadata = JSON.parse(await handler.readFile(join(backupId, 'metadata.json')))
|
|
26
|
-
return String(await handler.readFile(resolve(backupId, metadata.data ?? 'data.json')))
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
package/_backupType.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
exports.isMetadataFile = filename => filename.endsWith('.json')
|
|
4
|
-
exports.isVhdFile = filename => filename.endsWith('.vhd')
|
|
5
|
-
exports.isXvaFile = filename => filename.endsWith('.xva')
|
|
6
|
-
exports.isXvaSumFile = filename => filename.endsWith('.xva.checksum')
|
package/_filenameDate.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { utcFormat, utcParse } = require('d3-time-format')
|
|
4
|
-
|
|
5
|
-
// Format a date in ISO 8601 in a safe way to be used in filenames
|
|
6
|
-
// (even on Windows).
|
|
7
|
-
exports.formatFilenameDate = utcFormat('%Y%m%dT%H%M%SZ')
|
|
8
|
-
exports.parseFilenameDate = utcParse('%Y%m%dT%H%M%SZ')
|
package/_getVmBackupDir.js
DELETED
package/_runners/_runTask.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { mapValues } = require('lodash')
|
|
4
|
-
const { forkStreamUnpipe } = require('../_forkStreamUnpipe')
|
|
5
|
-
|
|
6
|
-
exports.forkDeltaExport = function forkDeltaExport(deltaExport) {
|
|
7
|
-
return Object.create(deltaExport, {
|
|
8
|
-
streams: {
|
|
9
|
-
value: mapValues(deltaExport.streams, forkStreamUnpipe),
|
|
10
|
-
},
|
|
11
|
-
})
|
|
12
|
-
}
|