In the previous article, I used a Python parser library called TTP (Template Text Parser) to parse the L2SW Config file and automatically generate a port management table. I tried to automatically generate a port management table from L2SW Config
This time, I took this parser as an Ansible custom filter so that I could parse the show command result obtained by the xxx_command
module.
parse_cli_textfsm
using TextFSM and parse_genie
using pyATS / Genie (installation is required from Ansible Galaxy. For details, see [GitHub / parse_genie]]( (Https://github.com/clay584/parse_genie)).I used Ansible installed in the virtual environment of Python 3.6.7. Initially, I was testing with version 2.9.0, but I am using 2.8.4 because I got multiple Logging error (KeyError) messages.
An additional TTP installation is required.
(venv) [centos@localhost ansible]$ pip install ttp
I created the following Python script.
custom_filters_ttp.py
from ansible.errors import AnsibleError
#Import ttp and json. If the import fails, an error can be output in the subsequent processing.
try:
from ttp import ttp
HAS_TTP = True
except ImportError:
HAS_TTP = False
try:
import json
HAS_JSON = True
except ImportError:
HAS_JSON = False
class FilterModule(object):
def parse_cli_ttp(self, cli_output, template_file):
if not HAS_TTP:
raise AnsibleError('parse_cli_ttp filter requires TTP library to be installed')
if not HAS_JSON:
raise AnsibleError('parse_cli_ttp filter requires JSON library to be installed')
with open(template_file, 'rt') as ft:
ttp_template = ft.read()
# create parser object and parse data using template
parser = ttp(data=cli_output, template=ttp_template)
parser.parse()
# return result in JSON format
results = parser.result(format='json')[0]
return results
def filters(self):
return {
#The left side is the filter name used in the playbook, and the right side is the function name to be associated.
'parse_cli_ttp': self.parse_cli_ttp,
}
According to best practice, I created a filter_plugins directory under the directory where the playbook is stored, and stored this file in it.
In addition, the settings in ansible.cfg have been rewritten as follows so that Ansible can recognize this custom filter.
ansible.cfg
[defaults]
filter_plugins = [Full path of the playbook storage directory]/filter_plugins
Playbook
Get the Running Config in the ʻios_commandmodule, and in the following
debug` module, get the obtained Config and the [L2 interface setting template] created in the previous article (https://qiita.com/tech_kitara/items/75ec526ff9a27932c565 # 3-l2% E3% 82% A4% E3% 83% B3% E3% 82% BF% E3% 83% BC% E3% 83% 95% E3% 82% A7% E3% 83% BC% E3% 82 % B9% E8% A8% AD% E5% AE% 9A) file path specified. It's simple!
playbook_ttp.yml
---
- hosts: cisco
gather_facts: no
connection: network_cli
tasks:
- name: run show command on remote devices
ios_command:
commands: show running-config
register: result
- name: display parsed output
debug:
msg: "{{ result.stdout[0] | parse_cli_ttp('catalyst2960_template_ttp2.txt') }}"
There is a difference in the result because the Config is different from the previous time, but the parse itself is done without problems.
$ ansible-playbook -i inventory_2960.ini playbook_ttp.yml
PLAY [cisco] *************************************************************************************************
TASK [run show command on remote devices] ********************************************************************
ok: [hqdist1A]
TASK [display parsed output] *********************************************************************************
ok: [hqdist1A] => {
"msg": [
{
"l2_interfaces": [
{
"description": "<< Connect hqdist1 and hqdist2 >>",
"duplex": "auto",
"mode": "trunk",
"port_no": "Port-channel1",
"portfast": "x",
"speed": "auto",
"status": "o",
"vlan": "1,101"
},
{
"description": "<< To hqborder1 Fa1 >>",
"duplex": "full",
"mode": "access",
"port_no": "FastEthernet0/1",
"portfast": "x",
"speed": "100",
"status": "o",
"vlan": "200"
},
{
"description": "<< To hqborder2 Fa1 >>",
"duplex": "full",
"mode": "access",
"port_no": "FastEthernet0/2",
"portfast": "x",
"speed": "100",
"status": "o",
"vlan": "202"
},
{
"description": "<< To hqaccess1 Fa0/23 >>",
"duplex": "full",
"mode": "access",
"port_no": "FastEthernet0/3",
"portfast": "x",
"speed": "100",
"status": "o",
"vlan": "100"
},
{
"duplex": "auto",
"mode": "trunk",
"port_no": "FastEthernet0/4",
"portfast": "x",
"speed": "auto",
"status": "o",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/5",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/6",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/7",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/8",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/9",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/10",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/11",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/12",
"portfast": "x",
"speed": "auto",
"status": "o",
"vlan": "203"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/13",
"portfast": "x",
"speed": "auto",
"status": "o",
"vlan": "100"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/14",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/15",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/16",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/17",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/18",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/19",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/20",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/21",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "FastEthernet0/22",
"portfast": "x",
"speed": "auto",
"status": "x",
"vlan": "1"
},
{
"description": "<< To hqdist2 Fa0/23 >>",
"duplex": "auto",
"mode": "trunk",
"port_no": "FastEthernet0/23",
"portfast": "x",
"speed": "auto",
"status": "o",
"vlan": "1,101"
},
{
"description": "<< To hqdist2 Fa0/24 >>",
"duplex": "auto",
"mode": "trunk",
"port_no": "FastEthernet0/24",
"portfast": "x",
"speed": "auto",
"status": "o",
"vlan": "1,101"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "GigabitEthernet0/1",
"portfast": "x",
"speed": "auto",
"status": "o",
"vlan": "1"
},
{
"duplex": "auto",
"mode": "access",
"port_no": "GigabitEthernet0/2",
"portfast": "x",
"speed": "auto",
"status": "o",
"vlan": "1"
}
]
}
]
}
PLAY RECAP ***************************************************************************************************
hqdist1A : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The plugin I made this time has been uploaded to GitHub / ansible-ttp. Not only Config but also the output results of other show commands can be parsed relatively easily, so please use it.
Recommended Posts