P2P風味のシステムモニタ
unagi.py は緩く結合されたクラスタ環境のためのシステム監視ツールです。 これは複数のユーザがクラスタ上でさまざまなプログラムを走らせるときに、 各マシンの使用状況を報告することによって、ユーザが協力してそのマシン資源を 有効利用できるようにします。このプログラムはクラスタ上のすべてのマシンで走り、 システム情報を共有します。これはまた簡単な HTTP サーバとしての機能も そなえており、ユーザは状況報告をブラウザ上で見ることができます。
注意: unagi.py は公開用のサーバで走ることを意図してつくられては *いません*。 セキュリティ上の理由から、マシンの状態を外部のユーザに見せるべきではありません。
11マシンからなるクラスタの状況報告サンプル (HTML, 220k)
unagi.py の目標は 2つあります:
unagi.py の機能は SNMP のそれに似ています。しかし、2つの異なる点があります: ひとつは、SNMP ではマネージャがすべてのデータを集め、決してダウンしてはいけないこと。 私たちの環境ではいつ、どのマシンもシャットダウンあるいは接続解除される可能性があったため、 すべてのマシンにお互いを監視させたかったのです。これによりユーザは (すべてのマシンが一斉に死なない限り) いつでもどれかのマシンに保存されているマシン 情報にアクセスすることができます。もうひとつは、SNMP の設定がひどく複雑なことです。 私たちは堅牢かつ簡単に設定可能なものを求めていました。
システム情報を集める方法は OS 依存のため、 unagi.py は 現在のところ Linux でしか走りません。これは以下のような情報を収集します:
このプログラムを走らせるには Python 2.3 以上 が必要です。 (Python 1.5.2 でも動きますが、古いバージョンの Python には特権を落とすための 関数が欠けているので新しいバージョンのほうがおすすめです。)
プログラムを走らせるには、まずスクリプトファイルを修正していくつかの パラメータを設定する必要があります (これらの値はコマンドラインからも設定できます)。 変更する必要のある箇所は以下のとおりです:
# ネットワーク情報 SIGNATURE = 'なんらかの文字列' P2P_PORT = P2Pネットワークのための TCPポート番号 # >1024 HTTP_PORT = 状況報告のための HTTPポート番号 # >1024 P2P_SCAN_RANGES = [ 最初のスキャンを行うアドレス範囲 ] # ex. [ "192.168.0.100-199" ] P2P_ALLOW_RANGES = [ 信頼する peer ホストのアドレス範囲 ] # ex. [ "192.168." ] HTTP_ALLOW_RANGES = [ HTTPアクセスを許すアドレス範囲 ] # ex. [ "192.168.", "127." ] UNAGI_USER = 'スクリプトを走らせる実効ユーザ名' # /etc/passwd を修正すること!
SIGNATURE
には識別子として、なんらかの文字列を指定します。
ある P2Pネットワークに属するすべてのマシンは同一の識別子をもつ必要があります
(識別子が違っている場合、他の peer からは無視されます)。
これの基本的な目的は複数の異なる P2Pネットワークを区別するためですが、
たとえネットワークがひとつしかない場合でもなんらかの文字列を指定する必要があります。
また、P2P_PORT
ポート番号と HTTP_PORT
ポート番号も
同一ネットワーク上のすべてのマシンで同じにする必要があります。
P2P_SCAN_RANGES
, P2P_ALLOW_RANGES
, および
HTTP_ALLOW_RANGES
の各値については、お使いのサブネットの
ネットワークアドレスを指定してください。状況報告を外部のネットワークからも
見られるようにしたい場合は HTTP_ALLOW_RANGES
に他のマシンの
IPアドレスを追加してください。また、P2P_ALLOW_RANGES
を変更することで、
サブネットの外のマシンが P2Pネットワークにアクセスすることもできます。
が、世界じゅうのすべてのマシンにお使いの P2P ネットワークを見せないようにしてください!
これはセキュリティ上問題となることがあります。
これらのポート番号は、外部のネットワークからは遮断しておくことをおすすめします。
プライベートネットワークで使っている場合は、これについてあまり深く心配する必要はないでしょう。
また、unagi.py は UDP パケットを他の peer との通信に使っているため、
ルータを越えた通信は信頼性がなくなることも覚えておいてください。
また、 P2P_SCAN_RANGES
はお使いのネットワーク内のアドレスだけに
厳密に制限するようにしてください。なぜなら unagi.py は最初にこの範囲にある
アドレスすべてをスキャンし、ネットワーク上にある他のマシンを探索するためです。
P2P_SCAN_RANGES
にはこのプログラムが走っているマシン自体のアドレスも
含まれていなければなりません。
アドレス範囲は Python のリストとして指定されます。 各リストは 1つ以上の範囲を含むことができます。範囲は以下のようにして指定します:
"a.b.c.d"
(特定のアドレスだけを指定)
"a.b.c.d-e"
(a.b.c.d から a.b.c.e までのアドレス (終端含む) を指定)
"a.b.c."
("a.b.c.1-254"
と同じ)
"a.b."
(a.b. から始まるアドレスすべて --
P2P_ALLOW_RANGES
および HTTP_ALLOW_RANGES
のみで使用可)
unagi.py doesn't need a root privilege to run. So usually
it should run as a harmless user (e.g. "nobody") which has minimum privilege. When
you run this program as root, the script changes its process UID and GID if a specific username is given
as UNAGI_USER
parameter. (However there is a small problem in the older Python -- since
Python 1.5.2 or older doesn't have setgroups
function, it cannot drop its groups
permission, which is not secure. This is why I recommend to use a newer version.)
However, it does need a permission to read several files
and execute ps
command to obtain system information.
In particular, it needs a permission to
read a syslog output file (usually stored in /var/log/messages
) which is
probably not world-readable in most Linux distributions. So you
will need to grant a permission to the user for reading this file.
The safest way is to create a new group named something like
"log
", and make the syslog file group-readable to this
group. Then create a user "unagi
" which belongs to this group
and run the script on this user. For example,
Add the following entry to /etc/group
:
log:x:888:
Add the following entry to /etc/passwd
:
unagi:x:10000:888::/:/sbin/nologin
After setting the configuration, make sure this script launched at startup. You can also run the script directly from the shell for testing purpose.
Running on Linux, unagi.py refers to the following files:
/proc/uptime
/proc/loadavg
/proc/meminfo
/proc/stat
/proc/net/dev
/var/run/utmp
/var/log/messages
ps
command (included in procps
package)
unagi.py [-d] [-u update] [-p p2pport] [-n p2pallow] [-h httpport] [-a httpallow] [-s scanaddrs] [-S signature] [-H nhistory] [-U username]
unagi.py accepts the following command line options.
-d
: Indicate debug mode. It produces verbose output. Two '-d' options increase the debug level.
-u update
: Specify an update interval in seconds. (default: 600)
-p p2pport
: Specify a TCP port number to use P2P communication. (no default)
-n p2pallow
: Specify an address range to accept P2P communication
(can be specified multiple times).
-h httpport
: Specify a TCP port number to publish a status report via HTTP. (no default)
-a httpallow
: Specify an address range to accept HTTP requests
(can be specified multiple times).
-s scanaddrs
: Specify an address range to scan peer machines at startup.
-S signature
: Specify a signature string. (no default)
-H nhistory
: Specify the number of past entries which the program preserves.
-U username
: Specify a username to run the script. (default: "unagi
")
If unspecified, the program doesn't attempt to change its process user id.
unagi.py shares system information with other peers by periodically asking every machine its status (default: every 10mins). Each peer has an internal on-memory database which contains the current status of each machine (including the machine itself). unagi.py uses a packet-based message to communicate with other peers. When a peer receives a message from an unknown machine, after confirming its signature it recognizes the sender as a new peer and registers it to the database. Ocasionally (default: every 30mins) each peer broadcasts a list of all known peers to the entire P2P network so that other peers can know newly added machines. When a machine doesn't respond for a while (default: 30mins), it marks the machine as "down". A machine is eventually removed from the database if it doesn't respond for a long time (default: 10days).
When it is started, unagi.py tries to drop a
privilege (if a username is given), then to bind two
sockets: a UDP socket is used to communicate with other peers. A
TCP socket is used to serve HTTP requests. It first scans a
certain range of addresses (specified by
P2P_SCAN_RANGES
) to find other peers by sending an
initial query packet to every machine in the specified range until
it receives a response from another peer. Since the initial query
range includes the machine itself, at lease one machine should
respond. After this, it enters an event loop and handles the following
protocol.
Communication protocol between peers is simple and stateless. Each message consists of a single UDP packet which contains a text string. Each peer must respond to a message as soon as it receives, or do nothing. Each message must start with its network signature string and it is checked whenever a message is received. There are four types of messages used in the current protocol:
signature?
: INITIAL-QUERY.
Each peer sends this message only once when it starts.
The receiver of this message must immediately respond with an address broadcast message.
signature!address1 address2 ...
:
ADDRESS-BROADCAST. This messaege contains a
space-seperated IP address list of all the peers that the sender currently knows.
This message is sent either by a request of an initial query or by
periodical broadcast by the peer itself. The receiver of this message can
add a new host entry to its internal database if the machine is not known so far,
but it should not update any system information in the database.
signature>
:
REQUEST-IF-UPDATED.
The receiver of this message must send its system status information
to its sender with a status-report message, only if its information has been
updated since the last time the sender asked. Otherwise this message is ignored.
signature<system-status-information
:
STATUS-REPORT.
This message is sent when a peer receives a report-if-updated message and
its system status has been updated since the last time the sender asked.
A status information is string separated with tabs and spaces, and its format
depends on the system it uses.
By giving the debug option (-d
), you can see which message is sent from
one peer to another.
ps
コマンドを自前で実装する。
(注: これはいわゆる「MITライセンス」と呼ばれる形式のものです)
Copyright (c) 2004 Yusuke Shinyama <yusuke at cs dot nyu dot edu>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.