diff --git a/src/apps.js b/src/apps.js index 8a854d17b..81b78280a 100644 --- a/src/apps.js +++ b/src/apps.js @@ -1925,7 +1925,7 @@ function listBackups(app, page, perPage, callback) { assert(typeof perPage === 'number' && perPage > 0); assert.strictEqual(typeof callback, 'function'); - backups.getByAppIdPaged(page, perPage, app.id, function (error, results) { + backups.getByIdentifierAndStatePaged(app.id, backups.BACKUP_STATE_NORMAL, page, perPage, function (error, results) { if (error) return callback(error); callback(null, results); diff --git a/src/backupdb.js b/src/backupdb.js index d9af21de0..93d885f52 100644 --- a/src/backupdb.js +++ b/src/backupdb.js @@ -9,24 +9,17 @@ var assert = require('assert'), var BACKUPS_FIELDS = [ 'id', 'identifier', 'creationTime', 'packageVersion', 'type', 'dependsOn', 'state', 'manifestJson', 'format', 'preserveSecs', 'encryptionVersion' ]; exports = module.exports = { - add: add, + add, - getByTypeAndStatePaged: getByTypeAndStatePaged, - getByTypePaged: getByTypePaged, + getByTypePaged, + getByIdentifierPaged, + getByIdentifierAndStatePaged, - get: get, - del: del, - update: update, - getByAppIdPaged: getByAppIdPaged, + get, + del, + update, - _clear: clear, - - BACKUP_TYPE_APP: 'app', - BACKUP_TYPE_BOX: 'box', - - BACKUP_STATE_NORMAL: 'normal', // should rename to created to avoid listing in UI? - BACKUP_STATE_CREATING: 'creating', - BACKUP_STATE_ERROR: 'error' + _clear: clear }; function postProcess(result) { @@ -38,15 +31,15 @@ function postProcess(result) { delete result.manifestJson; } -function getByTypeAndStatePaged(type, state, page, perPage, callback) { - assert(type === exports.BACKUP_TYPE_APP || type === exports.BACKUP_TYPE_BOX); +function getByIdentifierAndStatePaged(identifier, state, page, perPage, callback) { + assert.strictEqual(typeof identifier, 'string'); assert.strictEqual(typeof state, 'string'); assert(typeof page === 'number' && page > 0); assert(typeof perPage === 'number' && perPage > 0); assert.strictEqual(typeof callback, 'function'); - database.query('SELECT ' + BACKUPS_FIELDS + ' FROM backups WHERE type = ? AND state = ? ORDER BY creationTime DESC LIMIT ?,?', - [ type, state, (page-1)*perPage, perPage ], function (error, results) { + database.query('SELECT ' + BACKUPS_FIELDS + ' FROM backups WHERE identifier = ? AND state = ? ORDER BY creationTime DESC LIMIT ?,?', + [ identifier, state, (page-1)*perPage, perPage ], function (error, results) { if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); results.forEach(function (result) { postProcess(result); }); @@ -56,7 +49,7 @@ function getByTypeAndStatePaged(type, state, page, perPage, callback) { } function getByTypePaged(type, page, perPage, callback) { - assert(type === exports.BACKUP_TYPE_APP || type === exports.BACKUP_TYPE_BOX); + assert.strictEqual(typeof type, 'string'); assert(typeof page === 'number' && page > 0); assert(typeof perPage === 'number' && perPage > 0); assert.strictEqual(typeof callback, 'function'); @@ -71,15 +64,14 @@ function getByTypePaged(type, page, perPage, callback) { }); } -function getByAppIdPaged(page, perPage, appId, callback) { +function getByIdentifierPaged(identifier, page, perPage, callback) { + assert.strictEqual(typeof identifier, 'string'); assert(typeof page === 'number' && page > 0); assert(typeof perPage === 'number' && perPage > 0); - assert.strictEqual(typeof appId, 'string'); assert.strictEqual(typeof callback, 'function'); - // box versions (0.93.x and below) used to use appbackup_ prefix - database.query('SELECT ' + BACKUPS_FIELDS + ' FROM backups WHERE type = ? AND state = ? AND id LIKE ? ORDER BY creationTime DESC LIMIT ?,?', - [ exports.BACKUP_TYPE_APP, exports.BACKUP_STATE_NORMAL, '%app%\\_' + appId + '\\_%', (page-1)*perPage, perPage ], function (error, results) { + database.query('SELECT ' + BACKUPS_FIELDS + ' FROM backups WHERE identifier = ? ORDER BY creationTime DESC LIMIT ?,?', + [ identifier, (page-1)*perPage, perPage ], function (error, results) { if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); results.forEach(function (result) { postProcess(result); }); @@ -108,8 +100,9 @@ function add(id, data, callback) { assert.strictEqual(typeof id, 'string'); assert(data.encryptionVersion === null || typeof data.encryptionVersion === 'number'); assert.strictEqual(typeof data.packageVersion, 'string'); - assert(data.type === exports.BACKUP_TYPE_APP || data.type === exports.BACKUP_TYPE_BOX); + assert.strictEqual(typeof data.type, 'string'); assert.strictEqual(typeof data.identifier, 'string'); + assert.strictEqual(typeof data.state, 'string'); assert(util.isArray(data.dependsOn)); assert.strictEqual(typeof data.manifest, 'object'); assert.strictEqual(typeof data.format, 'string'); @@ -119,7 +112,7 @@ function add(id, data, callback) { var manifestJson = JSON.stringify(data.manifest); database.query('INSERT INTO backups (id, identifier, encryptionVersion, packageVersion, type, creationTime, state, dependsOn, manifestJson, format) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', - [ id, data.identifier, data.encryptionVersion, data.packageVersion, data.type, creationTime, exports.BACKUP_STATE_NORMAL, data.dependsOn.join(','), manifestJson, data.format ], + [ id, data.identifier, data.encryptionVersion, data.packageVersion, data.type, creationTime, data.state, data.dependsOn.join(','), manifestJson, data.format ], function (error) { if (error && error.code === 'ER_DUP_ENTRY') return callback(new BoxError(BoxError.ALREADY_EXISTS)); if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); diff --git a/src/backups.js b/src/backups.js index e482b50a9..1e137ae4d 100644 --- a/src/backups.js +++ b/src/backups.js @@ -4,8 +4,7 @@ exports = module.exports = { testConfig: testConfig, testProviderConfig: testProviderConfig, - getByStatePaged: getByStatePaged, - getByAppIdPaged: getByAppIdPaged, + getByIdentifierAndStatePaged, get: get, @@ -34,6 +33,15 @@ exports = module.exports = { generateEncryptionKeysSync: generateEncryptionKeysSync, + BACKUP_IDENTIFIER_BOX: 'box', + + BACKUP_TYPE_APP: 'app', + BACKUP_TYPE_BOX: 'box', + + BACKUP_STATE_NORMAL: 'normal', // should rename to created to avoid listing in UI? + BACKUP_STATE_CREATING: 'creating', + BACKUP_STATE_ERROR: 'error', + // for testing _getBackupFilePath: getBackupFilePath, _restoreFsMetadata: restoreFsMetadata, @@ -175,26 +183,14 @@ function generateEncryptionKeysSync(password) { }; } -function getByStatePaged(state, page, perPage, callback) { +function getByIdentifierAndStatePaged(identifier, state, page, perPage, callback) { + assert.strictEqual(typeof identifier, 'string'); assert.strictEqual(typeof state, 'string'); assert(typeof page === 'number' && page > 0); assert(typeof perPage === 'number' && perPage > 0); assert.strictEqual(typeof callback, 'function'); - backupdb.getByTypeAndStatePaged(backupdb.BACKUP_TYPE_BOX, state, page, perPage, function (error, results) { - if (error) return callback(error); - - callback(null, results); - }); -} - -function getByAppIdPaged(page, perPage, appId, callback) { - assert(typeof page === 'number' && page > 0); - assert(typeof perPage === 'number' && perPage > 0); - assert.strictEqual(typeof appId, 'string'); - assert.strictEqual(typeof callback, 'function'); - - backupdb.getByAppIdPaged(page, perPage, appId, function (error, results) { + backupdb.getByIdentifierAndStatePaged(identifier, state, page, perPage, function (error, results) { if (error) return callback(error); callback(null, results); @@ -959,7 +955,8 @@ function rotateBoxBackup(backupConfig, tag, appBackupIds, progressCallback, call const data = { encryptionVersion: backupConfig.encryption ? 2 : null, packageVersion: constants.VERSION, - type: backupdb.BACKUP_TYPE_BOX, + type: exports.BACKUP_TYPE_BOX, + state: exports.BACKUP_STATE_CREATING, identifier: 'box', dependsOn: appBackupIds, manifest: null, @@ -971,9 +968,9 @@ function rotateBoxBackup(backupConfig, tag, appBackupIds, progressCallback, call var copy = api(backupConfig.provider).copy(backupConfig, getBackupFilePath(backupConfig, 'snapshot/box', format), getBackupFilePath(backupConfig, backupId, format)); copy.on('progress', (message) => progressCallback({ message: `box: ${message}` })); copy.on('done', function (copyBackupError) { - const state = copyBackupError ? backupdb.BACKUP_STATE_ERROR : backupdb.BACKUP_STATE_NORMAL; + const state = copyBackupError ? exports.BACKUP_STATE_ERROR : exports.BACKUP_STATE_NORMAL; - backupdb.update(backupId, { state: state }, function (error) { + backupdb.update(backupId, { state }, function (error) { if (copyBackupError) return callback(copyBackupError); if (error) return callback(error); @@ -1054,7 +1051,8 @@ function rotateAppBackup(backupConfig, app, tag, options, progressCallback, call const data = { encryptionVersion: backupConfig.encryption ? 2 : null, packageVersion: manifest.version, - type: backupdb.BACKUP_TYPE_APP, + type: exports.BACKUP_TYPE_APP, + state: exports.BACKUP_STATE_CREATING, identifier: app.id, dependsOn: [ ], manifest, @@ -1067,9 +1065,9 @@ function rotateAppBackup(backupConfig, app, tag, options, progressCallback, call var copy = api(backupConfig.provider).copy(backupConfig, getBackupFilePath(backupConfig, `snapshot/app_${app.id}`, format), getBackupFilePath(backupConfig, backupId, format)); copy.on('progress', (message) => progressCallback({ message: `${message} (${app.fqdn})` })); copy.on('done', function (copyBackupError) { - const state = copyBackupError ? backupdb.BACKUP_STATE_ERROR : backupdb.BACKUP_STATE_NORMAL; + const state = copyBackupError ? exports.BACKUP_STATE_ERROR : exports.BACKUP_STATE_NORMAL; - backupdb.update(backupId, { preserveSecs: options.preserveSecs || 0, state: state }, function (error) { + backupdb.update(backupId, { preserveSecs: options.preserveSecs || 0, state }, function (error) { if (copyBackupError) return callback(copyBackupError); if (error) return callback(error); @@ -1125,7 +1123,7 @@ function backupAppWithTag(app, tag, options, progressCallback, callback) { assert.strictEqual(typeof callback, 'function'); if (!canBackupApp(app)) { // if we cannot backup, reuse it's most recent backup - getByAppIdPaged(1, 1, app.id, function (error, results) { + getByIdentifierAndStatePaged(app.id, exports.BACKUP_STATE_NORMAL, 1, 1, function (error, results) { if (error) return callback(error); if (results.length === 0) return callback(null, null); // no backup to re-use @@ -1231,7 +1229,7 @@ function ensureBackup(auditSource, callback) { debug('ensureBackup: %j', auditSource); - getByStatePaged(backupdb.BACKUP_STATE_NORMAL, 1, 1, function (error, backups) { + getByIdentifierAndStatePaged(exports.BACKUP_IDENTIFIER_BOX, exports.BACKUP_STATE_NORMAL, 1, 1, function (error, backups) { if (error) { debug('Unable to list backups', error); return callback(error); @@ -1343,7 +1341,7 @@ function cleanupAppBackups(backupConfig, referencedAppBackupIds, progressCallbac let removedAppBackupIds = []; // we clean app backups of any state because the ones to keep are determined by the box cleanup code - backupdb.getByTypePaged(backupdb.BACKUP_TYPE_APP, 1, 1000, function (error, appBackups) { + backupdb.getByTypePaged(exports.BACKUP_TYPE_APP, 1, 1000, function (error, appBackups) { if (error) return callback(error); for (const appBackup of appBackups) { // set the reason so that policy filter can skip it @@ -1374,7 +1372,7 @@ function cleanupBoxBackups(backupConfig, progressCallback, callback) { let referencedAppBackupIds = [], removedBoxBackupIds = []; - backupdb.getByTypePaged(backupdb.BACKUP_TYPE_BOX, 1, 1000, function (error, boxBackups) { + backupdb.getByTypePaged(exports.BACKUP_TYPE_BOX, 1, 1000, function (error, boxBackups) { if (error) return callback(error); if (boxBackups.length === 0) return callback(null, { removedBoxBackupIds, referencedAppBackupIds }); @@ -1382,7 +1380,7 @@ function cleanupBoxBackups(backupConfig, progressCallback, callback) { // search for the first valid backup var i; for (i = 0; i < boxBackups.length; i++) { - if (boxBackups[i].state === backupdb.BACKUP_STATE_NORMAL) break; + if (boxBackups[i].state === exports.BACKUP_STATE_NORMAL) break; } // keep the first valid backup diff --git a/src/routes/backups.js b/src/routes/backups.js index 14af246f4..2fb9ffbe7 100644 --- a/src/routes/backups.js +++ b/src/routes/backups.js @@ -7,7 +7,6 @@ exports = module.exports = { }; let auditSource = require('../auditsource.js'), - backupdb = require('../backupdb.js'), backups = require('../backups.js'), BoxError = require('../boxerror.js'), HttpError = require('connect-lastmile').HttpError, @@ -20,7 +19,7 @@ function list(req, res, next) { var perPage = typeof req.query.per_page !== 'undefined'? parseInt(req.query.per_page) : 25; if (!perPage || perPage < 0) return next(new HttpError(400, 'per_page query param has to be a postive number')); - backups.getByStatePaged(backupdb.BACKUP_STATE_NORMAL, page, perPage, function (error, result) { + backups.getByIdentifierAndStatePaged(backups.BACKUP_IDENTIFIER_BOX, backups.BACKUP_STATE_NORMAL, page, perPage, function (error, result) { if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, { backups: result })); diff --git a/src/test/backups-test.js b/src/test/backups-test.js index 38ccb7886..017f102d3 100644 --- a/src/test/backups-test.js +++ b/src/test/backups-test.js @@ -165,7 +165,7 @@ describe('backups', function () { identifier: 'box', encryptionVersion: null, packageVersion: '1.0.0', - type: backupdb.BACKUP_TYPE_BOX, + type: backups.BACKUP_TYPE__BOX, dependsOn: [ 'backup-app-00', 'backup-app-01' ], manifest: null, format: 'tgz' @@ -176,7 +176,7 @@ describe('backups', function () { identifier: 'app0', encryptionVersion: null, packageVersion: '1.0.0', - type: backupdb.BACKUP_TYPE_APP, + type: backups.BACKUP_TYPE_APP, dependsOn: [], manifest: null, format: 'tgz' @@ -187,7 +187,7 @@ describe('backups', function () { identifier: 'app1', encryptionVersion: null, packageVersion: '1.0.0', - type: backupdb.BACKUP_TYPE_APP, + type: backups.BACKUP_TYPE_APP, dependsOn: [], manifest: null, format: 'tgz' @@ -197,7 +197,7 @@ describe('backups', function () { id: 'backup-box-1', encryptionVersion: null, packageVersion: '1.0.0', - type: backupdb.BACKUP_TYPE_BOX, + type: backups.BACKUP_TYPE_BOX, identifier: 'box', dependsOn: [ 'backup-app-10', 'backup-app-11' ], manifest: null, @@ -208,7 +208,7 @@ describe('backups', function () { id: 'backup-app-10', encryptionVersion: null, packageVersion: '1.0.0', - type: backupdb.BACKUP_TYPE_APP, + type: backups.BACKUP_TYPE_APP, identifier: 'app0', dependsOn: [], manifest: null, @@ -219,7 +219,7 @@ describe('backups', function () { id: 'backup-app-11', encryptionVersion: null, packageVersion: '1.0.0', - type: backupdb.BACKUP_TYPE_APP, + type: backups.BACKUP_TYPE_APP, identifier: 'app1', dependsOn: [], manifest: null, @@ -242,7 +242,7 @@ describe('backups', function () { cleanupBackups(function (error) { expect(error).to.not.be.ok(); - backupdb.getByTypePaged(backupdb.BACKUP_TYPE_BOX, 1, 1000, function (error, result) { + backupdb.getByTypePaged(backups.BACKUP_TYPE__BOX, 1, 1000, function (error, result) { expect(error).to.not.be.ok(); expect(result.length).to.equal(1); expect(result[0].id).to.equal(BACKUP_1.id); @@ -263,7 +263,7 @@ describe('backups', function () { cleanupBackups(function (error) { expect(error).to.not.be.ok(); - backupdb.getByTypePaged(backupdb.BACKUP_TYPE_BOX, 1, 1000, function (error, result) { + backupdb.getByTypePaged(backups.BACKUP_TYPE__BOX, 1, 1000, function (error, result) { expect(error).to.not.be.ok(); expect(result.length).to.equal(1); expect(result[0].id).to.equal(BACKUP_1.id); @@ -288,7 +288,7 @@ describe('backups', function () { cleanupBackups(function (error) { expect(error).to.not.be.ok(); - backupdb.getByTypePaged(backupdb.BACKUP_TYPE_APP, 1, 1000, function (error, result) { + backupdb.getByTypePaged(backups.BACKUP_TYPE__APP, 1, 1000, function (error, result) { expect(error).to.not.be.ok(); expect(result.length).to.equal(2); diff --git a/src/test/database-test.js b/src/test/database-test.js index 294d6db10..b06322db6 100644 --- a/src/test/database-test.js +++ b/src/test/database-test.js @@ -9,6 +9,7 @@ var appdb = require('../appdb.js'), apps = require('../apps.js'), async = require('async'), backupdb = require('../backupdb.js'), + backups = require('../backups.js'), BoxError = require('../boxerror.js'), database = require('../database'), domaindb = require('../domaindb'), @@ -1326,7 +1327,7 @@ describe('database', function () { id: 'backup-box', encryptionVersion: 2, packageVersion: '1.0.0', - type: backupdb.BACKUP_TYPE_BOX, + type: backups.BACKUP_TYPE__BOX, identifier: 'box', dependsOn: [ 'dep1' ], manifest: null, @@ -1344,7 +1345,7 @@ describe('database', function () { expect(error).to.be(null); expect(result.encryptionVersion).to.be(2); expect(result.packageVersion).to.be('1.0.0'); - expect(result.type).to.be(backupdb.BACKUP_TYPE_BOX); + expect(result.type).to.be(backups.BACKUP_TYPE__BOX); expect(result.creationTime).to.be.a(Date); expect(result.dependsOn).to.eql(['dep1']); expect(result.manifest).to.eql(null); @@ -1362,7 +1363,7 @@ describe('database', function () { }); it('getByTypePaged succeeds', function (done) { - backupdb.getByTypePaged(backupdb.BACKUP_TYPE_BOX, 1, 5, function (error, results) { + backupdb.getByTypePaged(backups.BACKUP_TYPE__BOX, 1, 5, function (error, results) { expect(error).to.be(null); expect(results).to.be.an(Array); expect(results.length).to.be(1); @@ -1396,7 +1397,7 @@ describe('database', function () { id: 'app_appid_123', encryptionVersion: null, packageVersion: '1.0.0', - type: backupdb.BACKUP_TYPE_APP, + type: backups.BACKUP_TYPE__APP, identifier: 'appid', dependsOn: [ ], manifest: { foo: 'bar' }, @@ -1414,7 +1415,7 @@ describe('database', function () { expect(error).to.be(null); expect(result.encryptionVersion).to.be(null); expect(result.packageVersion).to.be('1.0.0'); - expect(result.type).to.be(backupdb.BACKUP_TYPE_APP); + expect(result.type).to.be(backups.BACKUP_TYPE__APP); expect(result.creationTime).to.be.a(Date); expect(result.dependsOn).to.eql([]); expect(result.manifest).to.eql({ foo: 'bar' });