diff --git a/src/backups.js b/src/backups.js index 1451d8cf0..a6b47f5b2 100644 --- a/src/backups.js +++ b/src/backups.js @@ -470,32 +470,41 @@ function cleanup(callback) { }, function () { debug('cleanup: done cleaning box backups'); - backupdb.getPaged(backupdb.BACKUP_TYPE_APP, 1, 1000, function (error, result) { + apps.getAll(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(); + result.forEach(function (app) { + if (!app.lastBackupId) return; + referencedAppBackups.push(app.lastBackupId); + }); - debug('cleanup: removing %s', backup.id); + backupdb.getPaged(backupdb.BACKUP_TYPE_APP, 1, 1000, function (error, result) { + if (error) return callback(new BackupsError(BackupsError.INTERNAL_ERROR, error)); - api(backupConfig.provider).removeBackups(backupConfig, [ backup.id ], function (error) { - if (error) { - debug('cleanup: error removing backup %j : %s', backup, error.message); - iteratorDone(); - } + async.eachSeries(result, function iterator(backup, iteratorDone) { + if (referencedAppBackups.indexOf(backup.id) !== -1) return iteratorDone(); + if ((now - backup.creationTime) < (backupConfig.retentionSecs * 1000)) return iteratorDone(); - backupdb.del(backup.id, function (error) { - if (error) debug('cleanup: error removing from database', error); - else debug('cleanup: removed %s', backup.id); + debug('cleanup: removing %s', backup.id); - iteratorDone(); + 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'); + }, function () { + debug('cleanup: done cleaning app backups'); - callback(); + callback(); + }); }); }); }); diff --git a/src/test/backups-test.js b/src/test/backups-test.js index 518c94a43..13dacaf88 100644 --- a/src/test/backups-test.js +++ b/src/test/backups-test.js @@ -7,6 +7,7 @@ 'use strict'; var async = require('async'), + appdb = require('../appdb.js'), backupdb = require('../backupdb.js'), backups = require('../backups.js'), database = require('../database'), @@ -158,5 +159,55 @@ describe('backups', function () { }, 2000); }); }); + + it('succeeds for app backups not referenced by a box backup or app', function (done) { + var APP_0 = { + id: 'appid-0', + appStoreId: 'appStoreId-0', + dnsRecordId: null, + installationState: appdb.ISTATE_PENDING_INSTALL, + installationProgress: null, + runState: null, + location: 'some-location-0', + manifest: { version: '0.1', dockerImage: 'docker/app0', healthCheckPath: '/', httpPort: 80, title: 'app0' }, + httpPort: null, + containerId: null, + portBindings: { port: 5678 }, + health: null, + accessRestriction: null, + lastBackupId: null, + oldConfig: null, + memoryLimit: 4294967296, + altDomain: null, + xFrameOptions: 'DENY', + sso: true, + debugMode: null + }; + + 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 () { + // now reference one backup + APP_0.lastBackupId = BACKUP_0_APP_0.id; + + appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.portBindings, APP_0, function (error) { + expect(error).to.not.be.ok(); + + 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(3); + + done(); + }); + }); + }); + }, 2000); + }); + }); }); });