ズッキーニのプログラミング実験場

プログラミング + アカデミック + 何か面白いこと。 記載されているものは基本的に私が所属する団体とは関係がありません。

   Sep 13

[Node.js][Kibana]リバースプロキシ機能を追加してみた

by zuqqhi2 at 2014年9月13日
Pocket

概要

Elastic Searchクラスタが内部ネットワークからしかアクセスできないようになっていて、
そのためにリバースプロキシ経由でKibanaからElastic Searchクラスタにアクセスしていた。
だけど、そのリバースプロキシが使えなくなって、コストの関係で新規サーバを構築できないからKibanaにリバースプロキシ機能を追加した。

http://${kibana domain}/proxy/${elastic search url}
という形式でkibanaにアクセスすると、
裏で
${elastic search url}
にアクセスしてElastic Search からデータを取得してくる。

20140912_Kibana_ReverseProxy

環境

  • 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
    • version: v0.10.26

ソースコード

ここ(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);
>     });
>   }

完全なソースコードはここ

Related Posts

Pocket

You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.