diff --git a/packages/xo-server/src/api/backup-ng.js b/packages/xo-server/src/api/backup-ng.js index f5b6f7477..e4c5aaee3 100644 --- a/packages/xo-server/src/api/backup-ng.js +++ b/packages/xo-server/src/api/backup-ng.js @@ -11,7 +11,7 @@ export function createJob({ schedules, ...job }) { createJob.permission = 'admin' createJob.params = { compression: { - enum: ['', 'native'], + enum: ['', 'native', 'zstd'], optional: true, }, mode: { @@ -68,7 +68,7 @@ export function editJob(props) { editJob.permission = 'admin' editJob.params = { compression: { - enum: ['', 'native'], + enum: ['', 'native', 'zstd'], optional: true, }, id: { diff --git a/packages/xo-server/src/api/vm.js b/packages/xo-server/src/api/vm.js index 8280d0b38..c63d48b83 100644 --- a/packages/xo-server/src/api/vm.js +++ b/packages/xo-server/src/api/vm.js @@ -706,7 +706,7 @@ export async function copy({ compress, name: nameLabel, sr, vm }) { copy.params = { compress: { - type: 'boolean', + type: ['boolean', 'string'], optional: true, }, name: { @@ -1132,7 +1132,7 @@ revert.resolve = { async function handleExport(req, res, { xapi, id, compress }) { const stream = await xapi.exportVm(id, { - compress: compress != null ? compress : true, + compress, }) res.on('close', () => stream.cancel()) // Remove the filename as it is already part of the URL. @@ -1167,7 +1167,7 @@ async function export_({ vm, compress }) { export_.params = { vm: { type: 'string' }, - compress: { type: 'boolean', optional: true }, + compress: { type: ['boolean', 'string'], optional: true }, } export_.resolve = { diff --git a/packages/xo-server/src/xapi/index.js b/packages/xo-server/src/xapi/index.js index 599c19a48..abee0edd6 100644 --- a/packages/xo-server/src/xapi/index.js +++ b/packages/xo-server/src/xapi/index.js @@ -539,7 +539,7 @@ export default class Xapi extends XapiBase { vmId, targetXapi, targetSrId, - { compress = true, nameLabel = undefined } = {} + { compress, nameLabel = undefined } = {} ) { // Fall back on local copy if possible. if (targetXapi === this) { @@ -783,7 +783,7 @@ export default class Xapi extends XapiBase { // Returns a stream to the exported VM. @concurrency(2, stream => stream.then(stream => fromEvent(stream, 'end'))) @cancelable - async exportVm($cancelToken, vmId, { compress = true } = {}) { + async exportVm($cancelToken, vmId, { compress = false } = {}) { const vm = this.getObject(vmId) const useSnapshot = isVmRunning(vm) const exportedVm = useSnapshot @@ -793,7 +793,12 @@ export default class Xapi extends XapiBase { const promise = this.getResource($cancelToken, '/export/', { query: { ref: exportedVm.$ref, - use_compression: compress ? 'true' : 'false', + use_compression: + compress === 'zstd' + ? 'zstd' + : compress === true || compress === 'gzip' + ? 'true' + : 'false', }, task: this.createTask('VM export', vm.name_label), }).catch(error => { diff --git a/packages/xo-server/src/xapi/index.js.flow b/packages/xo-server/src/xapi/index.js.flow index 4898d3adf..3f8b3204a 100644 --- a/packages/xo-server/src/xapi/index.js.flow +++ b/packages/xo-server/src/xapi/index.js.flow @@ -93,7 +93,7 @@ declare export class Xapi { exportVm( cancelToken: mixed, vm: Vm, - options ?: Object + options?: { compress?: true | false | 'gzip' | 'zstd' } ): Promise; getObject(object: Id): XapiObject; importDeltaVm(data: DeltaVmImport, options: Object): Promise<{ vm: Vm }>; diff --git a/packages/xo-server/src/xo-mixins/backups-ng/index.js b/packages/xo-server/src/xo-mixins/backups-ng/index.js index 784e1cb3a..0456a9e99 100644 --- a/packages/xo-server/src/xo-mixins/backups-ng/index.js +++ b/packages/xo-server/src/xo-mixins/backups-ng/index.js @@ -81,7 +81,7 @@ type SimpleIdPattern = {| export type BackupJob = {| ...$Exact, - compression?: 'native', + compression?: 'native' | 'zstd' | '', mode: Mode, remotes?: SimpleIdPattern, settings: $Dict, @@ -177,6 +177,9 @@ const isMetadataFile = (filename: string) => filename.endsWith('.json') const isVhd = (filename: string) => filename.endsWith('.vhd') const isXva = (filename: string) => filename.endsWith('.xva') +const getJobCompression = ({ compression: c }) => + c === undefined || c === '' ? false : c === 'native' ? 'gzip' : 'zstd' + const listReplicatedVms = ( xapi: Xapi, scheduleId: string, @@ -1119,7 +1122,7 @@ export default class BackupNg { parentId: taskId, }, xapi.exportVm($cancelToken, snapshot, { - compress: job.compression === 'native', + compress: getJobCompression(job), }) ) const exportTask = xva.task