一.简介
因为要监控每台机器启动的进程,机器太多又不想挨个手动加,所以有2种方式。可以采用自动发现进程脚本,然后lld方式批量加,但这样监控项只会写80端口监控,报警的时候也只会端口关闭。
使用第二种方式,根据客户端返回的信息,通过zabbix的api来批量添加端口监控就可以增加相关名称了。
可以用ansible下发agent脚本,然后开启服务端,再批量用ansible执行客户端脚本来达到批量操作。
二.服务端
需要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)