前言:Nagios是相当不错的监控工具,被称作是“监控之神”,但同样也有“难搞死”头衔。发挥 Nagios一切魅力的都是他的插件,正因为丰富多样的插件让nagios有血有肉。监控的内容不断在变化,插件也不断变化,默认的一些插件可能越来越不 能满足需求,这个时候就要自己来写些插件了。
以下就是用我的第一个Nagios插件来说明编写方法和我遇到一些问题调试方法。如果你有耐心可以通篇看完,应该对第一次写的人来说会有很大帮助(如果你看不懂,可能是我写得不清楚 那就没办法了 表达能力有限)
需求:
监控普通磁盘的健康状况(普通磁盘以外还有RAID、阵列的监控是不同方法来做的,这里先不讨论,先从最简单的入手),定期进行检测,并进行报警,报警内容磁盘是否正常,不正常是什么状态。
分析编写过程:
我写脚本的前提都是先从手动成功完成,再到自动化(我想其它人的思路应该都一样的)
1、找到监控磁盘的方法
通过一番查找 smartctl 这个命令是比较不错的 centos slackware一般的默认都有这个
smartctl -H /dev/sda 只检测状态
smartctl -i /dev/sda 只检测硬盘信息
smartctl -a /dev/sda 检测所有信息
2、获取检测信息
# smartctl -H /dev/sda
smartctl version 5.38 [x86_64-redhat-linux-gnu] Copyright (C) 2002-8 Bruce Allen
Home page is http://smartmontools.sourceforge.net/
SMART Health Status: OK
关键的最后一行说明磁盘的情况 截取 DISK_HEALTH=`smartctl -H /dev/sda | tail -1 | cut -d: -f2- `
3、 进行关键判断
据我所知道的 smartctl 5.38 是出以上的結果 为OK
而 smartctl 5.39 是出以下結果
=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED
关键词是PASSED
所以要分析判断多种情况
4、脚本编写步骤
1)了解nagios插件编写规范
Nagios的插件可以用脚本(shell、Perl)C编译后的可执行程序,但必须满足以下两件事:
A、既出时有一个返回值
B、至少向标准输出设备(STDOUT)输出一行文件。(但也不能太大,默认是4K,如果想大些,修改源程序吧,方法搜。。。)
返回值定义:
Plugin Return Code
|
Service State
|
DISK State
|
0
|
OK
|
OK 或者PASSED
|
1
|
WARNING
|
插件警告 DISK报警只分OK或者CRITICAL
|
2
|
CRITICAL
|
DISK检测非OK 或者PASSED
|
3 |
UNKNOWN
|
未知状态
|
2)插件编写SHELL速成法
在这里我选用我最熟悉的SHELL进行脚本编写 ,
我的速成法就是,直接去nagios exchange 去下比较成熟的比较简单的shell脚本,这样会从一开始借鉴别人好的方法,养成好的习惯,而且只要你有一点SHELL编程经验也可以很快写得像一个老手。(不过不要把自己搞晕了就行)
3)以下是我的check_disk_health.sh
#!/bin/bash
# ========================================================================================
# disk health plugin for Nagios
#
# Written by : Ajian
# Release : 1.2.0
# Creation date : 2009-07-28
# Revision date : 2009-07-30
# Description : Nagios plugin (script) to check disk health .
# This script has been designed and written on Linux System.
#
# USAGE : ./check_disk_health.sh [-d (disk)]
#
# Exemple: ./check_cpu_stats.sh
# ./check_cpu_stats.sh -d /dev/sda
#
#
# HISTORY :
# Release | Date | Authors | Description
# --------------+---------------+----------------------+-----------------------------------
# 1.0.0 | 2009-07-28 | Ajian | Create the script
# 1.2.0 | 2009-07-30 | Ajian | modify the script and run well ,fix a bug.
# -----------------------------------------------------------------------------------------
# NOTICE:
#-----------------------------------------------------------------------------------------
# You should have the root Permissions ,You can use sudo to realize .
# -----------------------------------------------------------------------------------------
# Nagios return codes
#定义 nagios返回的状态变量
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
# Paths to commands used in this script. These may have to be modified to match your system setup.
# 定义关键的核心命令smartctl 路径 如果你的系统不是这个地址,请更改。 以下注释的是调试的信息,是自动获取命令路径的方法。
SMARTCTL="/usr/sbin/smartctl"
#SMARTCTL=`which smartctl`
#if [ $? -ne 0 ]; then
# echo " smartctl is found in $SMARTCTL ; Go on ... "
# echo "smartctl the command cannot find"
# exit $STATE_UNKNOWN
#fi
# Plugin parameters value if not define
# 定义默认的检测硬盘
CHECK_DISK="/dev/sda"
# Plugin variable description
# 插件描述信息
PROGNAME=$(basename $0)
RELEASE="Revision 1.2.0"
AUTHOR="(c) 2009 Ajian (ajian521@gmail.com)"
# Functions plugin usage
# 插件的使用方法函数
print_release() {
echo "$RELEASE $AUTHOR"
}
print_usage() {
echo ""
echo "$PROGNAME $RELEASE - Disk health check script for Nagios"
echo ""
echo "Usage: check_disk_health.sh -d /dev/sdb"
echo ""
echo " -d the disk (/dev/sda) "
echo " not the Hard disk partition(sda2 is wrong)"
echo " -v check the version"
echo " -h Show this page"
echo ""
echo "Usage: $PROGNAME"
echo "Usage: $PROGNAME --help"
echo ""
exit 0
}
print_help() {
print_usage
echo ""
echo "This plugin will check disk health "
echo ""
exit 0
}
# Parse parameters
# 传递参数
while [ $# -gt 0 ]; do
case "$1" in
-h | --help)
print_help
exit $STATE_OK
;;
-v | --version)
print_release
exit $STATE_OK
;;
-d | --disk)
shift
CHECK_DISK=$1
#判断磁盘是否存在
if [ ! -b $CHECK_DISK ];then
echo "$CHECK_DISK is no exsit,Please change it "
exit $STATE_CRITICAL
fi
;;
*) echo "Unknown argument: $1"
print_usage
exit $STATE_UNKNOWN
;;
esac
shift
done
#根据不同的操作进行不同的操作,这里暂时只支持Linux
case `uname` in
Linux )
#最核心的部分 前面都是些脚本的基本功能 一个框架 因为第一个脚本牵扯到了很多东西,虽然功能很简单,
#但折腾了我不少,在后面的分析中会具体说到 总之注意sudo用法 脚本一开始就有说哦
DISK_HEALTH=`$SMARTCTL -H $CHECK_DISK | tail -1 | cut -d: -f2- `
#DISK_HEALTH="OK"
# DISK_INFO=`/usr/bin/sudo $SMARTCTL -i $CHECK_DISK | grep "Device:"`
if [ "$DISK_HEALTH" = " OK" ]|| [ "$DISK_HEALTH" = " PASSED" ];then
echo "OK - $CHECK_DISK status is $DISK_HEALTH "
#echo "OK - $CHECK_DISK status is $DISK_HEALTH | $DISK_INFO"
exit $STATE_OK
else
echo "CRITICAL - $CHECK_DISK status is $DISK_HEALTH "
#echo "CRITICAL - $CHECK_DISK status is $DISK_HEALTH | $DISK_INFO"
exit $STATE_CRITICAL
fi
;;
*) echo "UNKNOWN: `uname` not yet supported by this plugin. Coming soon !"
exit $STATE_UNKNOWN
;;
esac
4)运行脚本
(注意:在最开始自己写的脚本是没有sudo的,以上脚本是已经调试过后的,还需要配置一些其它的东西,慢慢看吧)
给与脚本执行权限,手动执行
# ./check_disk_health.sh
OK – /dev/sda status is OK
結果正确了,其实这个时候,高兴得太早了。 我先不说问题、继续正常的一般流程。
5、配置Nagios 调用插件
1)在远程NRPE 被监控服务器上修改nrpe.conf
# vim /usr/local/nagios/etc/nrpe.cfg
添加 command[check_sda_health]=/usr/local/nagios/libexec/check_disk_health.sh -d /dev/sda
(注意这里了,先提醒下,这里是错误的,一般是正确的,是这个脚本的特殊性造成的)
2)在Nagios 监控服务器上添加一些配置
定义服务
define service{
use Disk-Health
host_name DB-56
servicegroups Disk-Health
service_description check sda disk health
contact_groups admins
check_command check_nrpe!check_sda_health
}
如果像上面定义一个服务 那么就要注意相关的定义了 ,
定义Disk-Health 模版 把硬盘检测定义一个模版会比较好控制,因为硬盘的检测不像其它服务一样需要准确的及时性反正检测得太多可能会造成压力,一般一天检测几次就够了。
定义DB-56 主机需要定义
定义组 admins
以上这些只要安装过nagios 一般都知道的了 只是强调下模版的单独定义
3)通过WEB控制检测 查看結果
結果是失败 报警CRITCTL 但是状态里面的信息都是空的 CRITCTL – /dev/sda status is
6、调试
从Nagios的远程监控来看是失败的,并且没有获取到任务有用的信息。
分析可以看到,说明nrpe调用 这个变量获取到的是为空的信息
DISK_HEALTH=`$SMARTCTL -H $CHECK_DISK | tail -1 | cut -d: -f2- `
即是空的 只有一个原因,肯定是没有执行 如果执行了 肯定会有字段 不管这个字段是否相符。
但是手动执行是没有问题。
经过对smartctl的查看 原来这个命令是只允许root进行调用的。
现在需要解决的问题是:非root 用户 如何远程调用含有需要有root权限命令的脚本进行监控。
(不要小看这一句话,每一个词都是一个需要攻克的地方)
以下是调试步骤:
1)非root用户
NRPE插件是用nagios这个用户来执行的 所以要得到真实的情况需要
A: su nagios 再执行脚本 (这个方法比较好)
B: sudo -u nagios ./check_disk_health.sh
結果:
sudo -u nagios ./check_disk_health.sh
CRITICAL – /dev/sda status is
跟远程的結果是一样的了 没有信息
2)需要有root权限
需要root权限只有一个办法就是用sudo
将DISK_HEALTH=`$SMARTCTL -H $CHECK_DISK | tail -1 | cut -d: -f2- `
改为DISK_HEALTH=`/usr/bin/sudo $SMARTCTL -H $CHECK_DISK | tail -1 | cut -d: -f2- `
(最后发现这时加sudo 并不是关键 关键是很行脚本时用sudo )
結果:sudo -u nagios ./check_disk_health.sh
Password:
需要输入密码 sudo不用输入密码的方法
修改sudo配置文件
执行 visudo
添加
nagios ALL=(ALL) NOPASSWD:/usr/local/nagios/libexec/check_disk_health.sh
建议:最好进行sudo的一些控制,很多网方法就是nagios ALL=NOPASSWD:ALL
结果:
su nagios
/usr/bin/sudo check_disk_health.sh
OK – /dev/sda status is OK
那么在nrpe.conf配置文件中需要添加sudo
command[check_sda_health]=/usr/bin/sudo /usr/local/nagios/libexec/check_disk_health.sh
最开始那个是错误的 注意啊 这个是需要添加/usr/bin/sudo 就是说只要脚本中涉及到提升到root权限的命令那么就要用这个
3)远程调用
远程调用方法:./check_nrpe -H 192.168.0.56 -c check_sda_health
同上如果想模拟真实环境请切换到相应的执行用户 su nagios 再执行以上操作
结果:
这个错误的原因一定要明白,之所以报这个错意思是说NRPE没有获取到任何信息,也说是写脚本之前说的其中第二条规范
问题:在没有任何信息的情况下怎么来获取NRPE执行的日志呢
就是要确定问题在哪,经过一大番的查找眼睛偶尔看到一个有趣的小方法
修复nrpe.conf配置文件 在要检查的命令后面添加>>/tmp/output 2>&1 将错误导出到文件中进行查看
command[check_sda_health]=/usr/bin/sudo /usr/local/nagios/libexec/check_disk_health.sh -d /dev/sda >>/tmp/output 2>&1
重记nrpe服务
远程调用 结果当然还是NRPE: Unable to read output
查看/tmp/output
sudo: sorry, you must have a tty to run sudo
有错误就简单了 原来这个是默认不允许sudo 在后端进行
visudo
注释Defaults requiretty 就OK了
结果通过WEB查看也正确了。
(注意:注释后 检测仍然会是Unable 不过看/tmp/output就会有正确的結果,所以有正确的結果后,一定要去掉 >>/tmp/outpt 2>&1 信息都导到文件中了 nagios还是得不到任何消息。)
一个脚本执行成功后,就是大批量应用,用生产环境验证,出现问题继续调试。
以上为所有的分析调试方法。如果你看到最后一步了,说明你很有耐心,你也一定会成功的,至于写得好与坏、对与错请尽管说,这不会影响你的成功。呵呵
今天在搞nagios 的event handler时调试了半天没有结果,把我郁闷的,最后发现是在visudo里没有注释Defaults requiretty
注释后使用 check_nrpe -H 127.0.0.1 -c restart_nginx 命令可以正常工作
restartnginx.sh 内容如下
#*******************************
#Author sky
#20120206
/usr/bin/sudo /usr/local/nginx/sbin/nginx -s stop
/usr/bin/sudo /usr/local/nginx/sbin/nginx
printf "DONE!"
#*********************************
原先还有“NRPE: Unable to read output”错误,在脚本加一行’ printf "DONE!" ‘就可以了
特此备忘一下
明天再继续搞