概要
Elastic Searchクラスタが内部ネットワークからしかアクセスできないようになっていて、
そのためにリバースプロキシ経由でKibanaからElastic Searchクラスタにアクセスしていた。
だけど、そのリバースプロキシが使えなくなって、コストの関係で新規サーバを構築できないからKibanaにリバースプロキシ機能を追加した。
http://${kibana domain}/proxy/${elastic search url}
という形式でkibanaにアクセスすると、
裏で
${elastic search url}
にアクセスしてElastic Search からデータを取得してくる。
環境
- OS
- Linux www4322gi 3.2.0-64-generic #97-Ubuntu SMP Wed Jun 4 22:04:21 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
- Node
ソースコード
ここ(Kibana3)とのdiff(差分)は以下。
sample/server.js
7c7,8
< events = require('events');
---
> events = require('events'),
> path = require('path');
9c10,12
< var DEFAULT_PORT = 8000;
---
> var exec = require('child_process').exec;
>
> var DEFAULT_PORT = 80;
13,14c16,20
< 'GET': createServlet(StaticServlet),
< 'HEAD': createServlet(StaticServlet)
---
> 'GET' : createServlet(StaticServlet),
> 'POST' : createServlet(StaticServlet),
> 'PUT' : createServlet(StaticServlet),
> 'HEAD' : createServlet(StaticServlet),
> 'DELETE': createServlet(StaticServlet)
85c91
<   'svg': 'image/svg+xml'
---
> 'svg': 'image/svg+xml'
87a94,116
> // Common function for getting json data from ES
> function getDataFromES(url, method, postData, successCallback, failCallback, numRetry) {
> var options = {};
> var command = '';
>
> if (method === 'DELETE') {
> command = 'curl -X DELETE --max-time 20 -H "Accept-Encoding: gzip,deflate" "' + url + '"';
> } else if (method === 'POST' || method === 'PUT') {
> command = 'curl --max-time 20 -H "Accept-Encoding: gzip,deflate" -d \'' + postData + '\' "' + url + '"';
> } else {
> command = 'curl --max-time 20 -H "Accept-Encoding: gzip,deflate" "' + url + '"';
> }
>
> exec(command, function (err, stdout, stderr) {
> if (!err) {
> successCallback(stdout);
> } else {
> if (numRetry <= 0) failCallback();
> else getDataFromES(url, method, postData, successCallback, failCallback, numRetry - 1);
> }
> });
> }
>
90,102c119,160
< var path = ('../src/' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
< return String.fromCharCode(parseInt(hex, 16));
< });
< var parts = path.split('/');
< if (parts[parts.length-1].charAt(0) === '.')
< return self.sendForbidden_(req, res, path);
< fs.stat(path, function(err, stat) {
< if (err)
< return self.sendMissing_(req, res, path);
< if (stat.isDirectory())
< return self.sendDirectory_(req, res, path);
< return self.sendFile_(req, res, path);
< });
---
>
> // Reverse Proxy
> if (/^\/proxy/.test(req.url.pathname)) {
> var reqpath = req.url.pathname.substr(7);
> var requrl = 'http://' + reqpath;
>
> // Define callback funcs
> var successCallback = function (result) {
> res.writeHead(200, {'Content-Type' : 'application/json; charset=utf-8'});
> res.end(result);
> };
> var failCallback = function () {
> res.writeHead(503, {'Content-Type' : 'application/json; charset=utf-8'});
> res.end("ERROR");
> };
>
> if (req.method === 'POST' || req.method === 'PUT') {
> var postData='';
> req.on('data', function (data) { postData += data; });
> req.on('end',function(){
> getDataFromES(requrl, 'POST', postData, successCallback, failCallback, 3);
> });
> } else {
> getDataFromES(requrl, req.method, '', successCallback, failCallback, 3);
> }
> // Normal Kibana Function
> } else {
> if (req.url.pathname === '/') req.url.pathname = '/index.html';
> var path = (__dirname + '/' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
> return String.fromCharCode(parseInt(hex, 16));
> });
> var parts = path.split('/');
> if (parts[parts.length-1].charAt(0) === '.')
> return self.sendForbidden_(req, res, path);
> fs.stat(path, function(err, stat) {
> if (err)
> return self.sendMissing_(req, res, path);
> if (stat.isDirectory())
> return self.sendDirectory_(req, res, path);
> return self.sendFile_(req, res, path);
> });
> }
完全なソースコードは
ここ。