予行練習

今日は明後日のけいはんなサイクルロードレースに向けて予行練習。一周1.8kmの宝ヶ池プリンスホテル周りを後輩とグルグル。3週TTしてアベレージが35km/hくらい。
半分以上後輩に引っ張ってもらったけど、車や信号に邪魔されたのを差し引いたら、思ったよりはいいペース。
色々忙しかったので練習不足は否めないが、なんとか本番では集団から千切られずにゴールできそう。かな‥。

EVERNOTE と Minibuffer

evernoteでノートの更新、編集をする際にエラーが出て、処理が完了しなくなった。

Unknown exception (com.google.gwt.xml.client.impl.DOMParseException: Failed to parse: <success></success><div style="display: none;" id="FLASH_MESSAGE"></div>) during operation (Update note).

うーむさっぱり意味分からん。
とりあえず、ブラウザ再起動したり、キャッシュ飛ばしたり、firebug眺めたり色々やったけど駄目で、最終的にGreasemonkeyを無効にするとエラーが出くなりました。
さらに、userscriptを一個一個無効にして調べてみたところ、犯人はMinibufferのご様子。ということで、Minibufferを実行しないサイトにwww.evernote.comを追加することで、事無きを得ました。
最近Wescriptでuserscriptを全部更新したから、それ以降かなぁ。jsとか詳しくないのでこれ以上は調べません。

リポジトリ削除した かと思った

自宅サーバ内のsvnリポジトリがふと見たら消えてた。
普段から、rm -rf とか軽くやってるので、「もしや、やっちまったか。。」とアホほど冷や汗かいたけど、よく探したら有った。
mv して、変なとこに移動してただけだったよう。ふぅ。
そんだけ。
みんな再帰 rm ってどうしてんだろ。-f 無しでちゃんと確認してんだろうか。

Garuda解説 #1

まともにブクマしてもらったの初めてだ*1
というわけで、前回の続き書こうと思います。

動作フェーズ

Plaggerを踏襲しています。
ごちゃごちゃ書くより、Garuda.pmのコード見てもらえれば一目りょう然ですね。
ざっくりと書くと以下のような感じになってます。

  • new
    • *initialize
  • run
    • **may_run
    • testフェーズ
      • **dispatch
      • *test.finalize
    • filterフェーズ
      • *filter.failure
      • *filter.result
    • publisフェーズ
      • *publish.pre_run
      • *publish.failure
      • *publish.result
      • *publish.finalize

「*」がMethod、「**」がHookです。ロードしたプラグインに実装されているアトリビュート付きメソッドがこの順序で実行されていきます。
testフェーズでテストを実行しまくってResultオブジェクトを作り、filterでそれをfilterして、publishフェーズで公開(通知、保存等)ですね。
testフェーズだけ特殊なので後述しますが、その他のhookはアトリビュートを「RuleHook」という拡張hookにすることで、ruleを噛ますことが出来ます。rule機構はPlaggerのをまんまパクったので、実装の仕方も、configの記述方もまったく同じです。
「may_run」は、runすると最初に実行され、falseを返すとすぐにreturnするようになっています。何らかの理由で(targetがメンテナンス中とか)実行して欲しくないときなんかにpluginでその辺のコントロールできるよう入れておきました。G::Plugin::FailOverではこれを使っています。

dispatch

testの実行だけは、単純なhook呼び出しとは異なります。G::P::Test::*な名前空間のpluginは以下のように処理されます。

plugin->config->targetの解釈は、ロードしたTargetモジュールによって異なります。デフォはTarget::Simpleになっているので、単純にリストとして解釈します。その他のTargetモジュールの詳細ついてはpod参照。
たとえば、Target::DBICを使用した場合、$model->searchの第一引数にそのまま渡されます。

  - module: Target::DBIC
    connect_info:
      - "dbi:SQLite:/path/to/db"

  - module: Test::Hoge
    target:
      hostname:
        like: 'www%' 

は、

$rs = $model->search({hostname =>{like => 'www%'}}, { columns => [$column] });
return [ map { $_->$column } $rs->all ];

となります。columnのデフォはプライマリキーです。
で、その後のフェーズでは、こんな感じで他カラムをhashrefで参照可能なので、テンプレートでごにょごにょしたり出来ます。

$result->failures->[0]->target->info();

DispachプラグインのデフォはDispach::Simpleになっているので、特にロードしない限りはシーケンシャルに実行して行きますが、Dispach::Gearmanを使うと、並列、分散処理が可能になります。testの内容が軽く、Gearman周りのオーバーヘッドの方が気になる場合は、Simpleの方が早い場合もあると思います。

他のフェーズについてはまた後日書く(かもしれない)。
もし、使ってくれて、気になることがありましたらメール(特定のircチャンネルに常駐したりしてないので。。)ください。開発に参加してくれる方も募集しています。
今後はプラグインは増やしていく予定。とりあえずAssurerのを順次移植していこうと思います。

*1:その内の一人が実兄ってのが微妙だが。。

Garuda - サービス監視フレームワーク 作った

稼働中サーバのサービスの状態を監視するためのプラガブルフレームワークGarudaというのを作ったので、codereposに置いておきました。
Plaggerとか、mizzyさんのAssurerみたいなやつです。というか最初はそのAssurerを使う予定だったんですが、自分とこの環境に合わない部分を改造してるうちに、最初から作ってみたくなったんです。
とはいいつつ、かなりの部分をAssureから頂いたり参考にさせてもらっています。Garudaって名前も、Assurer(阿修羅)と同じく八部衆迦楼羅からとりました。迦楼羅って鳥らしいんで、サーバ間飛び回ってる感じで意味的にもいいかなぁと。
プラグインアーキテクチャに関してはClass::Componentをベースにしたので、さほど考える必要はなかったんですが、仕様とか設計で結構悩んで、思ったより時間かかっちゃいましたね。経験値の足りなさを痛感しましたよ。

Assurerとの主な違いは、

  1. テスト対象(target)の取得も、差し替え可能なプラグインのモデルで行うようにした。
  2. formatフェーズが無い。
  3. テストの結果は、失敗したときだけ保存。

です。
1については、大量のroleをconfigに書いていくと管理がしにくくなるので、設定を分けたかったというのと、結果をpublishするときに対象に付随する情報(dbレコードの他カラムとかね)も含められるようにしたかったからです。
2については、単純に監視だけであれば、結果の通知内容はそれほどリッチでなくてもいいような気がしたので、各publishプラグインでテンプレートを当てるだけにしました。
3について、これが自分のところでは一番問題でした。Assurerでは、テストが成功しても失敗しても結果オブジェクトを保存するようになっているのですが、大量のテストを一度に実行するとプロセスのサイズが大変なことになっちゃうんですよね。
そんなわけで、Garudaでは失敗したときだけ、Failureオブジェクトを作り、後のフェーズに渡すようにしました。本当はAssurerのようにTAP形式の出力にしたかったんですが、そこは諦めました。

あくまで、「監視に特化したアプリ」というイメージで開発しましたので、Assurerと比べて機能はかなりシンプルになっています。
他に工夫した点としては、テストジョブを処理するgearman周りの動作を安定させました。興味のある方はコード見みてください。gearman触ったので初めてで、もっといい実装があるかも知れません。つっこみ歓迎します。

テストがまだ足りてませんが、チェックアウトしてmake testが通れば動くと思います。

basic.tとかを参考にconfig書いて

# ./bin/garuda.pl -c /path/to/config

で、いけます。

--debugつけると、ログがターミナルに出力され、publishフェーズは飛ばすようになるので、最初はそれでやったほうがいいと思います。
プラグイン(まだあんまり無いけど)の使い方は、t/plugins/*とかpodとか見てください。

ブクマとかコメントがあれば、さらに詳しい説明も書こうと思います。

CentOs5.3 で trac インストール

GWなのにぎっくり腰で外出れないから、寝ながら新自宅サーバセットアップ中。
以下tracインストールのてっきとうなメモ。

dag追加。

python-setuptools
subversion
mod_dav_svn

rpmfind.net から python-genshi のdagなrpm拾ってきて、-i

  • GPG-KEY

mirror.centos.org から RPM-GPG-KEY-CentOS-5 を拾ってきて rpm --import

trac

勝手にレス>Test::Baseのyamlフィルタで空配列を作るときの動作が理解できない

http://d.hatena.ne.jp/foosin/20090416/1239903771

 ~~ snip ~~

__END__
=== 1st
--- i
--- e
[]

YAML Error: Expected separator '---'
   Code: YAML_PARSE_ERR_NO_SEPARATOR
   Line: 1
   Document: 2
 at /usr/lib/perl5/site_perl/5.8.5/YAML.pm line 33
# Looks like your test died before it could output anything.

Test::Baseがというか、yamlフィルターで使ってるYAML.pmがエラー吐いてる。事前の確認で使ってるYAML::Syckではokでも、YAMLでは(多分yaml仕様的にも)not validということで駄目なんでしょう。

use strict;
use warnings;

use Data::Dumper;
# use YAML::Syck;
use YAML;
use Test::More qw/no_plan/;

sub p { print Dumper shift }

my $not_valid = <<END;
[]
END

my $valid = <<END;
--- []
END

ok ! eval { Load($not_valid) };
ok   eval { Load($valid) };