TextFSM Value Key

Today, thanks to a question from a listener, I decided to figure out what Value Key means in TextFSM templates. Previously, for some reason, I thought that this was to check the uniqueness of the value, but a quick check showed that this was not the case. Key can be used to create a link between multiple templates and combine the data into a single data structure.

As far as I understand it only works with clitable

Basic Example

For example, we have the output of two show commands: the first shows the IP address and MAC address, and the second shows vlan, mac and port.

  IP address      Hardware address
---------------- --------------------
192.168.100.1      00:11:22:33:44:01
192.168.100.2      00:11:22:33:44:02
192.168.100.3      00:11:22:33:44:03
192.168.100.4      00:11:22:33:44:04

#sh mac address-table
    Vlan          Mac Address         Port       Type
------------ --------------------- ---------- ----------
     1         00:11:22:33:44:01      Po1      dynamic
     2         00:11:22:33:44:02      Po2      dynamic
     3         00:11:22:33:44:03      Po3      dynamic
     4         00:11:22:33:44:04      Po4      dynamic
     5         00:11:22:33:44:05      Po5      dynamic

From these two outputs, you need to get the following data.

[['192.168.100.1', '00:11:22:33:44:01', '1', 'Po1'],
 ['192.168.100.2', '00:11:22:33:44:02', '2', 'Po2'],
 ['192.168.100.3', '00:11:22:33:44:03', '3', 'Po3'],
 ['192.168.100.4', '00:11:22:33:44:04', '4', 'Po4']]

IP address and MAC address from the first output are combined with the corresponding VLAN and port from the second output. Data is combined based on MAC address match.

Of course, this can be done with Python by making separate TextFSM templates for each output, but as it turns out, this can also be achieved by TextFSM itself.

Magic

You need to create templates for each output, but with one caveat - mac must be marked as Key.

templates/1.txt:

Value ip ([\d.]+)
Value Key mac (\S+)

Start
  ^${ip} +${mac} -> Record

templates/2.txt:

Value vlan (\S+)
Value Key mac ([\w:]+)
Value port (\S+)

Start
  ^ *${vlan} +${mac} +${port} +\S+$$ -> Record

In the index file, both templates must be written in the first column separated by a colon (templates/index file):

Template, Hostname, Vendor, Command
sh_ip_int_br.txt, .*, cisco_ios, sh[[ow]] ip int[[erface]] br[[ief]]
1.txt:2.txt, .*, cisco_ios, sh[[ow]] mac

For comparison, an example of a regular template specification is shown (sh_ip_int_br.txt).

Basically, that’s all. We write code to use clitable and get the result:

from pprint import pprint
from textfsm import clitable


def parse_output_textfsm(output, attributes_dict, pth="templates", index="index"):
    cli = clitable.CliTable(index, pth)
    cli.ParseCmd(output, attributes_dict)
    data = [list(item) for item in cli]
    return data


if __name__ == "__main__":
    with open("output_sh_mac.txt") as f:
        output = f.read()
    pprint(parse_output_textfsm(output, {"Command": "sh mac"}))

Output

[['192.168.100.1', '00:11:22:33:44:01', '1', 'Po1'],
 ['192.168.100.2', '00:11:22:33:44:02', '2', 'Po2'],
 ['192.168.100.3', '00:11:22:33:44:03', '3', 'Po3'],
 ['192.168.100.4', '00:11:22:33:44:04', '4', 'Po4']]

Sources

stackoverflow

Use a captured value as row identifier

ntc-templates