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数据:

[root@xxxx-xx ~]# zabbix_get -s 10.0.0.210 -k net.if.discovery
{
	"data":[
		{
			"{#IFNAME}":"lo"},
		{
			"{#IFNAME}":"em1"},
		{
			"{#IFNAME}":"em2"},
		{
			"{#IFNAME}":"em3"},
		{
			"{#IFNAME}":"em4"}]}
[root@xxxx-xx ~]#

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

[root@xxxx-xx bin]# 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.discovery、vfs.fs.discovery格式结构相同,研究过源码的大神说zabbix的C代码解析json数据是以\t分割的,所以空白的地方得是tab键才行),数据中的key值命名规则满足{#[A-Z]{1,}},就是zabbix中宏的命名规则。

[root@SH-BA-01-WEB03 bin]# ./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"}]}
[root@SH-BA-01-WEB03 bin]#

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

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

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

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

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

zabbix_get -s 10.8.12.210 -k ports.discovery

2、server端
新建模板,命名为Ports Monitoring。保存模板并在该模板上创建新的发现规则;
auto_ports-01
与定义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
文章出处:http://www.xiaomastack.com/2015/07/03/zabbix-auto-tcp-port/

6 Comments

 Add your comment
  1. 你好我用這個腳本 取出來的端口只有 有ip 的才取出來
    像是 0 :::8029 這個的端口都沒有取出來 這是tomcat的端口
    請問能讓這些端口也取出來嗎?

    我改了好幾版都不行,感恩!!!

    網上只有你這個版本的 輸出 json 才能用zabbix 其他像是 .sh 的shell 腳本都不行…會顯示 (Value should be a JSON object.)

    請您幫幫忙!!!

    tcp 0 0 0.0.0.0:44919 0.0.0.0:* LISTEN 21740/sshd
    tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1428/master
    tcp 0 0 :::8029 :::* LISTEN 18098/java
    tcp 0 0 :::8030 :::* LISTEN 17932/java
    tcp 0 0 :::8031 :::* LISTEN 18258/java

  2. 你好,你的这个只要在提取端口号的时候稍微区别下,如果一行字符串中有:::字符的则已该字符分割字符串,没有的就用默认的:字符分割字符串,以此来获取端口号,其它的都不变即可。

  3. 只要把val[0] = valTmp[1] 改成val[0] = valTmp[-1]就行了

  4. 运行脚本 报下面的错是怎么回事啊
    [root@zabbix ~]# ./ports.py
    File “./ports.py”, line 42
    json_data = json_data + “\t\t” + “{” + “\n” + “\t\t\t” + ‘”{#PPORT}”:”‘ + str(net[0]) + “\”,\n” + “\t\t\t” + ‘”{#PNAME}”:”‘ + str(net[1]) + “\”},\n”
    ^
    IndentationError: expected an indented block

  5. 你代码缩进的问题:)

发表评论:

你的电子邮件地址将不会被公开.

− 2 = 2