diff --git a/src/backups.js b/src/backups.js index 7c78c3329..1451d8cf0 100644 --- a/src/backups.js +++ b/src/backups.js @@ -437,15 +437,20 @@ function cleanup(callback) { getPaged(1, 1000, function (error, result) { if (error) return callback(error); + if (result.length === 0) return callback(); + // ensure we keep at least the last backup to ensure we have one if backup creation failed for some reason + var referencedAppBackups = result[0].dependsOn; result = result.slice(1); var now = new Date(); async.eachSeries(result, function iterator(backup, iteratorDone) { + referencedAppBackups = referencedAppBackups.concat(backup.dependsOn); + if ((now - backup.creationTime) < (backupConfig.retentionSecs * 1000)) return iteratorDone(); - debug('cleanup: removing %j', backup.id); + debug('cleanup: removing %s', backup.id); var backupIds = [].concat(backup.id, backup.dependsOn); @@ -463,8 +468,36 @@ function cleanup(callback) { }); }); }, function () { - debug('cleanup: done cleaning backups'); - callback(); + debug('cleanup: done cleaning box backups'); + + backupdb.getPaged(backupdb.BACKUP_TYPE_APP, 1, 1000, function (error, result) { + if (error) return callback(new BackupsError(BackupsError.INTERNAL_ERROR, error)); + + async.eachSeries(result, function iterator(backup, iteratorDone) { + if (referencedAppBackups.indexOf(backup.id) !== -1) return iteratorDone(); + if ((now - backup.creationTime) < (backupConfig.retentionSecs * 1000)) return iteratorDone(); + + debug('cleanup: removing %s', backup.id); + + api(backupConfig.provider).removeBackups(backupConfig, [ backup.id ], function (error) { + if (error) { + debug('cleanup: error removing backup %j : %s', backup, error.message); + iteratorDone(); + } + + backupdb.del(backup.id, function (error) { + if (error) debug('cleanup: error removing from database', error); + else debug('cleanup: removed %s', backup.id); + + iteratorDone(); + }); + }); + }, function () { + debug('cleanup: done cleaning app backups'); + + callback(); + }); + }); }); }); }); diff --git a/src/test/backups-test.js b/src/test/backups-test.js index d98a7fcef..518c94a43 100644 --- a/src/test/backups-test.js +++ b/src/test/backups-test.js @@ -14,7 +14,7 @@ var async = require('async'), expect = require('expect.js'), settings = require('../settings.js'); -describe('janitor', function () { +describe('backups', function () { before(function (done) { async.series([ database.initialize, @@ -128,9 +128,35 @@ describe('janitor', function () { expect(result.length).to.equal(1); expect(result[0].id).to.equal(BACKUP_1.id); - done(); + // check that app backups are also still there + backupdb.get(BACKUP_1_APP_0.id, function (error, result) { + expect(error).to.not.be.ok(); + expect(result.id).to.equal(BACKUP_1_APP_0.id); + + done(); + }); }); }); }); + + it('succeeds for app backups not referenced by a box backup', function (done) { + async.eachSeries([BACKUP_0_APP_0, BACKUP_0_APP_1], backupdb.add, function (error) { + expect(error).to.not.be.ok(); + + // wait for expiration + setTimeout(function () { + backups.cleanup(function (error) { + expect(error).to.not.be.ok(); + + backupdb.getPaged(backupdb.BACKUP_TYPE_APP, 1, 1000, function (error, result) { + expect(error).to.not.be.ok(); + expect(result.length).to.equal(2); + + done(); + }); + }); + }, 2000); + }); + }); }); });