ansible-genie is a implementation of the pyATS network testing framework in an Ansible role. It contains modules, filters, and tasks:
- Run a command and get structured output
- "snapshot" the output of a command and save it to a file
- Compare the current output of a command to a previous "snapshot"
First, install the Python dependencies:
$ pip install pyats genie
<snip>
Installing collected packages: pyats, genie
Successfully installed genie-19.9 pyats-19.9.2
pyATS and Genie require Python >=3.4.
For manual installation, you can just clone the repository into your
ANSIBLE_ROLES_PATH
:
$ git clone https://github.com/CiscoDevNet/ansible-pyats "${ANSIBLE_ROLES_PATH:-roles}/ansible-pyats"
Cloning into 'roles/ansible-pyats'...
remote: Enumerating objects: 83, done.
remote: Counting objects: 100% (83/83), done.
remote: Compressing objects: 100% (56/56), done.
remote: Total 83 (delta 28), reused 56 (delta 12), pack-reused 0
Unpacking objects: 100% (83/83), done.
If you are using Ansible Galaxy,
you can use this role by adding the following to your requirements.yml
:
- src: https://github.com/CiscoDevNet/ansible-pyats
scm: git
name: ansible-pyats
Next, install your Galaxy dependencies:
$ ansible-galaxy install -r requirements.yml -p "${ANSIBLE_ROLES_PATH:-roles}"
pyats_parse_command
: Run a command on a remote device and return the structured output
pyats_parser
: provides structured data from unstructured command outputpyats_diff
: provides the difference between two data structures
- hosts: router
connection: network_cli
gather_facts: no
roles:
- ansible-pyats
tasks:
- pyats_parse_command:
command: show ip route bgp
register: output
- debug:
var: output.structured
- hosts: router
connection: network_cli
gather_facts: no
roles:
- ansible-pyats
tasks:
- include_role:
name: ansible-pyats
tasks_from: snapshot_command
vars:
command: show ip route
file: "{{ inventory_hostname }}_routes.json"
command
: the command to run on the devicefile
: the name of the file in which to store the command "shapshot"
- hosts: router
connection: network_cli
gather_facts: no
roles:
- ansible-pyats
tasks:
- include_role:
name: ansible-pyats
tasks_from: compare_command
vars:
command: show ip route
file: "{{ inventory_hostname }}_routes.json"
command
: the command to run on the devicefile
: the name of the file in which to store the command "shapshot"
- hosts: router
connection: network_cli
gather_facts: no
roles:
- ansible-pyats
tasks:
- name: Run command
cli_command:
command: show ip route
register: cli_output
- name: Parsing output
set_fact:
parsed_output: "{{ cli_output.stdout | pyats_parser('show ip route', 'iosxe') }}"
- name: Diff current and snapshot
set_fact:
diff_output: "{{ current_output | pyats_diff(previous_output) }}"
---
- hosts: cisco
gather_facts: no
connection: network_cli
tasks:
- name: collect config (before)
ios_command:
commands:
- show run
register: result_before
- name: load new acl into device
ios_config:
lines:
- permit ip host 192.168.114.1 any
- permit ip host 192.168.114.2 any
- permit ip host 192.168.114.3 any
parents: ip access-list extended test
save_when: modified
- name: collect config (after)
ios_command:
commands:
- show run
register: result_after
- name: debug
debug:
msg: "{{ result_before.stdout[0] | genie_config_diff(result_after.stdout[0], mode='add', exclude=exclude_list) }}"
vars:
exclude_list:
- (^Using.*)
- (Building.*)
- (Current.*)
- (crypto pki certificate chain.*)
The argument mode
can be add
(displays added commands in result_after), remove
(displays removed commands in result_after), or modified
(displays modified commands). If mode
argument is not specified, added, removed, and modified commands are displayed.
The argument exclude
means command lists which is excluded when comparing before and after configs.
In the playbook example above, variable excluded_list
, which is defined as the play variable, is used.
msg: "{{ result_before.stdout[0] | genie_config_diff(result_after.stdout[0]) }}"
msg: "{{ result_before.stdout[0] | genie_config_diff(result_after.stdout[0], mode='remove') }}"
msg: "{{ result_before.stdout[0] | genie_config_diff(result_after.stdout[0], exclude=exclude_list) }}"
PLAY [cisco] **********************************************************************************
TASK [collect config (before)] ****************************************************************
ok: [test3]
TASK [load new acl into device] ***************************************************************
ok: [test3]
TASK [collect config (after)] *****************************************************************
ok: [test3]
TASK [debug] **********************************************************************************
ok: [test3] => {
"msg": [
"ip access-list extended test:",
"+ permit ip host 192.168.114.1 any: ",
"+ permit ip host 192.168.114.2 any: ",
"+ permit ip host 192.168.114.3 any: "
]
}
PLAY RECAP ************************************************************************************
test3 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
This filter can compare the output of show commands parsed by Genie parser. The arguments mode
and exclude
also can be used.
- name: debug
debug:
msg: "{{ sh_int_parsed_before | genie_parser_diff(sh_int_parsed_after, mode='modified', exclude=exclude_list) }}"
vars:
exclude_list:
- (.*in_octets.*)
- (.*in_pkts.*)
- (.*out_octets.*)
- (.*out_pkts.*)
Cisco Sample License