Adding node.js server

This commit is contained in:
Chris Cowan 2015-01-06 17:29:36 -07:00
parent 26fed84187
commit e6d17d0641
12 changed files with 359 additions and 0 deletions

69
src/server/app.js Normal file
View file

@ -0,0 +1,69 @@
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var compression = require('compression');
var config = require('./config');
var routes = require('./routes/index');
var proxy = require('./routes/proxy');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
// The proxy must be set up before all the other middleware.
// TODO: WE might want to move the middleware to each of the individual routes
// so we don't have weird conflicts in the future.
app.use('/elasticsearch', proxy);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(compression());
// app.use(require('less-middleware')(config.public_folder));
app.use(express.static(config.public_folder));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;

65
src/server/bin/kibana.js Executable file
View file

@ -0,0 +1,65 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('node-server:server');
var http = require('http');
var config = require('../config');
/**
* Get port from environment and store in Express.
*/
var port = parseInt(process.env.PORT, 10) || config.port || 3000;
var host = process.env.HOST || config.host || '127.0.0.1';
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port, host);
server.on('error', onError);
server.on('listening', onListening);
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error('Port ' + port + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error('Port ' + port + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var address = server.address();
debug('Listening on ' + address.address + ':' + address.port);
}

View file

@ -0,0 +1,27 @@
var _ = require('lodash');
var fs = require('fs');
var yaml = require('js-yaml');
var path = require('path');
var listPlugins = require('../lib/listPlugins');
var configPath = process.env.CONFIG_PATH || path.join(__dirname, 'kibana.yml');
var kibana = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'));
var env = process.env.NODE_ENV || 'development';
var public_folder = path.resolve(__dirname, '..', '..', 'kibana');
if (env !== 'development') {
public_folder = path.resolve(__dirname, '..', 'public');
}
var config = module.exports = {
port : kibana.port || 5601,
host : kibana.host || '0.0.0.0',
elasticsearch : kibana.elasticsearch_url || 'http : //localhost : 9200',
root : path.normalize(path.join(__dirname, '..')),
quiet : false,
public_folder : public_folder,
external_plugins_folder : process.env.PLUGINS_FOLDER || null,
bundled_plugins_folder : path.resolve(public_folder, 'plugins'),
kibana : kibana
};
config.plugins = listPlugins(config);

View file

@ -0,0 +1,38 @@
# Kibana is served by a back end server. This controls which port to use.
port: 5601
# The host to bind the server to.
host: "0.0.0.0"
# The Elasticsearch instance to use for all your queries.
elasticsearch_url: "http://localhost:9200"
# If your Elasticsearch is protected with basic auth:
# elasticsearch_username: user
# elasticsearch_password: pass
# preserve_elasticsearch_host true will send the hostname specified in `elasticsearch`. If you set it to false,
# then the host you use to connect to *this* Kibana instance will be sent.
elasticsearch_preserve_host: true
# Kibana uses an index in Elasticsearch to store saved searches, visualizations
# and dashboards. It will create a new index if it doesn't already exist.
kibana_index: ".kibana"
# The default application to load.
default_app_id: "discover"
# Time in seconds to wait for responses from the back end or elasticsearch.
# Note this should always be higher than "shard_timeout".
# This must be > 0
request_timeout: 60
# Time in milliseconds for Elasticsearch to wait for responses from shards.
# Note this should always be lower than "request_timeout".
# Set to 0 to disable (not recommended).
shard_timeout: 30000
# Set to false to have a complete disregard for the validity of the SSL
# certificate.
verify_ssl: true

View file

@ -0,0 +1,18 @@
var _ = require('lodash');
var glob = require('glob');
var path = require('path');
var plugins = function (dir) {
if (!dir) return [];
var files = glob.sync(path.join(dir, '*', 'index.js')) || [];
return files.map(function (file) {
return file.replace(dir, 'plugins').replace(/\.js$/, '');
});
};
module.exports = function (config) {
var bundled_plugins = plugins(config.bundled_plugins_folder);
var external_plugins = plugins(config.external_plugins_folder);
return bundled_plugins.concat(external_plugins);
};

47
src/server/package.json Normal file
View file

@ -0,0 +1,47 @@
{
"name": "kibana",
"description": "Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elasticsearch.",
"keywords": [
"kibana",
"elasticsearch",
"logstash",
"analytics",
"visualizations",
"dashboards",
"dashboarding"
],
"homepage": "http://www.elasticsearch.org/overview/kibana/",
"bugs": "https://github.com/elasticsearch/kibana/issues",
"license": "Apache-2.0",
"author": "Rashid Khan <rashid.khan@elasticsearch.com>",
"contributors": [
"Spencer Alger <spencer.alger@elasticsearch.com>",
"Chris Cowan <chris.cowan@elasticsearch.com>",
"Joe Fleming <joe.fleming@elasticsearch.com>",
"Lukas Olson <lukas.olson@elasticsearch.com>"
],
"version": "4.0.0-rc1",
"private": false,
"scripts": {
"start": "node ./bin/kibana.js"
},
"repository": {
"type": "git",
"url": "https://github.com/elasticsearch/kibana.git"
},
"dependencies": {
"body-parser": "~1.10.1",
"compression": "^1.3.0",
"cookie-parser": "~1.3.3",
"debug": "~2.1.1",
"express": "~4.10.6",
"glob": "^4.3.2",
"http-proxy": "^1.8.1",
"jade": "~1.8.2",
"js-yaml": "^3.2.5",
"less-middleware": "1.0.x",
"lodash": "^2.4.1",
"morgan": "~1.5.1",
"serve-favicon": "~2.2.0"
}
}

View file

@ -0,0 +1,8 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}

View file

@ -0,0 +1,18 @@
var express = require('express');
var router = express.Router();
var config = require('../config');
var _ = require('lodash');
router.get('/config', function (req, res, next) {
var excludedKeys = [
'elasticsearch_url',
'elasticsearch_username',
'elasticsearch_password',
'elasticsearch_preserve_host'
];
var data = _.omit(config.kibana, excludedKeys);
data.plugins = config.plugins;
res.json(data);
});
module.exports = router;

View file

@ -0,0 +1,51 @@
var express = require('express');
var router = module.exports = express.Router();
var httpProxy = require('http-proxy');
var config = require('../config');
var url = require('url');
var target = url.parse(config.elasticsearch);
var proxy = new httpProxy.createProxyServer();
var buffer = require('buffer');
proxy.on('proxyReq', function (proxyReq, req, res, options) {
// To support the elasticsearch_preserve_host feature we need to change the
// host header to the target host header.
if (config.kibana.elasticsearch_preserve_host) {
proxyReq.setHeader('host', target.host);
}
// Support for handling basic auth
if (config.kibana.elasticsearch_username && config.kibana.elasticsearch_password) {
var code = new buffer.Buffer(config.kibana.elasticsearch_username + ':' + config.kibana.elasticsearch_password);
var auth = 'Basic ' + code.toString('base64');
proxyReq.setHeader('authorization', auth);
}
});
// Error handling for the proxy
proxy.on('error', function (err, req, res) {
console.log(err.code, err.message);
var code = 502;
var body = { message: 'Bad Gateway' };
if (err.message === 'ECONNREFUSED') {
body.message = 'Unable to connect to Elasticsearch';
}
if (err.message === 'DEPTH_ZERO_SELF_SIGNED_CERT') {
body.message = 'SSL handshake with Elasticsearch failed';
}
res.writeHead(502, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(body));
});
router.use(function (req, res, next) {
var options = {
target: config.elasticsearch,
secure: config.kibana.verify_ssl,
xfwd: true
};
proxy.web(req, res, options);
});

View file

@ -0,0 +1,6 @@
extends layout
block content
h1= message
h2= error.status
pre #{error.stack}

View file

@ -0,0 +1,5 @@
extends layout
block content
h1= title
p Welcome to #{title}

View file

@ -0,0 +1,7 @@
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content