参考地址:https://www.chenghuajie.cn/906.html
首先,监控硬盘状态分为几种情况:
1、如果zabbix官方提供监控模板,直接导入应用就行,像我前面写过的dell R720等服务器。
2、参考地址里面写的主要监控方式是分区,这样的如果我一个磁盘阵列12块硬盘,这些硬盘就划了一个分区,这样监控没有意义。真的就是死就死了,只不过死了以后你能第一时间知道罢了。
3、也是我下面要说的这种情况,我不监控分区。使用场景是如果磁盘整列做了RAID5,死一块硬盘,及时替换上去新的硬盘,这样就没有问题了。最多也是等他重新给新硬盘同步一份数据,并不影响使用,真正能做到故障第一之间发现。
硬件需求:
1、python 2.6.6
2、CentOS release 6.5
3、服务器型号DELL T410
4、因为使用的是zabbix_agentd配置文件,所以这个台服务器必须是安装了zabbix_agentd。
5、zabbix3.2.6
一、MegaCli工具
1、安装就不在这里阐述了,网上一搜一大堆。
Slot Number: 11 #硬盘编号,一个组是从0开始计算,依次类推。
Media Error Count: 0 #坏道,如果硬盘出现问题,这个值就不会等于0
Other Error Count: 0 #硬盘松动,越需要注意
Firmware state: Online, Spun Up #在线状态
2、安装方式:
打开https://www.broadcom.com/support/download-search,在这里面搜索MegaCli
下载下来以后copy到系统脸里面直接rpm -ivh安装即可。
命令位置在 /opt/MegaRAID/MegaCli/MegaCli64
#/opt/MegaRAID/MegaCli/MegaCli64 -LDInfo -Lall -aALL #查看raid级别
#/opt/MegaRAID/MegaCli/MegaCli64 -AdpAllInfo -aALL #查看raid卡信息
#/opt/MegaRAID/MegaCli/MegaCli64 -PDList -aALL #查看硬盘信息
#/opt/MegaRAID/MegaCli/MegaCli64 -AdpBbuCmd -aAll #查看电池信息
#/opt/MegaRAID/MegaCli/MegaCli64 -FwTermLog -Dsply -aALL #查看raid卡日志
#/opt/MegaRAID/MegaCli/MegaCli64 -adpCount #显示适配器个数
#/opt/MegaRAID/MegaCli/MegaCli64 -AdpGetTime –aALL #显示适配器时间
#/opt/MegaRAID/MegaCli/MegaCli64 -LDInfo -LALL -aAll #显示所有逻辑磁盘组信息
#/opt/MegaRAID/MegaCli/MegaCli64 -AdpBbuCmd -GetBbuStatus -aALL |grep 'Charger Status' #查看电池充电状态
#/opt/MegaRAID/MegaCli/MegaCli64 -AdpBbuCmd -GetBbuStatus -aALL #显示BBU状态信息
#/opt/MegaRAID/MegaCli/MegaCli64 -AdpBbuCmd -GetBbuCapacityInfo -aALL #显示BBU容量信息
#/opt/MegaRAID/MegaCli/MegaCli64 -AdpBbuCmd -GetBbuDesignInfo -aALL #显示BBU设计参数
#/opt/MegaRAID/MegaCli/MegaCli64 -AdpBbuCmd -GetBbuProperties -aALL #显示当前BBU属性
#/opt/MegaRAID/MegaCli/MegaCli64 -cfgdsply -aALL #显示raid卡型号,raid设置,disk相关信息
其他命令
3、查看所有硬盘信息及状态,参数很详细。
megacli -PDList -aALL
4、使用下面命令抓取我们需要的信息,这里提示因为Other Error Count我这里在监控的时候是抓取的,但是监控的时候没有选择这项,主要原因是线上有用的硬盘报这样的错,但是不影响使用,就偷个懒。
megacli -PDList -aALL |egrep "Slot Number|Media Error Count|Other Error Count|Firmware state”
5、zabbix_agentd安装方式
二、编写脚本
1、自动发现脚本,自动查询机器上有多少块硬盘。这里需要注意一项zabbix接收的json数据,注意输出的结果,如下:
数据结果案例:
{
"data":[
{"{#DISK_NAME}":"sda"},
{"{#DISK_NAME}":"sdb"},
{"{#DISK_NAME}":"sdc"}
]
}
输出以后记得检测一下,是不是合法的json数据,https://www.json.cn/
下面当有硬盘真的被拔出来以后,就彻底没有了,所以你检测时候它会返回一个空,这就尴尬了。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
data_all = []
info_dict = {}
data = {}
data_list= []
def disk_list_info():
info_all = os.popen('sudo megacli -PDList -aALL |egrep "Slot Number|Media Error Count|Firmware state"')
for i in info_all:
data_all.append(i.strip())
solt_num = 0
for i in data_all:
info=i.strip("\n")
name=info.split(":")[0]
value=info.split(":")[1]
if name == "Slot Number":
solt_num += 1
info_dict["Slot Number"] = json.dumps(solt_num)
elif name == "Media Error Count":
info_dict["Media Error Count"] = value
elif name == "Other Error Count":
info_dict["Other Error Count"] = value
elif name == "Firmware state":
info_dict["Firmware state"] = value
disk_info_format(info_dict)
else:
pass
def disk_info_format(args):
global data
disk_name = {}
if args["Slot Number"]:
disk_name["{#DISK_NAME}"] = args["Slot Number"]
data_list.append(disk_name)
if __name__ == '__main__':
disk_list_info()
os.popen('sudo rm -rf /etc/zabbix/scripts/test/MegaSAS.log')
data["data"] = data_list
jsonStr = json.dumps(data)
print(jsonStr)
disk-diskcovery.py
下面是最终版,这里面要注意两点:1、你的MegaCli的执行命令在什么位置,需要更改。2、每次执行完命令以后,会生成一个MegaSAS.log,必须要删除,它是以a+的方式增加的,不清理会变的异常庞大。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
data_all = []
info_dict = {}
data = {}
data_list= []
def disk_list_info():
info_all = os.popen('sudo megacli -PDList -aALL -Nolog |egrep "Media Error Count|SAS Address|Firmware state"')
for h in info_all:
data_all.append(h.strip())
for i in data_all:
info = i.strip('\n')
name=info.split(":")[0]
value=info.split(":")[1]
if name == "Media Error Count":
info_dict["Media Error Count"] = value
elif name == "Firmware state":
info_dict["Firmware state"] = value
elif name == "SAS Address(0)":
info_dict["SAS Address(0)"] = value
disk_info_format(info_dict)
else:
pass
def disk_info_format(args):
global data
disk_name = {}
if args["SAS Address(0)"]:
disk_name["{#DISK_NAME}"] = args["SAS Address(0)"]
data_list.append(disk_name)
else:
pass
if __name__ == '__main__':
disk_list_info()
data["data"] = data_list
jsonStr = json.dumps(data)
print(jsonStr)
disk-discovery.py 最终版
2、监控脚本
脚本解释,如果硬盘信息是Media Error Count不等于0,Predictive Failure Count不等于0,Firmware state: Online, Spun Up 不是在线状态,就输出1,否则输出0。当然你也改改,如果0提醒硬盘有坏道,如果1提醒硬盘不在线,如果输出3硬盘状态良好等等。
注意,在执行megacli命令的时候,在脚本当前目录会生成一个MegaSAS.log文件,在执行完命令以后需要删除该文件,这里需要注意,需要加上绝对路劲,os.path.join()不行,python2.7
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import time
arg = sys.argv[1]
data_all = []
info_dict = {}
data = []
data_format = {}
def disk_list_info():
info_all = os.popen('sudo megacli -PDList -aALL |egrep "Slot Number|Media Error Count|Firmware state"')
for i in info_all:
data_all.append(i.strip())
solt_num = 0
for i in data_all:
info = i.strip("\n")
name = info.split(":")[0]
value = info.split(":")[1]
if name == "Slot Number":
solt_num += 1
info_dict["Slot Number"] = solt_num
elif name == "Media Error Count":
info_dict["Media Error Count"] = value
elif name == "Other Error Count":
info_dict["Other Error Count"] = value
elif name == "Firmware state":
info_dict["Firmware state"] = value
disk_info_format(info_dict)
else:
pass
def disk_info_format(args):
global data_format
if args["Slot Number"]:
val = {'Slot Number {0}'.format(args["Slot Number"]):{'Media Error Count':args['Media Error Count'],'Firmware state':args['Firmware state']}}
data_format.update(val)
if __name__ == '__main__':
disk_list_info()
os.popen('sudo rm -rf /etc/zabbix/scripts/test/MegaSAS.log')
for i in data_format:
keva = 'Slot Number '+''+ i[12::] +''
if arg == i[12::]:
if data_format[keva]['Media Error Count'].strip() == "0" and data_format[keva]['Firmware state'].strip() == "Online, Spun Up":
print("0")
else:
print("1")
else:
pass
disk-health.py
终极版,我们以SAS Address唯一值去判断,这个硬盘在不在,然后再判断他Media Error Count等不等于0,Firmware state: Online, Spun Up 是不是在线状态。最终版的自动发现也是这么一个逻辑。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
arg = sys.argv[1]
data_all = []
info_dict = {}
data = []
data_format = {}
def disk_list_info():
info_all = os.popen('sudo megacli -PDList -aALL -Nolog |egrep "Media Error Count|SAS Address|Firmware state|Predictive Failure Count"')
for h in info_all:
data_all.append(h.strip())
for i in data_all:
info = i.strip("\n")
name = info.split(":")[0]
value = info.split(":")[1]
if name == "Media Error Count":
info_dict["Media Error Count"] = value.strip()
elif name == "Firmware state":
info_dict["Firmware state"] = value.strip()
elif name == "Predictive Failure Count":
info_dict["Predictive Failure Count"] = value.strip()
elif name == "SAS Address(0)":
info_dict["SAS Address(0)"] = value.strip()
disk_info_format(info_dict)
else:
pass
def disk_info_format(args):
global data_format
if args["SAS Address(0)"]:
val = {args["SAS Address(0)"]:{'Media Error Count':args['Media Error Count'],'Firmware state':args['Firmware state'],'Predictive Failure Count':args['Predictive Failure Count']}}
data_format.update(val)
if __name__ == '__main__':
disk_list_info()
# os.popen('sudo rm -rf /etc/zabbix/scripts/MegaSAS.log')
if data_format.get(arg):
info = data_format.get(arg)
if info.get("Media Error Count") != "0":
print("2")
elif info.get("Firmware state") == "Online, Spun Up" and info.get("Predictive Failure Count") == "0":
print("0")
else:
print("1")
else:
print("1")
disk-healthe.py最终版
三、部署zabbix监控环境(Linux)
1、修改zabbix_agentd的配置文件,开启自定义脚本监控开关。
vim /etc/zabbix/zabbix_agentd.conf
增加下面两项,开启自定义脚本开关,并制定脚本位置。
Include=/etc/zabbix/zabbix_agentd.conf.d/*.conf
UnsafeUserParameters=1
2、查看zbbix配置文件会自动包含加载/etc/zabbix/zabbix_agentd.conf.d/这个目录下的conf
配置文件。稍后我们将自定义的配置写到这个目录下。
新建配置文件:
vim /etc/zabbix/zabbix_agentd.conf.d/disk-smart-health.conf
键入如下内容
UserParameter=disk.discovery[*],/etc/zabbix/scripts/test/disk-discovery.py
UserParameter=disk.health[*],/etc/zabbix/scripts/test/disk-health.py $1
别忘记了,将前面说过的脚本分别放到制定的路径下面,并赋予755权限。
3、设定zabbix用户免密以sudo权限执行:
echo "zabbix ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/zabbix
或者直接在 /etc/sudoers
这个文件中配置,先给予写权限:
chmod +w /etc/sudoers
echo "zabbix ALL=(ALL) NOPASSWD:/usr/sbin/smartctl" >> /etc/sudoers
chmod -w /etc/sudoers
重启zabbix,理论只需重启agent端即可:
service zabbix_agentd restart
在zabbix server机器上测试下获取下自定义键值数据:
这步很重要,先测试一下监控脚本能不能用,括号里面的数字是代表第几块硬盘,是什么状态,0代表正常,1证明故障。
UserParameter=key[*],command
key
为唯一值,[*]
表示参数。
command
为要执行的命令或脚本,key
的[*]
里面的参数一一对应$1
到$9
,一共9个参数。$0
表示脚本命令。返回结果数据最大为512KB
。
参数禁止使用下列字符:\ ‘ ” ` * ? [ ] { } ~ $ ! & ; ( ) <> | # @
测试步骤:
1、一般zabbix_get获取不到ip地址原因有几个,本机测试没问题,在本机上和zabbixserver上zabbix_get都获取不到数据,有人说在zabbix_agentd.conf里面的加上Timeout=10,加上超时参数。
1、获取不到数据的主要原因是可能没有权限,在脚本里面需要执行命令的话,一定要加上sudo。
2、尽量不适用文件操作比如python的with open,尽量都存在变量里面。
zabbix_get -s 192.168.8.253 -p10050 -k "disk.health[1]"
四、配置zabbix自动发现等配置
1、这里我并没有单独创建一个模板,我这里是给对应的服务器里面配置了自动发现及监控。
创建自动发现
2、给自动发现创建监控项(通过输入硬盘编号,查看对应的硬盘信息检测返回值)
3、给自动发现创建触发器(如果最后一次检测返回的值是1,就报警。)
4、给自动发现创建触发器(方便查看历史记录)
这里有话要说,因为我们判断是Media Error Count不等于0,Predictive Failure Count不等于0,Firmware state: Online, Spun Up 不是在线状态,就输出1,否则输出0。把SAS Address(0)作为唯一识别符,但是这篇博主所写的值得我们深思
所以这里我们增加一项触发器,就是Media Error Count不等于0的话输出2,最终版里面就是这么写的。这里我们让他触发严重,而不是灾难,当然你也可以选择一般严重。
四、Windows版
一、准备环境
1、安装python2.7以上,并添加环境变量,https://www.python.org/
2、下载megacli的windows版,最前面我们说过。
3、安装zabbix_agentd,这里可以参考原来的博客地址:
二、为什么这里要单独写个windows版本呢,因为windows没有egrep这么命令,用的是findstr命令。而且路径等都不相同。
1、在C盘创建三个文件夹,python,megacli,zabbix。分别把安装程序安装到这三个对应的目录里面。在zabbix下新建scripts目录,把自动发现和检查脚本放到此文件夹里面。
2、自动发现脚本
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
data_all = []
info_dict = {}
data = {}
data_list= []
def disk_list_info():
info_all = os.popen('C:\\megacli\\MegaCli64 -PDList -aALL | findstr "Media Error Count Count Firmware state SAS Address"')
for h in info_all:
data_all.append(h.strip())
for i in data_all:
info = i.strip('\n')
name=info.split(":")[0]
value=info.split(":")[1]
if name == "Media Error Count":
info_dict["Media Error Count"] = value
elif name == "Firmware state":
info_dict["Firmware state"] = value
elif name == "SAS Address(0)":
info_dict["SAS Address(0)"] = value
disk_info_format(info_dict)
else:
pass
def disk_info_format(args):
global data
disk_name = {}
if args["SAS Address(0)"]:
disk_name["{#DISK_NAME}"] = args["SAS Address(0)"]
data_list.append(disk_name)
else:
pass
if __name__ == '__main__':
disk_list_info()
os.popen('del C:\\Windows\\System32\\MegaSAS.log')
data["data"] = data_list
jsonStr = json.dumps(data)
print(jsonStr)
disk-discovery.py
线上最终版
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
data_all = []
info_dict = {}
data = {}
data_list= []
def disk_list_info():
info_all = os.popen('C:\\megacli\\MegaCli64 -PDList -aALL -Nolog | findstr "Media Error Count Count Firmware state SAS Address"')
for h in info_all:
data_all.append(h.strip())
for i in data_all:
info = i.strip('\n')
name=info.split(":")[0]
value=info.split(":")[1]
if name == "Media Error Count":
info_dict["Media Error Count"] = value
elif name == "Firmware state":
info_dict["Firmware state"] = value
elif name == "SAS Address(0)":
info_dict["SAS Address(0)"] = value
disk_info_format(info_dict)
else:
pass
def disk_info_format(args):
global data
disk_name = {}
if args["SAS Address(0)"]:
disk_name["{#DISK_NAME}"] = args["SAS Address(0)"]
data_list.append(disk_name)
else:
pass
if __name__ == '__main__':
disk_list_info()
data["data"] = data_list
jsonStr = json.dumps(data)
print(jsonStr)
disk-discovery.py 最终版
3、检查脚本
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
arg = sys.argv[1]
data_all = []
info_dict = {}
data = []
data_format = {}
def disk_list_info():
info_all = os.popen('C:\\megacli\\MegaCli64 -PDList -aALL | findstr "Media Error Count Predictive Failure Count Firmware state SAS Address"')
for h in info_all:
data_all.append(h.strip())
for i in data_all:
info = i.strip("\n")
name = info.split(":")[0]
value = info.split(":")[1]
if name == "Media Error Count":
info_dict["Media Error Count"] = value.strip()
elif name == "Firmware state":
info_dict["Firmware state"] = value.strip()
elif name == "Predictive Failure Count":
info_dict["Predictive Failure Count"] = value.strip()
elif name == "SAS Address(0)":
info_dict["SAS Address(0)"] = value.strip()
disk_info_format(info_dict)
else:
pass
def disk_info_format(args):
global data_format
if args["SAS Address(0)"]:
val = {args["SAS Address(0)"]:{'Media Error Count':args['Media Error Count'],'Firmware state':args['Firmware state'],'Predictive Failure Count':args['Predictive Failure Count']}}
data_format.update(val)
if __name__ == '__main__':
disk_list_info()
os.popen('del C:\\Windows\\System32\\MegaSAS.log')
if data_format.get(arg):
info = data_format.get(arg)
if info.get("Firmware state") == "Online, Spun Up" and info.get("Media Error Count") == "0" and info.get("Predictive Failure Count") == "0":
print("0")
else:
print("1")
else:
print("1")
disk-health.py
线上最终版
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
arg = sys.argv[1]
data_all = []
info_dict = {}
data = []
data_format = {}
def disk_list_info():
info_all = os.popen('C:\\megacli\\MegaCli64 -PDList -aALL -Nolog | findstr "Media Error Count Predictive Failure Count Firmware state SAS Address"')
for h in info_all:
data_all.append(h.strip())
for i in data_all:
info = i.strip("\n")
name = info.split(":")[0]
value = info.split(":")[1]
if name == "Media Error Count":
info_dict["Media Error Count"] = value.strip()
elif name == "Firmware state":
info_dict["Firmware state"] = value.strip()
elif name == "Predictive Failure Count":
info_dict["Predictive Failure Count"] = value.strip()
elif name == "SAS Address(0)":
info_dict["SAS Address(0)"] = value.strip()
disk_info_format(info_dict)
else:
pass
def disk_info_format(args):
global data_format
if args["SAS Address(0)"]:
val = {args["SAS Address(0)"]:{'Media Error Count':args['Media Error Count'],'Firmware state':args['Firmware state'],'Predictive Failure Count':args['Predictive Failure Count']}}
data_format.update(val)
if __name__ == '__main__':
disk_list_info()
if data_format.get(arg):
info = data_format.get(arg)
if info.get("Media Error Count") != "0":
print("2")
elif info.get("Firmware state") == "Online, Spun Up" and info.get("Predictive Failure Count") == "0":
print("0")
else:
print("1")
else:
print("1")
disk-health.py 最终版
4、在C:\zabbix\zabbix_agentd.conf.d\这个目录下新建配置文件disk-smart-health.conf,并将内容填写进去。
UserParameter=disk.discovery[*],C:\zabbix\scripts\disk-discovery.py
UserParameter=disk.health[*],C:\zabbix\scripts\disk-health.py $1
disk-smart-health.conf
5、修改zabbix_agentd.win.conf,启用脚本监控。
Include=C:\zabbix\zabbix_agentd.conf.d\*.conf
UnsafeUserParameters=1
6、重启zabbix_agentd服务。
7、如第四大标题一样,zabbix server里面添加自动发现等信息,你要是嫌麻烦,可以直接再模板里新建,以后就可以重复使用了。
注意!!!
1、在监控windows 服务器过程中出现过 Zabbix agent item "disk.discovery" on host "服务器监控名称" failed: first network error, wait for 90 seconds错误,是因为zabbix的客户端配置文件里面的Timeout文件默认是3秒导致的,改成30秒就OK了,如果还不行,就需要将zabbix服务端的配置文件里面的Timeout文件也改成30秒,就OK了。
2、我的自动发现开始的时候,都是在每个监控主机里面建的,你可以直接在模板里面新建,这样用着方便。
3、千万记得每次改完脚本或者配置文件,一定要重启zabbix_agentd服务。