之前零零碎碎写了一些zabbix 线路监控的脚本,工作中agnet较多,每条线路监控需求不一致,比较杂乱,现在整理成一个py模块,集合之前的所有功能
环境
python3.6以上版本,pip3(pip 9.0.1以上版本),mysql,pymysql库
使用zabbix自定义脚本获取线路时延丢包率不做介绍,参考上一篇zabbix文章
如果系统当前python版本是python3.5,升级3.6时有两个注意事项
1 先升级python至3.6再升级pip3否则会导致pip3无法正常使用
2 python3.5升级到3.6后需要把lsb_release.py
文件复制到python3.6的lib里,否则pip3无法正常使用
3 上两步完成后再进行pip3升级
darkping包文件如下
-----bin----程序入口,接收参数调用views
-----views-----逻辑函数,计算并返回
-----mtr.sh----shell脚本,供views调用
-----start-sql----初始化数据插入
------tcping----使用socket计算tcp时延丢包工具
-----log----日志文件
-----models-----数据库相关
-----settings----配置文件,sql语句,文件路径,重要参数等
bin代码
#!/usr/bin/env python3 #-*-coding:utf-8-*- #----------------------------------------------------------zabbixping脚本---------------------------------------------------- import argparse from views import dark_zabbix if __name__ == "__main__": parser = argparse.ArgumentParser(description=‘icmp for monitor‘) parser.add_argument(‘-t‘,action = ‘store‘,dest=‘tip‘) parser.add_argument(‘-i‘,action=‘store‘,dest=‘interval‘,default=‘1‘) parser.add_argument(‘-I‘,action=‘store‘,dest=‘item‘) parser.add_argument(‘-p‘,action=‘store‘,dest=‘port‘,default=‘0‘) parser.add_argument(‘-T‘,action = ‘store‘,dest=‘type‘,default=‘icmp‘) args= parser.parse_args() ip = args.tip i = float(args.interval) item = args.item port = int(args.port) t_ype = args.type print(dark_zabbix(ip,item,i,port,t_ype))
views代码
#!/usr/bin/env python3 #-*-coding:utf-8-*- import log,models,time,subprocess from models import db from settings import dbinfo def dark_zabbix(ip,item,i,port,t_ype): #初始化 res_ret = 0 pkloss_ret = 0 #根据频率计算所select的数据数量,20是zabbix前端获取数据的时间间隔 packet_count= int(20/i) #实例化dbinfo dbvalues = dbinfo() #logger对象 logger = log.logger() #获取调用pingsql命令 cmd = dbvalues.cmd(ip,i,port,t_ype) #获取sql语句 sql_statues = dbvalues.sql_sqlstatues(ip,t_ype,port) sql_getvalue = dbvalues.sql_getvalue(ip,packet_count,t_ype,port) sql_mtr = dbvalues.sql_mtr(ip,packet_count,t_ype,port) #实例化mysql对象,调用readone/all方法 my_sql = db(dbvalues.dbinfo()) lasttime = my_sql.db_readone(sql_statues) now_time = int(time.time()) #判断最新数据时间与当前时间间隔是否超过1分钟,新建item或防止系统重启后台程序异常等 try: ctime = (lasttime[‘time‘]) if now_time - ctime > 60: raise Exception(‘dberror‘) except Exception as a: #调用pingsql脚本开始进行探测并写入数据库 subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) return(res_ret) #根据所设置的粒度取相应的数据 ret = my_sql.db_readall(sql_getvalue) if len(ret) <packet_count: return(res_ret) else: for x in ret: res_ret+=x[‘res‘] pkloss_ret+=x[‘pkloss‘] #计算时延和丢包率 restime = (round(float(res_ret/packet_count),2)) pkloss = (round(float(pkloss_ret/packet_count*100),2)) #计算本次与上次时延差值与本次丢包率,决定是否调用mtr try: history_restime = round(float(my_sql.db_readone(sql_mtr)[‘avg(a.res)‘]),2) if restime - history_restime > 20 or 100> pkloss >20: mtr = dbvalues.mtr(ip) subprocess.Popen(mtr,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) except Exception as a: logger.info(a) if item ==‘restime‘: my_sql.db_close() return restime if item == ‘pkloss‘: my_sql.db_close() return pkloss
start-sql代码
#!/usr/bin/env python3 #-*-coding:utf-8-*- import subprocess,re,time,pymysql,argparse from settings import dbinfo from models import db import log def ping(cmd): pkloss = 0 ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0].decode(‘utf8‘) try: ret =re.findall(‘\d+\.?\d*‘ ,(re.findall(‘time=\d+\.?\d*‘,ret)[0]))[0] return(ret,pkloss) except Exception as a : ret = 0 pkloss = 1 return(ret,pkloss) def value(i,ipaddress,port,t_ype): if t_ype == ‘icmp‘: cmd = ‘ping -c 1 -W 1 %s‘%ipaddress elif t_ype ==‘tcp‘: cmd = ‘./tcping.py %s %s 1‘%(ipaddress,port) i = float(i) logger = log.logger() logger.debug(‘初始化%s‘%ipaddress) dbvalues = dbinfo() mysql = db(dbvalues.dbinfo()) while True:
start_time = time.time() res,pkloss = ping(cmd) t_time = int(time.time()) ctime = t_time - 86400*2 #获取清空历史数据sql语句 sql = dbvalues.sql_clearhistory(ctime) sql1 = dbvalues.sql_insert(res,pkloss,ipaddress,t_time,t_ype,port)#清空48小时前数据 mysql.db_delete(sql) #写入新数据 mysql.db_write(sql1)
use_time = time.time()-start_time
#时间修正 time.sleep(i-use_time) return if __name__ == "__main__": parser = argparse.ArgumentParser(description=‘icmp for monitor‘) parser.add_argument(‘-t‘,action = ‘store‘,dest=‘tip‘) parser.add_argument(‘-i‘,action=‘store‘,dest=‘interval‘) parser.add_argument(‘-p‘,action=‘store‘,dest=‘port‘) parser.add_argument(‘-T‘,action = ‘store‘,dest=‘type‘) args= parser.parse_args() ip = args.tip i = args.interval port = args.port t_ype = args.type value(i,ip,port,t_ype)
tcping代码
#!/usr/bin/env python3 """ TCP Ping Test (defaults to port 80, 10000 packets) Usage: ./tcpping.py host [port] [maxCount] - Ctrl-C Exits with Results """ import sys import socket import time import signal from timeit import default_timer as timer host = None port = 80 maxCount = 10000 count = 0 # try: # sip = sys.argv[1] # except IndexError: # print("Usage: tcpping.py host [port] [maxCount]") # sys.exit(1) try: host = sys.argv[1] except IndexError: print("Usage: tcpping.py host [port] [maxCount]") sys.exit(1) try: port = int(sys.argv[2]) except ValueError: print("Error: Port Must be Integer:", sys.argv[3]) sys.exit(1) except IndexError: pass try: maxCount = int(sys.argv[3]) except ValueError: print("Error: Max Count Value Must be Integer", sys.argv[3]) sys.exit(1) except IndexError: pass passed = 0 failed = 0 def getResults(): """ Summarize Results """ lRate = 0 if failed != 0: lRate = failed / (count) * 100 lRate = "%.2f" % lRate print("\nTCP Ping Results: Connections (Total/Pass/Fail): [{:}/{:}/{:}] (Failed: {:}%)".format((count), passed, failed, str(lRate))) def signal_handler(signal, frame): """ Catch Ctrl-C and Exit """ getResults() sys.exit(0) signal.signal(signal.SIGINT, signal_handler) while count < maxCount: count += 1 success = False s = socket.socket( socket.AF_INET, socket.SOCK_STREAM) s.settimeout(1) s_start = timer() try: # s.bind((sip,0)) s.connect((host, int(port))) s.shutdown(socket.SHUT_RD) success = True except socket.timeout: print("Connection timed out!") failed += 1 except OSError as e: print("OS Error:", e) failed += 1 s_stop = timer() s_runtime = "%.2f" % (1000 * (s_stop - s_start)) if success: print("Connected to %s[%s]: tcp_seq=%s time=%s ms" % (host, port, (count-1), s_runtime)) passed += 1 if count < maxCount: time.sleep(1) getResults()
log代码
#!/usr/bin/env python3 #-*-coding:utf-8-*- import logging,time from settings import dbinfo def logger(): base_dir = dbinfo() log_name = base_dir.log_dir() logger = logging.getLogger() fh = logging.FileHandler(log_name) formater = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s") fh.setFormatter(formater) logger.setLevel(logging.DEBUG) logger.addHandler(fh) return logger
models代码
#!/usr/bin/env python3 #-*-coding:utf-8-*- #-----------------------------------------------------创建db类-------------------------------------------------------- import pymysql,settings class db: def __init__(self,conninfo): self.host = conninfo[‘host‘] self.port = conninfo[‘port‘] self.user = conninfo[‘user‘] self.passwd = conninfo[‘passwd‘] self.db = conninfo[‘db‘] self.ch = conninfo[‘charset‘] self.conn = pymysql.connect(host=self.host,port = self.port,user = self.user,passwd = self.passwd, db=self.db,charset=self.ch) self.coursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def db_readone(self,sql): self.coursor.execute(sql) return self.coursor.fetchone() def db_readall(self,sql): self.coursor.execute(sql) return self.coursor.fetchall() def db_write(self,sql): self.coursor.execute(sql) self.conn.commit() def db_delete(self,sql): self.coursor.execute(sql) self.conn.commit() def db_close(self): self.conn.close()
settings代码
#!/usr/bin/env python3 #-*-coding:utf-8-*- #---------------------------------------------配置文件,定义sql语句,路径等------------------------------------------------ import os,time class dbinfo: def __init__(self): self.dir = os.path.dirname(os.path.abspath(__file__)) def base_dir(self): return self.dir def log_dir(self): log_dir = self.dir + ‘/log/‘ + time.strftime(‘%Y-%m-%d‘,time.localtime()) + ‘.log‘ return log_dir def mtr(self,ip): mtr_dir = self.dir+‘/log/‘+ip+‘-‘+time.strftime(‘%Y-%m-%d‘,time.localtime()) + ‘.log‘ cmd = self.dir + ‘/mtr.sh‘+‘ ‘+ip+‘ ‘+mtr_dir return cmd def dbinfo(self): dbinfo = {‘host‘:‘127.0.0.1‘,‘port‘:3306,‘user‘:‘root‘,‘passwd‘:‘test‘, ‘db‘:‘pingvalues‘,‘charset‘:‘utf8‘} return dbinfo def sql_sqlstatues(self,ip,t_ype,port): sql = ‘select time from zabbixvalue where ipaddress like "%s" and type like "%s" and port like %s order by nid desc limit 1;‘%(ip,t_ype,port) return sql def sql_getvalue(self,ip,packet_count,t_ype,port): sql = ‘select res,pkloss,ipaddress,time from zabbixvalue where ipaddress like "%s" and type like "%s" and port like %s order by nid desc limit %s;‘%(ip,t_ype,port,packet_count) return sql def cmd(self,ip,i,port,t_ype): cmd = ‘nohup‘+‘ ‘+self.dir + ‘/start-sql.py -t %s -i %s -p %s -T %s >/dev/null 2>&1 &‘%(ip,i,port,t_ype) return cmd def sql_clearhistory(self,ctime): sql = ‘delete from zabbixvalue where time<%s;‘%ctime return sql def sql_insert(self,res,pkloss,ipaddress,t_time,t_ype,port): sql = ‘insert into zabbixvalue(res,pkloss,ipaddress,time,type,port) values(%s,%s,"%s",%s,"%s",%s)‘%(res,pkloss,ipaddress,t_time,t_ype,port) return sql def sql_mtr(self,ip,packet_count,t_ype,port): sql = ‘select avg(a.res) from (select res from zabbixvalue where ipaddress like "%s" and type like "%s" and port like %s order by nid desc limit %s,%s) as a;‘%(ip,t_ype,port,packet_count,packet_count) return sql
mtr shell脚本
#!/usr/bin/env bash IP=$1 dir=$2 mtr -r -n -c 30 -w -b $IP >> $2
mysql
mysql> desc zabbixvalue; +-----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+-------------+------+-----+---------+----------------+ | nid | int(11) | NO | PRI | NULL | auto_increment | | res | float | YES | | NULL | | | pkloss | int(11) | YES | | NULL | | | ipaddress | varchar(64) | YES | | NULL | | | time | int(11) | YES | | NULL | | | type | varchar(64) | YES | | NULL | | | port | int(11) | YES | | NULL | | +-----------+-------------+------+-----+---------+----------------+ 7 rows in set (0.01 sec)
zabbix_agentd.conf
UserParameter=dark_ping_restime[*],/etc/zabbix/darkping/bin.py -t $1 -I restime UserParameter=dark_ping_pkloss[*],/etc/zabbix/darkping/bin.py -t $1 -I pkloss UserParameter=dark_tcpping_restime[*],/etc/zabbix/darkping/bin.py -t $1 -p $2 -T tcp -I restime UserParameter=dark_tcpping_pkloss[*],/etc/zabbix/darkping/bin.py -t $1 -p $2 -T tcp -I pkloss
Item 配置略
zabbix python线路质量监控模块,自定义监控粒度,链路丢包或时延抖动联动mtr
原文:https://www.cnblogs.com/darkchen/p/14744242.html