centos7之zabbix使用Megacli监控磁盘整列中的硬盘状态
参考地址: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安装方式
https://www.cnblogs.com/lei0213/p/8858269.html
二、编写脚本
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)
下面是最终版,这里面要注意两点: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)
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
终极版,我们以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")
三、部署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)作为唯一识别符,但是这篇博主所写的值得我们深思https://segmentfault.com/a/1190000011402256。
所以这里我们增加一项触发器,就是Media Error Count不等于0的话输出2,最终版里面就是这么写的。这里我们让他触发严重,而不是灾难,当然你也可以选择一般严重。
四、Windows版
一、准备环境
1、安装python2.7以上,并添加环境变量,https://www.python.org/
2、下载megacli的windows版,最前面我们说过。
3、安装zabbix_agentd,这里可以参考原来的博客地址:https://www.cnblogs.com/lei0213/p/8858269.html
二、为什么这里要单独写个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)
线上最终版
#!/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)
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")
线上最终版
#!/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")
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
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服务。