zabbix自动发现并监控主机的TCP监听端口

zabbix有两类发现,一类是服务器的自动发现,一类是服务器上设备的自动发现(lld),用zabbix的low-level discovery(低层次的自动发现)功能实现设备的自动发现和监控。
zabbix2.0.9本身只持文件系统(vfs.fs.discovery)、网卡(net.if.discovery)、SNMPOIDs三种设备的自动发现,其它的发现需要用户自定义。自定义自动发现需要注意的是agent返回给server端的json数据格式有严格的限制(我测试了不同格式化后的json数据,发现自定义的json数据格式化后要和net.if.discovery、vfs.fs.discovery结构相同才行)。
下面是net.if.discovery返回的json数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ zabbix_get -s 10.0.0.210 -k net.if.discovery
{
"data":[
{
"{#IFNAME}":"lo"},
{
"{#IFNAME}":"em1"},
{
"{#IFNAME}":"em2"},
{
"{#IFNAME}":"em3"},
{
"{#IFNAME}":"em4"}]}
$

下面是我获取主机本地服务和端口的py脚本(本来用json.dumps格式化数据,由于格式要求严格,发现还是直接拼接来的快):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
cat ports.py

#!/usr/bin/python
#coding=utf-8
import commands

##########返回命令执行结果
def getComStr(comand):
try:
stat, proStr = commands.getstatusoutput(comand)
except:
print "command %s execute failed, exit" % comand
#将字符串转化成列表
#proList = proStr.split("\n")
return proStr

##########获取系统服务名称和监听端口
def filterList():
tmpStr = getComStr("netstat -tpln")
tmpList = tmpStr.split("\n")
del tmpList[0:2]
newList = []
for i in tmpList:
val = i.split()
del val[0:3]
del val[1:3]
#提取端口号
valTmp = val[0].split(":")
val[0] = valTmp[1]
#提取服务名称
valTmp = val[1].split("/")
val[1] = valTmp[-1]
if val[1] != '-' and val not in newList:
newList.append(val)
return newList

def main():
netInfo = filterList()
#格式化成适合zabbix lld的json数据
json_data = "{\n" + "\t" + '"data":[' + "\n"
#print netInfo
for net in netInfo:
if net != netInfo[-1]:
json_data = json_data + "\t\t" + "{" + "\n" + "\t\t\t" + '"{#PPORT}":"' + str(net[0]) + "\",\n" + "\t\t\t" + '"{#PNAME}":"' + str(net[1]) + "\"},\n"
else:
json_data = json_data + "\t\t" + "{" + "\n" + "\t\t\t" + '"{#PPORT}":"' + str(net[0]) + "\",\n" + "\t\t\t" + '"{#PNAME}":"' + str(net[1]) + "\"}]}"
print json_data

if __name__ == "__main__":
main()

输出的格式是这样的与net.if.discoveryvfs.fs.discovery格式结构相同,研究过源码的大神说zabbix的C代码解析json数据是以\t分割的所以空白的地方得是tab键才行。
数据中的key值命名规则满足

1
{#[A-Z]{1,}}

就是zabbix中宏的命名规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ python ports.py
{
"data":[
{
"{#PPORT}":"199",
"{#PNAME}":"snmpd"},
{
"{#PPORT}":"873",
"{#PNAME}":"rsync"},
{
"{#PPORT}":"70204",
"{#PNAME}":"money"},
{
"{#PPORT}":"60660",
"{#PNAME}":"king"},
{
"{#PPORT}":"80",
"{#PNAME}":"nginx"},
{
"{#PPORT}":"34522",
"{#PNAME}":"sshd"},
{
"{#PPORT}":"73456",
"{#PNAME}":"king"},
{
"{#PPORT}":"443",
"{#PNAME}":"nginx"},
{
"{#PPORT}":"3451",
"{#PNAME}":"scribed"},
{
"{#PPORT}":"10050",
"{#PNAME}":"zabbix_agentd"},
{
"{#PPORT}":"5412",
"{#PNAME}":"castle"},
{
"{#PPORT}":"5666",
"{#PNAME}":"nrpe"}]}
$

写好这个最核心的脚本后,就开始部署了。
1、agent端
定义一个用于自动发现的key,这里key定义为ports.discovery

1
UserParameter=ports.discovery,sudo python /usr/local/zabbix/bin/ports.py

取json数据的脚本是通过netstat取原始数据的,执行脚本必须有root用户权限才能取到服务名,所以给zabbix用户sudo权限

1
2
Defaults:zabbix    !requiretty
zabbix SH-BA-01-WEB03= NOPASSWD: /usr/bin/python

重启agent,使key值生效,可以在server端测试key值

1
zabbix_get -s 10.8.12.210 -k ports.discovery

2、server端
新建模板,命名为Ports Monitoring。保存模板并在该模板上创建新的发现规则;
auto_ports-01](/images/2015/07/auto_ports-01.png)
与定义item时的各项类似,需要注意过滤需要的正则表达式在”管理”–>”一般”–>”正则表达式”(”Administration”–>”General”–>”Regular expressions”)定义,当前定义的正则表达式是过滤掉4位数以下的端口;
auto_ports-02
创建项目原型,与定义item时的各项类似(net.tcp.listen.grep用的是自定义的key,与net.tcp.listen功能相同),用好自定义json数据中的宏;
auto_ports-03
创建触发器原型,关联好项目原型;
auto_ports-04
另外还可以定义图形原型(这里没有定义)。
定义好模板的自动发现规则后就可以在相应的主机上套用该模板了,主机套用模板后,会自动发现并添加项目,触发器等,如下:
自动添加的项目
auto_ports-05
自动添加的触发器
auto_ports-06

----------------本文结束 感谢阅读----------------