backups: add backup multiple targets

This commit is contained in:
Girish Ramakrishnan
2025-07-24 19:02:02 +02:00
parent 100bea981d
commit 3aafbd2ccb
25 changed files with 744 additions and 535 deletions

View File

@@ -16,15 +16,15 @@ const assert = require('assert'),
tar = require('tar-stream'),
zlib = require('zlib');
function getBackupFilePath(backupConfig, remotePath) {
assert.strictEqual(typeof backupConfig, 'object');
function getBackupFilePath(backupTarget, remotePath) {
assert.strictEqual(typeof backupTarget, 'object');
assert.strictEqual(typeof remotePath, 'string');
const rootPath = backupConfig.rootPath;
const fileType = backupConfig.encryption ? '.tar.gz.enc' : '.tar.gz';
const rootPath = backupTarget.config.rootPath;
const fileType = backupTarget.encryption ? '.tar.gz.enc' : '.tar.gz';
// we don't have a rootPath for noop
if (backupConfig.provider === 'noop') return remotePath + fileType;
if (backupTarget.provider === 'noop') return remotePath + fileType;
return path.join(rootPath, remotePath + fileType);
}
@@ -231,39 +231,39 @@ async function tarExtract(inStream, dataLayout, encryption, progressCallback) {
debug(`tarExtract: pipeline finished: ${ps.stats()}`);
}
async function download(backupConfig, remotePath, dataLayout, progressCallback) {
assert.strictEqual(typeof backupConfig, 'object');
async function download(backupTarget, remotePath, dataLayout, progressCallback) {
assert.strictEqual(typeof backupTarget, 'object');
assert.strictEqual(typeof remotePath, 'string');
assert(dataLayout instanceof DataLayout, 'dataLayout must be a DataLayout');
assert.strictEqual(typeof progressCallback, 'function');
debug(`download: Downloading ${remotePath} to ${dataLayout.toString()}`);
const backupFilePath = getBackupFilePath(backupConfig, remotePath);
const backupFilePath = getBackupFilePath(backupTarget, remotePath);
await promiseRetry({ times: 5, interval: 20000, debug }, async () => {
progressCallback({ message: `Downloading backup ${backupFilePath}` });
const sourceStream = await storage.api(backupConfig.provider).download(backupConfig, backupFilePath);
await tarExtract(sourceStream, dataLayout, backupConfig.encryption, progressCallback);
const sourceStream = await storage.api(backupTarget.provider).download(backupTarget.config, backupFilePath);
await tarExtract(sourceStream, dataLayout, backupTarget.encryption, progressCallback);
});
}
async function upload(backupConfig, remotePath, dataLayout, progressCallback) {
assert.strictEqual(typeof backupConfig, 'object');
async function upload(backupTarget, remotePath, dataLayout, progressCallback) {
assert.strictEqual(typeof backupTarget, 'object');
assert.strictEqual(typeof remotePath, 'string');
assert.strictEqual(typeof dataLayout, 'object');
assert.strictEqual(typeof progressCallback, 'function');
debug(`upload: Uploading ${dataLayout.toString()} to ${remotePath}`);
const backupFilePath = getBackupFilePath(backupConfig, remotePath);
const backupFilePath = getBackupFilePath(backupTarget, remotePath);
await promiseRetry({ times: 5, interval: 20000, debug }, async () => {
progressCallback({ message: `Uploading backup ${backupFilePath}` });
const uploader = await storage.api(backupConfig.provider).upload(backupConfig, backupFilePath);
await tarPack(dataLayout, backupConfig.encryption, uploader, progressCallback);
const uploader = await storage.api(backupTarget.provider).upload(backupTarget.config, backupFilePath);
await tarPack(dataLayout, backupTarget.encryption, uploader, progressCallback);
});
}