diff --git a/src/apps.js b/src/apps.js index 77a52bfa2..cec3d5ae5 100644 --- a/src/apps.js +++ b/src/apps.js @@ -684,7 +684,8 @@ function install(data, user, auditSource, callback) { env = data.env || {}, mailboxName = data.mailboxName || '', label = data.label || null, - tags = data.tags || []; + tags = data.tags || [], + overwriteDns = 'overwriteDns' in data ? data.overwriteDns : false; assert(data.appStoreId || data.manifest); // atleast one of them is required @@ -790,7 +791,7 @@ function install(data, user, auditSource, callback) { const restoreConfig = backupId ? { backupId: backupId, backupFormat: backupFormat } : null; - scheduleTask(appId, { restoreConfig }, { installationState: exports.ISTATE_PENDING_INSTALL }, function (error, result) { + scheduleTask(appId, { restoreConfig, overwriteDns }, { installationState: exports.ISTATE_PENDING_INSTALL }, function (error, result) { if (error) return callback(error); const newApp = _.extend({ fqdn: domains.fqdn(location, domainObject) }, data, { appStoreId, manifest, location, domain, portBindings }); @@ -1329,7 +1330,7 @@ function restore(appId, data, auditSource, callback) { }; const restoreConfig = data.backupId ? { backupId: data.backupId, backupFormat: backupInfo.format, oldManifest: app.manifest } : null; // when null, apptask simply reinstalls - scheduleTask(appId, { restoreConfig }, values, function (error, result) { + scheduleTask(appId, { restoreConfig, overwriteDns: true }, values, function (error, result) { if (error) return callback(error); eventlog.add(eventlog.ACTION_APP_RESTORE, auditSource, { app: app, backupId: backupInfo.id, fromManifest: app.manifest, toManifest: backupInfo.manifest, taskId: result.taskId }); @@ -1376,7 +1377,8 @@ function clone(appId, data, user, auditSource, callback) { domain = data.domain.toLowerCase(), portBindings = data.portBindings || null, backupId = data.backupId, - mailboxName = data.mailboxName || ''; + mailboxName = data.mailboxName || '', + overwriteDns = 'overwriteDns' in data ? data.overwriteDns : false; assert.strictEqual(typeof backupId, 'string'); assert.strictEqual(typeof location, 'string'); @@ -1438,7 +1440,7 @@ function clone(appId, data, user, auditSource, callback) { const restoreConfig = { backupId: backupId, backupFormat: backupInfo.format }; - scheduleTask(newAppId, { restoreConfig }, { installationState: exports.ISTATE_PENDING_CLONE }, function (error, result) { + scheduleTask(newAppId, { restoreConfig, overwriteDns }, { installationState: exports.ISTATE_PENDING_CLONE }, function (error, result) { if (error) return callback(error); const newApp = _.extend({}, data, { appStoreId, manifest, location, domain, portBindings }); @@ -1692,7 +1694,7 @@ function restoreInstalledApps(callback) { appdb.update(app.id, { taskId: null }, function (error) { // clear any stale taskId if (error) debug(`Error marking ${app.fqdn} for restore: ${JSON.stringify(error)}`); - scheduleTask(app.id, { restoreConfig }, { installationState: exports.ISTATE_PENDING_RESTORE }, () => iteratorDone()); // always succeed + scheduleTask(app.id, { restoreConfig, overwriteDns: true }, { installationState: exports.ISTATE_PENDING_RESTORE }, () => iteratorDone()); // always succeed }); }); }, callback); diff --git a/src/apptask.js b/src/apptask.js index affc72c90..3fb0e6c69 100644 --- a/src/apptask.js +++ b/src/apptask.js @@ -491,13 +491,15 @@ function downloadImage(manifest, callback) { // - setup the container (requires image, volumes, addons) // - setup collectd (requires container id) // restore is also handled here since restore is just an install with some oldConfig to clean up -function install(app, restoreConfig, progressCallback, callback) { +function install(app, args, progressCallback, callback) { assert.strictEqual(typeof app, 'object'); - assert.strictEqual(typeof restoreConfig, 'object'); + assert.strictEqual(typeof args, 'object'); assert.strictEqual(typeof progressCallback, 'function'); assert.strictEqual(typeof callback, 'function'); const isInstalling = app.installationState !== apps.ISTATE_PENDING_RESTORE; // install or clone + const restoreConfig = args.restoreConfig || {}; + const overwriteDns = args.overwriteDns; async.series([ // this protects against the theoretical possibility of an app being marked for install/restore from @@ -534,7 +536,7 @@ function install(app, restoreConfig, progressCallback, callback) { downloadIcon.bind(null, app), progressCallback.bind(null, { percent: 30, message: 'Registering subdomains' }), - registerSubdomains.bind(null, app, !isInstalling /* overwrite */), + registerSubdomains.bind(null, app, overwriteDns), progressCallback.bind(null, { percent: 40, message: 'Downloading image' }), downloadImage.bind(null, app.manifest), @@ -1026,7 +1028,7 @@ function run(appId, args, progressCallback, callback) { debugApp(app, 'startTask installationState: %s runState: %s', app.installationState, app.runState); switch (app.installationState) { - case apps.ISTATE_PENDING_INSTALL: return install(app, args.restoreConfig || {}, progressCallback, callback); + case apps.ISTATE_PENDING_INSTALL: return install(app, args, progressCallback, callback); case apps.ISTATE_PENDING_CONFIGURE: return configure(app, args.oldConfig, progressCallback, callback); case apps.ISTATE_PENDING_RECREATE_CONTAINER: case apps.ISTATE_PENDING_RESIZE: @@ -1035,8 +1037,8 @@ function run(appId, args, progressCallback, callback) { case apps.ISTATE_PENDING_LOCATION_CHANGE: return changeLocation(app, args, progressCallback, callback); case apps.ISTATE_PENDING_DATA_DIR_MIGRATION: return migrateDataDir(app, args.oldDataDir, progressCallback, callback); case apps.ISTATE_PENDING_UNINSTALL: return uninstall(app, progressCallback, callback); - case apps.ISTATE_PENDING_CLONE: return install(app, args.restoreConfig || {}, progressCallback, callback); - case apps.ISTATE_PENDING_RESTORE: return install(app, args.restoreConfig || {}, progressCallback, callback); + case apps.ISTATE_PENDING_CLONE: return install(app, args, progressCallback, callback); + case apps.ISTATE_PENDING_RESTORE: return install(app, args, progressCallback, callback); case apps.ISTATE_PENDING_UPDATE: return update(app, args.updateConfig, progressCallback, callback); case apps.ISTATE_PENDING_BACKUP: return backup(app, progressCallback, callback); case apps.ISTATE_INSTALLED: diff --git a/src/routes/apps.js b/src/routes/apps.js index b21384a4a..7e8ae72bd 100644 --- a/src/routes/apps.js +++ b/src/routes/apps.js @@ -151,6 +151,8 @@ function installApp(req, res, next) { if (Object.keys(data.env).some(function (key) { return typeof data.env[key] !== 'string'; })) return next(new HttpError(400, 'env must contain values as strings')); } + if ('overwriteDns' in req.body && typeof req.body.overwriteDns !== 'boolean') return next(new HttpError(400, 'overwriteDns must be boolean')); + debug('Installing app :%j', data); apps.install(data, req.user, auditSource.fromRequest(req), function (error, result) { @@ -390,6 +392,8 @@ function cloneApp(req, res, next) { if (typeof data.domain !== 'string') return next(new HttpError(400, 'domain is required')); if (('portBindings' in data) && typeof data.portBindings !== 'object') return next(new HttpError(400, 'portBindings must be an object')); + if ('overwriteDns' in req.body && typeof req.body.overwriteDns !== 'boolean') return next(new HttpError(400, 'overwriteDns must be boolean')); + apps.clone(req.params.id, data, req.user, auditSource.fromRequest(req), function (error, result) { if (error) return next(toHttpError(error));