diff --git a/src/cloudron.js b/src/cloudron.js index f116edc9b..b269d4e69 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -16,7 +16,6 @@ exports = module.exports = { updateToLatest: updateToLatest, update: update, reboot: reboot, - migrate: migrate, backup: backup, retire: retire, ensureBackup: ensureBackup, @@ -460,49 +459,6 @@ function reboot(callback) { shell.sudo('reboot', [ REBOOT_CMD ], callback); } -function migrate(size, region, callback) { - assert.strictEqual(typeof size, 'string'); - assert.strictEqual(typeof region, 'string'); - assert.strictEqual(typeof callback, 'function'); - - var error = locker.lock(locker.OP_MIGRATE); - if (error) return callback(new CloudronError(CloudronError.BAD_STATE, error.message)); - - function unlock(error) { - if (error) { - debug('Failed to migrate', error); - locker.unlock(locker.OP_MIGRATE); - } else { - debug('Migration initiated successfully'); - // do not unlock; cloudron is migrating - } - - return; - } - - // initiate the migration in the background - backupBoxAndApps(function (error, restoreKey) { - if (error) return unlock(error); - - debug('migrate: size %s region %s restoreKey %s', size, region, restoreKey); - - superagent - .post(config.apiServerOrigin() + '/api/v1/boxes/' + config.fqdn() + '/migrate') - .query({ token: config.token() }) - .send({ size: size, region: region, restoreKey: restoreKey }) - .end(function (error, result) { - if (error && !error.response) return unlock(error); - if (result.statusCode === 409) return unlock(new CloudronError(CloudronError.BAD_STATE)); - if (result.statusCode === 404) return unlock(new CloudronError(CloudronError.NOT_FOUND)); - if (result.statusCode !== 202) return unlock(new CloudronError(CloudronError.EXTERNAL_ERROR, util.format('%s %j', result.status, result.body))); - - return unlock(null); - }); - }); - - callback(null); -} - function update(boxUpdateInfo, callback) { assert.strictEqual(typeof boxUpdateInfo, 'object'); assert.strictEqual(typeof callback, 'function'); diff --git a/src/routes/cloudron.js b/src/routes/cloudron.js index 719c1487d..13897c119 100644 --- a/src/routes/cloudron.js +++ b/src/routes/cloudron.js @@ -10,7 +10,6 @@ exports = module.exports = { getProgress: getProgress, getConfig: getConfig, update: update, - migrate: migrate, feedback: feedback }; @@ -129,20 +128,6 @@ function update(req, res, next) { }); } -function migrate(req, res, next) { - if (typeof req.body.size !== 'string') return next(new HttpError(400, 'size must be string')); - if (typeof req.body.region !== 'string') return next(new HttpError(400, 'region must be string')); - - debug('Migration requested', req.body.size, req.body.region); - - cloudron.migrate(req.body.size, req.body.region, function (error) { - if (error && error.reason === CloudronError.BAD_STATE) return next(new HttpError(409, error.message)); - if (error) return next(new HttpError(500, error)); - - next(new HttpSuccess(202, {})); - }); -} - function feedback(req, res, next) { assert.strictEqual(typeof req.user, 'object'); diff --git a/src/routes/test/cloudron-test.js b/src/routes/test/cloudron-test.js index c4ab7a284..ae245ddbe 100644 --- a/src/routes/test/cloudron-test.js +++ b/src/routes/test/cloudron-test.js @@ -24,8 +24,8 @@ var token = null; // authentication token var server; function setup(done) { nock.cleanAll(); + config._reset(); config.set('version', '0.5.0'); - config.set('fqdn', 'localhost'); server.start(done); } @@ -33,6 +33,8 @@ function cleanup(done) { database._clear(function (error) { expect(error).to.not.be.ok(); + config._reset(); + server.stop(done); }); } @@ -258,181 +260,6 @@ describe('Cloudron', function () { }); - describe('migrate', function () { - before(function (done) { - async.series([ - setup, - - function (callback) { - var scope1 = nock(config.apiServerOrigin()).get('/api/v1/boxes/' + config.fqdn() + '/setup/verify?setupToken=somesetuptoken').reply(200, {}); - var scope2 = nock(config.apiServerOrigin()).post('/api/v1/boxes/' + config.fqdn() + '/setup/done?setupToken=somesetuptoken').reply(201, {}); - - config._reset(); - - superagent.post(SERVER_URL + '/api/v1/cloudron/activate') - .query({ setupToken: 'somesetuptoken' }) - .send({ username: USERNAME, password: PASSWORD, email: EMAIL }) - .end(function (error, result) { - expect(result).to.be.ok(); - expect(scope1.isDone()).to.be.ok(); - expect(scope2.isDone()).to.be.ok(); - - // stash token for further use - token = result.body.token; - - callback(); - }); - }, - - function setupBackupConfig(callback) { - superagent.post(SERVER_URL + '/api/v1/settings/backup_config') - .send({ provider: 'caas', token: 'BACKUP_TOKEN', bucket: 'Bucket', prefix: 'Prefix' }) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(200); - - callback(); - }); - } - - ], done); - }); - - after(cleanup); - - it('fails without token', function (done) { - superagent.post(SERVER_URL + '/api/v1/cloudron/migrate') - .send({ size: 'small', region: 'sfo'}) - .end(function (error, result) { - expect(result.statusCode).to.equal(401); - done(); - }); - }); - - it('fails without password', function (done) { - superagent.post(SERVER_URL + '/api/v1/cloudron/migrate') - .send({ size: 'small', region: 'sfo'}) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('fails with missing size', function (done) { - superagent.post(SERVER_URL + '/api/v1/cloudron/migrate') - .send({ region: 'sfo', password: PASSWORD }) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('fails with wrong size type', function (done) { - superagent.post(SERVER_URL + '/api/v1/cloudron/migrate') - .send({ size: 4, region: 'sfo', password: PASSWORD }) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('fails with missing region', function (done) { - superagent.post(SERVER_URL + '/api/v1/cloudron/migrate') - .send({ size: 'small', password: PASSWORD }) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('fails with wrong region type', function (done) { - superagent.post(SERVER_URL + '/api/v1/cloudron/migrate') - .send({ size: 'small', region: 4, password: PASSWORD }) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(400); - done(); - }); - }); - - it('fails when in wrong state', function (done) { - var scope2 = nock(config.apiServerOrigin()) - .post('/api/v1/boxes/' + config.fqdn() + '/awscredentials?token=BACKUP_TOKEN') - .reply(201, { credentials: { AccessKeyId: 'accessKeyId', SecretAccessKey: 'secretAccessKey', SessionToken: 'sessionToken' } }); - - var scope3 = nock(config.apiServerOrigin()) - .post('/api/v1/boxes/' + config.fqdn() + '/backupDone?token=APPSTORE_TOKEN', function (body) { - return body.boxVersion && body.restoreKey && !body.appId && !body.appVersion && body.appBackupIds.length === 0; - }) - .reply(200, { id: 'someid' }); - - var scope1 = nock(config.apiServerOrigin()) - .post('/api/v1/boxes/' + config.fqdn() + '/migrate?token=APPSTORE_TOKEN', function (body) { - return body.size && body.region && body.restoreKey; - }).reply(409, {}); - - injectShellMock(); - - superagent.post(SERVER_URL + '/api/v1/cloudron/migrate') - .send({ size: 'small', region: 'sfo', password: PASSWORD }) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(202); - - function checkAppstoreServerCalled() { - if (scope1.isDone() && scope2.isDone() && scope3.isDone()) { - restoreShellMock(); - return done(); - } - - setTimeout(checkAppstoreServerCalled, 100); - } - - checkAppstoreServerCalled(); - }); - }); - - it('succeeds', function (done) { - var scope1 = nock(config.apiServerOrigin()).post('/api/v1/boxes/' + config.fqdn() + '/migrate?token=APPSTORE_TOKEN', function (body) { - return body.size && body.region && body.restoreKey; - }).reply(202, {}); - - var scope2 = nock(config.apiServerOrigin()) - .post('/api/v1/boxes/' + config.fqdn() + '/backupDone?token=APPSTORE_TOKEN', function (body) { - return body.boxVersion && body.restoreKey && !body.appId && !body.appVersion && body.appBackupIds.length === 0; - }) - .reply(200, { id: 'someid' }); - - var scope3 = nock(config.apiServerOrigin()) - .post('/api/v1/boxes/' + config.fqdn() + '/awscredentials?token=BACKUP_TOKEN') - .reply(201, { credentials: { AccessKeyId: 'accessKeyId', SecretAccessKey: 'secretAccessKey', SessionToken: 'sessionToken' } }); - - injectShellMock(); - - superagent.post(SERVER_URL + '/api/v1/cloudron/migrate') - .send({ size: 'small', region: 'sfo', password: PASSWORD }) - .query({ access_token: token }) - .end(function (error, result) { - expect(result.statusCode).to.equal(202); - - function checkAppstoreServerCalled() { - if (scope1.isDone() && scope2.isDone() && scope3.isDone()) { - restoreShellMock(); - return done(); - } - - setTimeout(checkAppstoreServerCalled, 100); - } - - checkAppstoreServerCalled(); - }); - }); - }); - describe('feedback', function () { before(function (done) { async.series([ diff --git a/src/server.js b/src/server.js index 23676c62b..9fddcd8ad 100644 --- a/src/server.js +++ b/src/server.js @@ -93,7 +93,6 @@ function initializeExpressSync() { router.get ('/api/v1/cloudron/config', rootScope, routes.cloudron.getConfig); router.post('/api/v1/cloudron/update', rootScope, routes.user.requireAdmin, routes.user.verifyPassword, routes.cloudron.update); router.post('/api/v1/cloudron/reboot', rootScope, routes.cloudron.reboot); - router.post('/api/v1/cloudron/migrate', rootScope, routes.user.requireAdmin, routes.user.verifyPassword, routes.cloudron.migrate); router.get ('/api/v1/cloudron/graphs', rootScope, routes.graphs.getGraphs); // feedback