基于Python的Telnet客户端和网页下载脚本
一、背景:工作上掌管着近百台交换机,其中赫斯曼大概有60台。现在需要定期备份配置和查看日志检查隐患。可是用网页方式下载太费时间,安排2人轮着下载用了1天,而且ms1600的配置是二进制的,所以萌生研究python脚本的想法。
二、方案:在Windows的NMS上运行脚本自动获取保存交换机配置到本地,下载日志网页。
①确认非运营时间下载②获取时间,作于文件夹名字③读取IpAddress文件,获取交换机ip④登陆交换机⑤按命令列表输入命令⑥读取返回值并保存文件⑦下载日志网页
三、实现代码:
1 #! python3 2 # Download Hirschmann eventlog & configuration 3 import os, requests, time, logging, telnetlib 4 5 # TODO: Telnet登陆、命令、退出模块 6 class TelnetClient(): 7 def __init__(self,): 8 self.tn = telnetlib.Telnet() 9 def login_host(self,host_ip,username,password): 10 try: 11 # self.tn = telnetlib.Telnet(host_ip,port=23) 另一种方法 12 self.tn.open(host_ip,port=23) 13 except: 14 logging.warning('%s network connection failed' % k) #连接失败 15 errorlog = open(os.path.join("D:\\%s" % DirName, "error.log"), 'a') 16 errorlog.write('%s connection failed \n' % host_ip) 17 errorlog.close() 18 return False 19 self.tn.read_until(b'User:', timeout=5) #接入后读取“User”的返回值,最多等5s,超出执行下一步 20 self.tn.write(username.encode('utf-8') + b'\n') #写入用户名,换行符代表回车 21 self.tn.read_until(b'Password:', timeout=5) 22 self.tn.write(password.encode('utf-8') + b'\n') 23 time.sleep(5) #等待5s反应时间 24 command_result = self.tn.read_very_eager().decode('utf-8') #读取返回值,read_very_eager()获取到的是的是上次获取之后本次获取之前的所有输出 25 26 if '>' in command_result: #判断登陆成功 27 print('%s Logging successfully' %host_ip) 28 return True 29 else: 30 logging.warning('%s Logging unsuccessfully' % host_ip) 31 errorlog = open(os.path.join("D:\\%s" % DirName, "error.log"), 'a') 32 errorlog.write('%s Logging unsuccessfully \n' % host_ip) 33 errorlog.close() 34 return False 35 def exec_command(self,command): 36 for i in range(len(command)): 37 self.tn.write(command[i].encode('utf-8') + b'\n') #执行命令列表 38 time.sleep(5) #务必提供反应时间 39 command_result = self.tn.read_very_eager().decode('utf-8') 40 if "snooping" in command_result: #判断数据完整 41 config_file = open(os.path.join("D:\\%s" % DirName, "%s" % k + "_config.txt"), 'a') #新建config文件 42 config_file.write(command_result) #写入读取的数据 43 config_file.close() 44 else: 45 Errorconfig = open(os.path.join("D:\\%s" % DirName, "error.log"), 'a') #打开error文件 46 Errorconfig.write('%s configuration isn\'t complete \n' % v) #记录错误数据 47 Errorconfig.close() 48 def logout_host(self): 49 self.tn.write(b"exit\n") #输入exit退出 50 51 52 # TODO:下载网页模块: 53 class Dnld(): 54 def dnldevent(self, name, ip): 55 url = "http://" + ip + "/base/system/event_log.html" #制作url 56 res = requests.get(url) #获取网页 57 res.raise_for_status() 58 EventFile = open(os.path.join("D:\\%s" % DirName, "%s" % name + "_eventlog.html"), 'wb') #新建html文件 59 for chunk in res.iter_content(100000): #分片写入 60 EventFile.write(chunk) 61 EventFile.close() 62 def dnldsys(self, name, ip): 63 url = "http://" + ip + "/base/system/systemInfo.html" 64 res = requests.get(url) 65 res.raise_for_status() 66 EventFile = open(os.path.join("D:\\%s" % DirName, "%s" % name + "systemInfo.html"), 'wb') 67 for chunk in res.iter_content(100000): 68 EventFile.write(chunk) 69 EventFile.close() 70 71 # TODO:建立主程序,导入字典 72 if __name__ == '__main__': 73 confirm = input('请确认在非运营时段操作下载配置,确认请在下方输入"ok" \n') 74 if confirm.lower() == 'ok': 75 localtime = time.strftime("%Y%m%d%H%M", time.localtime()) #获取当前年月日时分 76 DirName = localtime + "_dump" #生成文件夹名 77 DirName2 = DirName #复式文件夹,为后面文件夹重名做容器 78 Dic = [] #新建字典做ip地址容器 79 i = 1 80 while os.path.exists("D:\\%s" % DirName): #预防文件夹重名 81 DirName = DirName2 + '_' + '%s' % i #末尾增加序号 82 i += 1 83 os.makedirs("D:\\%s" % DirName) # 新建文件夹 84 f = open('IpAddress.txt', 'r') # IpAddress.txt中的url结尾不要有"/" 85 for line in f.readlines(): 86 line = line.strip('\n') # 去掉换行符\n 87 b = line.split(' ') # 将每一行以空格为分隔符转换成列表 88 Dic.append(b) # 按行读取txt文件,然后转换成嵌套列表 89 Dic = dict(Dic) # 通过dict方法将嵌套列表转换成字典 90 else: 91 exit() #未输入ok直接退出程序 92 93 # TODO:导入用户密码命令参数 94 for k, v in Dic.items(): 95 host_ip = v 96 host_name = k 97 username = 'xxxxx' 98 password = 'xxxxx' 99 command = ['en', 'show running-config'] #命令列表 100 #Respond = ['#'] #回应特征值,暂未用 101 telnet_client = TelnetClient() 102 Download_web = Dnld() 103 if telnet_client.login_host(host_ip, username, password): 104 telnet_client.exec_command(command) 105 telnet_client.logout_host() 106 Download_web.dnldevent(host_name, host_ip) 107 Download_web.dnldsys(host_name, host_ip)
后面是编译成exe,我使用的是Pyinstaller,使用pycharm安装编译器后就能在terminal上输入pyinstaller -F xxx.py编译成一个exe了,注意编译系统如果是64位的是不能放在32位系统上运行的。
四、期间遇到如下问题:
1、文件夹重名:本时间精确到分,故一分钟内重复运行os.makedirs会报文件已存在,故增加了文件夹存在的判断,若重名结尾递增数字。
2、日志下载不完整:此问题主要是命令间给的反应时间不够导致,需要现场调试增加反应时间。同时增加了判断点,将配置末端的特征值作为判断,若不完整记录到errorlog里。
3、网页下载若错误无记录:这点还在研究中,初步是换下顺序,先telnet连接,ok后下载网页。
五、心得:
这是我做的第一个相对实用性的脚本,的确是摸着石头过河,参考了网上大神的方案,遇到问题解决问题。最终还是要到现场实测才能验证功能的好坏,继续研究一些其他实用的脚本,做好自动化运维。