cfengine よりも puppet がよさげ
I, newbie » Links Roundup 経由で puppet というシステム管理ツールを知って以来ずっと気になっていたのですが、このエントリの著者さんが OSC2007 の発表資料(PDF)で「Puppet is so sexy.」と書かれているのを見て、本気で触ってみることにしました。
puppet がどんなものかは、上記資料とか だ!日記さんのエントリ にも書かれているのですが、本家の Cfengine vs. Puppet というエントリから cfengine との違いを一部適当に意訳してみると、こんな感じです。
- next-generation version of cfengine ということで、cfengine をベースとしながらも、より良いものを目指している。
- リソース抽象化レイヤーにより、OS やディストリビューションの違いを意識しなくても良い。
- タスクの実行順序を制御できる。(cfengine ではできないor難しいらしい。)
- 設定ファイルで記述する内部言語が強力になっている。
- type の拡張が簡単。
- Ruby でできている。
というわけで、cfengine の導入を検討して、こんなエントリ を書いたりしてたのですが、cfengine は捨てて puppet でいこうかな、と思ってます。
emacs 用のヘルパーモード なんかも提供されているのがさらに好印象です。vim 用もあるし。
それから、まだ Experimental ですが、puppetshow という Rails でできたウェブインターフェースもあるようです。
Plagger について本に書きました
タイトルは MASHUP++ です。その名の通り、マッシュアップを主題とした本なのですが、主に自分でマッシュアップな開発をしてみたい、という方向けの本で、自分は「マッシュアップとプラガブルなフレームワーク」をテーマに、Plagger プラグインの開発方法について書きました。
内容としては、プラグイン開発の基礎知識として、
- 内部データ形式である Plagger::Feed と Plagger::Entry
- フィードデータがどの様に入力、加工、出力されるのか
- プラグインの用途と種類にはどんなものがあるのか
- 各プラグインの関係や実行フェーズ、実行順序
といったことを解説しています。また、後半は
- 各フェーズの実際のプラグインソースコードを引用しながらの解説
- プラグインの雛形生成、ドキュメント、テストの書き方といったプラグイン開発の流れ
といった感じになっています。プラグインを開発してみたいけど、どこから手をつけていいのかわからない、という方に是非ご覧頂きたいです。
他にも さうなまん さん、鹿倉公維 さん、セトウナオ さん、タナカミノル さんといった .fla の執筆陣による Flash を主体としたマッシュアップ(タナカさんは今回は Flash ではないですが)や、CATWALK の三宅涼さん、澤久裕昭さんによる、これぞ正当なマッシュアップ、といった感じの PHP と JavaScript によるマッシュアップ、そして、タナカミノルさんと原央樹 さんによる、Gainerというハードウェアを使ったマッシュアップなど、バリエーション豊かなマッシュアップがソースコードつきで解説されています。必読。
Assurer 近況
Assurer の最近の状況など。
franck が開発に参加
Plagger コミッタでもある franck がジョインしてくれ、プラグインやパッチなどを送ってくれたり、新しいアイデアを提案/実装してくれたりしてます。この週末も素敵な機能を実装してくれるみたいです。
Notify フェーズの追加
Notify フェーズを追加して、Notify::IRC を実装してみました。ほとんど Plagger からのパクリです。
Kwalify によるコンフィグバリデーション
Assurer::ConfigLoader に、Kwalify によるコンフィグバリデーション処理が追加されました。実行時に設定ファイルのミスをお知らせしてくれます。
プラグインの場合は、当然プラグイン毎に設定内容が異なるわけですが、この辺りもちゃんと対応しています。
シェルモードのブラッシュアップ
$ assurer.pl -c config.yaml --role=web
といった形で、シェルモード起動時に、ターゲットとなるロールを指定できるのですが、機能追加により、
assurer> !on app1.foo.com app2.foo.com do uptime assurer> !on /.*.foo.com/ do uptime assurer> !with web db do uptime assurer> !with /web|mail/ do uptime
といった形で、シェルモード中にもターゲットホストやロールが指定できるようになっています。正規表現も使えます。
また、シェルモードからもテストが実行できるようになっています。こんな感じで。
assurer> !test SSH on app1.foo.com assurer> !test SSH on /.*.foo.com/ assurer> !test SSH with web assurer> !test SSH with /web|mail/
並列度のコントロールと分散処理
テストの実行は assurer_test.pl を POE::Wheel::Run で起動することにより、並列実行させていたのですが、POE::Component::JobQueue を併用することにより、並列度をコントロールできるようにしました。
また、
exec_on:
- host: localhost
priority: 3
- host: host0.example.com
priority: 2
- host: host1.example.cm
priority: 1
といった設定を行うことにより、複数のマシンで分散してテストを行う、ということができるようになってます。priority は今のところ設定しても意味はなく、ラウンドロビンでテストジョブを割り当ててるのですが、今後は priority に応じて割りてるジョブの数を調整したり、各マシンの負荷状況を見て調整したり、といったことができるようにしたいと考えています。
Test::WWW::Mechanize プラグイン
Test::WWW::Mechanize をつかったテストも組み込めるようにしました。
まあ、こんな感じです。あまり詳しく書くと YAPC で話すネタがなくなるので、この辺で。
「PlaggerになくてYahoo!pipesにあるもの」は書き方が悪かったのではなく Plagger を理解してないだけ
「PlaggerになくてYahoo!pipesにあるもの」は書き方が悪かった について。
Plagger について理解できてないだけです。書き方の問題じゃありません。まず、
このときPublish::Gmailがおかしいなと思った。なにがおかしいかというとフィルター機能があることだ。
Publish::Gmail にはフィルタ機能はありません。Plagger に実装されているものを、Publish::Gmail で利用しているだけです。
また、Publish::Gmail で利用しているのは、実際はフィルタ機能ではなく、ルール機能だったりします。似たような機能でややこしいかもしれませんが、Plagger では フィルタとルールは別物です。
本来フィルターの機能はFilterが担うべきで、Publishのプラグインにつけるべき機能ではない。
はい、Plagger はちゃんとそうなってますよ。
例えばBloglineからフィードを取得し、その中からいくつかのブログのフィードを各ブログごと取り出し各ブログごと異なる条件でフィルタリングしたり、はてなブックマークに登録し、残りのフィードはそのままGmailに送るということは本来的にはできないのでは無いかと考えた。
できます。たとえば、mizzy.org だけローマ字変換して Gmail へ、残りはそのままはてブへ、ということであればこんな感じ。(設定はかなりはしょってますが。)
plugins:
- module: Subscription::Bloglines
- module: Filter::Romanize::Japanese
rule:
expression: $args->{feed}->title eq 'mizzy.org'
- module: Publish::Gmail
rule:
expression: $args->{feed}->title eq 'mizzy.org'
- module: Publish::HatenaBookmark
rule:
expression: $args->{feed}->title ne 'mizzy.org'
この例では、2つの Publish プラグインの出力対象フィードが別だから、プラグイン毎に rule 設定してるけど、両プラグインが同じフィードを出力するのであれば、Filter::Rule プラグインでフィルタすれば、rule を指定する必要がなくなる。
まあ、この辺りは分かりやすくはないから、誤解するのもしょうがいない気がするけれど、設定例だけ見て、そこから推測したものがあたかも実際の Plagger の仕様であるかのように書くのはやめようよ。
Angerwhale #0
コメント/トラックバックスパムがうざいので、一時的に受け付けないようにしました。
で、blosxom で対策してもいいのですが、これを機会にブログツールを乗り換えようと、Angerwhale を試すことに。(本当は Catlxom への乗換えを前々から検討していたのですが、大きく作り変えると typester さんがおっしゃっていたので、ちょっと様子見。)
Angerwhale と同様に、Catalyst ベースのブログツールに Typeface というのがあるのですが、Angerwhale はエントリをファイルベースで管理するので、blosxom に近いものがあるし、作者の jrockway は YAPC::Asia Tokyo 2007 にも来るので、もしかしたら話す機会もあるかもしれないので、こちらを使ってみることに。
使ってみてちょっと不便だな、と思ったのは、
- エントリタイトルはメタデータとして管理する。
- カテゴリ名はディレクトリ名そのまま表示。
の2点。
以下、もう少し詳しく説明します。まずはエントリタイトルの件。
Angerwhale ではエントリの作成時間などを、メタデータとして管理します。メタデータは File::Attributes を利用して作られ、.entry_file_name.attributes といったファイルが、エントリファイルと同じディレクトリに作られます。内容は以下のように YAML になってます。
--- creation_time: 1172377648 guid: 813B071C-C488-11DB-BB28-6F396B4151C7
このメタデータファイルに、
title: エントリタイトル
といった記述があれば、これをエントリのタイトルとみなします。なければ、ファイル名から拡張子を除いたものがエントリのタイトルになります。
ファイル名とタイトルが違う、なんてことがよくあるわけですが、そうしたい場合には今の仕様だと、
- エントリファイルを置く
- 一度ブラウザでアクセスしてメタデータファイルを作らせる
- メタデータファイルを開いてエントリタイトルを記述する
なんてことをしなければいけない、ということになります。めんどいですね。
次にカテゴリ名の問題。
Angerwhale は カテゴリ = ディレクトリなんですが、ブラウザ上にはディレクトリ名をそのまま表示しちゃうんですね。ディレクトリは英語で、表示は日本語でしたい、ってのもよくあることなので、これも不便ですね。
この辺り、パッチ作ったりして対応したいな、と思ってます。
また、以下のバグと思わしき問題もありました。
- ホームにアクセスすると、カテゴリわけされたエントリが表示されない。
- カテゴリにアクセスすると、404 エラー。
これは以下のパッチを書いて、jrockway に送ってみました。
Index: lib/Angerwhale/Model/Filesystem.pm
===================================================================
--- lib/Angerwhale/Model/Filesystem.pm (revision 573)
+++ lib/Angerwhale/Model/Filesystem.pm (working copy)
@@ -58,7 +58,7 @@
sub get_article {
my $self = shift;
my $article = shift;
- my $base = $self->base;
+ my $base = shift || $self->base;
die "article name contains weird characters"
if $article =~ m{/};
@@ -90,10 +90,14 @@
my $entry = "$base/$article";
next if $article =~ m{^[.]}; # hidden files are also ignored
next if !-r $entry;
- next if -d $entry;
+ #next if -d $entry;
+ if ( -d $entry ) {
+ push @articles, $self->_ls($entry);
+ next;
+ }
#entry is acceptable
- my $article = $self->get_article($article);
+ my $article = $self->get_article($article, $base);
push @articles, $article;
}
Plagger にあって Yahoo!pipes にあるもの
前回のエントリ で取り上げた方のブログに、Plagger になくてYahoo!pipesにあるもの というエントリがあったので、それについても釣られて言及してみます。
基本的に Plagger の処理は一本道であり、複数の基本データを扱うことができなかったはず
それ Plagger でもできるよ。複数の入力から一つの出力もできるし、一つの入力から複数の出力もできるし、複数の入力から複数の出力もできる。
いってみればPlaggerは一つの入力に一つの出力が対応している直線的な処理しかできない。それに対しYahoo!pipesは複数の入力に一つの出力が対応するという、逆ピラミッド的な処理もできる。これがPlagger になくてYahoo!pipesにあるものだ。(もしかして今はできるのかもしれない。)
id:otsune さんも指摘してるけど、それ smartfeed で。
「Plagger の発展をフォローしてないので不正確かもしれない」とか「もしかして今はできるのかもしれない」などと書かれてますが、少なくとも SmartFeed::All は 2006/05/03 には作られているので、複数の入力に対して一つの出力は、かなり前からできます。
また、一つの入力から複数の出力、複数の入力から複数の出力は最初からできます。なので、「基本的に Plagger の処理は一本道」というのは完全に間違い。Plagger の発展をフォローしてない、というのは言い訳にならない。「少なくとも自分が使っていた頃のPlagger になくて」と書いてるけど、本当に使ってたの?
まあ、Yahoo!Books のエントリを見てもわかるように、Plagger が何かをまったくわかっていない人間のたわごとなので、適当に流しておくのが大人の対応なんでしょうが、Plagger ラブな人間としては、間違った情報広められるのは嫌な気分になるので。
Plagger で Yahoo!Booksのランキングをとってくる
さすがにPlaggerでもこれは無理だと思いたい。PythonでYahoo!Booksのランキングをとってくる。 というエントリを見て、なんか釣りっぽいタイトルだけど敢えて釣られてみた。
ちょっとアウトプット違うけど、Plagger なら 10 分でできた。
以下の2つのファイルを用意してやるだけ。
config.yaml
plugins:
- module: Subscription::Config
config:
feed:
- url: http://books.yahoo.co.jp/ranking/general/all/all/weekly/index.html
meta:
follow_link: /book_detail/.*
- module: CustomFeed::Simple
- module: Filter::EntryFullText
- module: Publish::Gmail
config:
mailto: xxx@gmail.com
mailfrom: plagger@mizzy.org
mailroute:
via: smtp
host: localhost
attach_enclosures: 1
EntryFullText 用 yaml
author: Gosuke Miyashita handle: http:\/\/books\.yahoo\.co\.jp\/book_detail\/\d+ extract: <!-- 書籍紹介 -->.+<small>(.*?)</small>.+<!-- //書籍紹介 --> extract_capture: body
既存の設定からほぼコピペなので、10 分のうち7割ぐらいは、EFT 用 yaml の文字コードが UTF-8 じゃないといけないのに、euc-jp にしてて「なんかうまくいかねー」とかやってた時間。
デブサミ出張 Shibuya イベントの補足
デブサミ発表資料中に、テストプラグインがどういうコードなのかを書いていたのですが、時間がなくてまったく説明できなかったので、ここで補足しておきます。
テストプラグインのコードはこの様になっています。
package Assurer::Plugin::Test::SMTP; use strict; use warnings; use base qw( Assurer::Plugin::Test ); #(A) use Assurer::Test; #(B) use Net::SMTP;sub register { my $self = shift; $self->register_tests( qw/ connect / ); #(C) }sub connect { my ( $self, $context, $args ) = @_; my $conf = $self->conf; my $host = $conf->{host} || $context->conf->{host}; my $timeout = $conf->{timeout} || 10; my $smtp = Net::SMTP->new(Host => $host, Timeout => $timeout); ok($smtp, "smtp ok $host"); #(D) } 1;
青字の部分が、プラグインを書く際のお約束というかポイントとなる部分なので、順に説明していきます。
(A) では Assurer::Plugin::Test を継承しているわけですが、テストプラグイン共通の処理はすべて Assurer::Plugin::Test に記述することにより、各プラグインでのコード量を減らそうという目論見になってます。
(B) で Assurer::Test を use することより、ok(), is(), like() といったテスト用メソッドをインポートしています。
(C) ではテストを行うメソッドを登録しています。複数登録する場合には、
$self->register_tests( qw/ test1 test2 test3 / );
といった記述をします。この場合、test1(), test2(), test3() の順で実行されます。
(D) が実際にテストを行っているところで、Test::More の ok() と同じ動作をします。この ok() は上で書いたように、Assurer::Test からインポートしたメソッドです。このような組み込みのテストメソッドを使うことで、if 文で結果を判断して適切なステータスを返す、といった処理を書く必要がなくなります。
kazeburo さんの発表にある、Nagios プラグインと対比してみると、Nagios は exit 時のステータスコードだけ気にすればいい、というのに対して、Assurer では、上のコード (A), (B), (C) の様に、Assurer 特有のお約束を守る必要があるものの、exit コードは気にしなくていい、といった特徴があります。また、お約束を守ることによってコード量も減らせます。(特に結果判定で if を書かなくていい。)
Nagios の場合、ステータスコードだけ気にすればいい、とは言っても、ステータスが OK, Warning, Crtitical, Unknown とあるわけで、OK はまだしも、どういった場合が Warning でどういった場合が Critical なのか、ということを気にするのは、ちょっと面倒な気もします。
また、結果を受け取る側も、Warning とか Unknown とか受け取ると、それって問題あるの?ないの?って迷ったりしないのかな、とか、Warning と Critical の解釈って、人によって違うんじゃないかな、って思ったりします。(Nagios使ったことないんで、変なこと言ってるかもしれませんが。)
そういった曖昧さをなくしたくて、Assurer では OK か NOT OK かの2種類の結果しか返さない、というポリシーにしました。
とは言っても、Nagios の様にステータスが何種類かある方が便利だという場面はあるんでしょうね。その辺りは Assurer では、エラーメッセージでフィルタリングできるようにして、「こういったエラーメッセージの場合は、問題ないから OK にする」といった設定ができるような形にして、結果の解釈を利用者に委ねられるようにしようと考えています。
デブサミ出張 Shibuya イベント
デブサミ出張 Shibuya イベントで、Assurer についてしゃべってきました。発表資料をここに置いておきます。
感想とか書きたいのですが、嘔吐下痢性の風邪にやれられて、一日何も食べることができず、打ち上げにも参加できないぐらい体調悪いので、今日はこの辺で。
Assurer にシェルモード
Assurer についてその後あんまり書いてないですが、何もしてないわけではなく、リトライをハンドリングできるようにしたり、並列実行できるようにしたりと、ちょこちょこと開発は進めています。
で、前回のエントリ で、Archer にシェルモードをつけてみたわけなんですが、シェルモードってテスト/監視ツールにこそふさわしい、と思ったので、Assurer にもつけてみました。こんな感じになります。
$ assurer.pl --config=config.yaml --shell --role=app --para=3 shell> uptime [www.mizzy.org] 02:59:34 up 4 days, 3:39, 1 user, load average: 0.21, 0.23, 0.22 [svn.mizzy.org] 02:59:34 up 4 days, 3:39, 1 user, load average: 0.21, 0.23, 0.22 [ftp.mizzy.org] 02:59:34 up 4 days, 3:39, 1 user, load average: 0.21, 0.23, 0.22 shell>
--role がなければ、config.yaml で列挙されているホスト全部で実行します。