python通过zabbix-api批量添加监听端口

一.简介

因为要监控每台机器启动的进程,机器太多又不想挨个手动加,所以有2种方式。可以采用自动发现进程脚本,然后lld方式批量加,但这样监控项只会写80端口监控,报警的时候也只会端口关闭。

使用第二种方式,根据客户端返回的信息,通过zabbix的api来批量添加端口监控就可以增加相关名称了。
file

可以用ansible下发agent脚本,然后开启服务端,再批量用ansible执行客户端脚本来达到批量操作。
file

二.服务端

需要python3,zabbix-net-server.py

#!/usr/bin/python3
import socket, sys, time
import json
import requests

#当前master监听
host = "172.16.5.4"
port = 4312

#自定义监控项所在的应用集名称
zabbix_app = "netstat"

#禁止的监控的服务列表,比如sshd,master,ntpd
deny_server = ["sshd", "hblog", "zabbix_agentd", "master", "staragent-core", "DragoonAgent", "filebeat", "agent"]
deny_port = ["32000"]

#触发器告警级别,(0:未分类; 1:信息; 2:警告; 3:一般严重 ...)
trigger_pri = 4

#zabbix服务器的IP地址
zabbix_ip = "172.16.1.46"

#zabbix的用户名
zabbix_user = "Admin"

#zabbix的密码
zabbix_pass = "123456"

#zabbix api接口地址
url = "http://" + zabbix_ip + ":8000/api_jsonrpc.php"

#zabbix api定义的访问头部信息
post_header = {'Content-Type': 'application/json'}

#调用zabbix api需要身份令牌auth
def get_auth():
    post_data = {
        "jsonrpc": "2.0",
        "method": "user.login",
        "params": {
            "user": zabbix_user,
            "password": zabbix_pass
        },
        "id": "1"
    }

    ret = requests.post(url, data=json.dumps(post_data), headers=post_header)
    zabbix_ret = json.loads(ret.text)
    if 'result' not in zabbix_ret:
        print('login error')
    else:
        return zabbix_ret.get('result')

#用于给api提交并提交
def post_info(values, id_name):
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    try:
        req_error = zabbix_req['error']['data'] #如果获取不到就说明成功了,则返回信息
    except:
        req_info = zabbix_req['result'][id_name]
        return req_info

#以IP信息获取主机id
def get_hostid(auth, host_ip):
    values = {
        "jsonrpc": "2.0",
        "method": "host.get",
        "params": {
            "output": "extend",
            "filter": {
                "host": [host_ip]
            }
        },
        "auth": auth,
        "id": 2,
    }
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    zabbix_req = zabbix_req['result']
    try:
        host_id = zabbix_req[0]['hostid']
        return host_id
    except:
        return 1

#根据主机id获取监控项,这块的条件没用,后面还是要写循环匹配
def get_interfaces(auth, host_id):
    values = {
                "jsonrpc": "2.0",
                "method": "host.get",
                "params": {
                    "output": ['name','hostid',],
                    "filter": {
                        'hostids':[host_id]   #根据主机id获取
                    },
                    "selectInterfaces": [  # 添加这个参数为了获取interfaceid的值
                        "interfaceid",
                        "ip"
                    ],
                },
                "auth": auth,
                "id": 1
            }
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    zabbix_req = zabbix_req['result']
    for i in range(len(zabbix_req)):
        if zabbix_req[i]['hostid'] == host_id:
            return zabbix_req[i]['interfaces'][0]['interfaceid']

#根据主机id和interfaceid定位,传入端口号来添加监控端口,成功返回监控项id
def post_item(auth, host_id, host_interfaceid, server_name, host_port, app_id):
    item_name = server_name + "的" + host_port + "端口-gd"
    item_key = 'check_net[' + host_port + ']'
    values = {
        "jsonrpc": "2.0",
        "method": "item.create",
        "params": {
            "name": item_name,
            "key_": item_key,
            "hostid": host_id,
            "interfaceid": host_interfaceid,
            "applications": [app_id],
            "type": 0,
            "value_type": 3,
            "delay": "60s"
        },
        "auth": auth,
        "id": 1
    }
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    print(zabbix_req)
    return zabbix_req['result']['itemids'][0]

#根据主机ip来定位,传入端口号和服务名来添加触发器,成功返回触发器id
def post_trigger(auth, host_ip, server_name, host_port):
    description = server_name + "的" + host_port + "端口关闭"
    expression = '{' + host_ip + ':check_net[' + host_port + '].sum(#5)}=5'
    values = {
        "jsonrpc": "2.0",
        "method": "trigger.create",
        "params": {
            "description": description,
            "expression": expression,
            "priority": trigger_pri
            },
        "auth": auth,
        "id": 4
    }
    return post_info(values, 'triggerids')

#创建主机的应用集,成功返回应用集id
def post_app(auth, zabbix_app, host_id):
    values = {
        "jsonrpc": "2.0",
        "method": "application.create",
        "params": {
            "name": zabbix_app,
            "hostid": host_id
        },
        "auth": auth,
        "id": 1
    }
    return post_info(values, 'applicationids')

#根据host_id返回应用集列表,
def get_appid(auth, zabbix_app, host_id):
    values = {
        "jsonrpc": "2.0",
        "method": "application.get",
        "params": {
            "output": "extend",
            "hostids": host_id,
            "sortfield": "name"
        },
        "auth": auth,
        "id": 1
    }
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    zabbix_req = zabbix_req['result']
    for i in range(len(zabbix_req)):
        if zabbix_req[i]['name'] == zabbix_app:
            return zabbix_req[i]['applicationid']

#正式步骤
def post_all(host_ip, dict_info):
    print(host_ip + "开始添加监控项和对应触发器,并加入到应用集" + zabbix_app)

    #初始化链接,获得基本信息
    auth = get_auth()
    host_id = get_hostid(auth, host_ip)
    host_interfaceid = get_interfaces(auth, host_id)

    #先创建应用集,如果已经存在则从循环里找出id
    app_id = post_app(auth, zabbix_app, host_id)
    if app_id is None:
        app_id = get_appid(auth, zabbix_app, host_id)

    for k,v in dict_info.items():
        if v[1] in deny_server:
            continue
        else:
            if v[0] in deny_port:
                continue
            else:
                item_id = post_item(auth, host_id, host_interfaceid, v[1], v[0], app_id)
                trigger_id = post_trigger(auth, host_ip, v[1], v[0])

        print(str(item_id))
        if item_id:
            print("添加" + v[1] + "的" + v[0] + "端口监控完成")
        else:
            print("跳过" + v[1] + "的" + v[0] + "监控添加")
    print(" ")

#持续监听端口,对客户端传入的数据进行监控项和触发器添加
def main(host, port):
    serversocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    serversocket.bind((host,port))
    serversocket.listen(200) #最大连接数
    while True:
        print('服务器启动,监听客户端链接')
        clientsocket,addr=serversocket.accept()
        host_ip = addr[0]
        data=clientsocket.recv(1024)
        dict_info = eval(data.decode('utf-8')) #变成字典
        post_all(host_ip, dict_info)
        clientsocket.close()
    serversocket.closel()

if __name__ == '__main__':
    main(host, port)

三.客户端

需要python2和net-tools包,zabbix-net-agent.py

#!/usr/bin/python
#coding=utf-8
#通过netstat -unltp命令收集监听端口,需要客户端安装net-tools
#发送的字典结构:{'pid号',['端口号', '进程名']},pid号主要用于去重,因为一个进程可能监控多个端口

import json, commands, string
import socket, sys

#填写服务端地址和端口
host = "172.16.5.4"
port = 4312

#常用端口列表,防止临时端口
eternal_port = ["80", "8080", "8005"]

#返回当前机器 {'pid号',['端口号', '进程名']}
def get_port():
    prostr = commands.getstatusoutput('netstat -unltp')
    prostr = str(prostr)
    prolist = prostr.split('\\n') #用两个\才行
    del prolist[0]
    del prolist[0]
    prolist = prolist[::-1]
    port_list = {}
    lock_pid = [] #用于锁定pid

    for info in prolist:
        port_info = info.split()
        if len(port_info) >= 7:
            tmp_port = port_info[3].split(':')
            tmp_port = tmp_port.pop()
            tmp_info = port_info[6].split('/')
            tmp_pid = tmp_info[0]
            try:
                tmp_name = tmp_info[1]
            except:
                continue

            if tmp_pid in lock_pid: #如果端口是常用端口组里,就跳过这个,只监控常用端口
                continue

            if tmp_port in eternal_port: #如果在表里就把pid锁定了,加入到锁定数组里
                lock_pid = lock_pid + [tmp_pid]

            port_list[tmp_pid] = [tmp_port, tmp_name]
    return port_list

#向master程序提交信息
def post_port(host, port):
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    host=host
    port=port
    s.connect((host,port))

    data = get_port()
    data = str(data)
    s.send(data.encode('utf-8'))
    s.close()

if __name__ == "__main__": 
#    post_port(host, port)
     print(get_port())

四.检测脚本

check_net.py

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

#返回当前机器 {'pid号',['端口号', '进程名']}
def get_port(port):
    prostr = commands.getstatusoutput('netstat -unltp')
    prostr = str(prostr)
    prolist = prostr.split('\\n') #用两个\才行
    del prolist[0]
    del prolist[0]
    port_list = []

    for info in prolist:
        port_info = info.split()
        if len(port_info) >= 7:
            tmp_port = port_info[3].split(':')
            tmp_port = tmp_port.pop()
            port_list = port_list + [tmp_port]
    if port in port_list:
        print("0")
    else:
        print("1")

if __name__ == "__main__": 
    get_port(sys.argv[1])

五.清理脚本

如果添加后不想要了或者觉得有点问题,可以使用清理脚本批量清理掉。脚本根据Ip.txt逐行读取ip地址,查询这台机器拥有的id号,根据匹配[端口]结尾的监控项名字进行删除。

clear_item.py

#!/usr/bin/python3
import json, re, requests

#zabbix服务器的IP地址
zabbix_ip = "1.1.1.1"

#zabbix的用户名
zabbix_user = "Admin"

#zabbix的密码
zabbix_pass = "zabbix"

#zabbix api接口地址
url = "http://" + zabbix_ip + ":8000/api_jsonrpc.php"

#zabbix api定义的访问头部信息
post_header = {'Content-Type': 'application/json'}

#调用zabbix api需要身份令牌auth
def get_auth():
    post_data = {
        "jsonrpc": "2.0",
        "method": "user.login",
        "params": {
            "user": zabbix_user,
            "password": zabbix_pass
        },
        "id": "1"
    }

    ret = requests.post(url, data=json.dumps(post_data), headers=post_header)
    zabbix_ret = json.loads(ret.text)
    if 'result' not in zabbix_ret:
        print('login error')
    else:
        return zabbix_ret.get('result')

#用于给api提交并提交
def post_info(values, id_name):
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    try:
        req_error = zabbix_req['error']['data'] #如果获取不到就说明成功了,则返回信息
    except:
        req_info = zabbix_req['result'][id_name]
        return req_info

#以IP信息获取主机id
def get_hostid(auth, host_ip):
    values = {
        "jsonrpc": "2.0",
        "method": "host.get",
        "params": {
            "output": "extend",
            "filter": {
                "host": [host_ip]
            }
        },
        "auth": auth,
        "id": 2,
    }
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    zabbix_req = zabbix_req['result']

    try:
        host_id = zabbix_req[0]['hostid']
        return host_id
    except:
        return 1

def get_iteminfo(auth,host_id):
    values = {
        "jsonrpc": "2.0",
        "method": "item.get",
        "params": {
            "output": ['name','key','itemid'],
            "hostids": [host_id],
        },
        "auth": auth,
        "id": 1
    }
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    zabbix_req = zabbix_req['result']
    NameRe = re.compile('端口-gd$') #做匹配
    for i in range(len(zabbix_req)):
        if NameRe.search(zabbix_req[i]['name']):
            print(del_item(auth, zabbix_req[i]['itemid']))

def del_item(auth, item_id):
    values = {
        "jsonrpc": "2.0",
        "method": "item.delete",
        "params": [item_id],
        "auth": auth,
        "id": 1
    }
    zabbix_req = requests.post(url, data=json.dumps(values), headers=post_header)
    zabbix_req = zabbix_req.json()
    return zabbix_req

if  __name__ == '__main__':
    for host_ip in open("ip.txt"):   
        host_ip = host_ip.strip()

        auth = get_auth()
        host_id = get_hostid(auth, host_ip)
        get_iteminfo(auth, host_id)
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论