In this recipe, we will outline how to execute operational commands on IOS devices and store these outputs to text files for further processing. This allows us to capture any operational commands from IOS devices during pre- or post-validation after we perform any deployment so that we can compare the results.
Retrieving operational data from IOS devices
Getting ready
In order to follow along with this recipe, an Ansible inventory file should be in place and the network should already be set up as per the previous recipes.
How to do it...
- Create a new playbook called pb_op_cmds.yml and populate it with the following tasks to create the directory structure to save the output from the devices:
---
- name: "Play 1: Execute Operational Commands"
hosts: network
vars:
config_folder: "configs"
op_folder: "op_data"
op_cmds:
- show ip ospf neighbor
- show ip route
tasks:
- name: "P1T1: Build Directories to Store Data"
block:
- name: "Create folder to store Device config"
file:
path: "{{ config_folder }}"
state: directory
- name: "Create Folder to store operational commands"
file:
path: "{{ op_folder }}"
state: directory
run_once: yes
delegate_to: localhost
- Update the pb_op_cmds.yml playbook and populate it with the following tasks to retrieve the running configuration from the devices:
- name: "P1T2: Get Running configs from Devices"
ios_command:
commands: show running-config
register: show_run
- name: "P1T3: Save Running Config per Device"
copy:
content: "{{ show_run.stdout[0] }}"
dest: "{{ config_folder }}/{{ inventory_hostname }}.cfg"
- Update the playbook and populate it with the following tasks to retrieve the operational commands from the devices and save it:
- name: "P1T4: Create Folder per Device"
file:
path: "{{ op_folder}}/{{ inventory_hostname }}"
state: directory
delegate_to: localhost
- name: "P1T5: Get Operational Data from Devices"
ios_command:
commands: "{{ item }}"
register: op_output
loop: "{{ op_cmds }}"
- name: "P1T6: Save output per each node"
copy:
content: "{{ item.stdout[0] }}"
dest: "{{ op_folder}}/{{ inventory_hostname }}/{{item.item | replace(' ', '_')}}.txt"
loop: "{{ op_output.results }}"
How it works...
In this recipe, we are using the ios_command module in order to execute operational commands on the IOS devices, and saving them to text files. In order to achieve this goal, we perform the following steps:
- We create the folders that we will store the output to, and we create a folder called configs to store the running config of all the devices. We also create an op_data file to store the output of the operational commands that we will get from the devices.
- We then execute the show running command on all the IOS devices in our inventory and we register the output in a new variable called show_run.
- We use the copy module to save the output from the previous task to a file for each device. The output from the command run is saved in the stdout variable. As we executed a single command, the stdout variable only has a single item (stdout[0]).
Once we execute this task, we can see that the configs folder is populated as shown in the following output:
$ tree configs/
configs/
├── access01.cfg
├── access02.cfg
├── core01.cfg
├── core02.cfg
├── isp01.cfg
├── wan01.cfg
└── wan02.cfg
For the next part, we create a folder for each node to store the output from the multiple show commands that we will execute on the IOS devices.
We use the ios_command module to execute the show commands on the devices, and save all the output in a new variable called op_output. We use the copy execute command, show ip route, and we create a file for the output of this command with the name show_ip_route.txt.
After running this task, we can see that this is the current structure of the op_data folder:
$ tree op_data/
op_data/
├── access01
│ ├── show_ip_ospf_neighbor.txt
│ └── show_ip_route.txt
├── access02
│ ├── show_ip_ospf_neighbor.txt
│ └── show_ip_route.txt
├── core01
│ ├── show_ip_ospf_neighbor.txt
│ └── show_ip_route.txt
├── core02
│ ├── show_ip_ospf_neighbor.txt
│ └── show_ip_route.txt
├── isp01
│ ├── show_ip_ospf_neighbor.txt
│ └── show_ip_route.txt
├── wan01
│ ├── show_ip_ospf_neighbor.txt
│ └── show_ip_route.txt
└── wan02
├── show_ip_ospf_neighbor.txt
└── show_ip_route.txt
We can check the content of one of the files to confirm that all the data has been stored:
$ head op_data/core01/show_ip_ospf_neighbor.txt
Neighbor ID Pri State Dead Time Address Interface
10.100.1.3 0 FULL/ - 00:00:37 10.3.1.2 Ethernet1/0
10.100.1.2 0 FULL/ - 00:00:36 10.1.200.2 Vlan200