CLI Command result to json using Ansible

Viewed 255

Good afternoon guys,

I need to get the BGP table details from 5 switches. In order to do it, I'm using Ansible with a Cisco module to send the CLI command "show bgp l2vpn evpn vrf all" on these 5 switch.

It's working well but I need to get JSON to be able to filter the results.

The first option I tried is to use the | json option in Ansible:

---
- name: Playbook
  hosts: all
  gather_facts: false
  tasks:
  - name: run show bgp on remote devices
    cisco.nxos.nxos_command:
      commands: show bgp l2vpn evpn vrf all | json
    register: cli_result
  - local_action: 
      module: copy 
      content: "{{ cli_result | to_nice_json(indent=2) }}"
      dest: home/cli_result.json

This option is working for one switch but as soon as I'm launching it on the 5 switches, I'm like out of memory or something else and I get the error ERROR! A worker was found in a dead state.

I don't know if this issue comes from the server I'm working on, which is not enough powerful or if it's something else.

Also, I noticed that the | json option makes the playbook very slow and when I'm launching the playbook without this option, it's 5 time faster.

So my question is: Is there a way to convert the CLI command result onto json with Python for example?

Of course I tried to use the python module json to convert it but it's converting it onto one big block of 12000 lines with only one key and one enormous value. Whereas the | json option in Ansible makes it very clear with a lot of different keys.

Here is the result of the CLI command:

BGP routing table information for VRF default, address family L2VPN EVPN
BGP table version is xxxxx, Local Router ID is xx.xx.xx.xx
Status: s-suppressed, x-deleted, S-stale, d-dampened, h-history, *-valid, >-best
Path type: i-internal, e-external, c-confed, l-local, a-aggregate, r-redist, I-injected
Origin codes: i - IGP, e - EGP, ? - incomplete, | - multipath, & - backup, 2 - best2

   Network            Next Hop            Metric     LocPrf     Weight Path
Route Distinguisher: xxxxx:xxxxx
* i[x]:[0]:[0]:[xx]:[xxxx.xxxx.xxxx]:[0]:[0.0.0.0]/xxx
                      xx.xx.xx.xx                     000          0 xxxxx xxxxx i
*>i                   xx.xx.xx.xx                     000          0 xxxxx xxxxx i
* i[x]:[0]:[0]:[xx]:[xxxx.xxxx.xxxx]:[0]:[0.0.0.0]/xxx
                      xx.xx.xx.xx                     000          0 xxxxx xxxxx i
*>i                   xx.xx.xx.xx                     000          0 xxxxx xxxxx i
.......

Here is the result of the | json option of Ansible:

{
  "changed": false,
  "failed": false,
  "stdout": [
    {
      "TABLE_vrf": {
        "ROW_vrf": {
          "TABLE_afi": {
            "ROW_afi": {
              "TABLE_safi": {
                "ROW_safi": {
                  "TABLE_rd": {
                    "ROW_rd": [
                      {
                        "TABLE_prefix": {
                          "ROW_prefix": [
                            {
                              "TABLE_path": {
                                "ROW_path": [
                                  {
                                    "aspath": "xxxxx xxxxx",
                                    "best": "none",
                                    "bestcode": null,
                                    "ipnexthop": "0.0.0.0",
                                    "localpref": "000",
                                    "origin": "i",
                                    "pathnr": "0",
                                    "status": "valid",
                                    "statuscode": "*",
                                    "type": "internal",
                                    "typecode": "i",
                                    "weight": "0"
                                  },
                                  {
                                    "aspath": "xxxxx xxxxx",
                                    "best": "bestpath",
                                    "bestcode": ">",
                                    "ipnexthop": "0.0.0.0",
                                    "localpref": "000",
                                    "origin": "i",
                                    "pathnr": "1",
                                    "status": "valid",
                                    "statuscode": "*",
                                    "type": "internal",
                                    "typecode": "i",
                                    "weight": "0"
                                  }
                                ]
                              },
                              "nonipprefix": "[x]:[0]:[0]:[xx]:[xxxx.xxxx.xxxx]:[0]:[0.0.0.0]/xxx"
                            },

And here is the result of the CLI Command that I converted with Python:

{
  "changed": false,
  "failed": false,
  "stdout": [containing the whole block of cli command result with ',' after each line]
}

Thank you very much for your help,

1 Answers

Q: "Is there a way to convert the CLI command result onto JSON?"

A: Probably the best choice is ansible.netcommon.cli_parse in your case.


Q: "Is working for one switch but as soon as I'm launching it on the 5 switches ..."

A: You run the task local_action concurrently for all switches. Run it only once and write all data, for example, in a dictionary. Given the inventory and the playbook below for testing

shell> cat hosts
sw1
sw2
sw3
shell> cat playbook.yml
- name: Playbook
  hosts: all
  gather_facts: false
  tasks:
  - set_fact:
      cli_result:
        stdout:
          - TABLE_vrf:
              ROW_vrf: to be continued
  - copy:
      content: "{{ _dict|to_nice_yaml(indent=2) }}"
      dest: cli_result.json
    delegate_to: localhost
    run_once: true
    vars:
      _keys: "{{ ansible_play_hosts }}"
      _vals: "{{ ansible_play_hosts|
                 map('extract', hostvars, ['cli_result', 'stdout'])|
                 list }}"
      _dict: "{{ dict(_keys|zip(_vals)) }}"

The playbook creates the file cli_result.json

sw1:
- TABLE_vrf:
    ROW_vrf: to be continued
sw2:
- TABLE_vrf:
    ROW_vrf: to be continued
sw3:
- TABLE_vrf:
    ROW_vrf: to be continued
Related