用nagiosql来管理nagios

下午蚊子抽空也装上了nagiosql,这是一款web方式管理nagios的软件,安装过程确实很简单,只要符合官方要求后,一路下一步就搞定了,基本上没有遇到啥问题

关于权限上的设置可以参考http://www.nagiosql.org/faq/31-general-documentation/71-nagiosql3-documentation.html#Download

感谢老曲的大力支持,有了这个,确实能达到事半功倍的效果,而且可以不用太多的关注关联问题,只需要根据自己的需求点点鼠标,悄悄键盘就行了。

官方放出了个demo,有兴趣的可以去看看http://demo.nagiosql.org,用户名密码都是demo。

放两张截图

nagios监控NFS挂载脚本更新[原创]

在蚊子上篇文章《nagios监控NFS是否被正确的挂载》中,介绍了一个脚本,是用了监控nfs是否被正常挂载的,在这几天使用过程中还是发现了一些小问题。

如果nfs挂载的顺序没有按照fstab中写的顺序进行挂载,监控就会发出warning的警告,但报警信息中没挂载的硬盘信息是空的,实际查看机器确是所有挂载正常。

于是对我的脚本进行了调整,将check_mount函数提前运行,然后根据LIST变量内容判断是否挂载正常,调整后脚本的如下,同时后面提供了脚本下载地址。

有需要的朋友可以去下面的地址下载

下载check_nfsmount文件

nagios监控NFS是否被正确的挂载[原创]

今天蚊子与大家分享的nagios监控脚本是监控NFS是否被挂载上的脚本

先说下我写这个脚本的初衷吧,事情还是因为上次网络部调整我服务器机柜位置引起的,当时蚊子自信满满的认为服务器上我已经配置好了自动挂载NFS,所以我根本不用担心NFS挂载的情况,当服务器启动恢复后,我的nagios给我发了一个recovery的邮件,我就想当然的认为好了,也就没管。第二天开发人员居然找到我,问我昨天是不是有两台机器重启了,我说是呀,他们就说NFS没有挂载上,我当时还很强调说不可能呢,结果我手动重启了一下昨天的机器,发现真的没有自动挂载上,让我很是郁闷。

没有自动挂载到还不是让人最郁闷,那个我已经通过技术问题解决了,郁闷的是有了问题居然不是nagios第一时间通知我。由于之前我使用的是nagios的check_disk这个脚本,在NFS磁盘有问题,不可读写或空间不足的时候给我报过警,但我经过测试发现,这个脚本只能监控本地磁盘(包括挂载好的NFS)可用性,而不管是否NFS被正确挂载了,所以才有了今天这个脚本。

脚本名称:check_nfsmount
脚本作用:
1,检查NFS磁盘是否被挂载
2,报告哪些NFS没有被挂载
使用方法:
1,将需要mount的NFS磁盘写入到fstab,如下

# cat /etc/fstab
/dev/VolGroup00/LogVol00 /                       ext3    defaults,usrquota,grpquota        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
/dev/VolGroup00/LogVol01 swap                    swap    defaults        0 0
192.168.211.129:/home/tst       /data/tst       nfs     defaults        0 0
192.168.211.129:/home/tst02     /data/tst02     nfs     defaults        0 0
192.168.211.129:/home/tst03     /data/tst03     nfs     defaults        0 0

2,将脚本nagios安装目录的libexec下,并赋予可执行权限
3,配置nrpe配置文件,添加相应的command
4,nagios监控机上添加相应的服务
脚本内容:

对于脚本中还没有考虑到的还希望各位指出。

nagios监控apache进程数[技术]

蚊子今天写了一个nagios监控apache的进程数的脚本,同时学习到了一个新的命令:getopts,现把脚本分享如下。

 

有需要的朋友拿去用吧,此脚本参考了nagios-exchange站点上的check_apacheconcreq这个脚本,这个脚本是监控当前请求的数量,有兴趣的可以去下载:http://exchange.nagios.org/components/com_mtree/attachment.php?link_id=1374&cf_id=29

解决nagios报警不发邮件通知一例[技术]

今天早上来到公司,打开nagios页面,发现服务这部分有10多个严重的报警,都是红色的,蚊子我就特别的诧异了,周六的时候我还收到了很多的warning的邮件呢,怎么这两天这么消停呢,好在目前还只是在测试阶段,不然,可就郁闷坏了。

不说这个了,先来排查错误吧。

第一个想到的是warning报警发了邮件,而CRITICAL就报警不发邮件通知了,又看了一下nagios的日志,我service的状态变化是出在周六,也就是从warning转变成critical就不发邮件了,问题可能出在服务报警通知那部分,于是先看了一下我定义的所有服务和主机的模板文件,内容如下

# vi genericdef.cfg

  1 define host{
  2     name                                                generic-host
  3     check_period                                  24×7
  4     notifications_enabled                   1
  5     event_handler_enabled               1
  6     process_perf_data                       1
  7     retain_nonstatus_information    0
  8     contact_groups                              admins
  9     notification_interval                       60
10     notification_period                        24×7
11     notification_options                      d,u,r
12     stalking_options                           o,d,u
13     register                                           0
14 }
15
16 define service{
17     name                                               generic-service
18     active_checks_enabled               1
19     passive_checks_enabled           1
20     notifications_enabled                   1
21     event_handler_enabled               1
22     check_period                                  24×7
23     max_check_attempts                   3
24     normal_check_interval                10
25     retry_check_interval                      2
26     contact_groups                             admins
27     notification_options                      w,u,c,r
28     notification_interval                       60
29     notification_period                        24×7
30     register                                            0
31 }

从上面service定义来看,通知选项已经加入了c(CRITICAL)这个参数了,看了问题不是出在这里。

第二个我想到的地方就是contract的配置文件,打开看了一下

1 define contact{
2         contact_name                                    nagios-msn-admin       
3         alias                                                     Nagios msn Admin       
4         email                                                    [email protected]
5         host_notification_commands         notify-host-by-msn
6         host_notification_options                d,u
7         host_notification_period                  24×7
8         service_notification_period             24×7
9         service_notification_options           w,u,r,c         //这个位置之前是没有c
10       service_notification_commands   notify-service-by-msn
11       }
12            
13 define contact{
14         contact_name                                   nagios-mail-admin
15         alias                                                    Nagios mail Admin
16         email                                                   [email protected]wenzizone.cn
17         host_notification_commands        notify-host-by-email
18         host_notification_options               d,u
19         host_notification_period                 24×7
20         service_notification_period            24×7
21         service_notification_options          w,u,r,c    //这个位置之前没有c
22         service_notification_commands   notify-service-by-email
23         }

在上面的第9和21行的位置加上c之后,然后重新reload一下nagios,如果没有报错,说明配置更新完毕,很快蚊子又可以收到报警的邮件了。

nagios调整是一个细致的活,看了蚊子还需要做很多的工作才行了。

nagios通过msn/飞信发送报警通知[技术]

蚊子最近一直在弄公司的nagios,最近进行的监控报警这部分了,主要锁定在了msn和短信报警上,下面我把我这边实现的方法整理出来,有需要的朋友可以参考。

1,msn报警

先在这里http://code.google.com/p/phpmsnclass/downloads/list下载最新的msn类文件,这个下载后其实是一套完整的msnbot的php程序,我们这里只是使用了其中的msn.class.php这个文件。

遵循nagios的标准结构,程序文件都会放在/usr/local/nagios/libexec文件夹下,所以我在此文件夹下创建phpmsnclass文件夹,将msn.class.php文件放置其中,并在此目录下创建用于发送msn报警的php程序,内容如下。# cat sendmsnmsg.php

#!/usr/local/php529/bin/php -q

<?php
include_once(‘msn.class.php’);
$msn_username =’YOUR_MSN_ID’; //消息发送人的msn帐号
$msn_password = "yourpassword"; //消息发送人msn密码
$msn_list = array(‘[email protected]’,’[email protected]’); //消息接收人msn地址,这里可选,因为会使用nagios传递过来的地址
$fp=fopen(‘/tmp/tmp/1′,’r’);  //1这个文件是消息发送的内容,这个文件由nagios自动生成,路径根据自己实际自行修改
$file="";
while (! feof($fp)){
$cont=fgets($fp);
$file=$file.$cont;   //拼接报警消息内容
}
$msn =new MSN(‘MSNP15’);  //采用MSNP15协议,支持离线消息
if (!$msn->connect($msn_username,$msn_password)) {
    echo "Error for connect to MSN networkn";
    echo "$msn->errorn";
    exit;
}
else {
        $msn->sendMessage("$file",$argv[1]);  //将$file内容发送给$argv[1]传递进来的msn消息接收者。
}
fclose($fp);
?>

将此文件设置可执行权限,就可以进行测试了,首先在1文件中放入些内容比如

# cat 1
this is a test by wenzizone.cn

然后执行

./sendmsnmsg.php [email protected]  //后面跟的这个是接收人msn地址

可以看到下图

说明msn发送是正常的。

2,飞信报警

首先到这里http://code.google.com/p/phpfetionapi/downloads/list下载飞信的php写的api接口,解压后,同样在/usr/local/nagios/libexec创建phpfetion目录,将class_fetion.php放到此目录下,然后创建发送短信的php程序,如下

#!/usr/local/php529/bin/php -q

<?php
include_once(‘class_fetion.php’);

$sms_username = "1381126xxxx"; //飞信帐号
$sms_password = "your password"; //飞信密码
$fp=fopen(‘/tmp/tmp/1′,’r’); //同msn内容
$file="";
while (! feof($fp)){
$cont=fgets($fp);
$file=$file.$cont;
}

$fetion = new fetion($sms_username,$sms_password);
$fetion->init() or die("fetion init failure!n");
$fetion->sent_sms(‘tel:’.$argv[1],$file);  //根据传送进来的电话发送报警内容
fclose($fp);
?>

分配sendsms.php可执行权限,然后进行测试,执行

./sendsms.php 13810xxxxxx  //后面这个是接受消息的手机号

用不了多一会就会收到消息,消息内容和msn那条一样,因为我们的测试内容不变。

3,和nagios的结合使用

首先编辑command.cfg文件,添加新的如下内容

# ‘notify-host-by-msn’ command definition
define command{
        command_name    notify-host-by-msn
        command_line    /usr/bin/printf "%b" "***** Nagios *****nNotification Type: $NOTIFICATIONTYPE$nHost: $HOSTNAME$nState:    $HOSTSTATE$nIP: $HOSTADDRESS$nInfo: HOSTOUTPUT$nDate/Time: $LONGDATETIME$n" >/tmp/tmp/1 | $USER$/phpmsnclass/sendmsnmsg.php $CONTACTEMAIL$
}

# ‘notify-host-by-fetion’ command definition
define command{
    command_name    notify-host-by-fetion
    command_line    /usr/bin/printf "%b" "***** Nagios *****nNotification Type: $NOTIFICATIONTYPE$nHost: $HOSTNAME$nState: $HOST
STATE$nIP: $HOSTADDRESS$nInfo: $HOSTOUTPUT$nDate/Time: $LONGDATETIME$n" >/tmp/tmp/1 | $USER1$/phpfetion/sendsms.php $CONTACTPAGER$
}

然后修改contacts.cfg文件,如下

define contact{
        contact_name                    nagiosadmin
        alias                                     Nagios Admin
        email                                    http://www.wenzizone.cn/
        pager                                    13810xxxxxx
        host_notification_commands      notify-host-by-msn
        host_notification_options       d,u
        host_notification_period                24×7
        host_notifications_enabled              1
        service_notifications_enabled   1
        service_notification_period             24×7
        service_notification_options    w,u,r
        service_notification_commands   notify-service-by-msn
}

define contact{
        contact_name                    nagiosadmin01
        alias                                     Nagios Admin
        email                                    http://www.wenzizone.cn/
        pager                                    13810xxxxxx
        host_notification_command    snotify-host-by-fetion
        host_notification_options       d,u
        host_notification_period                24×7
        host_notifications_enabled              1
        service_notifications_enabled   1
        service_notification_period             24×7
        service_notification_options    w,u,r
        service_notification_commands   notify-service-by-fetion
}

接下来再host或者service上填上对应的contact然后就可以随时收到相应的报警了。

蚊子在这两天的测试用发现,飞信报警的送达率还是很高的,基本是每条都能收到,但是msn的送达率就令人担忧了,我发送10个能收到一个就算不错了,所以还请根据自己测试情况酌情考虑。

另外一点需要注意的是msn或者飞信发送报警,接收人都必须是发送人msn或飞信的好友才行,不然是不能送达的。

蚊子完成本篇文章参考了如下两篇文章

1.http://blog.s135.com/post/390/,主要参考了msn的php脚本

2.http://www.ritto.cn/?p=308,受到博主使用class.fetion.php的启发,去google上找到飞信的php-api

nagios平台从apache迁移到nginx

为了学习nginx,又苦于公司生产环境没有打算要换到nginx上,于是就想到拿自己搭建的监控环境开刀了,一路配置下来确实还是遇到不少麻烦,不过还好最终还都是圆满解决掉了,下面就把我这次从apache迁移到nginx的过程整理下来

原来的监控环境是apache+cacti+nagios,按照网上相关的文档,配置起来那真是傻瓜之所及也,我也不太想赘述了,网上google一下后大把大把的。

新的监控环境nginx+cacti+nagios,其实就是把apache换成了nginx而已,cacti和nagios的安装方法我也不多说了,自己去搜好了,就把转换过程和需要注意的地方写下来。

nginx安装我不赘述,首先是cacti相关的配置,详细如下

location /cacti/ {
         alias /data/wwwroot/web/cacti/;
         index index.php index.html index.htm;
         }

location ~ \.php$ {
         root           /data/wwwroot/web/;
         fastcgi_pass   127.0.0.1:9000;
         fastcgi_index  index.php;
         fastcgi_param  SCRIPT_FILENAME  $document_root/$fastcgi_script_name;
         include        fastcgi_params;
        }

下面解释一下上面的配置,因为我的地址是http://ip/cacti/这样的形式,所以我定义了location /cacti/这个,然后把这个目录重定向到了cacti所在的目录,再看后面php的配置,首先定义了root地址是/data/wwwroot/web/这个就是后面$document_root内容,我的访问php的页面是http://ip/cacti/plugins/monitor/monitor.php,在这个url里cacti/plugins/monitor/monitor.php这部分是$fastcgi_script_name的值,因为涉及到了php页面,所以就会到$document_root即/data/wwwroot/web/下去找,这也就是为什么root定义的时候我不是直接的定义到了/data/wwwroot/web/cacti下,之前我就是在这里出的错误,结果就是始终找不到所需要的文件。

因为nginx本身是不支持cgi的,所以需要使用一个perl脚本来进行转换,脚本如下

#!/usr/bin/perl
use FCGI;
use Socket;
use FCGI::ProcManager;
sub shutdown { FCGI::CloseSocket($socket); exit; }
sub restart  { FCGI::CloseSocket($socket); &main; }
use sigtrap ‘handler’, \&shutdown, ‘normal-signals’;
use sigtrap ‘handler’, \&restart,  ‘HUP’;
require ‘syscall.ph’;
use POSIX qw(setsid);

END()   { }
BEGIN() { }
{
 no warnings;
*CORE::GLOBAL::exit = sub { die "fakeexit\nrc=" . shift() . "\n"; };
};
eval q{exit};
if ([email protected]) {
 exit unless [email protected] =~ /^fakeexit/;
}
&main;

sub daemonize() {
 chdir ‘/’ or die "Can’t chdir to /: $!";
 defined( my $pid = fork ) or die "Can’t fork: $!";
 exit if $pid;
 setsid() or die "Can’t start a new session: $!";
 umask 0;
}

sub main {

 $proc_manager = FCGI::ProcManager->new( {n_processes => 5} );
 $socket = FCGI::OpenSocket( "/usr/local/nginx/logs/cgi.sock", 10 )
 ; #use UNIX sockets – user running this script must have w access to the ‘nginx’ folder!!
 $request =
 FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket,
 &FCGI::FAIL_ACCEPT_ON_INTR );
 $proc_manager->pm_manage();
 if ($request) { request_loop() }
 FCGI::CloseSocket($socket);
}

sub request_loop {
 while ( $request->Accept() >= 0 ) {
 $proc_manager->pm_pre_dispatch();

 #processing any STDIN input from WebServer (for CGI-POST actions)
 $stdin_passthrough = ”;
 { no warnings; $req_len = 0 + $req_params{‘CONTENT_LENGTH’}; };
 if ( ( $req_params{‘REQUEST_METHOD’} eq ‘POST’ ) && ( $req_len != 0 ) )
 {
 my $bytes_read = 0;
 while ( $bytes_read < $req_len ) {
 my $data = ”;
 my $bytes = read( STDIN, $data, ( $req_len – $bytes_read ) );
 last if ( $bytes == 0 || !defined($bytes) );
 $stdin_passthrough .= $data;
 $bytes_read += $bytes;
 }
 }

 #running the cgi app
 if (
 ( -x $req_params{SCRIPT_FILENAME} ) &&    #can I execute this?
 ( -s $req_params{SCRIPT_FILENAME} ) &&    #Is this file empty?
 ( -r $req_params{SCRIPT_FILENAME} )       #can I read this file?
 )
 {
 pipe( CHILD_RD,   PARENT_WR );
 pipe( PARENT_ERR, CHILD_ERR );
 my $pid = open( CHILD_O, "-|" );
 unless ( defined($pid) ) {
 print("Content-type: text/plain\r\n\r\n");
 print
"Error: CGI app returned no output – Executing $req_params{SCRIPT_FILENAME} failed !\n";
 next;
 }
 $oldfh = select(PARENT_ERR);
 $|     = 1;
 select(CHILD_O);
 $| = 1;
 select($oldfh);
 if ( $pid > 0 ) {
 close(CHILD_RD);
 close(CHILD_ERR);
 print PARENT_WR $stdin_passthrough;
 close(PARENT_WR);
 $rin = $rout = $ein = $eout = ”;
 vec( $rin, fileno(CHILD_O),    1 ) = 1;
 vec( $rin, fileno(PARENT_ERR), 1 ) = 1;
 $ein    = $rin;
 $nfound = 0;

 while ( $nfound =
 select( $rout = $rin, undef, $ein = $eout, 10 ) )
 {
 die "$!" unless $nfound != -1;
 $r1 = vec( $rout, fileno(PARENT_ERR), 1 ) == 1;
 $r2 = vec( $rout, fileno(CHILD_O),    1 ) == 1;
 $e1 = vec( $eout, fileno(PARENT_ERR), 1 ) == 1;
 $e2 = vec( $eout, fileno(CHILD_O),    1 ) == 1;

 if ($r1) {
 while ( $bytes = read( PARENT_ERR, $errbytes, 4096 ) ) {
 print STDERR $errbytes;
 }
 if ($!) {
 $err = $!;
 die $!;
 vec( $rin, fileno(PARENT_ERR), 1 ) = 0
 unless ( $err == EINTR or $err == EAGAIN );
 }
 }
 if ($r2) {
 while ( $bytes = read( CHILD_O, $s, 4096 ) ) {
 print $s;
 }
 if ( !defined($bytes) ) {
 $err = $!;
 die $!;
 vec( $rin, fileno(CHILD_O), 1 ) = 0
 unless ( $err == EINTR or $err == EAGAIN );
 }
 }
 last if ( $e1 || $e2 );
 }
 close CHILD_RD;
 close PARENT_ERR;
 waitpid( $pid, 0 );
 } else {
 foreach $key ( keys %req_params ) {
 $ENV{$key} = $req_params{$key};
 }

 # cd to the script’s local directory
 if ( $req_params{SCRIPT_FILENAME} =~ /^(.*)\/[^\/] +$/ ) {
 chdir $1;
 }
 close(PARENT_WR);

 #close(PARENT_ERR);
 close(STDIN);
 close(STDERR);

 #fcntl(CHILD_RD, F_DUPFD, 0);
 syscall( &SYS_dup2, fileno(CHILD_RD),  0 );
 syscall( &SYS_dup2, fileno(CHILD_ERR), 2 );

 #open(STDIN, "<&CHILD_RD");
 exec( $req_params{SCRIPT_FILENAME} );
 die("exec failed");
 }
 } else {
 print("Content-type: text/plain\r\n\r\n");
 print
"Error: No such CGI app – $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n";
 }
 }
}

把上面这个脚本存放在/usr/local/bin下或者你习惯放置的位置,起名cgiwrap-fcgi.pl,当然你也可以使用其他的名字。当执行这个pl脚本的时候会在/usr/local/nginx/logs/生成一个cgi.sock文件,这个生成的文件要对nginx运行用户有访问的权限,因为我nginx用daemon这个用户跑的,所以我设置这个文件对daemon用户有访问的权限。

这个脚本设置好了之后再来看下nginx里的配置

location ~\.cgi$ {
         rewrite ^/nagios/cgi-bin/(.*)\.cgi /$1.cgi break;
         fastcgi_pass unix:/usr/local/nginx/logs/cgi.sock;
         fastcgi_param  SCRIPT_FILENAME  /usr/local/nagios/sbin/$fastcgi_script_name;
         include        fastcgi_params; 
         fastcgi_index  index.cgi;
         auth_basic      "nagios";
        auth_basic_user_file    /usr/local/nagios/etc/htpasswd.users; 
         }

location /nagios/ { 
         alias /usr/local/nagios/share/; 
         index index.html; 
         auth_basic      "nagios"; 
        auth_basic_user_file    /usr/local/nagios/etc/htpasswd.users; 
         }

location /pub/images/ {
                        alias /usr/local/nagios/share/docs/images/; 
         auth_basic      "nagios";
            auth_basic_user_file    /usr/local/nagios/etc/htpasswd.users; 
         }

接下来就是需要生成nagios执行cgi的用户和设置密码

/usr/local/apache2/bin/htpasswd -c /usr/local/nginx/conf/htpasswd.users nagiosadmin

接下来修改/usr/local/nagios/etc/cgi.cfg文件,在其中找到#default_user_name=guest这行,将其改为default_user_name=nagiosadmin,到此迁移工作就已经完成了,下面来启动相应的程序来测试吧,再次我写了一个nginx的启动脚本,内容如下

#!/bin/sh

spswfile=/usr/local/php529/bin/spawn-fcgi
phpcgi=/usr/local/php529/bin/php-cgi
nginxfile=/usr/local/nginx/sbin/nginx
cgifile=/usr/local/bin/cgiwrap-fcgi.pl

isrun() {
    if
        (ps auxf|grep nginx|grep -v grep >/dev/null 2>&1) && (ps auxf|grep php-cgi|grep -v grep >/dev/null 2>&1)
    then
        return 0
    else
        return 1
    fi
}

nginx_start() {
    if isrun
    then
        echo "nginx already start"
        exit 0
    else
        killall -9 php-cgi >/dev/null 2>&1
        killall -9 nginx >/dev/null 2>&1
                killall -9 perl >/dev/null 2>&1
        $spswfile -a 127.0.0.1 -p 9000 -f $phpcgi >/dev/null 2>&1
                /usr/bin/perl $cgifile >/dev/null 2>&1 &
        $nginxfile >/dev/null 2>&1
                sleep 10
                /bin/chown daemon /usr/local/nginx/logs/cgi.sock
    fi
}

nginx_stop() {
        killall -9 php-cgi >/dev/null 2>&1
        killall -9 nginx >/dev/null 2>&1
                killall -9 perl >/dev/null 2>&1
        rm -rf /usr/local/nginx/logs/nginx.pid
}

case $1 in
    start)      nginx_start;;
    stop)       nginx_stop;;
    restart)    nginx_stop
                nginx_start
                ;;
    *)          echo "useage: {start|stop}";;
esac

这样只需要执行这个脚本就可以启动fastcgi和cgi及nginx了,接下来就可以进行真正的测试了

以上文章参考了:

http://wiki.nginx.org/NginxSimpleCGI
http://www.lazysa.com/2009/05/392.html

另外有一点需要注意的就是cgi.cfg的修改,网上很多文章都没有提到,就是我上面写的那个是有默认用户的,如果那个不做修改的话,访问nagios的主机和服务的时候都显示如下,更改之后就没有问题了

无权查看任何主机的信息…
请检查HTTP服务器关于该CGI的访问权限设置。