我们之前的文章"玩转网络自动化之Netmiko模块"给大家介绍了网络自动化配置模块Netmiko,该模块通过SSH连接至设备然后把我们要执行的命令下发至设备,同时捕获命令回显。

由于命令行的回显都是半格式化的文本字符串,我们需要通过正则表达式来匹配其中我们需要的数据,若只匹配简单的字段还好,如果要匹配批量的数据(如接口信息、路由表)相信大多数读者和小编一样头大的发麻。为了解决这个场景下的痛点小编今天为大家介绍一个半格式化文本字符串的解析神器Python TextFSM模块,下面我们就一起来了解该模块的使用吧。

1、 模块介绍

TextFSM是一个Python模块,该模块实现了用于解析半格式化文本基于编写的模板状态机。该模块由谷歌开源的,最初被开发为允许以编程方式访问由CLI驱动的设备(例如网络路由器和交换机)的输出所给出的信息,但是它可以用于任何此类文本输出。

TextFSM模块从命名就可以看出其是由两部分组成,其中Text就是指半格式化的文本(半格式化是指有一定规律的文本如网络设备配置、Linux系统的配置文件等),FSM是指状态机也就是解析模板,通过这个模板对Text文本数据进行解析并格式化输出(一般都是列表套字典)。

2、 模块安装

1. #TextFSM模块安装非常简单,具体安装命令如下:

2. pip install textfsm

3. #如果出现'Read timed out'可以用阿里云镜像安装,具体命令如下:

4. pip install -i https://mirrors.aliyun.com/pypi/simple/ textfsm

3、 模块使用

1) 简单使用

先来看看textfsm模块的解析模板格式,及其相关定义,这边的模板内容是写在一个文本文件中,不能直接给textfsm传入模板字符串,因为textfsm传入的模板必须是文件对象(IOTextWapper)

1. #匹配的模板(注意:"#"号开头为注释)  2. #1.变量的定义  3. #定义变量Slot(这边的Value就表示这是个变量)同时定义其匹配的规则(其实就是正则表达式)  4. Value Required Slot (d+)  5. #定义变量State及其匹配的规则  6. Value State (w+)  7. #定义变量Temp及其匹配的规则  8. Value Temp (d+)  9. #定义变量CPUTemp及其匹配的规则  10. Value CPUTemp (d+)  11. #定义变量DRAM及其匹配的规则  12. Value DRAM (d+)  13. #定义变量Model及其匹配的规则  14. Value Model (S+)  15.   16. #2.State的定义  17. #Start后面的这段内容称为State,其下的每一段就是匹配rule,这个是跟我们的格式文本内容是对应的  18. #Start是textfsm缺省的State,我们也可以自定义,像模板下面的RESlot就是自己定义的名称,Start必须放在最开始的位置  19. #模块匹配都是以这个为标识就行开始的规则匹配  20. Start  21. #这边意思是匹配到'Routing Engine'开头的字符串就转移到RESlot进行规则匹配  22.   ^Routing Engine status: -> RESlot  23.   24. RESlot  25. #这边是具体每行的匹配规则,其中${}中的变量会替换成上面自己定义的变量所对应的正则内容  26. #第一行的内容将变量替换后就是'^s+Slots+(d+)'  27.   ^s+Slots+${Slot}  28.   ^s+Current states+${State}  29.   ^s+Temperatures+${Temp} degrees  30.   ^s+CPU temperatures+${CPUTemp} degrees  31.   ^s+DRAMs+${DRAM} MB  32.   #这边的意思是RESlot解析完记录到结果中,同时返回至Start进行下一轮匹配  33.   ^s+Models+${Model} -> Record Start

我们要匹配的文本是一个路由器板卡硬件信息的命令行输出,具体内容如下:

Routing Engine status:Slot 0:Current state MasterElection priority Master (default)Temperature 39 degrees C / 102 degrees FCPU temperature 55 degrees C / 131 degrees FDRAM 2048 MBMemory utilization 76 percentCPU utilization:User 95 percentBackground 0 percentKernel 4 percentInterrupt 1 percentIdle 0 percentModel RE-4.0Serial ID xxxxxxxxxxxxStart time 2008-04-10 20:32:25 PDTUptime 180 days, 22 hours, 45 minutes, 20 secondsLoad averages: 1 minute 5 minute 15 minute0.96 1.03 1.03Routing Engine status:Slot 1:Current state BackupElection priority BackupTemperature 30 degrees C / 86 degrees FCPU temperature 31 degrees C / 87 degrees FDRAM 2048 MBMemory utilization 14 percentCPU utilization:User 0 percentBackground 0 percentKernel 0 percentInterrupt 1 percentIdle 99 percentModel RE-4.0Serial ID xxxxxxxxxxxxStart time 2008-01-22 07:32:10 PSTUptime 260 days, 10 hours, 45 minutes, 39 seconds

下面我们来看看textfsm的具体使用方法吧(我们把上面的命令行输出赋值给变量cli_output),具体使用代码如下:

1. #!/usr/bin/env/ python  2. # -*- coding:utf-8 -*-  3.   4. from textfsm import TextFSM  5.   6. if __name__ == "__main__":  7.     #将打开的解析模板文件对象传参给TextFSM模块  8.     ins = TextFSM(open("parse_template.txt", "r", encoding='utf8'))  9.     #将文本简析成字典(其实是列表套字典因为存在多个Slot板卡)  10.     result = ins.ParseTextToDicts(cli_output)  11.     print(result)

代码运行结果如下(读者们可以把这边的结果与命令行输入的内容进行对比的查看,是不是想要的数据就这样都解析出来啦):

1. [  2.   {'Slot': '0', 'State': 'Master', 'Temp': '39', 'CPUTemp': '55', 'DRAM': '2048', 'Model': 'RE-4.0'},   3.   {'Slot': '1', 'State': 'Backup', 'Temp': '30', 'CPUTemp': '31', 'DRAM': '2048', 'Model': 'RE-4.0'}  4. ]

2) 简析模板定义详解

a) Value的定义

Value就是我们要匹配的提取的字段名称及其匹配规则,其必须在State段的前面,一般我们会将其放在简析模板的头部,Value每行的格式如下:

1. #注意正则表达式必须在括号中,其中options是可选项可以不用定义

2. Value [options] 提取字段名 (匹配的正则表达式)

3. #列如

4. Value interface (.*)

Options目前有如下五个值:

Filldown : 先前匹配的值将保留用于后续记录(除非明确清除或再次匹配)。换句话说,除非再次匹配,否则将最近匹配的值复制到较新的行。

Key: 声明该字段值是一行的唯一标识。

Required: 这一行的这个字段必须能够匹配到,匹配到才会记录这一行匹配的数据否则不记录,也就是如果匹配不到返回的数据列表中没有改行的值。

List: 该值类型是个列表

Fillup: 跟Filldown是相反操作,该字段与Required字段不兼容

b) State的定义

在定义完Value之后就需要定义State,其与Value之间必须空一行,State定义的格式如下:

stateName
^rule
^rule
...

多个State之间也需要用一个空行隔开,State名称必须顶格写,大多数模板的第一个State一般是Start(textfsm保留的State名称),State名称下面就是定义的正则表达式规则rule,每个rule之前都要有1个或2个空格,同时rule必须以^为开头。下面我们写个简单的State:

1. Start 2.  # ->这个为action,就是匹配到执行什么动作,Record表示将匹配的值进行记录  3.  ^Boot image version:s${version},sReleases${release_num} -> Record

State还有个隐式的保留名称就是EOF(就是匹配结束标识操作),意思将匹配的内容进行记录,其作用语法如下:

^.* -> Record

3) 配合Netmiko的使用

现在textfsm模块我们了解其大概使用方法及模板的编写,现在我们看看怎么结合Netmiko使用吧。我们通过Netmiko查询到设备的Mac表项然后通过textfsm模板进行解析。

要匹配的MAC表项命令行回显如下:

leaf1# show mac address-tableLegend:* - primary entry, G - Gateway MAC, (R) - Routed MAC, O - Overlay MACage - seconds since last seen,+ - primary entry using vPC Peer-Link,(T) - True, (F) - False, C - ControlPlane MAC, ~ - vsanVLAN MAC Address Type age Secure NTFY Ports---------+-----------------+--------+---------+------+----+------------------* 32 5000.0001.0007 static - F F Vlan32G - 1234.1234.1234 static - F F sup-eth1(R)G - 5000.0001.0007 static - F F (R)G 32 5000.0001.0007 static - F F sup-eth1(R)G 33 5000.0001.0007 static - F F sup-eth1(R)G 34 5000.0001.0007 static - F F sup-eth1(R)

定义我们的简析模板:

1. Value origin (S)  2. Value vlan (S+)  3. #一行中必须匹配到MAC才记录  4. Value Required mac (([0-9a-fA-F]{4}.){2}[0-9a-fA-F]{4})  5. Value type (S+)  6. #分析回显接口有四种类型一个是Eth接口,一个是VLAN接口,一个是sup-eth接口,还有为空的接口  7. Value port ((Ethd+/d+)|(Vland+)|(sup-ethd+)|(s{1}))  8.   9. Start  10.  ^${origin}s+${vlan}s+${mac}s+${type}[sS]+${port} -> Record

最后我们来上代码:

1. from textfsm import TextFSM  2. from netmiko import ConnectHandler  3.   4. if __name__ == "__main__":  5.     kwargs = {  6.         "ip": "10.1.1.1",  7.         "username": "admin",  8.         "password": "admin",  9.         "device_type": "cisco_nxos"  10.     }  11.   12.     ssh_conn = ConnectHandler(**kwargs)  13.     cli_output = ssh_conn.send_command("show mac address-table")  14.     ins = TextFSM(open("mac_parse_template", "r", encoding='utf8'))  15.     result = ins.ParseTextToDicts(cli_output)  16.     print(result)

代码执行结果如下,读者老爷们可以把执行结果与MAC表项内容对照看,看看匹配的结果是否正确:

1. [{  2.     'origin': '*',  3.     'vlan': '32',  4.     'mac': '5000.0001.0007',  5.     'type': 'static',  6.     'port': 'Vlan32'  7. }, {  8.     'origin': 'G',  9.     'vlan': '-',  10.     'mac': '1234.1234.1234',  11.     'type': 'static',  12.     'port': 'sup-eth1'  13. }, {  14.     'origin': 'G',  15.     'vlan': '-',  16.     'mac': '5000.0001.0007',  17.     'type': 'static',  18.     'port': ' '  19. }, {  20.     'origin': 'G',  21.     'vlan': '32',  22.     'mac': '5000.0001.0007',  23.     'type': 'static',  24.     'port': 'sup-eth1'  25. }, {  26.     'origin': 'G',  27.     'vlan': '33',  28.     'mac': '5000.0001.0007',  29.     'type': 'static',  30.     'port': 'sup-eth1'  31. }, {  32.     'origin': 'G',  33.     'vlan': '34',  34.     'mac': '5000.0001.0007',  35.     'type': 'static',  36.     'port': 'sup-eth1'  37. }]

Textfsm模块的使用方法先介绍到这了,如果有什么疑问的地方欢迎在下方留言