Add proper response for port conflicts on installation

This commit is contained in:
Johannes Zellner
2015-03-23 18:34:49 +01:00
parent bfc27c95a2
commit 69f6a6b841
3 changed files with 28 additions and 4 deletions
+2 -2
View File
@@ -174,7 +174,7 @@ function add(id, appStoreId, manifest, location, portBindings, accessRestriction
});
database.transaction(queries, function (error, results) {
if (error && error.code === 'ER_DUP_ENTRY') return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS));
if (error && error.code === 'ER_DUP_ENTRY') return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, error.message));
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
callback(null);
@@ -260,7 +260,7 @@ function updateWithConstraints(id, app, constraints, callback) {
queries.push({ query: 'INSERT INTO appPortBindings (hostPort, environmentVariable, appId) VALUES(?, ?, ?)', args: values });
});
}
var fields = [ ], values = [ ];
for (var p in app) {
if (p === 'manifest') {
+24 -1
View File
@@ -129,6 +129,7 @@ AppsError.NOT_FOUND = 'Not Found';
AppsError.BAD_FIELD = 'Bad Field';
AppsError.BAD_STATE = 'Bad State';
AppsError.PORT_RESERVED = 'Port Reserved';
AppsError.PORT_CONFLICT = 'Port Conflict';
// Hostname validation comes from RFC 1123 (section 2.1)
// Domain name validation comes from RFC 2181 (Name syntax)
@@ -187,6 +188,28 @@ function validatePortBindings(portBindings, tcpPorts) {
return null;
}
function getDuplicateErrorDetails(location, portBindings, error) {
assert(typeof location === 'string');
assert(typeof portBindings === 'object');
assert(error.reason === DatabaseError.ALREADY_EXISTS);
var match = error.message.match(/ER_DUP_ENTRY: Duplicate entry '(.*)' for key/);
if (!match) {
console.error('Unexpected SQL error message.', error);
return new AppsError(AppsError.INTERNAL_ERROR);
}
// check if the location conflicts
if (match[1] === location) return new AppsError(AppsError.ALREADY_EXISTS);
// check if any of the port bindings conflict
for (var env in portBindings) {
if (portBindings[env] === parseInt(match[1])) return new AppsError(AppsError.PORT_CONFLICT, match[1]);
}
return new AppsError(AppsError.ALREADY_EXISTS);
}
function getIconUrlSync(app) {
var iconPath = paths.APPICONS_DIR + '/' + app.id + '.png';
return fs.existsSync(iconPath) ? '/api/v1/apps/' + app.id + '/icon' : null;
@@ -288,7 +311,7 @@ function install(appId, appStoreId, manifest, location, portBindings, accessRest
debug('Will install app with id : ' + appId);
appdb.add(appId, appStoreId, manifest, location.toLowerCase(), portBindings, accessRestriction, function (error) {
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new AppsError(AppsError.ALREADY_EXISTS));
if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(getDuplicateErrorDetails(location.toLowerCase(), portBindings, error));
if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error));
stopTask(appId);
+2 -1
View File
@@ -110,8 +110,9 @@ function installApp(req, res, next) {
debug('Installing app id:%s storeid:%s loc:%s port:%j restrict:%s manifest:%j', appId, data.appStoreId, data.location, data.portBindings, data.accessRestriction, data.manifest);
apps.install(appId, data.appStoreId, data.manifest, data.location, data.portBindings, data.accessRestriction, function (error) {
if (error && error.reason === AppsError.ALREADY_EXISTS) return next(new HttpError(409, 'App already exists'));
if (error && error.reason === AppsError.ALREADY_EXISTS) return next(new HttpError(409, error.message));
if (error && error.reason === AppsError.PORT_RESERVED) return next(new HttpError(409, 'Port ' + error.message + ' is reserved.'));
if (error && error.reason === AppsError.PORT_CONFLICT) return next(new HttpError(409, 'Port ' + error.message + ' is already in use.'));
if (error && error.reason === AppsError.BAD_FIELD) return next(new HttpError(400, error.message));
if (error) return next(new HttpError(500, error));