読者です 読者をやめる 読者になる 読者になる

apacheのtrunk版で mod_luaを動かして遊んでみたログ

apacheの2.4系から Luaでapacheのフックを制御できる mod_luaモジュールが入るというネタを見かけたので、svnのtrunk版(2.3.*) を引っ張って試してみました。
(元々 mod_wombatという名前で開発されてたモジュールが2.4系からはmod_luaとしてリリースされるって経緯ぽい。ドキュメントはこちら)

現状のmod_luaでサポートしてるApacheのフックは下記の通りになります。

  • ap_hook_translate_name
  • ap_hook_map_to_storage
  • ap_hook_header_parser
  • ap_hook_access_checker
  • ap_hook_check_user_id
  • ap_hook_auth_checker
  • ap_hook_type_checker
  • ap_hook_fixups
  • ap_hook_insert_filter(未実装)

これらのフックにLuaのコードを噛ませていろいろ制御できる、という感じです。

ざっくり触った感じだと

  • Aapacheモジュールのプロトタイプすぐ作れるお手軽感
  • server_recとかconn_recはいじれない(ぽい)ので、本気な機能作るのだと どうなのかなっていう。
  • というあたりでシンプルな機能つくる時にはちょいちょい利用してみたい

という感想です。Luaのフットワーク軽さを生かしつつ使えという感じなんでしょうか

実際に入れてみるよ

( 以下はosxでの作業ログをまとめたものになります )

Lua入れる
  • Luaはportで入れる方法もあります
$ wget http://www.lua.org/ftp/lua-5.1.4.tar.gz
$ tar xvfz lua-5.1.4.tar.gz       
$ cd lua-5.1.4                    
$ make macosx && sudo make install  
apacheのtrunk入れる

オプションは適当

# mod_lua用 ( だったはず.. )
$ wget 'http://downloads.sourceforge.net/sourceforge/pcre/pcre-7.9.tar.bz2?use_mirror=jaist'
$ tar xvfj pcre-7.9.tar.bz2      
$ cd pcre-7.9          
$ ./configure && make  && sudo make install

$ svn checkout http://svn.apache.org/repos/asf/httpd/httpd/trunk httpd-trunk
$ cd httpd-trunk
$ svn co http://svn.apache.org/repos/asf/apr/apr/trunk srclib/apr
$ svn co http://svn.apache.org/repos/asf/apr/apr-util/trunk srclib/apr-util
$ ./buildconf
$ ./configure --with-included-apr --with-lua=/usr/local --enable-mods-shared=all --enable-lua --with-mpm=worker --enable-so
$ make -j2
 
テスト

とりあえず動くかどうかのテスト。ログに"hello, this is test_hook"と出てればok

<LuaHookTranslateName test_hook>
function test_hook(r)
  r:info("hello, this is test_hook");
  return apache2.DECLINED
end
</LuaHookTranslateName>

セクションの中にLuaのコードを書けるのが新鮮ですね!

ホスト名に応じてDocumentRootをMySQLから引っ張ってきてマッピングするコード

これだけだとあまりに残念な紹介なんで、livedoorのいけべさんが昔公開されてたmod_vhost_mysqlの機能をmod_luaで真似してみます。以下の用な設定でいけます。

  • LuaからMySQL扱えるようにする
# luarocksとかいうrubyのgem的なツールを入れる
$ wget http://luaforge.net/frs/download.php/3981/luarocks-1.0.1.tar.gz
$ tar xvfz luarocks-1.0.1.tar.gz
$ cd luarocks-1.0.1
$ ./configure && make && sudo make install

# luaでmysqlするluasql.mysqlを入れる
$ sudo luarocks install http://luarocks.randomba.org/luasql-mysql-2.1.1.rockspec
  • httpd.conf
    • httpd.confにLuaのコードを書かないでLuaコードを任意のファイルに書くための設定
LuaRoot      /usr/local/apache2/scripts/lua
LuaCodeCache stat
LuaScope     once
LuaHookTranslateName mysql_vhost.lua mysql_vhost
  • /usr/local/apache2/scripts/lua/mod_vhost.lua
    • 実戦で使うならキャッシュとかいろいろ考えることあるけど、コンセプトってことでざっくり
require 'luarocks.require'
require 'luasql.mysql'

dbuser = "root"
dbname = "test"
dbhost = "localhost"
dbpass = nil

-- ここがエントリポイント
-- rは request_rec
function mysql_vhost(r)
   local root

   root = find_document_root(r.hostname)
   if root then
      r.filename = root .. r.uri
      return apache2.OK
   else
      r:err("DocumentRoot Not Found For " .. r.hostname)
      return 500
   end
end

-- mysqlからDocumentRoot引っ張ってくる
function find_document_root(hostname)
   local root, env, conn, cursor, row
   
   env    = assert(luasql.mysql())
   conn   = assert(env:connect(dbname, dbuser, dbpass, dbhost))
   cursor = conn:execute( string.format([[
      SELECT * FROM virtualhost where servername = '%s'
   ]], hostname))
   
   row = cursor:fetch({}, "a")
   if not row then
      return nil
   end
   return row.document_root
end