muninを少し変更 その2
muninのソースコードって結構ガチガチに作ってあるところがある。
特にプラグインを実行する部分って/usr/sbin/munin-node っていう perlスクリプトなんだけど、
こんな感じ↓になって切り離し大変面倒。
/usr/sbin/sbin/munin-node より
sub run_service { my ($service,$command,$autoreap) = @_; $command ||=""; my @lines = ();; my $timed_out = 0; if ($services{$service} and ($caddr eq "" or &has_access ($service))) { my $child = 0; my $timeout = get_var (\%sconf, $service, 'timeout'); $timeout = $sconf{'timeout'} unless defined $timeout and $timeout =~ /^\d+$/; if ($child = open (CHILD, "-|")) { eval { local $SIG{ALRM} = sub { $timed_out=1; die "$!\n"}; alarm($timeout); while(<CHILD>) { push @lines,$_; } }; 中略 } wait; alarm(0); } else { print "# Unknown service\n"; } chomp @lines; return (@lines); } sub process_request { my $self = shift; $caddr = $self->{server}->{peeraddr}; print "# munin node at $FQDN\n"; local $SIG{ALRM} = sub { logger ("Connection timed out."); die "timeout" }; alarm($sconf{'timeout'}); while( <STDIN> ){ alarm($sconf{'timeout'}); chomp; if (m/^list\s*([0-9a-zA-Z\.\-]+)?/) { &list_services($1); } elsif (/^quit/ || /^\./) { exit 1; } elsif (/^version/) { &show_version; } elsif (/^nodes/) { &show_nodes; } elsif (/^fetch\s?(\S*)/) { print_service (&run_service($1)) } elsif (/^config\s?(\S*)/) { print_service (&run_service($1,"config")); } else { print "# Unknown command. Try list, nodes, config, fetch, version or quit\n"; } } }
これをコピペして改変なんてダーティーなことはやりたくないし。
で、よく考えたら、この関数って引数は自由に渡せるようになっているから、ここに値を追加すればいいんだよ。
info って値を追加してみた。
sub process_request { my $self = shift; $caddr = $self->{server}->{peeraddr}; print "# munin node at $FQDN\n"; local $SIG{ALRM} = sub { logger ("Connection timed out."); die "timeout" }; alarm($sconf{'timeout'}); while( <STDIN> ){ alarm($sconf{'timeout'}); chomp; if (m/^list\s*([0-9a-zA-Z\.\-]+)?/) { &list_services($1); } elsif (/^quit/ || /^\./) { exit 1; } elsif (/^version/) { &show_version; } elsif (/^nodes/) { &show_nodes; } elsif (/^fetch\s?(\S*)/) { print_service (&run_service($1)) } elsif (/^config\s?(\S*)/) { print_service (&run_service($1,"config")); } elsif (/^info\s?(\S*)/) { print_service (&run_service($1,"info")); } else { print "# Unknown command. Try list, nodes, config, fetch, version, info or quit\n"; } } }
/usr/share/munin/plugins/neet
#!/bin/sh # # neet plugin # # Parameters: # # info # [ "$commands" ] || commands="ps aux ; free ; df -h ; tail --lines 100 /var/log/messages ; dmesg | tail --lines 100 ; netstat -np" if [ "$1" = "autoconf" ]; then # neet not work. echo no exit 1 fi if [ "$1" = "config" ]; then exit 1 fi if [ "$1" = "info" ]; then OLDIFS=IFS IFS=";" for command in $commands ; do echo "==============================================" echo "command: $command" bash -c $command echo "==============================================" done IFS=OLDIFS exit 0 fi exit 1
名前のごとくニートなので、グラフも書かなければ基本何もしない。
だけど、infoって名前で呼ばれたときだけ本気出して仕事する。
ニートは普段休んでいるだけで実力を出すとすごいんだ。三年寝たろう的な感じ。
アニメによるある何のとりえもない男が女の子を守るために本気出して世界を救っちゃってハーレムエンドになる感じ。
これでニートに対して設定を行っておければあらかじめ登録していたコマンドが発行できるよ。
ディフォルトでも結構な情報が取れるとは思うけどね。
んで、メールが送信されるときに、こんな感じで 外の muninにリクエストを投げるといいよ。
http://goungoun.dip.jp/app/fswiki/wiki.cgi/debianetch?page=2007%2F09%2F27%A1%A2munin%A1%A2munin-limits%20%A4%C7%A5%E1%A1%BC%A5%EB%C4%CC%C3%CE に掲載されているコマンドを改変しています。
vi /etc/munin/munin.conf
contact.email.command /usr/local\/sbin/mailmessage.sh "${var:host}" "Munin-notification for ${var:group} ::${var:host}" nareka@example.com.local
メール送信プログラムはこんな感じ /usr/local/sbin/mailmessage.sh です。
#!/bin/bash if [ $# -ne 3 ]; then echo "Usage:" echo "$0 remote_munin_ip mailsubject mailaddress" echo "" echo "Ex" echo " echo "body" | $0 127.0.0.1 'server alert!' nareka@example.com.local" echo " echo "body" | $0 192.168.1.200 'server alert!' nareka@example.com.local" exit 1 fi HOST=$1 PORT=4949 echo "read stdin..." BODY="" while read LINE do BODY="$BODY$LINE\n" done echo "sendmail..." #cat <<EOM | mail -s "$2" $3 cat <<EOM $body --- `( sleep 2 ;echo "info neet" ;sleep 3 ) | telnet $HOST $PORT` EOM
普段でも、このサーバの詳細情報みてーとおもったら、こんな感じでコマンド発行すればいつでも見れるよ。
( sleep 2 ;echo "info neet" ;sleep 3 ) | telnet サーバ名 4949
いちいち該当サーバにログインなんてしなくてもok。楽チンですね。
ついでに、この前の web_access にプロキシ機能を追加してみた。
これで、プロキシを経由した外回りからのチェックもできるようになったよー。
/usr/share/munin/plugins/web_access
#!/usr/bin/perl # # Parameters supported: # # config # autoconf # # hide option # # autoconfigfile # ---> /etc/munin/plugin-conf.d/munin-node auto make. =head1 NAME web_accesses is web health check plugin. INSPIRE wget_page. This source was made based on apache_accesses. This configuration section shows the defaults of the plugin: [web_accesses] env.web0_url http://127.0.0.1/ env.web0_host myhost.local env.web0_grep <html> env.web0_proxy http://192.168.1.1:8080 env.web0_proxy_auth userid:password env.web1_url https://127.0.0.1/ env.web1_host secure.myhost.local env.web1_grep <html> env.web2_url https://127.0.0.1/ env.web2_host super.myhost.local <snip> env.web99_url https://127.0.0.1:8080/ env.web99_grep <html> env.web0_host and env.web0_grep is option paramater. The graph can hang by the response speed. The time-out is 60 seconds. The figure of 61 abnormalities is returned when becoming an error. 61 timeout or server status error (404 403 ... more) 62 When contents specified for grep are not included. health check ga dekiruyo! yattane taechan!! =head1 BUGS Does not support digest authentication. =head1 AUTHOR rti This source was made based on apache_accesses. =head1 LICENSE GPLv2 =cut my $ret = undef; if (! eval "require LWP::UserAgent;") { $ret = "LWP::UserAgent not found"; } # for ssl eval "require Crypt::SSLeay;"; if ( defined $ARGV[0] and $ARGV[0] eq "autoconf" ) { if ($ret) { print "no ($ret)\n"; exit 1; } if ( length(getHttpdSOption()) <= 0 ) { print "no (httpd)\n"; exit 1; } print "yes\n"; exit 0; } #hide option. if ( defined $ARGV[0] and $ARGV[0] eq "autoconfigfile" ) { # httpd -S my $virtualhosts = getHttpdSOption(); if ( length($virtualhosts) <= 0 ) { print "no (httpd)\n"; exit 1; } print "[web_accesses]\n"; my $scanmode = 0; my $i = 0; foreach my $line (split("\n",$virtualhosts)) { if ($scanmode == 0) { if ( $line =~ /^VirtualHost configuration/im || $line =~ /^wildcard NameVirtualHosts/im) { $scanmode = 1; } } elsif ($scanmode == 1) { #VirtualHost configuration if ( $line =~ /^.*?:([0-9]+?) +?([0-9a-zA-Z\.\-_]+?) /im || $line =~ /^ .*?port ([0-9\*]+?) +?namevhost ([0-9a-zA-Z\.\-_]+?) /im) { my $protocol = "http"; my $port = $1; my $host = $2; if ($port == "*") { $port = 80; } if ($port == 443) { $protocol = "https"; } print "env.web${i}_url $protocol://127.0.0.1:$port/\n"; print "env.web${i}_host $host\n"; print "#env.web${i}_ua mozilla\n"; print "#env.web${i}_grep <html>\n"; print "#env.web${i}_proxy http://192.168.1.1:8080\n"; print "#env.web${i}_proxy_auth userid:password\n"; $i ++; } } } exit; } if ( defined $ARGV[0] and $ARGV[0] eq "config" ) { print "graph_title Web Access Time\n"; print "graph_args --base 1000 --lower-limit -10 --upper-limit 70\n"; print "graph_vlabel sec of web access\n"; print "graph_category HealthCheck\n"; print "graph_info web access time\n"; for(my $i = 0; $i < 100 ; $i ++ ) { if (!exists $ENV{"web${i}_url"}) { next; } my $url = $ENV{"web${i}_url"}; my $host = "web{$i}"; if (exists $ENV{"web${i}_host"}) { $host = $ENV{"web${i}_host"}; } print "web${i}.label $host\n"; print "web${i}.info $host($url)\n"; print "web${i}.type gauge\n"; print "web${i}.draw LINE2\n"; print "web${i}.max 70\n"; print "web${i}.min -10\n"; print "web${i}.warning 50\n"; print "web${i}.critical 60\n"; } exit 0; } for(my $i = 0; $i < 100 ; $i ++ ) { if (!exists $ENV{"web${i}_url"}) { next; } my $ua = LWP::UserAgent->new(timeout => 60); my $request = HTTP::Request->new('GET',$ENV{"web${i}_url"}); if (exists $ENV{"web${i}_host"}) { $ua->default_header("Host"=>$ENV{"web${i}_host"}); } if (exists $ENV{"web${i}_ua"}) { $ua->agent($ENV{"web${i}_ua"}); } #proxy and proxy auth support. if (exists $ENV{"web${i}_proxy"}) { $ua->proxy('http', $ENV{"web${i}_proxy"}); if (exists $ENV{"web${i}_proxy_auth"}) { my $auth_sep = index($ENV{"web${i}_proxy_auth"} , ":"); if ($auth_sep >= 1) { $request->proxy_authorization_basic( substr($ENV{"web${i}_proxy_auth"},0 , $auth_sep) , substr($ENV{"web${i}_proxy_auth"},$auth_sep + 1) ); } } } #redirect off. $ua->requests_redirectable([]); my $requesttime = time; my $response = $ua->request($request); $requesttime = time - $requesttime; if ( $response->code <= 199 || $response->code >= 400 ) { #bad respons code $requesttime = 61; } else { if (exists $ENV{"web${i}_grep"}) { my $grep = $ENV{"web${i}_grep"}; if ( ! ($response->content =~ /$grep/im) ) { #bad respons contents $requesttime = 62; } } } print "web${i}.value $requesttime\n"; } #`httpd -S` result. sub getHttpdSOption() { my $virtualhosts = `httpd -S 2>&1`; if (length($virtualhosts) > 0) { return $virtualhosts; } my $virtualhosts = `/usr/sbin/httpd -S 2>&1`; if (length($virtualhosts) > 0) { return $virtualhosts; } #for debian $virtualhosts = `apache2 -S 2>&1`; if (length($virtualhosts) > 0) { return $virtualhosts; } #for source build $virtualhosts = `/usr/local/apache2/sbin/apache -S 2>&1`; if (length($virtualhosts) > 0) { return $virtualhosts; } #not found... return ""; } # vim:syntax=perl
あとは、設定の簡易化ツールとメンテナンス時間帯の設定がほしいんだけど、、、
どうしたもんかねー。
メンテナンスの時間帯は何とかなるとして、設定の簡易化はどうしたものか。
webベースのUIが理想なんだけど、、、、 muninのファイルは root権限で作られているから手が出せぬ。
sudo するなんてイヤだし。。。