diff --git a/dashboard/src/views/emails.js b/dashboard/src/views/emails.js index 70aefdcea..393485528 100644 --- a/dashboard/src/views/emails.js +++ b/dashboard/src/views/emails.js @@ -10,18 +10,6 @@ angular.module('Application').controller('EmailsController', ['$scope', '$locati $scope.user = Client.getUserInfo(); $scope.domains = []; - // this is required because we need to rewrite the MAIL_SERVER_NAME env var - $scope.reconfigureEmailApps = function () { - var installedApps = Client.getInstalledApps(); - for (var i = 0; i < installedApps.length; i++) { - if (!installedApps[i].manifest.addons.email) continue; - - Client.repairApp(installedApps[i].id, { }, function (error) { - if (error) console.error(error); - }); - } - }; - $scope.mailLocation = { busy: false, percent: 0, @@ -72,7 +60,6 @@ angular.module('Application').controller('EmailsController', ['$scope', '$locati $scope.mailLocation.percent = 100; $scope.mailLocation.errorMessage = data.success ? '' : data.error.message; - $scope.reconfigureEmailApps(); $scope.mailLocation.refreshTasks(); // update the tasks list dropdown return; diff --git a/src/apps.js b/src/apps.js index 0df5283ab..6a8b4a0cb 100644 --- a/src/apps.js +++ b/src/apps.js @@ -79,8 +79,8 @@ exports = module.exports = { canAutoupdateApp, autoupdateApps, - restoreInstalledApps, - configureInstalledApps, + restoreApps, + configureApps, schedulePendingTasks, restartAppsUsingAddons, @@ -2640,11 +2640,11 @@ async function getBackupDownloadStream(app, backupId) { return { stream: ps, filename }; } -async function restoreInstalledApps(options, auditSource) { +async function restoreApps(apps, options, auditSource) { + assert(Array.isArray(apps)); assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof auditSource, 'object'); - let apps = await list(); apps = apps.filter(app => app.installationState !== exports.ISTATE_ERROR); // remove errored apps. let them be 'repaired' by hand apps = apps.filter(app => app.installationState !== exports.ISTATE_PENDING_RESTORE); // safeguard against tasks being created non-stop if we crash on startup @@ -2668,34 +2668,37 @@ async function restoreInstalledApps(options, auditSource) { requireNullTaskId: false // ignore existing stale taskId }; - debug(`restoreInstalledApps: marking ${app.fqdn} for restore using restore config ${JSON.stringify(restoreConfig)}`); + debug(`restoreApps: marking ${app.fqdn} for restore using restore config ${JSON.stringify(restoreConfig)}`); const [addTaskError, taskId] = await safe(addTask(app.id, installationState, task, auditSource)); - if (addTaskError) debug(`restoreInstalledApps: error marking ${app.fqdn} for restore: ${JSON.stringify(addTaskError)}`); - else debug(`restoreInstalledApps: marked ${app.id} for restore with taskId ${taskId}`); + if (addTaskError) debug(`restoreApps: error marking ${app.fqdn} for restore: ${JSON.stringify(addTaskError)}`); + else debug(`restoreApps: marked ${app.id} for restore with taskId ${taskId}`); } } -async function configureInstalledApps(apps, auditSource) { +async function configureApps(apps, options, auditSource) { assert(Array.isArray(apps)); + assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof auditSource, 'object'); apps = apps.filter(app => app.installationState !== exports.ISTATE_ERROR); // remove errored apps. let them be 'repaired' by hand apps = apps.filter(app => app.installationState !== exports.ISTATE_PENDING_CONFIGURE); // safeguard against tasks being created non-stop if we crash on startup + const scheduleNow = !!options.scheduleNow; + for (const app of apps) { - debug(`configureInstalledApps: marking ${app.fqdn} for reconfigure`); + debug(`configureApps: marking ${app.fqdn} for reconfigure (scheduleNow: ${scheduleNow})`); const task = { args: {}, values: {}, - scheduleNow: false, // task will be scheduled by autoRestartTasks when platform is ready + scheduleNow, requireNullTaskId: false // ignore existing stale taskId }; const [addTaskError, taskId] = await safe(addTask(app.id, exports.ISTATE_PENDING_CONFIGURE, task, auditSource)); - if (addTaskError) debug(`configureInstalledApps: error marking ${app.fqdn} for configure: ${JSON.stringify(addTaskError)}`); - else debug(`configureInstalledApps: marked ${app.id} for re-configure with taskId ${taskId}`); + if (addTaskError) debug(`configureApps: error marking ${app.fqdn} for configure: ${JSON.stringify(addTaskError)}`); + else debug(`configureApps: marked ${app.id} for re-configure with taskId ${taskId}`); } } diff --git a/src/apptaskmanager.js b/src/apptaskmanager.js index a1df3c908..3686eded1 100644 --- a/src/apptaskmanager.js +++ b/src/apptaskmanager.js @@ -44,7 +44,7 @@ function scheduleTask(appId, taskId, options, onFinished) { if (!gInitialized) initializeSync(); if (appId in gActiveTasks) { - return onFinished(new BoxError(BoxError.CONFLICT, `Task for %s is already active: ${appId}`)); + return onFinished(new BoxError(BoxError.CONFLICT, `Task for ${appId} is already active`)); } if (Object.keys(gActiveTasks).length >= TASK_CONCURRENCY) { diff --git a/src/mailserver.js b/src/mailserver.js index f3da689f6..0eaa62207 100644 --- a/src/mailserver.js +++ b/src/mailserver.js @@ -38,6 +38,7 @@ const assert = require('assert'), os = require('os'), path = require('path'), paths = require('./paths.js'), + platform = require('./platform.js'), reverseProxy = require('./reverseproxy.js'), safe = require('safetydance'), services = require('./services.js'), @@ -282,8 +283,8 @@ async function changeLocation(auditSource, progressCallback) { } progressCallback({ percent: 90, message: 'Restarting mail server' }); - await restartIfActivated(); + await platform.onMailServerLocationChanged(); } async function setLocation(subdomain, domain) { diff --git a/src/platform.js b/src/platform.js index e9436a538..9086a5b53 100644 --- a/src/platform.js +++ b/src/platform.js @@ -6,6 +6,7 @@ exports = module.exports = { onActivated, onDashboardLocationChanged, + onMailServerLocationChanged, getStatus }; @@ -93,12 +94,12 @@ async function markApps(existingInfra, restoreOptions) { assert.strictEqual(typeof restoreOptions, 'object'); if (existingInfra.version === 'none') { // cloudron is being restored from backup - debug('markApps: restoring installed apps'); - await apps.restoreInstalledApps(restoreOptions, AuditSource.PLATFORM); + debug('markApps: restoring apps'); + await apps.restoreApps(await apps.list(), restoreOptions, AuditSource.PLATFORM); } else if (existingInfra.version !== infra.version) { - debug('markApps: reconfiguring installed apps'); + debug('markApps: reconfiguring apps'); reverseProxy.removeAppConfigs(); // should we change the cert location, nginx will not start - await apps.configureInstalledApps(await apps.list(), AuditSource.PLATFORM); + await apps.configureApps(await apps.list(), { scheduleNow: false }, AuditSource.PLATFORM); // we will schedule it when infra is ready } else { let changedAddons = []; if (infra.images.mysql !== existingInfra.images.mysql) changedAddons.push('mysql'); @@ -235,10 +236,18 @@ async function onDashboardLocationChanged(auditSource) { // mark apps using oidc addon to be reconfigured const [, installedApps] = await safe(apps.list()); - await safe(apps.configureInstalledApps(installedApps.filter((a) => !!a.manifest.addons.oidc), auditSource)); + await safe(apps.configureApps(installedApps.filter((a) => !!a.manifest.addons?.oidc), { scheduleNow: true }, auditSource)); await safe(services.rebuildService('turn', auditSource), { debug }); // to update the realm variable await oidc.stop(); await oidc.start(); } + +async function onMailServerLocationChanged(auditSource) { + assert.strictEqual(typeof auditSource, 'object'); + + // mark apps using email addon to be reconfigured + const [, installedApps] = await safe(apps.list()); + await safe(apps.configureApps(installedApps.filter((a) => !!a.manifest.addons?.email), { scheduleNow: true }, auditSource)); +} diff --git a/src/test/apps-test.js b/src/test/apps-test.js index 8fa451f42..74285a698 100644 --- a/src/test/apps-test.js +++ b/src/test/apps-test.js @@ -342,7 +342,7 @@ describe('Apps', function () { }); }); - describe('configureInstalledApps', function () { + describe('configureApps', function () { const app1 = Object.assign({}, app, { id: 'id1', installationState: apps.ISTATE_ERROR, subdomain: 'loc1' }); const app2 = Object.assign({}, app, { id: 'id2', installationState: apps.ISTATE_INSTALLED, subdomain: 'loc2' }); @@ -358,7 +358,7 @@ describe('Apps', function () { }); it('can mark apps for reconfigure', async function () { - await apps.configureInstalledApps(await apps.list(), AuditSource.PLATFORM); + await apps.configureApps(await apps.list(), { scheduleNow: false }, AuditSource.PLATFORM); const result = await apps.list(); expect(result[0].installationState).to.be(apps.ISTATE_PENDING_CONFIGURE); @@ -367,7 +367,7 @@ describe('Apps', function () { }); }); - describe('restoreInstalledApps', function () { + describe('restoreApps', function () { const app1 = Object.assign({}, app, { id: 'id1', installationState: apps.ISTATE_ERROR, subdomain: 'loc1' }); const app2 = Object.assign({}, app, { id: 'id2', installationState: apps.ISTATE_INSTALLED, subdomain: 'loc2' }); @@ -383,7 +383,7 @@ describe('Apps', function () { }); it('can mark apps for reconfigure', async function () { - await apps.restoreInstalledApps({}, AuditSource.PLATFORM); + await apps.restoreApps(await apps.list(), { scheduleNow: false }, AuditSource.PLATFORM); const result = await apps.list(); expect(result[0].installationState).to.be(apps.ISTATE_PENDING_INSTALL);