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
ホスト名に応じてDocumentRootをMySQLから引っ張ってきてマッピングするコード
これだけだとあまりに残念な紹介なんで、livedoorのいけべさんが昔公開されてたmod_vhost_mysqlの機能をmod_luaで真似してみます。以下の用な設定でいけます。
# 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
LuaRoot /usr/local/apache2/scripts/lua LuaCodeCache stat LuaScope once LuaHookTranslateName mysql_vhost.lua mysql_vhost
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