@xen-orchestra/backups 0.54.1 → 0.54.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/ImportVmBackup.mjs +6 -1
- package/RemoteAdapter.mjs +15 -0
- package/_getTmpDir.mjs +8 -1
- package/package.json +5 -6
package/ImportVmBackup.mjs
CHANGED
|
@@ -79,8 +79,13 @@ export class ImportVmBackup {
|
|
|
79
79
|
debug('found disks, wlll search its snapshots', { snapshots: xapiDisk.snapshots })
|
|
80
80
|
for (const snapshotRef of xapiDisk.snapshots) {
|
|
81
81
|
const snapshot = await this._xapi.getRecord('VDI', snapshotRef)
|
|
82
|
-
debug('handling snapshot', { snapshot })
|
|
83
82
|
|
|
83
|
+
debug('handling snapshot', { snapshot })
|
|
84
|
+
if (snapshot.type === 'cbt_metadata') {
|
|
85
|
+
// disk without data can't be used as a base
|
|
86
|
+
debug('cbt metadata snapshot, skip')
|
|
87
|
+
continue
|
|
88
|
+
}
|
|
84
89
|
// take only the first snapshot
|
|
85
90
|
if (snapshotCandidate && snapshotCandidate.snapshot_time < snapshot.snapshot_time) {
|
|
86
91
|
debug('already got a better candidate')
|
package/RemoteAdapter.mjs
CHANGED
|
@@ -107,10 +107,13 @@ export class RemoteAdapter {
|
|
|
107
107
|
async *_getLvmLogicalVolumes(devicePath, pvId, vgName) {
|
|
108
108
|
yield this._getLvmPhysicalVolume(devicePath, pvId && (await this._findPartition(devicePath, pvId)))
|
|
109
109
|
|
|
110
|
+
debug('activate LVM volume group', { vgName })
|
|
110
111
|
await fromCallback(execFile, 'vgchange', ['-ay', vgName])
|
|
111
112
|
try {
|
|
113
|
+
debug('get LVM volume group name and path', { vgName })
|
|
112
114
|
yield lvs(['lv_name', 'lv_path'], vgName)
|
|
113
115
|
} finally {
|
|
116
|
+
debug('deactivate LVM volume group', { vgName })
|
|
114
117
|
await fromCallback(execFile, 'vgchange', ['-an', vgName])
|
|
115
118
|
}
|
|
116
119
|
}
|
|
@@ -121,15 +124,22 @@ export class RemoteAdapter {
|
|
|
121
124
|
args.push('-o', partition.start * 512, '--sizelimit', partition.size)
|
|
122
125
|
}
|
|
123
126
|
args.push('--show', '-f', devicePath)
|
|
127
|
+
|
|
128
|
+
debug('attach loop device', { devicePath, partition })
|
|
124
129
|
const path = (await fromCallback(execFile, 'losetup', args)).trim()
|
|
125
130
|
try {
|
|
131
|
+
debug('list LVM physical volume', { path })
|
|
126
132
|
await fromCallback(execFile, 'pvscan', ['--cache', path])
|
|
133
|
+
|
|
127
134
|
yield path
|
|
128
135
|
} finally {
|
|
129
136
|
try {
|
|
130
137
|
const vgNames = await pvs('vg_name', path)
|
|
138
|
+
|
|
139
|
+
debug('deactivate LVM volume groups', { vgNames })
|
|
131
140
|
await fromCallback(execFile, 'vgchange', ['-an', ...vgNames])
|
|
132
141
|
} finally {
|
|
142
|
+
debug('detach loop device', { path })
|
|
133
143
|
await fromCallback(execFile, 'losetup', ['-d', path])
|
|
134
144
|
}
|
|
135
145
|
}
|
|
@@ -150,6 +160,7 @@ export class RemoteAdapter {
|
|
|
150
160
|
|
|
151
161
|
const path = yield getTmpDir()
|
|
152
162
|
const mount = options => {
|
|
163
|
+
debug('mount device', { devicePath, mountPath: path })
|
|
153
164
|
return fromCallback(execFile, 'mount', [
|
|
154
165
|
`--options=${options.join(',')}`,
|
|
155
166
|
`--source=${devicePath}`,
|
|
@@ -167,6 +178,7 @@ export class RemoteAdapter {
|
|
|
167
178
|
try {
|
|
168
179
|
yield path
|
|
169
180
|
} finally {
|
|
181
|
+
debug('umount device', { devicePath, mountPath: path })
|
|
170
182
|
await fromCallback(execFile, 'umount', ['--lazy', path])
|
|
171
183
|
}
|
|
172
184
|
}
|
|
@@ -336,6 +348,8 @@ export class RemoteAdapter {
|
|
|
336
348
|
|
|
337
349
|
const diskPath = handler.getFilePath('/' + diskId)
|
|
338
350
|
const mountDir = yield getTmpDir()
|
|
351
|
+
|
|
352
|
+
debug('mount VHD (vhdimount)', { diskPath, mountPath: mountDir })
|
|
339
353
|
await fromCallback(execFile, 'vhdimount', [diskPath, mountDir])
|
|
340
354
|
try {
|
|
341
355
|
let max = 0
|
|
@@ -357,6 +371,7 @@ export class RemoteAdapter {
|
|
|
357
371
|
|
|
358
372
|
yield `${mountDir}/${maxEntry}`
|
|
359
373
|
} finally {
|
|
374
|
+
debug('umount VHD (fusermount)', { diskPath, mountPath: mountDir })
|
|
360
375
|
await fromCallback(execFile, 'fusermount', ['-uz', mountDir])
|
|
361
376
|
}
|
|
362
377
|
}
|
package/_getTmpDir.mjs
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import Disposable from 'promise-toolbox/Disposable'
|
|
2
|
+
import { createLogger } from '@xen-orchestra/log'
|
|
2
3
|
import { join } from 'node:path'
|
|
3
4
|
import { mkdir, rmdir } from 'node:fs/promises'
|
|
4
5
|
import { tmpdir } from 'os'
|
|
5
6
|
|
|
7
|
+
const { debug } = createLogger('xo:backups:getTmpDir')
|
|
8
|
+
|
|
6
9
|
const MAX_ATTEMPTS = 3
|
|
7
10
|
|
|
8
11
|
export async function getTmpDir() {
|
|
9
12
|
for (let i = 0; true; ++i) {
|
|
10
13
|
const path = join(tmpdir(), Math.random().toString(36).slice(2))
|
|
11
14
|
try {
|
|
15
|
+
debug('creating directory', { path })
|
|
12
16
|
await mkdir(path)
|
|
13
|
-
return new Disposable(() =>
|
|
17
|
+
return new Disposable(() => {
|
|
18
|
+
debug('removing directory', { path })
|
|
19
|
+
return rmdir(path)
|
|
20
|
+
}, path)
|
|
14
21
|
} catch (error) {
|
|
15
22
|
if (i === MAX_ATTEMPTS) {
|
|
16
23
|
throw error
|
package/package.json
CHANGED
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/vatesfr/xen-orchestra.git"
|
|
10
10
|
},
|
|
11
|
-
"version": "0.54.
|
|
11
|
+
"version": "0.54.2",
|
|
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.mjs"
|
|
17
|
+
"test-integration": "node --test *.integ.mjs"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@iarna/toml": "^2.2.5",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@vates/nbd-client": "^3.1.1",
|
|
29
29
|
"@vates/parse-duration": "^0.1.1",
|
|
30
30
|
"@xen-orchestra/async-map": "^0.1.2",
|
|
31
|
-
"@xen-orchestra/fs": "^4.2.
|
|
31
|
+
"@xen-orchestra/fs": "^4.2.1",
|
|
32
32
|
"@xen-orchestra/log": "^0.7.0",
|
|
33
33
|
"@xen-orchestra/template": "^0.1.0",
|
|
34
34
|
"app-conf": "^3.0.0",
|
|
@@ -48,18 +48,17 @@
|
|
|
48
48
|
"uuid": "^9.0.0",
|
|
49
49
|
"value-matcher": "^0.2.0",
|
|
50
50
|
"vhd-lib": "^4.11.1",
|
|
51
|
-
"xen-api": "^4.
|
|
51
|
+
"xen-api": "^4.5.0",
|
|
52
52
|
"yazl": "^2.5.1"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"fs-extra": "^11.1.0",
|
|
56
56
|
"rimraf": "^5.0.1",
|
|
57
57
|
"sinon": "^18.0.0",
|
|
58
|
-
"test": "^3.2.1",
|
|
59
58
|
"tmp": "^0.2.1"
|
|
60
59
|
},
|
|
61
60
|
"peerDependencies": {
|
|
62
|
-
"@xen-orchestra/xapi": "^7.
|
|
61
|
+
"@xen-orchestra/xapi": "^7.7.0"
|
|
63
62
|
},
|
|
64
63
|
"license": "AGPL-3.0-or-later",
|
|
65
64
|
"author": {
|