python 路由表监测
来源:互联网 发布:视频网站如何优化 编辑:程序博客网 时间:2024/05/07 11:26
‘由于从事通信行业,经常有检测交换机路由器路由表变化的需要。之前比较用得多的是java,但是最近开始接触python,就想着用python来练练手。实际开发的时候发现用python写运维脚本还是挺方便的,最重要的是第三方库比较多。
这次主要用到的第三方库是pysnmp。
pysnmp依赖两个第三方的Python库:
(1) ASN.1 : Structure of Management Information:管理信息结构
(2) Cryptography Toolkit: 用来加密的
安装的过程为先安装ASN.1 和Cryptography的python库,最后安装pysnmp
其次还有一些平时可能比较少用python自带库,pickle,还有collections里的defaultdict。
我个人使用defaultdict较多,与dict类型不同,你不需要检查key是否存在。并且当你在一个字典中对一个键进行嵌套赋值时,如果这个键不存在,会触发keyError异常。 defaultdict允许我们用一个聪明的方式绕过这个问题。
import collectionsdef tree(): return defaultdict(int)some_dict = tree()some_dict['colours']['favourite'] = "yellow"
Python中可以使用 pickle 模块将对象转化为文件保存在磁盘上,在需要的时候再读取并还原。
使用pickle主要是为了方便存储读写defaultdict的数据。
下面直接撸代码。
检测到路由表变化,要把变化发送到syslog服务器上:
# -*- encoding: utf-8 -*-"""Python syslog client."""import socket# 设备类型FACILITY = { 'kern': 0, 'user': 1, 'mail': 2, 'daemon': 3, 'auth': 4, 'syslog': 5, 'lpr': 6, 'news': 7, 'uucp': 8, 'cron': 9, 'authpriv': 10, 'ftp': 11, 'local0': 16, 'local1': 17, 'local2': 18, 'local3': 19, 'local4': 20, 'local5': 21, 'local6': 22, 'local7': 23,}# 告警等级LEVEL = { 'emerg': 0, 'alert': 1, 'crit': 2, 'err': 3, 'warning': 4, 'notice': 5, 'info': 6, 'debug': 7}# 发送信息,告警等级,设备类型,syslog服务器地址、端口def syslog(message, level=LEVEL['notice'], facility=FACILITY['daemon'], host='localhost', port=514): try: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) data = '<%d>%s' % (level + facility * 8, message) sock.sendto(data, (host, port)) sock.close() except Exception: pass
路由表监测主要代码(注释一开始用英文写,不过英文比较烂,必要的地方我在再改中文注释):
# -*encoding:utf-8*-import datetimefrom pysnmp.entity.rfc3413.oneliner import cmdgenfrom collections import defaultdictimport pickleimport threadingimport timefrom syslog import sendSyslog_version = '1.0''''def tree(): return defaultdict(int) => defaultdict(<function tree at 0x03BD9670>int:while no value return 0'''def tree(): return defaultdict(int)'''format nowtime to output ip routing-table changes and log'''def getNow(): now = datetime.datetime.now() return str(now.strftime("%Y-%m-%d")) + ' ' + str(now.strftime("%H:%M:%S"))'''dict for route proto'''dict_proto = {'2': 'local', '3': 'netmgmt', '9': 'isis', '14': 'bgp'}'''dict for route oidsnmp oid节点'''oid = { 'nexthop': (1, 3, 6, 1, 2, 1, 4, 21, 1, 7), 'mask': (1, 3, 6, 1, 2, 1, 4, 21, 1, 11), 'proto': (1, 3, 6, 1, 2, 1, 4, 21, 1, 9), 'age': (1, 3, 6, 1, 2, 1, 4, 21, 1, 10)}'''sort by ip like:1.1.1.12.2.2.2ip地址排序'''def dictSort(defaultdict={}): return sorted(defaultdict.iteritems(), key=lambda x: ip2int(str(x[0])))'''ip to int for sort'''def ip2int(s): l = [int(i) for i in s.split('.')] return (l[0] << 24) | (l[1] << 16) | (l[2] << 8) | l[3]'''like 255.255.255.0 => 24'''def mask2int(mask): count_bit = lambda bin_str: len([i for i in bin_str if i == '1']) mask_splited = mask.split('.') mask_count = [count_bit(bin(int(i))) for i in mask_splited] return sum(mask_count)'''like 2 => local'''def int2proto(num): return dict_proto[num]'''compare new routing-table with old routing-tablereturn the changes"+":plus route"-":minus route'*':nexthop change"~":link unstableunstable_link_time=interval-snmptime,if route exists and age becomes less than interval-snmptime,link is unstable新ip route table与旧的比较:+:新增路由-:减少路由*:路由下一跳改变~:路由不稳定(如果路由项一直存在,age=1000,,但下一次监测到age=60,说明该路由曾经消失了又重新出现,则可以判断该链路不稳定,unstable_link_time为监测间隔)'''def cmpp(old, new, unstable_link_time): tmp = defaultdict(tree) for key, value in old.items(): if not new.has_key(key): tmp[key] = value tmp[key]['tag'] = '-' else: if int(new[key]['age']) <= unstable_link_time: tmp[key] = value tmp[key]['tag'] = '~' for key, value in new.items(): if not old.has_key(key): tmp[key] = value tmp[key]['tag'] = '+' elif old[key]['nexthop'] != new[key]['nexthop']: tmp[key] = value tmp[key]['tag'] = "*" tmp[key]['_mask'] = old[key]['mask'] tmp[key]['mask'] = new[key]['mask'] tmp[key]['_nexthop'] = old[key]['nexthop'] tmp[key]['nexthop'] = new[key]['nexthop'] return tmp'''check attribute[nexthop,mask,proto,age] in tableif less some attribute,raise error 'route has changed when getting snmp data'正常获取snmp时,defaultdict[ip]里有四项,nexthop、mask、age、proto,如果在获取snmp数据期间如果路由发生变化,defaultdict[ip]里的值将少于四项,出现该状况时停止监测,等待下一次监测'''def checkAttr(table={}): for key in table: if len(table[key]) < 4: # raise ValueError,'route has changed when getting snmp data' print table[key] return False return True'''format to print like:+ 6.6.0.0/16 -> 6.6.6.66 local+ 6.6.6.66/32 -> 127.0.0.1 local+ 6.6.255.255/32 -> 6.6.6.66 local'''def prettyprint(changelist): for ip in changelist: if ip[1]['tag'] == '*': print '%s %s/%s -> %s ===>>> %s/%s -> %s %s' % ( ip[1]['tag'], ip[0], mask2int(ip[1]['_mask']), ip[1]['_nexthop'], ip[0], mask2int(ip[1]['mask']), ip[1]['nexthop'], int2proto(ip[1]['proto'])) else: print '%s %s/%s -> %s %s' % ( ip[1]['tag'], ip[0], mask2int(ip[1]['mask']), ip[1]['nexthop'], int2proto(ip[1]['proto']))'''format to syslog like:+ 6.6.0.0/16 -> 6.6.6.66 local+ 6.6.6.66/32 -> 127.0.0.1 local+ 6.6.255.255/32 -> 6.6.6.66 local'''def prettysyslog(changelist, syslogIP='localhost'): message = '' for ip in changelist: if ip[1]['tag'] == '*': message += '%s %s/%s -> %s ===>>> %s/%s -> %s %s\n' % ( ip[1]['tag'], ip[0], mask2int(ip[1]['_mask']), ip[1]['_nexthop'], ip[0], mask2int(ip[1]['mask']), ip[1]['nexthop'], int2proto(ip[1]['proto'])) else: message += '%s %s/%s -> %s %s\n' % ( ip[1]['tag'], ip[0], mask2int(ip[1]['mask']), ip[1]['nexthop'], int2proto(ip[1]['proto'])) sendSyslog(message, host=syslogIP)'''save log like:2016-10-02 18:06:22+ 6.6.0.0/16 -> 6.6.6.66 local+ 6.6.6.66/32 -> 127.0.0.1 local+ 6.6.255.255/32 -> 6.6.6.66 local'''def prettysave(time, changelist): with open('log.txt', 'a') as mytxt: mytxt.write('=' * 32 + time + '=' * 32 + '\n') for ip in changelist: if ip[1]['tag'] == '*': mytxt.write('%s %s/%s -> %s ===>>> %s/%s -> %s %s\n' % ( ip[1]['tag'], ip[0], mask2int(ip[1]['_mask']), ip[1]['_nexthop'], ip[0], mask2int(ip[1]['mask']), ip[1]['nexthop'], int2proto(ip[1]['proto']))) else: mytxt.write('%s %s/%s -> %s %s\n' % ( ip[1]['tag'], ip[0], mask2int(ip[1]['mask']), ip[1]['nexthop'], int2proto(ip[1]['proto'])))'''use snmpwark for ip routing-tablepublic:snmp read string1:snmp v2c161:udp portreturn defaultdict name table'''def snmpwalk(ip, table, oid, type=''): # try: cg = cmdgen.CommandGenerator() errorIndication, errorStatus, errorIndex, varBinds = cg.nextCmd( cmdgen.CommunityData('my-agent', 'public', 1), cmdgen.UdpTransportTarget((ip, 161)), oid) for varBind in varBinds: for name, val in varBind: table[name[-4:]][type] = val.prettyPrint(0) # except ValueError: # print 'can not connect to device'class IpRoute(): def __init__(self, ip, interval=600, isThread=False, syslogIP='localhost'): self.ip = ip self.interval = interval self.isThread = isThread self.syslogIP = syslogIP def setSyslogIP(self, syslogIP): self.syslogIP = syslogIP ''' run it with Threading may take more CPU,if route count more than 200,try not use it old ip routing-table will use model 'pickle' to persist interval:compare interval time:run times ''' def monitor(self): # run times:10 year times = 31536000 / self.interval for i in range(times): ''' defaultdict for saving snmp data _table:旧路由表记录 table:新路由表记录 ''' _table = defaultdict(tree) table = defaultdict(tree) try: #从pickle文件获取旧路由表记录 mydb = open('table', 'r') _table = pickle.load(mydb) mydb.close() except IOError: pass t0 = time.clock() #以线程方式获取snmp数据,占用设备cpu过多,效果不明显,不建议 if self.isThread: for key in oid: t = threading.Thread(target=snmpwalk, args=(self.ip, table, oid[key], key,)) t.start() # wait for all thread ned for t in threading.enumerate(): if t is threading.currentThread(): continue t.join() else: try: #按顺序获取snmp数据 for key in oid: snmpwalk(self.ip, table, oid[key], key) # not connect snmp sleep half time and rerun except ValueError: # raise ValueError,'snmp connect error' print 'snmp connect error' time.sleep(self.interval / 2) continue snmptime = time.clock() - t0 print getNow() + ' snmp time:' + str(snmptime) unstable_link_time = self.interval - snmptime if unstable_link_time < 0: raise ValueError, 'interval is less than snmp time,please set it longer' # miss some attr sleep half time and rerun if not checkAttr(table): print 'route has been changed while getting snmp data' time.sleep(self.interval / 2) continue try: change = dictSort(cmpp(_table, table, unstable_link_time)) if len(change) > 0: prettyprint(change) prettysave(getNow(), change) prettysyslog(change, self.syslogIP) except Exception: pass #保存刚获取的路由表 with open('table', 'w') as mydb: pickle.dump(table, mydb) time.sleep(self.interval)if __name__ == '__main__': router = IpRoute('x.x.x.x')#监测设备地址 router.setSyslogIP('x.x.x.x')#syslog服务器地址 router.monitor()
如果要监测多台设备路由器的话,用Threading多线程来运行。
然后修改一下prettyprint、prettysave、prettylog方法,把设备ip记录下来就可以。
有问题可以邮箱联系,545949185@qq.com
- python 路由表监测
- python线程状态监测
- Python 监测文件是否更新
- python 添加路由
- python 用ping循环监测服务器心跳
- 利用Python监测MySQL主从状态
- python监测当前联网状态并连接
- python监测mysql,并自动重启
- linux路由表,策略路由,路由查找
- 路由表
- 路由表
- 路由表
- 路由表
- 路由域和路由表
- IP路由和路由表
- python添加随机静态路由
- python+selenium定时登录路由并重启路由
- python监测程序状态,定时重启程序
- LINUX 数据盘的格式化与挂载
- Android 蓝牙服务端实现
- OpenCV Tutorial: OpenCV基本結構(Point、Size、Rect等)
- 设计模式笔记——(一:单例模式 Singleton Pattern)
- java中的interface接口
- python 路由表监测
- 什么是格式化?
- ListView自定义Adapter中getView(int position, View convertView, ViewGroup parent) 使用
- Laravel框架开发调试工具Laravel Debugbar使用
- 【C#】C#面向对象OOP编程
- 证书迁移可能遇到推送不支持现象 Missing Push Notification Entitlement
- Spring in action--Part4-Integrating Spring
- 基本算法练习四
- Jprofiler9的使用的关键步骤