[python]TextFSM to match show interface summary

The Cisco ASAv has a command show interface summary, this command output has a lot of information, these are the interesting information I need from this command:

  1. Interface id including the sub interface if available
  2. nameif, which is the name interface which must be configured
  3. administrative status
  4. protocol status
  5. vlan id if available
  6. ip address if available
  7. subnet mask
  8. description if available
  9. mac address

Sample output from cisco asa

fw02# sh int summary
Interface GigabitEthernet0/0 "", is up, line protocol is up
  Hardware is i82540EM rev03, BW 1000 Mbps, DLY 10 usec
        Auto-Duplex(Full-duplex), Auto-Speed(1000 Mbps)
        Input flow control is unsupported, output flow control is off
        Available but not configured via nameif
        MAC address 5000.0002.0001, MTU not set
        IP address unassigned
        0 packets input, 0 bytes, 0 no buffer
        Received 0 broadcasts, 0 runts, 0 giants
        0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort
        0 pause input, 0 resume input
        0 L2 decode drops
        2 packets output, 0 bytes, 0 underruns
        0 pause output, 0 resume output
        0 output errors, 0 collisions, 2 interface resets
        0 late collisions, 0 deferred
        0 input reset drops, 0 output reset drops
        input queue (blocks free curr/low): hardware (511/511)
        output queue (blocks free curr/low): hardware (511/510)
Interface GigabitEthernet0/0.100 "dmz_net100", is up, line protocol is up
  Hardware is i82540EM rev03, BW 1000 Mbps, DLY 10 usec
        VLAN identifier 100
        MAC address 5000.0002.0001, MTU 1500
        IP address 10.0.100.1, subnet mask 255.255.255.0
Interface GigabitEthernet0/0.101 "dmz_secondary_net101", is up, line protocol is up
  Hardware is i82540EM rev03, BW 1000 Mbps, DLY 10 usec
        VLAN identifier 101
        MAC address 5000.0002.0001, MTU 1500
        IP address 10.0.101.1, subnet mask 255.255.255.0

TextFSM to match the interesting data

Value Required interface ([0-9A-Za-z/.]+)
Value nameif (\S*)
Value a_state (up|down|administratively down)
Value p_state (up|down)
Value vlan (\d+)
Value ip_address (\d+.\d+.\d+.\d+)
Value mask (\d+.\d+.\d+.\d+)
Value description ([\w\s\-]+)
Value mac_address (\S+)


Start
# detects if there is a word Interface after show int summary
# if there is on next line start recording.
 ^Interface -> Continue.Record
 ^Interface\s+${interface}\s+"${nameif}",\s*is\s+${a_state},\s*line\s+protocol\s+is\s+${p_state}
 ^\s*VLAN\s+identifier\s+${vlan}
 ^\s*Description:\s*${description}
 ^\s*MAC\s+address\s+${mac_address},\s+MTU\s+(\d+)
 ^\s*IP\s+address\s+${ip_address},\s*subnet\s+mask\s+${mask}

The Continue line action is ignoring the match row, and go to the next.

Code to test

For testing I am using nornir framework to call netmiko.

from network.ciscoasa import connect_asa_host
from nornir.plugins.tasks.networking import netmiko_send_command
from textfsm import TextFSM
from pathlib import Path
from os.path import join
from pprint import pprint

filename = "show_int_summary.textfsm"
file_path = join(Path(__file__).parent.parent.absolute(), "network", "templates", filename)
hostname = "fw02"
asa = connect_asa_host(hostname=hostname)
response = asa.run(task=netmiko_send_command,
                   command_string="show interface summary")
result = response[hostname][0].result

with open(file_path, "r") as tp:
    template = TextFSM(tp)

processed_result = template.ParseTextToDicts(result)
pprint(processed_result)

from network.ciscoasa import connect_asa_host is my personal code that does the InitNornir and filter the host in the hosts.yaml file.

from nornir.plugins.tasks.networking import netmiko_send_command this imports the netmiko_send_command function, this is similar to below when calling netmiko directly without Nornir:

cmd = "show interface summary"
        with ConnectHandler(**config) as task:
            try:
                collect_results.append(task.send_command(cmd))
            except Exceptions as e:
                print(e)

To send single command use netmiko_send_command, to send configuration set use netmiko_send_config. Single command has one index in AggregatedResult, hence the result can be obtained from result = response[hostname][0].result, to check for failure use result = response[hostname][0].failed which is a boolean.

If you use netmiko_send_config then the result is in the second index of AggregatedResult i.e. result = response[hostname][1].result, to refer to the failure state use the first index result = response[hostname][0].failed

TextFSM has a ParseTextToDicts which helps to combine the header with the result and output as a dictionary, I did not know this previously and hence I was re-inventing the wheel by using zip and dict to get the dictionary.

Result

[{'a_state': 'up',
  'description': '',
  'interface': 'GigabitEthernet0/0',
  'ip_address': '',
  'mac_address': '',
  'mask': '',
  'nameif': '',
  'p_state': 'up',
  'vlan': ''},
 {'a_state': 'up',
  'description': '',
  'interface': 'GigabitEthernet0/0.100',
  'ip_address': '10.0.100.1',
  'mac_address': '5000.0002.0001',
  'mask': '255.255.255.0',
  'nameif': 'dmz_net100',
  'p_state': 'up',
  'vlan': '100'},
 {'a_state': 'up',
  'description': '',
  'interface': 'GigabitEthernet0/0.101',
  'ip_address': '10.0.101.1',
  'mac_address': '5000.0002.0001',
  'mask': '255.255.255.0',
  'nameif': 'dmz_secondary_net101',
  'p_state': 'up',
  'vlan': '101'},
 {'a_state': 'up',
  'description': '',
  'interface': 'GigabitEthernet0/1',
  'ip_address': '',
  'mac_address': '',
  'mask': '',
  'nameif': '',
  'p_state': 'up',
  'vlan': ''},
 {'a_state': 'up',
  'description': '',
  'interface': 'GigabitEthernet0/1.90',
  'ip_address': '10.0.90.1',
  'mac_address': '5000.0002.0002',
  'mask': '255.255.255.0',
  'nameif': 'reserved_net90',
  'p_state': 'up',
  'vlan': '90'},
 {'a_state': 'up',
  'description': '',
  'interface': 'GigabitEthernet0/2',
  'ip_address': '',
  'mac_address': '',
  'mask': '',
  'nameif': '',
  'p_state': 'up',
  'vlan': ''},
 {'a_state': 'up',
  'description': 'This is a description test ',
  'interface': 'GigabitEthernet0/2.20',
  'ip_address': '10.0.20.1',
  'mac_address': '5000.0002.0003',
  'mask': '255.255.255.0',
  'nameif': 'user_space_net20',
  'p_state': 'up',
  'vlan': '20'},
 {'a_state': 'administratively down',
  'description': '',
  'interface': 'GigabitEthernet0/3',
  'ip_address': '',
  'mac_address': '',
  'mask': '',
  'nameif': '',
  'p_state': 'up',
  'vlan': ''},
 {'a_state': 'administratively down',
  'description': '',
  'interface': 'GigabitEthernet0/4',
  'ip_address': '',
  'mac_address': '',
  'mask': '',
  'nameif': '',
  'p_state': 'up',
  'vlan': ''},
 {'a_state': 'administratively down',
  'description': '',
  'interface': 'GigabitEthernet0/5',
  'ip_address': '',
  'mac_address': '',
  'mask': '',
  'nameif': '',
  'p_state': 'up',
  'vlan': ''},
 {'a_state': 'administratively down',
  'description': '',
  'interface': 'GigabitEthernet0/6',
  'ip_address': '',
  'mac_address': '',
  'mask': '',
  'nameif': '',
  'p_state': 'up',
  'vlan': ''},
 {'a_state': 'up',
  'description': '',
  'interface': 'Management0/0',
  'ip_address': '192.168.100.30',
  'mac_address': '5000.0002.0000',
  'mask': '255.255.255.0',
  'nameif': 'management',
  'p_state': 'up',
  'vlan': ''}]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s