組み込みPerlインタプリタの使用
イントロダクション
Stephen Daviesによって寄与されたコードにより、Nagiosは組み込みPerlインタプリタを有効にしてコンパイル出来るようになりました。Perlで書かれたプラグインに大きく依存している場合には興味深いものとなるでしょう。
Stanley Hopcroftはほんの少し組み込みPerlの作業をし、その使用による有利不利を書き記しました。また彼は適切に動作する組み込みPerlによるPerlプラグインの作成に関して、いくつかの役に立つヒントも与えました。このドキュメントの大部分は彼の解説によっています。
このドキュメントで"ePN"として使用されている単語は、embedded Perl Nagiosをさしています。それか、Nagios compiled with an embedded Perl interpreter のほうがよければこちらでもかまいません。
有利な点
ePN (embedded Perl Nagios)の有利な点には以下があります:
- NagiosはPerlプラグインをずっと少ない時間で実行出来ます。なぜなら(Perlインタプリタをロードする度に)プラグインを実行するのにフォークしないからです。代わりにライブラリコールによってプラグインを実行します。
- Perlプラグインによるシステム負荷を大きく減らし、組み込みPerl無しの時より多くのチェックが可能になります。言い換えれば、一般的にPerlより開発時間が必要と考えられている(そのかわりTCL以外は10倍速く実行出来るが)CやC++、Expect、TCLなどの他の言語でプラグインを書く魅力はなくなります。
- It greatly reduces the system impact of Perl plugins and/or allows you to run more checks with Perl plugin than you otherwise would be able to. In other words, you have less incentive to write plugins in other languages such as C/C++, or Expect/TCL, that are generally recognised to have development times at least an order of magnitude slower than Perl (although they do run about ten times faster also - TCL being an exception).
- Cプログラマでなくても、Perlに重たい処理をさせることでNagiosを遅くさせずパフォーマンスを上げることが出来ます。しかし、インタープリターのロード時間と別でePNによってプラグインは速くならないことに注意してください。もし速いプラグインが必要なら、使っているPerlがチューニングされていて最適なアルゴリズムを用いていることを確認した後で(Benchmark.pmはPerl言語の本質的なパフォーマンス比較に欠かせません)、XSUBs (XS)かCを検討してください。
- If you are not a C programmer, then you can still get a huge amount of mileage out of Nagios by letting Perl do all the heavy lifting without having Nagios slow right down. Note however, that the ePN will not speed up your plugin (apart from eliminating the interpreter load time). If you want fast plugins then consider Perl XSUBs (XS), or C after you are sure that your Perl is tuned and that you have a suitable algorithm (Benchmark.pm is invaluable for comparing the performance of Perl language elements).
- ePNの使用はさらにPerlを学ぶこの上無い機会です
Disadvantages
欠点
ePN (embedded Perl Nagios)の欠点はApacheのmod_perl (組込みインタープリター付きのApache) とそのままのApacheとを比較した場合とほぼ同じです。
The disadvantages of ePN (embedded Perl Nagios) are much the same as Apache mod_perl (i.e. Apache with an embedded interpreter) compared to a plain Apache:
- そのままのNagiosで調子良く動作するPerlプログラムはePNを使うと動かないかもしれません。動作するようにプラグインを修正する必要があります。
- A Perl program that works fine with plain Nagios may not work with the ePN. You may have to modify your plugins to get them to work.
- ePN無しの時よりPerlプラグインのデバッグが困難になります
- Perl plugins are harder to debug under an ePN than under a plain Nagios.
- ePNはそのままのNagiosよりサイズが大きくなります (メモリ消費)
- Your ePN will have a larger SIZE (memory footprint) than a plain Nagios.
- あるPerlの概念は使用出来ない、または思ったのと違うように振る舞います。
- Some Perl constructs cannot be used or may behave differently than what you would expect.
- "何かをするのには複数の方法がある"ことに気づき、おもしろくなさそうであったり明白な方法を選ばなければなりません。
- You may have to be aware of 'more than one way to do it' and choose a way that seems less attractive or obvious.
- Perlのより深い知識が必要になるでしょう。しかしXSUBSを使用するプラグインでなければ、非常に難解であったりPerlの内部的なものはありません。
- You will need greater Perl knowledge (but nothing very esoteric or stuff about Perl internals - unless your plugin uses XSUBS).
Target Audience
対象となる読者
- 平均的なPerl開発者 - 内部的な知識は無いが言語のパワフルな特性を理解している人、またはそれら特性の知識がある人
- Average Perl developers; those with an appreciation of the languages powerful features without knowledge of internals or an in depth knowledge of those features.
- 深い理解というよりは実用的な認識のある人
- Those with a utilitarian appreciation rather than a great depth of understanding.
- もしPerlのオブジェクトや名前操作、データ構造、デバッガーに満足していれば、おそらくそれで十分でしょう。
- If you are happy with Perl objects, name management, data structures, and the debugger, that's probably sufficient.
Perlプラグイン(ePNやそれ以外)を開発する時にすべき事
Things you should do when developing a Perl Plugin (ePN or not)
- 常に何かを出力しなさい
- Always always generate some output
- 'use utils'を使って、それがエクスポートする ($TIMEOUT %ERRORS &print_revision &support) をインポートしなさい
- Use 'use utils' and import the stuff it exports ($TIMEOUT %ERRORS &print_revision &support)
- 標準的なPerlプラグインがどうなっているのか見なさい
- Have a look at how the standard Perl plugins do their stuff e.g.
- 常に $ERRORS{CRITICAL}, $ERRORS{OK},等で終了しなさい
- Always exit with $ERRORS{CRITICAL}, $ERRORS{OK}, etc.
- コマンドライン引数を読み取るのにgetoptを使いなさい
- Use getopt to read command line arguments
- タイムアウトを管理しなさい
- Manage timeouts
- コマンドライン引数が無ければ、print_usage関数(あなたが用意する)を呼び出しなさい
- Call print_usage (supplied by you) when there are no command line arguments
- 標準的なスイッチ名 (例えば H 'host', V 'version') を使いなさい
- Use standard switch names (eg H 'host', V 'version')
ePNのPerlプラグインを開発するのにしなければならない事
Things you must do to develop a Perl plugin for ePN
- <DATA> は使えません。代わりにヒアドキュメントを使いなさい
- <DATA> can not be used; use here documents instead e.g.
my $data = <<DATA;
portmapper 100000
portmap 100000
sunrpc 100000
rpcbind 100000
rstatd 100001
rstat 100001
rup 100001
..
DATA
%prognum = map { my($a, $b) = split; ($a, $b) } split(/\n/, $data) ;
- BEGINブロックは思ったようには動作しません。避けるのがおそらく一番良いでしょう。
- BEGIN blocks will not work as you expect. May be best to avoid.
- コンパイル時にクリーンなことを確認しなさい。例えば
- Ensure that it is squeaky clean at compile time i.e.
- strictを使いなさい
- perl -w (他のスイッチ[-Tが有名] は役に立たないだろう)を使いなさい
- perl -c を使いなさい
-
- Avoid lexical variables (my) with global scope as a means of passing __variable__ data into subroutines. In fact this is __fatal__ if the subroutine is called by the plugin more than once when the check is run. Such subroutines act as 'closures' that lock the global lexicals first value into subsequent calls of the subroutine. If however, your global
is read-only (a complicated structure for example) this is not a problem. What Bekman recommends you do instead, is any of the following:
- make the subroutine anonymous and call it via a code ref e.g.
turn this into
my $x = 1 ; my $x = 1 ;
sub a { .. Process $x ... } $a_cr = sub { ... Process $x ... } ;
. .
. .
a ; &$a_cr ;
$x = 2 $x = 2 ;
a ; &$a_cr ;
# anon closures __always__ rebind the current lexical value
- put the global lexical and the subroutine using it in their own package (as an object or a module)
- pass info to subs as references or aliases (\$lex_var or $_[n])
- replace lexicals with package globals and exclude them from 'use strict' objections with 'use vars qw(global1 global2 ..)'
- Be aware of where you can get more information.
Useful information can be had from the usual suspects (the O'Reilly books, plus Damien Conways "Object Oriented Perl") but for the really useful stuff in the right context start at Stas Bekman's mod_perl guide at http://perl.apache.org/guide/.
This wonderful book sized document has nothing whatsoever about Nagios, but all about writing Perl programs for the embedded Perl interpreter in Apache (ie Doug MacEacherns mod_perl).
The perlembed manpage is essential for context and encouragement.
On the basis that Lincoln Stein and Doug MacEachern know a thing or two about Perl and embedding Perl, their book 'Writing Apache Modules with Perl and C' is almost certainly worth looking at.
- Be aware that your plugin may return strange values with an ePN and that this is likely to be caused by the problem in item #4 above
- Be prepared to debug via:
- having a test ePN and
- adding print statements to your plugin to display variable values to STDERR (can't use STDOUT)
- adding print statements to p1.pl to display what ePN thinks your plugin is before it tries to run it (vi)
- running the ePN in foreground mode (probably in conjunction with the former recommendations)
- use the 'Deparse' module on your plugin to see how the parser has optimised it and what the interpreter will actually get. (see 'Constants in Perl' by Sean M. Burke, The Perl Journal, Fall 2001)
perl -MO::Deparse <your_program>
- Be aware of what ePN is transforming your plugin too, and if all else fails try and debug the transformed version.
As you can see below p1.pl rewrites your plugin as a subroutine called 'hndlr' in the package named 'Embed::<something_related_to_your_plugin_file_name>'.
Your plugin may be expecting command line arguments in @ARGV so pl.pl also assigns @_ to @ARGV.
This in turn gets 'eval' ed and if the eval raises an error (any parse error and run error), the plugin gets chucked out.
The following output shows how a test ePN transformed the check_rpc plugin before attempting to execute it. Most of the code from the actual plugin is not shown, as we are interested in only the transformations that the ePN has made to the plugin). For clarity, transformations are shown in red:
package main;
use subs 'CORE::GLOBAL::exit';
sub CORE::GLOBAL::exit { die "ExitTrap: $_[0]
(Embed::check_5frpc)"; }
package Embed::check_5frpc; sub hndlr { shift(@_);
@ARGV=@_;
#! /usr/bin/perl -w
#
# check_rpc plugin for Nagios
#
# usage:
# check_rpc host service
#
# Check if an rpc serice is registered and running
# using rpcinfo - $proto $host $prognum 2>&1 |";
#
# Use these hosts.cfg entries as examples
#
# command[check_nfs]=/some/path/libexec/check_rpc $HOSTADDRESS$ nfs
# service[check_nfs]=NFS;24x7;3;5;5;unix-admin;60;24x7;1;1;1;;check_rpc
#
# initial version: 3 May 2000 by Truongchinh Nguyen and Karl DeBisschop
# current status: $Revision: 1.8 $
#
# Copyright Notice: GPL
#
... rest of plugin code goes here (it was removed for brevity) ...
}
-
ePNで実行されるプラグインの中で決して 'use diagnostics'
を使ってはいけません。私はそのせいで全てのPerlプラグインはクリティカルを返すようになると思っています 。
- Don't use 'use diagnostics' in a plugin run by your production ePN. I think it causes__all__ the Perl plugins to return CRITICAL.
- プラグインのチェックにはミニ組込みPerlのCプログラムを使うと良いでしょう。これはプラグインがePNで上手く動作することを保証するには十分ではありませんが、このテストで失敗したらePNでも上手くいかない可能性が高いです。[サンプルのミニePNは、Perlプラグインのテスト用にNagiosソースのcontrib/ディレクトリに含まれています。contrib/
ディレクトリに移動し、"make
mini_epn"とタイプしてコンパイルしてください。それは同じディレクトリにあるp1.pl(このファイルはNagiosと一緒に配布されている)から実行可能でなければなりません。]
- Consider using a mini embedded Perl C program to check your plugin. This is not sufficient to guarantee your plugin will perform Ok with an ePN but if the plugin fails this test it will ceratinly fail with your ePN. [ A sample mini ePN is included in the contrib/ directory of the Nagios distribution for use in testing Perl plugins. Change to the contrib/ directory and type 'make mini_epn' to compile it. It must be executed from the same directory that the p1.pl file resides in (this file is distributed with Nagios). ]
Compiling Nagios With The Embedded Perl Interpreter
組込みPerlを有効にしてNagiosをコンパイル
さて、一休み出来ますね。まだ組込みPerlを有効にしてNagiosをコンパイルしたいですか? ;-)
Okay, you can breathe again now. So do you still want to compile Nagios with the embedded Perl interpreter? ;-)
組込みPerlを有効にしてNagiosをコンパイルしたいのなら、--enable-embedded-perl
オプションを付けて再度コンフィギュアスクリプトを実行する必要があります。コンパイルしたスクリプトを内部的にキャッシュさせたければ、--with-perlcache オプションも付けて下さい。例:
If you want to compile Nagios with the embedded Perl interpreter you need to rerun the configure script with the addition of the --enable-embedded-perl option. If you want the embedded interpreter to cache internally compiled scripts, add the --with-perlcache option as well. Example:
./configure --enable-embedded-perl --with-perlcache ...other options...
コンフィギュアスクリプトを新しいオプションで実行し直したら、Nagiosを忘れずコンパイルし直して下さい。Nagiosが組込みPerlを有効にしてコンパイルされているかは、-m コマンドラインオプションで確認することが出来ます。そのコマンドラインの実行結果は次のようになります。(組込みPerlはオプションのセクションにあることに注意)
Once you've rerun the configure script with the new options, make sure to recompile Nagios. You can check to make sure that Nagios has been compile with the embedded Perl interpreter by executing it with the -m command-line argument. Output from executing the command will look something like this (notice that the embedded perl interpreter is listed in the options section):
[nagios@firestore ]# ./nagios -m
Nagios 1.0a0
Copyright (c) 1999-2001 Ethan Galstad (nagios@nagios.org)
Last Modified: 07-03-2001
License: GPL
External Data I/O
-----------------
Object Data: DEFAULT
Status Data: DEFAULT
Retention Data: DEFAULT
Comment Data: DEFAULT
Downtime Data: DEFAULT
Performance Data: DEFAULT
Options
-------
* Embedded Perl compiler (With caching)