定义用于解析非结构化输出的 Junos PyEZ 操作表
总结 创建自定义表,从 CLI 或 vty 命令输出中选择数据,以从 Junos 设备提取操作信息。
Junos PyEZ 操作 (op) 表,用于从在 Junos 设备上执行的 CLI 命令或在给定灵活 PIC 集中器 (FPC) 上执行的 vty 命令的文本输出中提取数据。然后将提取的数据转换为 JSON。这使您能够快速检索和分析设备的操作状态信息。当您需要解析无法以结构化格式(如 XML)返回的命令输出时,用于非结构化输出的 Junos PyEZ 操作表特别有用。
本主题讨论表的不同组件。
操作表中用于解析非结构化输出的参数摘要
Junos PyEZ 表使用 YAML 进行格式化。Op 表定义可以包含许多必需参数和可选参数, 表 1 汇总了这些参数。
表参数名称 |
表参数 |
描述 |
---|---|---|
表名 |
– |
表的用户定义标识符。 |
命令 |
|
要执行的 CLI 或 vty 命令。 |
命令参数 |
|
(可选)将命令定义为 Jinja 模板时, |
目标 FPC |
|
(可选)在其上执行 vty 命令的灵活 PIC 集中器 (FPC)。 |
表项 |
|
(可选)定义如何将输出拆分为多个部分的字符串或正则表达式。这些部分将成为关联视图的可迭代参考。 指定“*”以提取并匹配整个字符串,而不是每一行。 |
表项键 |
|
(可选)字符串或字符串列表,用于定义唯一标识每个表项的一个或多个键。 |
所选键 |
|
(可选)要为其返回数据的一个或多个表项键的列表。 |
章节标题 |
|
(可选)选择包含要分析的数据的输出部分的字符串。 |
字段分隔符 |
|
(可选)分隔符,用于定义如何在由键值对组成的命令输出中拆分数据。提取的数据作为键值对存储在字典中。 |
评估表达式 |
|
(可选)一个或多个键值对的关联数组或字典,用于将用户定义的键映射到包含数学表达式的字符串。检索数据时,将使用 Python |
表视图 |
|
(可选)用于从表项目中提取字段数据的视图。 |
文本FSM 模板 |
|
(可选)指定是否使用 TextFSM 模板分析数据的布尔值。 |
文本FSM 模板平台标识符 |
|
(可选)使用 TextFSM 模板时,请指定模板的平台。 |
表名
表名称是表的用户定义标识符。YAML 文件或字符串可以包含一个或多个表。YAML 文档的开头必须左对齐。下面的示例定义一个名为 的表 ChassisFanTable
:
--- ChassisFanTable: command: show chassis fan key: fan-name view: ChassisFanView
命令
用于非结构化输出的 Junos PyEZ 操作表可从 CLI 或 vty 命令的文本输出中提取数据。您必须在表定义中包含该 command
属性,以指定要在设备上执行的 CLI 命令或要在给定 FPC 上执行的 vty 命令。您可以将命令定义为简单字符串或 Jinja 模板。
例如,下表在设备上执行 show chassis fan
命令。
--- ChassisFanTable: command: show chassis fan key: fan-name view: ChassisFanView
下表在 show cmerror module brief
目标 FPC 上执行 vty 命令。
--- CMErrorTable: command: show cmerror module brief target: fpc1 key: module view: CMErrorView
将命令定义为 Jinja 模板时,还必须为args
参数提供键值对字典,用于将模板中的变量映射到呈现模板时使用的值。有关将命令定义为 Jinja 模板的信息,请参阅命令参数 (args)。
命令参数(参数)
您可以使用 Jinja 模板为参数定义 CLI 或 vty 命令 command
,并用变量替换命令参数。使用 Jinja 模板时,还必须定义 args
参数,该参数是键值对的字典,用于将 Jinja 模板中的变量名称映射到呈现模板时使用的值。您可以在表定义中为模板变量提供默认值,也可以在 Junos PyEZ 应用程序中定义这些值。
若要定义模板变量的默认值,请在表定义中包含该 args
参数,并将每个模板变量映射到其默认值。下表使用具有一个变量 的 protocol
Jinja 模板定义了一个命令。该 args
参数定义 的 protocol
默认值,当您在脚本中调用 get()
该方法并且不提供覆盖该默认值的参数时,将使用该值。
--- DdosPolicerStatsTable: command: show ddos policer stats {{ protocol }} args: protocol: ospf target: Null title: "DDOS Policer Statistics:" key: location view: DdosPolicerStatsView
此外,还可以在 args
Table 的方法中将参数定义为字典, get()
以便:
为表中未定义默认值的任何模板变量定义值
覆盖表中为一个或多个模板变量定义的默认值
以下示例使用协议“bgp”而不是默认值“ospf”执行上表中的命令。
from jnpr.junos import Device from jnpr.junos.command.pfe_ddos_policer import DdosPolicerStatsTable from pprint import pprint import json with Device(host='router1.example.com') as dev: stats = DdosPolicerStatsTable(dev) stats.get(target='fpc0', args={'protocol':'bgp'}) pprint(json.loads(stats.to_json()))
目标 FPC (FPC)
Junos PyEZ 操作表可以在特定的灵活 PIC 集中器 (FPC) 上执行 vty 命令。使用 vty 命令时,表必须包含target
用于定义目标 FPC 的参数。您可以设置为target
Null
并强制用户在应用程序中指定目标 FPC,也可以设置为target
默认 FPC,用户可以选择性地在应用程序中覆盖此值。
下表执行 show memory
vty 命令,但设置 target: Null
,这要求用户在 Junos PyEZ 应用程序中提供目标 FPC:
--- FpcMemory: command: show memory target: Null key: ID key_items: - 0 - 1 view: FPCMemoryView
下表在 show memory
FPC 1 上执行 vty 命令,除非用户在 Junos PyEZ 应用程序中覆盖此值。
--- FpcMemory: command: show memory target: fpc1 key: ID key_items: - 0 - 1 view: FPCMemoryView
在 Junos PyEZ 应用程序中,要定义目标 FPC 或覆盖表中定义的默认 FPC,请将表中get()
方法中的参数设置为target
所需的 FPC,例如:
from jnpr.junos import Device from jnpr.junos.command.fpc_memory import FpcMemory from pprint import pprint import json with Device(host='router.example.com') as dev: stats = FpcMemory(dev) stats.get(target='fpc0') pprint(json.loads(stats.to_json()))
表项(项)
可选的 Table item
属性是一个字符串或正则表达式,用于定义如何拆分命令输出以进行分析。如果输出具有类似的重复数据集,则可以定义 item
匹配和提取数据的每次迭代。例如, 返回 show interfaces
许多接口的一组类似数据。或者,您可以定义 item: '*'
何时需要将数据提取为单个文本块。
请考虑 vty 命令的 show devices local
以下输出:
TSEC Ethernet Device Driver: .le1, Control 0x4296c218, (1000Mbit) HW reg base 0xff724000 [0]: TxBD base 0x7853ce20, RxBD Base 0x7853d640 [1]: TxBD base 0x7853d860, RxBD Base 0x7853e080 [2]: TxBD base 0x7853e2a0, RxBD Base 0x785422c0 [3]: TxBD base 0x785426e0, RxBD Base 0x78544700 Receive: 185584608 bytes, 2250212 packets, 0 FCS errors, 0 multicast packets 107271 broadcast packets, 0 control frame packets 0 PAUSE frame packets, 0 unknown OP codes 0 alignment errors, 0 frame length errors 0 code errors, 0 carrier sense errors 0 undersize packets, 0 oversize packets 0 fragments, 0 jabbers, 0 drops Receive per queue: [0]: 0 bytes, 0 packets, 0 dropped 0 jumbo, 0 truncated jumbo [1]: 0 bytes, 0 packets, 0 dropped 0 jumbo, 0 truncated jumbo [2]: 0 bytes, 0 packets, 0 dropped 0 jumbo, 0 truncated jumbo [3]: 203586808 bytes, 2250219 packets, 0 dropped 0 jumbo, 0 truncated jumbo Transmit: 288184646 bytes, 2038370 packets, 0 multicast packets 106531 broadcast packets, 0 PAUSE control frames 0 deferral packets, 0 excessive deferral packets 0 single collision packets, 0 multiple collision packets 0 late collision packets, 0 excessive collision packets 0 total collisions, 0 drop frames, 0 jabber frames 0 FCS errors, 0 control frames, 0 oversize frames 0 undersize frames, 0 fragments frames Transmit per queue: [0]: 10300254 bytes, 72537 packets 0 dropped, 0 fifo errors [1]: 4474302 bytes, 106531 packets 0 dropped, 0 fifo errors [2]: 260203538 bytes, 1857137 packets 0 dropped, 0 fifo errors [3]: 199334 bytes, 2179 packets 0 dropped, 0 fifo errors TSEC status counters: kernel_dropped:0, rx_large:0 rx_short: 0 rx_nonoctet: 0, rx_crcerr: 0, rx_overrun: 0 rx_bsy: 0,rx_babr:0, rx_trunc: 0 rx_length_errors: 0, rx_frame_errors: 0 rx_crc_errors: 0 rx_errors: 0, rx_ints: 2250110, collisions: 0 eberr:0, tx_babt: 0, tx_underrun: 0 tx_timeout: 0, tx_timeout: 0,tx_window_errors: 0 tx_aborted_errors: 0, tx_ints: 2038385, resets: 1 TSEC Ethernet Device Driver: .le3, Control 0x42979220, (1000Mbit) HW reg base 0xff726000 [0]: TxBD base 0x78545720, RxBD Base 0x78545f40 [1]: TxBD base 0x78546160, RxBD Base 0x78546980 [2]: TxBD base 0x78546ba0, RxBD Base 0x7854abc0 [3]: TxBD base 0x7854afe0, RxBD Base 0x7854d000 Receive: 0 bytes, 0 packets, 0 FCS errors, 0 multicast packets 0 broadcast packets, 0 control frame packets 0 PAUSE frame packets, 0 unknown OP codes 0 alignment errors, 0 frame length errors 0 code errors, 0 carrier sense errors 0 undersize packets, 0 oversize packets 0 fragments, 0 jabbers, 0 drops Receive per queue: [0]: 0 bytes, 0 packets, 0 dropped 0 jumbo, 0 truncated jumbo [1]: 0 bytes, 0 packets, 0 dropped 0 jumbo, 0 truncated jumbo [2]: 0 bytes, 0 packets, 0 dropped 0 jumbo, 0 truncated jumbo [3]: 0 bytes, 0 packets, 0 dropped 0 jumbo, 0 truncated jumbo Transmit: 6817984 bytes, 106531 packets, 0 multicast packets 106531 broadcast packets, 0 PAUSE control frames 0 deferral packets, 0 excessive deferral packets 0 single collision packets, 0 multiple collision packets 0 late collision packets, 0 excessive collision packets 0 total collisions, 0 drop frames, 0 jabber frames 0 FCS errors, 0 control frames, 0 oversize frames 0 undersize frames, 0 fragments frames Transmit per queue: [0]: 0 bytes, 0 packets 0 dropped, 0 fifo errors [1]: 4474302 bytes, 106531 packets 0 dropped, 0 fifo errors [2]: 0 bytes, 0 packets 0 dropped, 0 fifo errors [3]: 0 bytes, 0 packets 0 dropped, 0 fifo errors TSEC status counters: kernel_dropped:0, rx_large:0 rx_short: 0 rx_nonoctet: 0, rx_crcerr: 0, rx_overrun: 0 rx_bsy: 0,rx_babr:0, rx_trunc: 0 rx_length_errors: 0, rx_frame_errors: 0 rx_crc_errors: 0 rx_errors: 0, rx_ints: 0, collisions: 0 eberr:0, tx_babt: 0, tx_underrun: 0 tx_timeout: 0, tx_timeout: 0,tx_window_errors: 0 tx_aborted_errors: 0, tx_ints: 106531, resets: 1
下表提取了以 开头 TSEC Ethernet Device Driver:
的输出的每个部分。在这种情况下,的值 key: name
派生自 中 item
定义的正则表达式中的捕获组。
--- DevicesLocalTable: command: show devices local target: fpc1 item: 'TSEC Ethernet Device Driver: (\.?\w+),' key: name view: DevicesLocalView DevicesLocalView: fields: TSEC_status_counters: _TSECStatusCountersTable receive_counters: _ReceiveTable transmit_per_queue: _TransmitQueueTable
如果要匹配输出的整个部分而不是匹配每一行,也可以定义为item
星号 ('*')。如果包括 item: '*'
,则在大多数情况下,还必须包含参数以title
指定要提取的输出部分的标题。当您在视图中包含regex
参数并希望每个表达式与整个文本字符串匹配时,使用 提取item: '*'
输出非常有用。否则,regex
表达式将组合并匹配每一行。
下表提取标题 Receive:
下的文本块,并将每个正则表达式与整个文本字符串进行匹配:
_ReceiveTable: item: '*' title: 'Receive:' view: _ReceiveView _ReceiveView: regex: bytes: '(\d+) bytes' packets: '(\d+) packets' FCS_errors: '(\d+) FCS errors' broadcast_packets: '(\d+) broadcast packets'
表项键(键)
可选 key
属性定义用于唯一标识表项的输出字段。您可以使用单个键或键列表标识表项。如果表和视图返回迭代数据, key
则该值必须引用视图中定义的变量或字段名称。
请考虑以下 show chassis fan
输出:
Item Status RPM Measurement Fan 1 OK 5280 Spinning at normal speed Fan 2 OK 5280 Spinning at normal speed Fan 3 OK 5280 Spinning at normal speed Fan 4 OK 5280 Spinning at normal speed Fan 5 OK 5280 Spinning at normal speed
下表将表项键 fan-name
定义为 ,它映射到输出中列下 Item
的值。
ChassisFanTable: command: show chassis fan key: fan-name view: ChassisFanView ChassisFanView: columns: fan-name: Item fan-status: Status fan-rpm: RPM fan-measurement: Measurement
在 Junos PyEZ 应用程序中检索和打印数据时,生成的字典中的每个项目都使用此字段的值作为其键。
dict_keys(['Fan 1', 'Fan 2', 'Fan 3', 'Fan 4', 'Fan 5'])
还可以定义为 key
列表,以使用组合键标识表项。例如:
--- FPCIPV4AddressTable: command: show ipv4 address target: fpc1 key: - name - addr view: FPCIPV4AddressView FPCIPV4AddressView: columns: index: Index addr: Address name: Name
所选键 (key_items)
该 key
参数定义唯一标识表项的输出字段。在表中包括 key
参数时,可以使用可选 key_items
参数仅返回某些键值的数据。 key_items
定义要为其检索数据的 Table 项的键或键列表。您可以在表定义或 Junos PyEZ 应用程序中定义 key_items
参数。
请考虑以下 show chassis fan
输出:
Item Status RPM Measurement Fan 1 OK 5280 Spinning at normal speed Fan 2 OK 5280 Spinning at normal speed Fan 3 OK 5280 Spinning at normal speed Fan 4 OK 5280 Spinning at normal speed Fan 5 OK 5280 Spinning at normal speed
下表将表项键 fan-name
定义为且仅检索键值等于 Fan 1
的表项的数据。
ChassisFanTable: command: show chassis fan key: fan-name key_items: - Fan 1 view: ChassisFanView ChassisFanView: columns: fan-name: Item fan-status: Status fan-rpm: RPM fan-measurement: Measurement
在 Junos PyEZ 应用程序中,要定义key_items
要返回或覆盖表中定义的,key_items
请将表方法get()
中的参数设置为key_items
所需项的列表或元组,例如:
from jnpr.junos import Device from jnpr.junos.command.chassis_fan import ChassisFanTable from pprint import pprint import json with Device(host='router.example.com') as dev: fans = ChassisFanTable(dev) fans.get(key_items=['Fan 1', 'Fan 2']) pprint(json.loads(fans.to_json()))
user@host:~$ python3 junos-pyez-get-fan-data.py {'Fan 1': {'fan-measurement': 'Spinning at normal speed', 'fan-name': 'Fan 1', 'fan-rpm': 5280, 'fan-status': 'OK'}, 'Fan 2': {'fan-measurement': 'Spinning at normal speed', 'fan-name': 'Fan 2', 'fan-rpm': 5280, 'fan-status': 'OK'}}
章节标题(标题)
表可以包含可选 title
参数,用于定义命令输出中要从中提取和分析数据的部分的起点。当表定义 item: '*'
时,必须包括 title
以指定要提取的输出部分的标题
例如,请考虑以下命令输出,它包含在一组较大的输出中:
... TSEC status counters: kernel_dropped:0, rx_large:0 rx_short: 0 rx_nonoctet: 0, rx_crcerr: 0, rx_overrun: 0 rx_bsy: 0,rx_babr:0, rx_trunc: 0 rx_length_errors: 0, rx_frame_errors: 0 rx_crc_errors: 0 rx_errors: 0, rx_ints: 2250110, collisions: 0 eberr:0, tx_babt: 0, tx_underrun: 0 tx_timeout: 0, tx_timeout: 0,tx_window_errors: 0 tx_aborted_errors: 0, tx_ints: 2038385, resets: 1 ...
下表使用该参数从 title
输出部分提取 TSEC status counters
和分析数据。在这种情况下,表定义为 item
“*”,它将数据视为单个文本字符串。
_TSECStatusCountersTable: item: '*' title: 'TSEC status counters:' view: _TSECStatusCountersView _TSECStatusCountersView: regex: kernel_dropped: 'kernel_dropped:(\d+)' rx_large: 'rx_large:(\d+)'
字段分隔符(分隔符)
某些操作命令返回仅由键值对组成的输出。如果只想检索整个数据集并提取每个键值对,则可以使用该 delimiter
参数来定义如何拆分每个数据对,而不是定义单独的 View。Junos PyEZ 使用分隔符在指定边界处拆分数据,并将每个键值对存储在字典中。
请考虑 vty 命令的 show link stats
以下输出。
PPP LCP/NCP: 0 HDLC keepalives: 0 RSVP: 0 ISIS: 0 OSPF Hello: 539156 OAM: 0 BFD: 15 UBFD: 0 LMI: 0 LACP: 0 ETHOAM: 0 SYNCE: 0 PTP: 0 L2TP: 0 LNS-PPP: 0 ARP: 4292 ELMI: 0 VXLAN MRESOLVE: 0 Unknown protocol: 42
下表将分隔符定义为冒号 (:) 字符:
--- FPCLinkStatTable: command: show link stats target: fpc1 delimiter: ":"
在 Junos PyEZ 应用程序中检索数据时,表会在分隔符处拆分输出的每一行,并将键值对存储在字典中。
{'ARP': 4292, 'ELMI': 0, 'SYNCE': 0, 'ISIS': 0, 'BFD': 15, 'PPP LCP/NCP': 0, 'OAM': 0, 'ETHOAM': 0, 'LACP': 0, 'LMI': 0, 'Unknown protocol': 42, 'UBFD': 0, 'L2TP': 0, 'HDLC keepalives': 0, 'LNS-PPP': 0, 'OSPF Hello': 539156, 'RSVP': 0, 'VXLAN MRESOLVE': 0, 'PTP': 0}
评估表达式 (eval)
您可以使用可选 eval
参数在表视图返回的最终数据中添加或修改键值对。该 eval
参数将键名称映射到包含由 Python eval
函数计算的数学表达式的字符串。您可以在表和视图中包含 eval
参数,并且可以 eval
定义和计算多个值。
在表中使用 eval
时,它会引用用于计算的完整数据字典,并且键和计算值将作为单个附加项添加到字典中。在视图中使用 eval
时,表达式将在数据的每次迭代时计算,并将计算值添加到该迭代的数据中。 eval
如果键名称与视图中定义的键匹配, eval
则将该键的值替换为计算值。 eval
如果键名称与视图中定义的键不匹配, eval
则会将新键和计算值添加到数据中。
表达式 eval
可以引用视图返回的 data
字典。表达式必须使用 Jinja 模板变量进行引用 data
,以便 Junos PyEZ 可以在计算表达式时将变量替换为字典。
下面的示例在 eval
表定义中使用在数据字典中包含单个附加条目。添加项的键为 cchip_errors_from_lkup_chip
,其值是中断数的总和。
--- CChipLiInterruptStatsTable: command: show xmchip {{ chip_instance }} li interrupt-stats target: NULL args: chip_instance: 0 key: - li_block - name eval: cchip_errors_from_lkup_chip: "reduce(lambda x,y: x+y, [v['interrupts'] for k,v in {{ data }}.items()])" view: CChipLiInterruptStatsView CChipLiInterruptStatsView: columns: li_block: LI Block name: Interrupt Name interrupts: Number of Interrupts last_occurance: Last Occurrence
您还可以在表中定义 eval
以计算和添加多个键值对,例如:
--- CChipDRDErrTable: command: show xmchip {{ instance }} drd error-stats args: instance: 0 target: NULL key: Interrupt Name item: '*' eval: cchip_drd_wan_errors: sum([v['interrupt_count'] for k, v in {{ data }}.items() if k.endswith('_0')]) cchip_drd_fab_errors: sum([v['interrupt_count'] for k, v in {{ data }}.items() if k.endswith('_1')]) view: CChipDRDErrView CChipDRDErrView: regex: cchip_drd_wan_timeouts: 'Total WAN reorder ID timeout errors:\s+(\d+)' cchip_drd_fab_timeouts: 'Total fabric reorder ID timeout errors:\s+(\d+)' columns: interrupt_name: Interrupt Name interrupt_count: Number of Interrupts filters: - interrupt_count
有关在视图中使用eval
的信息,请参阅评估表达式 (eval)。
表视图(视图)
该 view
属性将表定义与特定视图相关联。视图定义应如何解析表输出,并将用户定义的 Python 变量名称映射到所选表项中的输出字段。您可以自定义视图以仅从表项目中选择某些字段。
如果输出仅包含键值对,则可以使用 Table 的 delimiter
参数提取数据并将键值对存储在字典中。在这种情况下,您不需要定义单独的视图。
文本FSM 模板(平台和use_textfsm)
Junos PyEZ 表可以引用 TextFSM 模板来解析来自瞻博网络设备或其他供应商设备的命令输出。必须在 Junos PyEZ 服务器或虚拟环境中安装 ntc-templates
库,才能在表中使用 TextFSM 模板。
若要使用 TextFSM 模板分析命令输出,请包含在use_textfsm: True
表中。您可以单独使用 TextFSM 模板,也可以与 Junos PyEZ View 结合使用。Junos PyEZ 使用和command
值来确定platform
模板的文件名。
例如,下表使用 juniper_junos_show_arp_no-resolve.textfsm 模板解析来自瞻博网络 Junos 设备的命令输出:
--- ArpTableTextFSM: command: show arp no-resolve platform: juniper_junos key: MAC use_textfsm: True
有关将 Junos PyEZ 表与 TextFSM 模板配合使用的详细信息,请参阅 将 Junos PyEZ 表与 TextFSM 模板配合使用。