“ Python自动运维,释放自我。”
01 面临问题
网络运维苦,电信级网络运维更苦。
账号密码是否过期?
设备能否正常登陆?
设备是否正常?
给定某设备IP地址,用户名和密码,完成以下任务:
-
模拟telnet/ssh设备,可以测试账号可用性,设备连通性
-
执行指令,返回结果,如查询配置文件
-
分析配置文件,比如关注拓扑信息,学习Python正则表达式的基本知识;
02 怎么办
模拟telnet/ssh
Python有很多第三方库,实现ssh、ftp、telnet等命令交互。
如pexpect、paramiko等,都没时间涉及。
先用Python自带的telnetlib实现最简单的telnet功能,
后续如果有需求再进一步学习。
模拟telnet的代码如下:
import telnetlib
host = "x.x.x.x" #设备IP,将来可以从一个地址池中读取
user =b 'x' #用户名密码
password =b 'x'
finsh = b"#" #结束符号
tn = telnetlib.Telnet(host) #创建telnet连接
tn.read_until(b"login: ") #读取到给定字符串
tn.write(user + b"\n") #输入用户名
tn.read_until(b"Password: ")
tn.write(password + b"\n")
tn.read_until(finsh)
确保网络是通的。
python正在模拟人工登陆。
telnetlib.Telnet(host) 没有报错,说明设备网络通的,也开放了telnet端口;
tn.read_until(finsh) 执行完毕,说明账号密码正常,可以正常登陆
执行指令并返回结果
正常telnet设备后,通过指令查询爱立信MME attach相关指标。
指令如下:
attach | tail -10
Python代码如下:
command =b "attach | tail -10" #待执行指令
tn.write(command + b"\n") #Python执行指令,模拟人工输入、回车
res = tn.read_until(finsh) #python读取指令结果
tn.read_until(finsh) 可以理解为从执行上条指令开始,一直读取到finsh结束。
这里是#,不同平台可能不一样,如~等。
查看res结果如下,说明已经正确完成指令结果读取。
分析本地配置文件
由于安全原因路由器无法直接telnet,
暂时通过分析本地配置文件。
其实对于上述MME的指令结果也可以继续分析。
分析指令结果
配置文件可以分析很多东西,
今天只分析路由器的接口数据,配置了哪些接口?对端分别是哪些网元?接口IP是多少?
接口配置样例如下:
interface GigabitEthernet2/0/8.1055
vlan-type dot1q 1055
description To-[HZMxx]-[MHRD|2|4|11|B|1]-1G
ip binding vpn-instance xx_xx_Media
ip address x.x.x.149 255.255.255.252
statistic enable
通过正则表达式匹配这段内容,并提取相应信息。
Python正则表达式re
关于Python正则表达式的知识非常多,可以写一本书,暂时写不出来。
所谓正则表达式,就是给定一个模式字符串表达式patten,然后逐一匹配字符串,正如我们熟悉的*表示任何东西一样。
比如要在一句英文中匹配是否存在hello?
import re
# 将正则表达式编译成Pattern对象
pattern = re.compile(r'hello')
s = pattern.search('hello world!') #调用search函数,查找
if s: #匹配成功为真
print(s.group())
#以上是输出
hello
Pattern对象是一个编译好的正则表达式,提供了很多方法使用,如match()、search()、findall()。
用findall()匹配设备接口信息,会以列表形式返回全部匹配的字串代码如下:
In[227]: import pandas as pd
f = open(u'XXXCE06-HWNE40E_配置备份文件保存.txt','r')
conf = f.read()
p_int= re.compile(r"interface GigabitEthernet(.*?)\n.*?description (.*?)\n")
ints = p_int.findall(conf)
#转换为DataFrame,以便后续输出报错
ints = pd.DataFrame(ints,columns = ['interface','description'])
ints['interface'] = ['GigabitEthernet'+i for i in list(ints['interface'])]
In[228]: ints.head()
Out[228]:
interface description
0 GigabitEthernet1/0/10 TO-[xxx]-[LSW01-GE0/0/13]_1G
1 GigabitEthernet1/0/23 TO-xxx-1G-WANGGUAN
2 GigabitEthernet2/0/1 TO-[GDHIZ-xxx-HWNE40E]-GE2/0/1-1G
3 GigabitEthernet2/0/2 TO-[GDHIZ-xxx-HWNE40E]-GE2/0/2-1G
4 GigabitEthernet2/0/3 To-[HZMxx]-[MHRD|1|2|11|B|1]-1G
其中正则表达式
"interface GigabitEthernet(.?)\n.?description (.*?)\n"
以下划重点
表示以interface GigabitEthernet开头,先匹配任意字符,直到换行\n;
第一个括号匹配接口号interface;
然后再忽略一些字符. *?,
找到description ,匹配对端网元,
以换行符\n结束匹配。
这个写法直接返回()中匹配上的内容,如端口号、desc等,
但是对于没有desc的端口则无法匹配命中。
整个配置文件findall()后可以全部匹配想要的接口号及对端信息。
更多接口信息
上面只匹配了有对端的GigabitEthernet接口信息,其实路由有很多接口类型,如vlan,还有子接口等。
下面尝试写一个更全面的功能,能够分析所有接口信息。
#给定配置文件conf,返回全部接口信息
def get_intferaces(conf):
p_int = re.compile(r'#\n(interface .*?)\n#',re.S)
ints = p_int.findall(conf)
cols = ['interface','is_shutdown','description','ipaddress','vpn-instance','vlan']
rows = []
for i in ints:
name = i.split('interface ')[1].split('\n')[0]
if ('NULL' not in name) & ('Virtual' not in name):
if 'description ' in i:
desc = i.split('description ')[1].split('\n')[0]
else:
desc = ''
if 'ip address ' in i:
ipaddress = i.split('ip address ')[1].split('\n')[0]
else:
ipaddress = ''
if 'ip binding vpn-instance ' in i:
vpn = i.split('ip binding vpn-instance ')[1].split('\n')[0]
else:
vpn = ''
if 'port default vlan ' in i:
vlan = i.split('port default vlan ')[1].split('\n')[0]
else:
vlan = ''
if 'undo shutdown' in i:
is_shutdow = 'undo shutdown'
elif 'shutdown' in i:
is_shutdow = 'shutdown'
else:
is_shutdow = '' #为空表示没有这个字段
row = [name,is_shutdow,desc,ipaddress,vpn,vlan]
rows.append(row)
interfaces = pd.DataFrame(rows,columns = cols)
return interfaces
由于接口类型很多,不好用统一的正则表达式匹配。
其实是我不会,没研究它。
大家有兴趣可以用一句话正则实现下。
通过get_intferaces(conf)可以获取到全部接口信息。
然后可以对这些接口信息进行处理,
比如只保留在用端口,IP地址用子网表示等。
# 保留在用端口
interfaces = interfaces[~interfaces['is_shutdown'].isin(['shutdown'])]
由于对端描述不是特别规范,
提取真实网元名称需要一些判断逻辑,不麻烦,
同时如果知道全部IP地址信息,可以用子网进行匹配,更准确。
最终代码
整理上面代码,汇总如下。
大家可以新建automain_demo.py,
复制以下代码,测试是否正常。
import telnetlib
import re
import pandas as pd
#在指定网元上执行指令,并返回指令结果
def doComd(host,user,password,finsh,commands):
tn = telnetlib.Telnet(host)
tn.read_until(b"login: ")
tn.write(user +b "\n")
tn.read_until(b"Password: ")
tn.write(password + b"\n")
tn.read_until(finsh)
print(host+"登陆成功!")
res = []
#可以执行多条指令
for command in commands:
tn.write(command +b "\n")
res.append(tn.read_until(finsh))
tn.close()
return res
#给定配置文件conf,返回全部接口信息
def get_intferaces(conf):
p_int = re.compile(r'#\n(interface .*?)\n#',re.S)
ints = p_int.findall(conf)
cols = ['interface','is_shutdown','description','ipaddress','vpn-instance','vlan']
rows = []
for i in ints:
name = i.split('interface ')[1].split('\n')[0]
if ('NULL' not in name) & ('Virtual' not in name):
if 'description ' in i:
desc = i.split('description ')[1].split('\n')[0]
else:
desc = ''
if 'ip address ' in i:
ipaddress = i.split('ip address ')[1].split('\n')[0]
else:
ipaddress = ''
if 'ip binding vpn-instance ' in i:
vpn = i.split('ip binding vpn-instance ')[1].split('\n')[0]
else:
vpn = ''
if 'port default vlan ' in i:
vlan = i.split('port default vlan ')[1].split('\n')[0]
else:
vlan = ''
if 'undo shutdown' in i:
is_shutdow = 'undo shutdown'
elif 'shutdown' in i:
is_shutdow = 'shutdown'
else:
is_shutdow = '' #为空表示没有这个字段
row = [name,is_shutdow,desc,ipaddress,vpn,vlan]
rows.append(row)
interfaces = pd.DataFrame(rows,columns = cols)
interfaces = interfaces[~interfaces['is_shutdown'].isin(['shutdown'])]
return interfaces
if __name__ == "__main__":
host = "x.x.x.x" #设备IP,将来可以从一个地址池中读取
user = b'x' #用户名密码
password =b 'x'
finsh = b"#" #结束符号
command = ["hostname","dispaly current-config"]
#result = doComd(host,user,password,finsh,command)
f = open(u'GDHIZ-NGN-CE06-HWNE40E_配置备份文件保存.txt','r')
result = f.read()
#hostname = result[0]
hostname = "test"
conf = result[1]
interface = get_intferaces(conf)
interface.to_csv(hostname+'.csv',encoding = 'utf8',index = False)
注意换成真实的IP、用户名和密码既可,然后在命令行中运行测试。
运行脚本后,新增test.csv文件:
以上脚本只是基础,还可以扩展出很多功能。
至此,在公司IT转型过程中,我用Python完成了第3个小项目,看到自动运维的曙光。
03 为什么
为什么要这么做?
通信运维IT化、自动化、智能化是趋势,不可逆。
CT设备IT化,网络云化,传统通信网络在近几年会快速转型升级。
运维再也不能只靠人力,得依赖算力。
从小事做起,从小功能做起,用自动化释放人力,用智能化提升效率。
Python在自动运维领域应用大有可为。
值得深入学习。
04 其他选择
有没有更好的选择?
自动运维互联网大厂肯定有更好的平台和经验,
但是作为通信人,只能借鉴,更多还是要找适合自己的。
欢迎大家留言讨论,也可以通过公众号求道轩“约我”私信交流。
下篇我会继续分享第4个小项目实践,欢迎关注。
期待更多道友分享。