diff --git a/src/backups.js b/src/backups.js index 3b3f80fcb..9d951970f 100644 --- a/src/backups.js +++ b/src/backups.js @@ -57,6 +57,7 @@ async function add(data) { assert.strictEqual(typeof data.manifest, 'object'); assert.strictEqual(typeof data.preserveSecs, 'number'); assert.strictEqual(typeof data.appConfig, 'object'); + assert.strictEqual(typeof data.targetId, 'string'); const creationTime = data.creationTime || new Date(); // allow tests to set the time const manifestJson = JSON.stringify(data.manifest); @@ -64,11 +65,8 @@ async function add(data) { const id = `${prefixId}_v${data.packageVersion}_${hat(32)}`; // id is used by the UI to derive dependent packages. making this a UUID will require a lot of db querying const appConfigJson = data.appConfig ? JSON.stringify(data.appConfig) : null; - const targets = await database.query(`SELECT id FROM backupTargets WHERE priority=?`, [ true ]); - const targetId = targets[0].id; - const [error] = await safe(database.query('INSERT INTO backups (id, remotePath, identifier, encryptionVersion, packageVersion, type, creationTime, state, dependsOnJson, manifestJson, preserveSecs, appConfigJson, targetId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', - [ id, data.remotePath, data.identifier, data.encryptionVersion, data.packageVersion, data.type, creationTime, data.state, JSON.stringify(data.dependsOn), manifestJson, data.preserveSecs, appConfigJson, targetId ])); + [ id, data.remotePath, data.identifier, data.encryptionVersion, data.packageVersion, data.type, creationTime, data.state, JSON.stringify(data.dependsOn), manifestJson, data.preserveSecs, appConfigJson, data.targetId ])); if (error && error.code === 'ER_DUP_ENTRY') throw new BoxError(BoxError.ALREADY_EXISTS, 'Backup already exists'); if (error) throw error; diff --git a/src/backuptargets.js b/src/backuptargets.js index 0533256b9..a85d4154e 100644 --- a/src/backuptargets.js +++ b/src/backuptargets.js @@ -28,9 +28,6 @@ exports = module.exports = { remount, getMountStatus, ensureMounted, - - _addDefault: addDefault, - _getDefault: getDefault, }; const assert = require('assert'), @@ -160,32 +157,12 @@ async function list(page, perPage) { return results; } -async function getDefault() { - const results = await database.query(`SELECT ${BACKUP_TARGET_FIELDS} FROM backupTargets WHERE priority=? LIMIT 1`, [ true ]); - return postProcess(results[0]); -} - async function get(id) { const results = await database.query(`SELECT ${BACKUP_TARGET_FIELDS} FROM backupTargets WHERE id=?`, [ id ]); if (results.length === 0) return null; return postProcess(results[0]); } -async function addDefault() { - const label = '', priority = true; - const limits = null, encryption = null; - const retention = { keepWithinSecs: 2 * 24 * 60 * 60 }; - const schedule = '00 00 23 * * *';; - const config = { backupFolder: paths.DEFAULT_BACKUP_DIR }; - const provider = 'filesystem'; - const format = 'tgz'; - - const id = `bc-${uuid.v4()}`; - await database.query('INSERT INTO backupTargets (id, label, provider, configJson, limitsJson, retentionJson, schedule, encryptionJson, format, priority) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', - [ id, label, provider, JSON.stringify(config), JSON.stringify(limits), JSON.stringify(retention), schedule, JSON.stringify(encryption), format, priority ]); - return id; -} - async function update(target, data) { assert.strictEqual(typeof target, 'object'); assert(data && typeof data === 'object'); diff --git a/src/backuptask.js b/src/backuptask.js index 34ca69f53..ed0bf9057 100644 --- a/src/backuptask.js +++ b/src/backuptask.js @@ -241,7 +241,8 @@ async function rotateBoxBackup(backupTarget, tag, options, dependsOn, progressCa dependsOn, manifest: null, preserveSecs: options.preserveSecs || 0, - appConfig: null + appConfig: null, + targetId: backupTarget.id }; const id = await backups.add(data); @@ -288,7 +289,8 @@ async function rotateAppBackup(backupTarget, app, tag, options, progressCallback dependsOn: [], manifest, preserveSecs: options.preserveSecs || 0, - appConfig: app + appConfig: app, + targetId: backupTarget.id }; const id = await backups.add(data); @@ -406,8 +408,8 @@ async function uploadMailSnapshot(backupTarget, progressCallback) { await backupTargets.setSnapshotInfo('mail', { timestamp: new Date().toISOString(), format: backupTarget.format }); } -async function rotateMailBackup(target, tag, options, progressCallback) { - assert.strictEqual(typeof target, 'object'); +async function rotateMailBackup(backupTarget, tag, options, progressCallback) { + assert.strictEqual(typeof backupTarget, 'object'); assert.strictEqual(typeof tag, 'string'); assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof progressCallback, 'function'); @@ -418,7 +420,7 @@ async function rotateMailBackup(target, tag, options, progressCallback) { const data = { remotePath, - encryptionVersion: target.encryption ? 2 : null, + encryptionVersion: backupTarget.encryption ? 2 : null, packageVersion: constants.VERSION, type: backups.BACKUP_TYPE_MAIL, state: backups.BACKUP_STATE_CREATING, @@ -426,11 +428,12 @@ async function rotateMailBackup(target, tag, options, progressCallback) { dependsOn: [], manifest: null, preserveSecs: options.preserveSecs || 0, - appConfig: null + appConfig: null, + targetId: backupTarget.id }; const id = await backups.add(data); - const [error] = await safe(copy(target, 'snapshot/mail', remotePath, progressCallback)); + const [error] = await safe(copy(backupTarget, 'snapshot/mail', remotePath, progressCallback)); const state = error ? backups.BACKUP_STATE_ERROR : backups.BACKUP_STATE_NORMAL; await backups.setState(id, state); if (error) throw error; @@ -438,16 +441,16 @@ async function rotateMailBackup(target, tag, options, progressCallback) { return id; } -async function backupMailWithTag(target, tag, options, progressCallback) { - assert.strictEqual(typeof target, 'object'); +async function backupMailWithTag(backupTarget, tag, options, progressCallback) { + assert.strictEqual(typeof backupTarget, 'object'); assert.strictEqual(typeof tag, 'string'); assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof progressCallback, 'function'); debug(`backupMailWithTag: backing up mail with tag ${tag}`); - await uploadMailSnapshot(target, progressCallback); - return await rotateMailBackup(target, tag, options, progressCallback); + await uploadMailSnapshot(backupTarget, progressCallback); + return await rotateMailBackup(backupTarget, tag, options, progressCallback); } async function downloadMail(restoreConfig, progressCallback) { diff --git a/src/routes/test/common.js b/src/routes/test/common.js index e55621796..8eb55419c 100644 --- a/src/routes/test/common.js +++ b/src/routes/test/common.js @@ -99,6 +99,8 @@ exports = module.exports = { aliasDomains: [] }, + getDefaultBackupTarget, + mockApiServerOrigin: 'http://localhost:6060', dashboardDomain: 'test.example.com', dashboardFqdn: 'my.test.example.com', @@ -115,7 +117,15 @@ async function setupServer() { await database.initialize(); await database._clear(); await appstore._setApiServerOrigin(exports.mockApiServerOrigin); - await backupTargets._addDefault(); + // duplicated here since we clear the database + await backupTargets.add({ + provider: 'filesystem', + label: '', + config: { backupFolder: '/tmp/boxtest' }, + format: 'tgz', + retention: { keepWithinSecs: 2 * 24 * 60 * 60 }, + schedule: '00 00 23 * * *' + }); await oidcServer.stop(); await server.start(); debug('Set up server complete'); @@ -231,3 +241,8 @@ async function waitForAsyncTask(es) { }); }); } + +async function getDefaultBackupTarget() { + const result = await backupTargets.list(1, 1); + return result[0]; +} diff --git a/src/test/archives-test.js b/src/test/archives-test.js index 8551ca228..142276dc0 100644 --- a/src/test/archives-test.js +++ b/src/test/archives-test.js @@ -13,7 +13,7 @@ const archives = require('../archives.js'), safe = require('safetydance'); describe('Archives', function () { - const { setup, cleanup, auditSource } = common; + const { setup, cleanup, auditSource, getDefaultBackupTarget } = common; const appBackup = { id: null, @@ -27,11 +27,13 @@ describe('Archives', function () { manifest: null, preserveSecs: 0, label: '', - appConfig: { loc: 'loc1' } + appConfig: { loc: 'loc1' }, + targetId: null }; before(async function () { await setup(); + appBackup.targetId = (await getDefaultBackupTarget()).id; appBackup.id = await backups.add(appBackup); }); after(cleanup); diff --git a/src/test/backupcleaner-test.js b/src/test/backupcleaner-test.js index cc3919958..c53407df1 100644 --- a/src/test/backupcleaner-test.js +++ b/src/test/backupcleaner-test.js @@ -17,7 +17,7 @@ const archives = require('../archives.js'), timers = require('timers/promises'); describe('backup cleaner', function () { - const { setup, cleanup, app } = common; + const { setup, cleanup, app, getDefaultBackupTarget } = common; before(setup); after(cleanup); @@ -139,7 +139,8 @@ describe('backup cleaner', function () { dependsOn: [ 'backup-app-00', 'backup-app-01' ], manifest: null, preserveSecs: 0, - appConfig: null + appConfig: null, + targetId: null }; const BACKUP_0_APP_0 = { // backup of installed app @@ -153,7 +154,8 @@ describe('backup cleaner', function () { dependsOn: [], manifest: null, preserveSecs: 0, - appConfig: null + appConfig: null, + targetId: null }; const BACKUP_0_APP_1 = { // this app is uninstalled @@ -167,7 +169,8 @@ describe('backup cleaner', function () { dependsOn: [], manifest: null, preserveSecs: 0, - appConfig: null + appConfig: null, + targetId: null }; const BACKUP_1_BOX = { @@ -181,7 +184,8 @@ describe('backup cleaner', function () { dependsOn: [ 'backup-app-10', 'backup-app-11' ], manifest: null, preserveSecs: 0, - appConfig: null + appConfig: null, + targetId: null }; const BACKUP_1_APP_0 = { @@ -195,7 +199,8 @@ describe('backup cleaner', function () { dependsOn: [], manifest: null, preserveSecs: 0, - appConfig: null + appConfig: null, + targetId: null }; const BACKUP_1_APP_1 = { @@ -209,7 +214,8 @@ describe('backup cleaner', function () { dependsOn: [], manifest: null, preserveSecs: 0, - appConfig: null + appConfig: null, + targetId: null }; const BACKUP_2_APP_2 = { // this is archived and left alone @@ -223,11 +229,12 @@ describe('backup cleaner', function () { dependsOn: [], manifest: null, preserveSecs: 0, - appConfig: null + appConfig: null, + targetId: null }; before(async function () { - target = await backupTargets._getDefault(); + target = await getDefaultBackupTarget(); await backupTargets.setConfig(target, { provider: 'filesystem', backupFolder: '/tmp/someplace', @@ -258,6 +265,10 @@ describe('backup cleaner', function () { }); it('add the backups', async function () { + for (const b of [BACKUP_0_APP_0, BACKUP_0_APP_1, BACKUP_0_BOX, BACKUP_1_APP_0, BACKUP_1_APP_1, BACKUP_1_BOX, BACKUP_2_APP_2]) { + b.targetId = target.id; + } + BACKUP_0_APP_0.id = await backups.add(BACKUP_0_APP_0); BACKUP_0_APP_1.id = await backups.add(BACKUP_0_APP_1); BACKUP_0_BOX.dependsOn = [ BACKUP_0_APP_0.id, BACKUP_0_APP_1.id ]; diff --git a/src/test/backups-test.js b/src/test/backups-test.js index 5f7f0d52e..3fad2b803 100644 --- a/src/test/backups-test.js +++ b/src/test/backups-test.js @@ -14,7 +14,7 @@ const backups = require('../backups.js'), safe = require('safetydance'); describe('backups', function () { - const { setup, cleanup } = common; + const { setup, cleanup, getDefaultBackupTarget } = common; const boxBackup = { id: null, @@ -52,13 +52,12 @@ describe('backups', function () { before(async function () { await setup(); - defaultBackupTarget = await backupTargets._getDefault(); + defaultBackupTarget = await getDefaultBackupTarget(); boxBackup.targetId = defaultBackupTarget.id; appBackup.targetId = defaultBackupTarget.id; }); after(cleanup); - describe('crud', function () { it('add succeeds', async function () { boxBackup.id = await backups.add(boxBackup); diff --git a/src/test/backuptargets-test.js b/src/test/backuptargets-test.js index 2fd57659d..8ed521325 100644 --- a/src/test/backuptargets-test.js +++ b/src/test/backuptargets-test.js @@ -32,7 +32,7 @@ describe('backups', function () { it('can get backup target', async function () { const backupTarget = await backupTargets.get(defaultBackupTarget.id); expect(backupTarget.config.provider).to.be('filesystem'); - expect(backupTarget.config.backupFolder).to.be('/var/backups'); + expect(backupTarget.config.backupFolder).to.be.ok(); // the test sets this to some tmp location expect(backupTarget.format).to.be('tgz'); expect(backupTarget.encryption).to.be(null); }); diff --git a/src/test/backuptask-test.js b/src/test/backuptask-test.js index 5ef72f5bd..a916ea357 100644 --- a/src/test/backuptask-test.js +++ b/src/test/backuptask-test.js @@ -17,7 +17,7 @@ const backups = require('../backups.js'), timers = require('timers/promises'); describe('backuptask', function () { - const { setup, cleanup } = common; + const { setup, cleanup, getDefaultBackupTarget } = common; before(setup); after(cleanup); @@ -34,7 +34,7 @@ describe('backuptask', function () { before(async function () { fs.rmSync(backupConfig.backupFolder, { recursive: true, force: true }); - defaultBackupTarget = await backupTargets._getDefault(); + defaultBackupTarget = await getDefaultBackupTarget(); await backupTargets.setConfig(defaultBackupTarget, backupConfig); }); diff --git a/src/test/cloudron-test.js b/src/test/cloudron-test.js index 73c1b4f8a..68d2e11cd 100644 --- a/src/test/cloudron-test.js +++ b/src/test/cloudron-test.js @@ -28,7 +28,7 @@ describe('Cloudron', function () { expect(error.reason).to.be(BoxError.BAD_FIELD); }); - it('cannot set valid timezone', async function () { + it('can set valid timezone', async function () { await cloudron.setTimeZone('Africa/Johannesburg'); const tz = await cloudron.getTimeZone(); expect(tz).to.be('Africa/Johannesburg'); diff --git a/src/test/common.js b/src/test/common.js index 2feddb10b..73edaf285 100644 --- a/src/test/common.js +++ b/src/test/common.js @@ -173,6 +173,8 @@ exports = module.exports = { checkMails, clearMailQueue, + getDefaultBackupTarget, + mockApiServerOrigin: 'http://localhost:6060', dashboardDomain: domain.domain, dashboardFqdn: `my.${domain.domain}`, @@ -218,7 +220,16 @@ async function databaseSetup() { await database._clear(); await appstore._setApiServerOrigin(exports.mockApiServerOrigin); await dashboard._setLocation(constants.DASHBOARD_SUBDOMAIN, exports.dashboardDomain); - await backupTargets._addDefault(); + + // duplicated here since we clear the database + await backupTargets.add({ + provider: 'filesystem', + label: '', + config: { backupFolder: '/tmp/boxtest' }, + format: 'tgz', + retention: { keepWithinSecs: 2 * 24 * 60 * 60 }, + schedule: '00 00 23 * * *' + }); } async function domainSetup() { @@ -263,3 +274,8 @@ async function checkMails(number) { // return for further investigation return emails; } + +async function getDefaultBackupTarget() { + const result = await backupTargets.list(1, 1); + return result[0]; +} diff --git a/src/test/storage-test.js b/src/test/storage-test.js index eb52ba1bd..324ce9ad3 100644 --- a/src/test/storage-test.js +++ b/src/test/storage-test.js @@ -24,7 +24,7 @@ const backupTargets = require('../backuptargets.js'), const chunk = s3._chunk; describe('Storage', function () { - const { setup, cleanup } = common; + const { setup, cleanup, getDefaultBackupTarget } = common; before(setup); after(cleanup); @@ -41,9 +41,7 @@ describe('Storage', function () { before(async function () { gTmpFolder = fs.mkdtempSync(path.join(os.tmpdir(), 'filesystem-storage-test_')); - - defaultBackupTarget = await backupTargets._getDefault(); - + defaultBackupTarget = await getDefaultBackupTarget(); gBackupConfig.backupFolder = path.join(gTmpFolder, 'backups/'); });