Fix various app state issues

Tasks initiated by repair/uninstall can run from any state
Clear taskId for failed uninstall
Clone/install can only be run on new entries
This commit is contained in:
Girish Ramakrishnan
2019-09-23 17:23:38 -07:00
parent 24dcb1b79c
commit 70b9000b0e
2 changed files with 20 additions and 14 deletions

View File

@@ -629,13 +629,13 @@ function scheduleTask(appId, installationState, task, callback) {
assert.strictEqual(typeof callback, 'function');
const { args, values } = task;
// by default, a task can only run on installed state. if it's null, it can be run on any state
const requiredState = 'requiredState' in task ? task.requiredState : exports.ISTATE_INSTALLED;
tasks.add(tasks.TASK_APP, [ appId, args ], function (error, taskId) {
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
values.error = null;
appdb.setTask(appId, _.extend({ installationState, taskId }, values), function (error) {
appdb.setTask(appId, _.extend({ installationState, taskId, error: null }, values), requiredState, function (error) {
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new AppsError(AppsError.ALREADY_EXISTS, error.message));
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.BAD_STATE, 'Another task is scheduled for this app')); // could be because app went away OR a taskId exists
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
@@ -649,7 +649,7 @@ function scheduleTask(appId, installationState, task, callback) {
boxError.details.stopped = error.code === tasks.ESTOPPED;
boxError.details.task = { args, installationState }; // see also apptask makeTaskError
appdb.update(appId, { installationState: exports.ISTATE_ERROR, error: boxError.toPlainObject(), taskId: null }, NOOP_CALLBACK);
} else if (installationState !== exports.ISTATE_PENDING_UNINSTALL) { // clear out taskId since it's done
} else if (!(installationState === exports.ISTATE_PENDING_UNINSTALL && !error)) { // clear out taskId except for successful uninstall
appdb.update(appId, { taskId: null }, NOOP_CALLBACK);
}
});
@@ -786,7 +786,8 @@ function install(data, user, auditSource, callback) {
env: env,
label: label,
tags: tags,
runState: exports.RSTATE_RUNNING
runState: exports.RSTATE_RUNNING,
installationState: exports.ISTATE_PENDING_INSTALL
};
appdb.add(appId, appStoreId, manifest, location, domain, translatePortBindings(portBindings, manifest), data, function (error) {
@@ -806,7 +807,8 @@ function install(data, user, auditSource, callback) {
const restoreConfig = backupId ? { backupId: backupId, backupFormat: backupFormat } : null;
const task = {
args: { restoreConfig, overwriteDns },
values: { }
values: { },
requiredState: exports.ISTATE_PENDING_INSTALL
};
scheduleTask(appId, exports.ISTATE_PENDING_INSTALL, task, function (error, result) {
@@ -1384,7 +1386,7 @@ function repair(appId, data, auditSource, callback) {
args.restoreConfig = data.backupId ? { backupId: data.backupId, backupFormat: data.backupFormat, oldManifest: app.manifest } : null; // when null, apptask simply reinstalls
args.overwriteDns = 'overwriteDns' in data ? data.overwriteDns : false;
scheduleTask(appId, newState, { args, values }, function (error, result) {
scheduleTask(appId, newState, { args, values, requiredState: exports.ISTATE_ERROR }, function (error, result) {
if (error) return callback(error);
eventlog.add(eventlog.ACTION_APP_REPAIR, auditSource, { taskId: result.taskId, app, newState });
@@ -1525,6 +1527,7 @@ function clone(appId, data, user, auditSource, callback) {
var data = {
installationState: exports.ISTATE_PENDING_CLONE,
runState: exports.RSTATE_RUNNING,
memoryLimit: app.memoryLimit,
accessRestriction: app.accessRestriction,
sso: !!app.sso,
@@ -1544,7 +1547,8 @@ function clone(appId, data, user, auditSource, callback) {
const restoreConfig = { backupId: backupId, backupFormat: backupInfo.format };
const task = {
args: { restoreConfig, overwriteDns },
values: {}
values: {},
requiredState: exports.ISTATE_PENDING_CLONE
};
scheduleTask(newAppId, exports.ISTATE_PENDING_CLONE, task, function (error, result) {
if (error) return callback(error);
@@ -1583,7 +1587,8 @@ function uninstall(appId, auditSource, callback) {
const task = {
args: {},
values: {}
values: {},
requiredState: null // can run in any state, as long as no task is active
};
scheduleTask(appId, exports.ISTATE_PENDING_UNINSTALL, task, function (error, result) {
if (error) return callback(error);