Perlbal::Plugin::Regex
昨日のPerlbal::Plugin::Regexcontrolを受けて、
いろいろPerlbalとかさわってみましたが、
結論として、selectorは多段で実行できません。
はじめにやりたいと思ってたことが、
selector Vhostsプラグインでホストの振り分け ↓ selector 拡張子によりサーバを振り分け ↓ reverse_proxy
大体こんな感じでできるのかなーーとか思ってたのですが、
無理でした。
Vhostsプラグインで、ホストがマッチした時に実行される、
adopt_base_clientメソッドではroleがweb_serverかreverse_proxyかしか
受け付けてくれないので、多段selectorの夢が破られました。
まあ、もともとの考え方もまずいのかなぁ。
で、仕方ないので次の手。
Perlbal::Plugin::Regexってのを書きました。
Perlbal::Plugin::Regexcontrolと何が違うかというと、
Vhostsプラグインの簡易版プラスRegexによるURLマッチングです。
ソースはこんなの。
Vhostsプラグインほど、ホスト名を面倒はみてません。
FQDNがベストなのかな。ってかFQDNならこんなの考えずにできるチューはなしもありますか。
package Perlbal::Plugin::Regex; use strict; use warnings; no warnings qw(deprecated); our %Services; # service_name => $svc # when "LOAD" directive loads us up sub load { my $class = shift; Perlbal::register_global_hook('manage_command.regex', sub { my $mc = shift->parse(qr/^regex\s+(?:(\w+)\s+)?(\S+)\s+(\S+)\s*=\s*(\w+)$/, "usage: REGEX [<service>] <host_or_pattern> <regex> = <dest_service>"); my ($selname, $host, $regex, $target) = $mc->args; unless ($selname ||= $mc->{ctx}{last_created}) { return $mc->err("omitted service name not implied from context"); } my $ss = Perlbal->service($selname); return $mc->err("Service '$selname' is not a selector service") unless $ss && $ss->{role} eq "selector"; $host = lc $host; return $mc->err("invalid host pattern: '$host'") unless $host =~ /^[\w\-\_\.\*\;\:]+$/; $ss->{extra_config}->{_regex} ||= {}; $ss->{extra_config}->{_regex}{$host}->{regex} = $target; $ss->{extra_config}->{_regex}{$host}->{target} = $target; return $mc->ok; }); return 1; } # unload our global commands, clear our service object sub unload { my $class = shift; Perlbal::unregister_global_hook('manage_command.regex'); unregister($class, $_) foreach (values %Services); return 1; } # called when we're being added to a service sub register { my ($class, $svc) = @_; unless ($svc && $svc->{role} eq "selector") { die "You can't load the regex plugin on a service not of role selector.\n"; } $svc->selector(\®ex_selector); $svc->{extra_config}->{_regex} = {}; $Services{"$svc"} = $svc; return 1; } # called when we're no longer active on a service sub unregister { my ($class, $svc) = @_; $svc->selector(undef); delete $Services{"$svc"}; return 1; } # call back from Service via ClientHTTPBase's event_read calling service->select_new_service(Perlbal::ClientHTTPBase) sub regex_selector { my Perlbal::ClientHTTPBase $cb = shift; my $req = $cb->{req_headers}; return $cb->_simple_response(404, "Not Found (no reqheaders)") unless $req; my $vhost = $req->header("Host"); my $uri = $req->request_uri; my $maps = $cb->{service}{extra_config}{_regex} ||= {}; $vhost =~ s/:\d+$//; my $regex = $maps->{$vhost}->{regex} ||= ''; my $target = $maps->{$vhost}->{target} ||= ''; if ($regex && $target) { my $svc = Perlbal->service($target) || undef; unless ($svc) { $cb->_simple_response(404, "Not Found (no configured regex)"); } else { $svc->adopt_base_client($cb); } } } 1;
設定方法はこんなの。以下の設定方法は間違ってます><
LOAD vhosts LOAD regex CREATE POOL a CREATE SERVICE ss SET ss.listen = 127.0.0.1:$pb_port SET ss.role = selector SET ss.persist_client = on SET ss.plugins = regex REGEX ss regex \\.(txt)\$ = ws SET ss.plugins = vhosts VHOST ss *.regex = ws VHOST ss proxy = pr VHOST ss webserver = ws VHOST ss *.webserver = ws VHOST ss manage = mgmt ENABLE ss CREATE SERVICE pr SET pr.role = reverse_proxy SET pr.persist_client = 1 SET pr.persist_backend = 1 SET pr.pool = a SET pr.connect_ahead = 0 ENABLE pr CREATE SERVICE ws SET ws.role = web_server SET ws.docroot = $dir SET ws.dirindexing = 0 SET ws.persist_client = 1 SET ws.enable_put = 1 SET ws.enable_delete = 1 ENABLE ws
テストスクリプトからの抜粋ですが。
先にRegexプラグインでマッチさせてみて、マッチしたらそっち
マッチしなかったら普通にVhostsプラグインで処理みたいな。
適当に作ったから穴はありそう。
この設定ファイル本当は
LOAD vhosts LOAD regex CREATE SERVICE ss SET ss.listen = 127.0.0.1:$pb_port SET ss.role = selector SET ss.persist_client = on SET ss.plugins = regex vhosts REGEX ss regex \\.(txt)\$ = ws VHOST ss *.regex = ws VHOST ss proxy = pr VHOST ss webserver = ws VHOST ss *.webserver = ws VHOST ss manage = mgmt ENABLE ss
こんな感じでPluginの部分を一気にかいておけるかなーとおもったら無理でした。
こんな感じでとりあえずうごきそげー。
PerlbalとかMogileFSのコードはなれないとちょっと大変。
本当はこのモジュール名Perlbal::Plugin::VhostsRegex
とかにしたかったのですが、Perlbalちゃんがキャメライズ微妙だったので。
とりあえずやむなし。
(追記)
だめだ、これも失敗作だわさ。
しょぼーん。