diff --git a/src/apps.js b/src/apps.js index 776649158..5bcea4f8b 100644 --- a/src/apps.js +++ b/src/apps.js @@ -33,6 +33,7 @@ exports = module.exports = { repair: repair, restore: restore, + importApp: importApp, clone: clone, update: update, @@ -726,8 +727,6 @@ function install(data, user, auditSource, callback) { debugMode = data.debugMode || null, enableBackup = 'enableBackup' in data ? data.enableBackup : true, enableAutomaticUpdate = 'enableAutomaticUpdate' in data ? data.enableAutomaticUpdate : true, - backupId = data.backupId || null, - backupFormat = data.backupFormat || 'tgz', alternateDomains = data.alternateDomains || [], env = data.env || {}, mailboxName = data.mailboxName || '', @@ -757,8 +756,6 @@ function install(data, user, auditSource, callback) { error = validateDebugMode(debugMode); if (error) return callback(error); - error = validateBackupFormat(backupFormat); - if (error) return callback(error); error = validateLabel(label); if (error) return callback(error); @@ -814,7 +811,7 @@ function install(data, user, auditSource, callback) { label: label, tags: tags, runState: exports.RSTATE_RUNNING, - installationState: backupId ? exports.ISTATE_PENDING_RESTORE : exports.ISTATE_PENDING_INSTALL + installationState: exports.ISTATE_PENDING_INSTALL }; appdb.add(appId, appStoreId, manifest, location, domain, translatePortBindings(portBindings, manifest), data, function (error) { @@ -831,9 +828,8 @@ function install(data, user, auditSource, callback) { if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, 'Error setting cert: ' + error.message)); } - const restoreConfig = backupId ? { backupId: backupId, backupFormat: backupFormat } : null; const task = { - args: { restoreConfig, overwriteDns }, + args: { restoreConfig: null, overwriteDns }, values: { }, requiredState: data.installationState }; @@ -1489,6 +1485,43 @@ function restore(appId, data, auditSource, callback) { }); } +function importApp(appId, data, auditSource, callback) { + assert.strictEqual(typeof appId, 'string'); + assert.strictEqual(typeof data, 'object'); + assert.strictEqual(typeof auditSource, 'object'); + assert.strictEqual(typeof callback, 'function'); + + debug('Will import app with id:%s', appId); + + get(appId, function (error, app) { + if (error) return callback(error); + + error = validateBackupFormat(data.backupFormat); + if (error) return callback(error); + + error = checkAppState(app, exports.ISTATE_PENDING_RESTORE); + if (error) return callback(error); + + // TODO: check if the file exists in the storage backend + const restoreConfig = { backupId: data.backupId, backupFormat: data.backupFormat, oldManifest: app.manifest }; + + const task = { + args: { + restoreConfig, + overwriteDns: true + }, + values: {} + }; + addTask(appId, exports.ISTATE_PENDING_RESTORE, task, function (error, result) { + if (error) return callback(error); + + eventlog.add(eventlog.ACTION_APP_RESTORE, auditSource, { app: app, backupId: data.backupId, fromManifest: app.manifest, toManifest: app.manifest, taskId: result.taskId }); + + callback(null, { taskId: result.taskId }); + }); + }); +} + function purchaseApp(data, callback) { assert.strictEqual(typeof data, 'object'); assert.strictEqual(typeof callback, 'function'); diff --git a/src/routes/apps.js b/src/routes/apps.js index 05f5e8708..c6ee76866 100644 --- a/src/routes/apps.js +++ b/src/routes/apps.js @@ -7,6 +7,7 @@ exports = module.exports = { installApp: installApp, uninstallApp: uninstallApp, restoreApp: restoreApp, + importApp: importApp, backupApp: backupApp, updateApp: updateApp, getLogs: getLogs, @@ -121,9 +122,6 @@ function installApp(req, res, next) { if (('portBindings' in data) && typeof data.portBindings !== 'object') return next(new HttpError(400, 'portBindings must be an object')); if ('icon' in data && typeof data.icon !== 'string') return next(new HttpError(400, 'icon is not a string')); - if (data.backupId && typeof data.backupId !== 'string') return next(new HttpError(400, 'backupId must be string or null')); - if (data.backupFormat && typeof data.backupFormat !== 'string') return next(new HttpError(400, 'backupFormat must be string or null')); - if ('label' in data && typeof data.label !== 'string') return next(new HttpError(400, 'label must be a string')); // falsy values in cert and key unset the cert @@ -407,6 +405,24 @@ function restoreApp(req, res, next) { }); } +function importApp(req, res, next) { + assert.strictEqual(typeof req.body, 'object'); + assert.strictEqual(typeof req.params.id, 'string'); + + var data = req.body; + + debug('Importing app id:%s', req.params.id); + + if (typeof data.backupId !== 'string') return next(new HttpError(400, 'backupId must be string')); + if (typeof data.backupFormat !== 'string') return next(new HttpError(400, 'backupFormat must be string')); + + apps.importApp(req.params.id, data, auditSource.fromRequest(req), function (error, result) { + if (error) return next(toHttpError(error)); + + next(new HttpSuccess(202, { taskId: result.taskId })); + }); +} + function cloneApp(req, res, next) { assert.strictEqual(typeof req.body, 'object'); assert.strictEqual(typeof req.params.id, 'string'); diff --git a/src/server.js b/src/server.js index 3ee30d52c..76bfedd73 100644 --- a/src/server.js +++ b/src/server.js @@ -258,6 +258,7 @@ function initializeExpressSync() { router.post('/api/v1/apps/:id/update', appsManageScope, routes.apps.updateApp); router.post('/api/v1/apps/:id/restore', appsManageScope, routes.apps.restoreApp); + router.post('/api/v1/apps/:id/import', appsManageScope, routes.apps.importApp); router.post('/api/v1/apps/:id/backup', appsManageScope, routes.apps.backupApp); router.get ('/api/v1/apps/:id/backups', appsManageScope, routes.apps.listBackups); router.post('/api/v1/apps/:id/stop', appsManageScope, routes.apps.stopApp);