@@ -0,0 +1,18 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
exports.up = function(db, callback) {
|
||||||
|
db.all('SELECT value FROM settings WHERE name="backup_config"', function (error, results) {
|
||||||
|
if (error || results.length === 0) return callback(error);
|
||||||
|
|
||||||
|
var backupConfig = JSON.parse(results[0].value);
|
||||||
|
backupConfig.retentionPolicy = { keepWithin: backupConfig.retentionSecs };
|
||||||
|
delete backupConfig.retentionSecs;
|
||||||
|
|
||||||
|
// mark old encrypted backups as v1
|
||||||
|
db.runSql('UPDATE settings SET value=? WHERE name="backup_config"', [ JSON.stringify(backupConfig) ], callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function(db, callback) {
|
||||||
|
callback();
|
||||||
|
};
|
||||||
+3
-3
@@ -1272,7 +1272,7 @@ function cleanupAppBackups(backupConfig, referencedAppBackups, callback) {
|
|||||||
async.eachSeries(appBackups, function iterator(appBackup, iteratorDone) {
|
async.eachSeries(appBackups, function iterator(appBackup, iteratorDone) {
|
||||||
if (referencedAppBackups.indexOf(appBackup.id) !== -1) return iteratorDone();
|
if (referencedAppBackups.indexOf(appBackup.id) !== -1) return iteratorDone();
|
||||||
if ((now - appBackup.creationTime) < (appBackup.preserveSecs * 1000)) return iteratorDone();
|
if ((now - appBackup.creationTime) < (appBackup.preserveSecs * 1000)) return iteratorDone();
|
||||||
if ((now - appBackup.creationTime) < (backupConfig.retentionSecs * 1000)) return iteratorDone();
|
if ((now - appBackup.creationTime) < (backupConfig.retentionPolicy.keepWithin * 1000)) return iteratorDone();
|
||||||
|
|
||||||
debug('cleanupAppBackups: removing %s', appBackup.id);
|
debug('cleanupAppBackups: removing %s', appBackup.id);
|
||||||
|
|
||||||
@@ -1317,7 +1317,7 @@ function cleanupBoxBackups(backupConfig, auditSource, callback) {
|
|||||||
async.eachSeries(boxBackups, function iterator(boxBackup, iteratorNext) {
|
async.eachSeries(boxBackups, function iterator(boxBackup, iteratorNext) {
|
||||||
// TODO: errored backups should probably be cleaned up before retention time, but we will
|
// TODO: errored backups should probably be cleaned up before retention time, but we will
|
||||||
// have to be careful not to remove any backup currently being created
|
// have to be careful not to remove any backup currently being created
|
||||||
if ((now - boxBackup.creationTime) < (backupConfig.retentionSecs * 1000)) {
|
if ((now - boxBackup.creationTime) < (backupConfig.retentionPolicy.keepWithin * 1000)) {
|
||||||
referencedAppBackups = referencedAppBackups.concat(boxBackup.dependsOn);
|
referencedAppBackups = referencedAppBackups.concat(boxBackup.dependsOn);
|
||||||
return iteratorNext();
|
return iteratorNext();
|
||||||
}
|
}
|
||||||
@@ -1391,7 +1391,7 @@ function cleanup(auditSource, progressCallback, callback) {
|
|||||||
settings.getBackupConfig(function (error, backupConfig) {
|
settings.getBackupConfig(function (error, backupConfig) {
|
||||||
if (error) return callback(error);
|
if (error) return callback(error);
|
||||||
|
|
||||||
if (backupConfig.retentionSecs < 0) {
|
if (backupConfig.retentionPolicy.keepWithin < 0) {
|
||||||
debug('cleanup: keeping all backups');
|
debug('cleanup: keeping all backups');
|
||||||
return callback(null, {});
|
return callback(null, {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ function setBackupConfig(req, res, next) {
|
|||||||
assert.strictEqual(typeof req.body, 'object');
|
assert.strictEqual(typeof req.body, 'object');
|
||||||
|
|
||||||
if (typeof req.body.provider !== 'string') return next(new HttpError(400, 'provider is required'));
|
if (typeof req.body.provider !== 'string') return next(new HttpError(400, 'provider is required'));
|
||||||
if (typeof req.body.retentionSecs !== 'number') return next(new HttpError(400, 'retentionSecs is required'));
|
|
||||||
if (typeof req.body.intervalSecs !== 'number') return next(new HttpError(400, 'intervalSecs is required'));
|
if (typeof req.body.intervalSecs !== 'number') return next(new HttpError(400, 'intervalSecs is required'));
|
||||||
if ('password' in req.body && typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be a string'));
|
if ('password' in req.body && typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be a string'));
|
||||||
if ('syncConcurrency' in req.body) {
|
if ('syncConcurrency' in req.body) {
|
||||||
@@ -107,6 +106,9 @@ function setBackupConfig(req, res, next) {
|
|||||||
if (typeof req.body.format !== 'string') return next(new HttpError(400, 'format must be a string'));
|
if (typeof req.body.format !== 'string') return next(new HttpError(400, 'format must be a string'));
|
||||||
if ('acceptSelfSignedCerts' in req.body && typeof req.body.acceptSelfSignedCerts !== 'boolean') return next(new HttpError(400, 'format must be a boolean'));
|
if ('acceptSelfSignedCerts' in req.body && typeof req.body.acceptSelfSignedCerts !== 'boolean') return next(new HttpError(400, 'format must be a boolean'));
|
||||||
|
|
||||||
|
if (!req.body.retentionPolicy || typeof req.body.retentionPolicy !== 'object') return next(new HttpError(400, 'retentionPolicy is required'));
|
||||||
|
if (typeof req.body.retentionPolicy.keepWithin !== 'number') return next(400, 'keepWithin is required');
|
||||||
|
|
||||||
// testing the backup using put/del takes a bit of time at times
|
// testing the backup using put/del takes a bit of time at times
|
||||||
req.clearTimeout();
|
req.clearTimeout();
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -145,7 +145,7 @@ let gDefaults = (function () {
|
|||||||
backupFolder: '/var/backups',
|
backupFolder: '/var/backups',
|
||||||
format: 'tgz',
|
format: 'tgz',
|
||||||
encryption: null,
|
encryption: null,
|
||||||
retentionSecs: 2 * 24 * 60 * 60, // 2 days
|
retentionPolicy: { keepWithin: 2 * 24 * 60 * 60 }, // 2 days
|
||||||
intervalSecs: 24 * 60 * 60 // ~1 day
|
intervalSecs: 24 * 60 * 60 // ~1 day
|
||||||
};
|
};
|
||||||
result[exports.PLATFORM_CONFIG_KEY] = {};
|
result[exports.PLATFORM_CONFIG_KEY] = {};
|
||||||
@@ -428,7 +428,7 @@ function setBackupCredentials(credentials, callback) {
|
|||||||
if (error) return callback(error);
|
if (error) return callback(error);
|
||||||
|
|
||||||
// preserve these fields
|
// preserve these fields
|
||||||
const extra = _.pick(currentConfig, 'retentionSecs', 'intervalSecs', 'copyConcurrency', 'syncConcurrency');
|
const extra = _.pick(currentConfig, 'retentionPolicy', 'intervalSecs', 'copyConcurrency', 'syncConcurrency');
|
||||||
|
|
||||||
const backupConfig = _.extend({}, credentials, extra);
|
const backupConfig = _.extend({}, credentials, extra);
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ describe('backups', function () {
|
|||||||
provider: 'filesystem',
|
provider: 'filesystem',
|
||||||
password: 'supersecret',
|
password: 'supersecret',
|
||||||
backupFolder: BACKUP_DIR,
|
backupFolder: BACKUP_DIR,
|
||||||
retentionSecs: 1,
|
retentionPolicy: { keepWithin: 1 },
|
||||||
format: 'tgz'
|
format: 'tgz'
|
||||||
})
|
})
|
||||||
], done);
|
], done);
|
||||||
|
|||||||
Reference in New Issue
Block a user