diff --git a/src/addons.js b/src/addons.js index 94f715903..5469736e6 100644 --- a/src/addons.js +++ b/src/addons.js @@ -1,8 +1,6 @@ 'use strict'; exports = module.exports = { - AddonsError: AddonsError, - getServices: getServices, getService: getService, configureService: configureService, @@ -64,31 +62,6 @@ var accesscontrol = require('./accesscontrol.js'), request = require('request'), util = require('util'); -// http://dustinsenos.com/articles/customErrorsInNode -// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi -function AddonsError(reason, errorOrMessage) { - assert.strictEqual(typeof reason, 'string'); - assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined'); - - Error.call(this); - Error.captureStackTrace(this, this.constructor); - - this.name = this.constructor.name; - this.reason = reason; - if (typeof errorOrMessage === 'undefined') { - this.message = reason; - } else if (typeof errorOrMessage === 'string') { - this.message = errorOrMessage; - } else { - this.message = 'Internal error'; - this.nestedError = errorOrMessage; - } -} -util.inherits(AddonsError, Error); -AddonsError.INTERNAL_ERROR = 'Internal Error'; -AddonsError.NOT_FOUND = 'Not Found'; -AddonsError.NOT_ACTIVE = 'Not Active'; - const NOOP = function (app, options, callback) { return callback(); }; const NOOP_CALLBACK = function (error) { if (error) debug(error); }; const RMADDONDIR_CMD = path.join(__dirname, 'scripts/rmaddondir.sh'); @@ -267,14 +240,14 @@ function restartContainer(serviceName, callback) { assert(KNOWN_SERVICES[serviceName], `Unknown service ${serviceName}`); docker.stopContainer(serviceName, function (error) { - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); docker.startContainer(serviceName, function (error) { if (error && error.reason === BoxError.NOT_FOUND) { callback(null); // callback early since rebuilding takes long return rebuildService(serviceName, function (error) { if (error) console.error(`Unable to rebuild service ${serviceName}`, error); }); } - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null); }); @@ -305,19 +278,18 @@ function getServiceDetails(containerName, tokenEnvName, callback) { assert.strictEqual(typeof callback, 'function'); docker.inspect(containerName, function (error, result) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(new AddonsError(AddonsError.NOT_ACTIVE, error)); - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); const ip = safe.query(result, 'NetworkSettings.Networks.cloudron.IPAddress', null); - if (!ip) return callback(new AddonsError(AddonsError.NOT_ACTIVE, `Error getting ${containerName} container ip`)); + if (!ip) return callback(new BoxError(BoxError.INACTIVE, `Error getting ${containerName} container ip`)); // extract the cloudron token for auth const env = safe.query(result, 'Config.Env', null); - if (!env) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, `Error getting ${containerName} env`)); + if (!env) return callback(new BoxError(BoxError.DOCKER_ERROR, `Error getting ${containerName} env`)); const tmp = env.find(function (e) { return e.indexOf(tokenEnvName) === 0; }); - if (!tmp) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, `Error getting ${containerName} cloudron token env var`)); + if (!tmp) return callback(new BoxError(BoxError.DOCKER_ERROR, `Error getting ${containerName} cloudron token env var`)); const token = tmp.slice(tokenEnvName.length + 1); // +1 for the = sign - if (!token) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, `Error getting ${containerName} cloudron token`)); + if (!token) return callback(new BoxError(BoxError.DOCKER_ERROR, `Error getting ${containerName} cloudron token`)); callback(null, { ip: ip, token: token, state: result.State }); }); @@ -329,7 +301,7 @@ function containerStatus(addonName, addonTokenName, callback) { assert.strictEqual(typeof callback, 'function'); getServiceDetails(addonName, addonTokenName, function (error, addonDetails) { - if (error && error.reason === AddonsError.NOT_ACTIVE) return callback(null, { status: exports.SERVICE_STATUS_STOPPED }); + if (error && error.reason === BoxError.NOT_FOUND) return callback(null, { status: exports.SERVICE_STATUS_STOPPED }); if (error) return callback(error); request.get(`https://${addonDetails.ip}:3000/healthcheck?access_token=${addonDetails.token}`, { json: true, rejectUnauthorized: false }, function (error, response) { @@ -337,7 +309,7 @@ function containerStatus(addonName, addonTokenName, callback) { if (response.statusCode !== 200 || !response.body.status) return callback(null, { status: exports.SERVICE_STATUS_STARTING, error: `Error waiting for ${addonName}. Status code: ${response.statusCode} message: ${response.body.message}` }); docker.memoryUsage(addonName, function (error, result) { - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); var tmp = { status: addonDetails.state.Running ? exports.SERVICE_STATUS_ACTIVE : exports.SERVICE_STATUS_STOPPED, @@ -363,7 +335,7 @@ function getService(serviceName, callback) { assert.strictEqual(typeof serviceName, 'string'); assert.strictEqual(typeof callback, 'function'); - if (!KNOWN_SERVICES[serviceName]) return callback(new AddonsError(AddonsError.NOT_FOUND)); + if (!KNOWN_SERVICES[serviceName]) return callback(new BoxError(BoxError.NOT_FOUND)); var tmp = { name: serviceName, @@ -376,7 +348,7 @@ function getService(serviceName, callback) { }; settings.getPlatformConfig(function (error, platformConfig) { - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); if (platformConfig[serviceName] && platformConfig[serviceName].memory && platformConfig[serviceName].memorySwap) { tmp.config.memory = platformConfig[serviceName].memory; @@ -404,10 +376,10 @@ function configureService(serviceName, data, callback) { assert.strictEqual(typeof data, 'object'); assert.strictEqual(typeof callback, 'function'); - if (!KNOWN_SERVICES[serviceName]) return callback(new AddonsError(AddonsError.NOT_FOUND)); + if (!KNOWN_SERVICES[serviceName]) return callback(new BoxError(BoxError.NOT_FOUND)); settings.getPlatformConfig(function (error, platformConfig) { - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); if (!platformConfig[serviceName]) platformConfig[serviceName] = {}; @@ -420,7 +392,7 @@ function configureService(serviceName, data, callback) { } settings.setPlatformConfig(platformConfig, function (error) { - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null); }); @@ -436,7 +408,7 @@ function getServiceLogs(serviceName, options, callback) { assert.strictEqual(typeof options.format, 'string'); assert.strictEqual(typeof options.follow, 'boolean'); - if (!KNOWN_SERVICES[serviceName]) return callback(new AddonsError(AddonsError.NOT_FOUND)); + if (!KNOWN_SERVICES[serviceName]) return callback(new BoxError(BoxError.NOT_FOUND)); debug(`Getting logs for ${serviceName}`); @@ -495,7 +467,7 @@ function restartService(serviceName, callback) { assert.strictEqual(typeof serviceName, 'string'); assert.strictEqual(typeof callback, 'function'); - if (!KNOWN_SERVICES[serviceName]) return callback(new AddonsError(AddonsError.NOT_FOUND)); + if (!KNOWN_SERVICES[serviceName]) return callback(new BoxError(BoxError.NOT_FOUND)); KNOWN_SERVICES[serviceName].restart(callback); } @@ -1805,10 +1777,10 @@ function statusSftp(callback) { docker.inspect('sftp', function (error, container) { if (error && error.reason === BoxError.NOT_FOUND) return callback(null, { status: exports.SERVICE_STATUS_STOPPED }); - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); docker.memoryUsage('sftp', function (error, result) { - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); var tmp = { status: container.State.Running ? exports.SERVICE_STATUS_ACTIVE : exports.SERVICE_STATUS_STOPPED, @@ -1826,14 +1798,14 @@ function statusGraphite(callback) { docker.inspect('graphite', function (error, container) { if (error && error.reason === BoxError.NOT_FOUND) return callback(null, { status: exports.SERVICE_STATUS_STOPPED }); - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); request.get('http://127.0.0.1:8417/graphite-web/dashboard', { timeout: 3000 }, function (error, response) { if (error) return callback(null, { status: exports.SERVICE_STATUS_STARTING, error: `Error waiting for graphite: ${error.message}` }); if (response.statusCode !== 200) return callback(null, { status: exports.SERVICE_STATUS_STARTING, error: `Error waiting for graphite. Status code: ${response.statusCode} message: ${response.body.message}` }); docker.memoryUsage('graphite', function (error, result) { - if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error)); + if (error) return callback(error); var tmp = { status: container.State.Running ? exports.SERVICE_STATUS_ACTIVE : exports.SERVICE_STATUS_STOPPED, diff --git a/src/boxerror.js b/src/boxerror.js index 484515871..39c61476d 100644 --- a/src/boxerror.js +++ b/src/boxerror.js @@ -43,6 +43,7 @@ BoxError.DNS_ERROR = 'DNS Error'; BoxError.DOCKER_ERROR = 'Docker Error'; BoxError.EXTERNAL_ERROR = 'External Error'; // use this for external API errors BoxError.FS_ERROR = 'FileSystem Error'; +BoxError.INACTIVE = 'Inactive'; BoxError.INTERNAL_ERROR = 'Internal Error'; BoxError.LICENSE_ERROR = 'License Error'; BoxError.LOGROTATE_ERROR = 'Logrotate Error'; diff --git a/src/externalldap.js b/src/externalldap.js index 4c47fae28..48fbe246b 100644 --- a/src/externalldap.js +++ b/src/externalldap.js @@ -96,9 +96,9 @@ function testConfig(config, callback) { client.search(config.baseDn, opts, function (error, result) { if (error) return callback(new ExternalLdapError(ExternalLdapError.EXTERNAL_ERROR, error)); - result.on('searchEntry', function (entry) {}); - result.on('error', function (error) { callback(new ExternalLdapError(ExternalLdapError.BAD_FIELD, 'Unable to search directory')); }); - result.on('end', function (result) { callback(); }); + result.on('searchEntry', function (/* entry */) {}); + result.on('error', function (error) { callback(new ExternalLdapError(ExternalLdapError.BAD_FIELD, `Unable to search directory: ${error.message}`)); }); + result.on('end', function (/* result */) { callback(); }); }); }); } diff --git a/src/routes/services.js b/src/routes/services.js index 32fa8e886..12f921733 100644 --- a/src/routes/services.js +++ b/src/routes/services.js @@ -10,17 +10,26 @@ exports = module.exports = { }; var addons = require('../addons.js'), - AddonsError = addons.AddonsError, assert = require('assert'), + BoxError = require('../boxerror.js'), debug = require('debug')('box:routes/addons'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess; +function toHttpError(error) { + switch (error.reason) { + case BoxError.NOT_FOUND: + return new HttpError(404, error); + default: + return new HttpError(500, error); + } +} + function getAll(req, res, next) { req.clearTimeout(); // can take a while to get status of all services addons.getServices(function (error, result) { - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(200, { services: result })); }); @@ -30,8 +39,7 @@ function get(req, res, next) { assert.strictEqual(typeof req.params.service, 'string'); addons.getService(req.params.service, function (error, result) { - if (error && error.reason === AddonsError.NOT_FOUND) return next(new HttpError(404, 'No such service')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(200, { service: result })); }); @@ -48,8 +56,7 @@ function configure(req, res, next) { }; addons.configureService(req.params.service, data, function (error) { - if (error && error.reason === AddonsError.NOT_FOUND) return next(new HttpError(404, 'No such service')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(202, {})); }); @@ -70,8 +77,7 @@ function getLogs(req, res, next) { }; addons.getServiceLogs(req.params.service, options, function (error, logStream) { - if (error && error.reason === AddonsError.NOT_FOUND) return next(new HttpError(404, 'No such service')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); res.writeHead(200, { 'Content-Type': 'application/x-logs', @@ -103,8 +109,7 @@ function getLogStream(req, res, next) { }; addons.getServiceLogs(req.params.service, options, function (error, logStream) { - if (error && error.reason === AddonsError.NOT_FOUND) return next(new HttpError(404, 'No such service')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); res.writeHead(200, { 'Content-Type': 'text/event-stream', @@ -130,7 +135,7 @@ function restart(req, res, next) { debug(`Restarting service ${req.params.service}`); addons.restartService(req.params.service, function (error) { - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(202, {})); });