Building an interface counter’s report on Arista (II): using Ansible

We can gather interface counters reasonably easily using Ansible (you can check how to do the same thing using Python+pyeapi here). I am going to focus on output drops in this post, but the same concepts can be applied to any other interface counter.

First of all, we need an inventory file in which we will have the connection details for the devices we want to pull data from. For this example, my inventory file has only one device and looks like this:

[all:vars]
ansible_connection=local
ansible_python_interpreter=/usr/bin/python3

[arista]
switch1 ansible_host=10.1.1.1
username=test
password=test

Secondly, following good practices, we will make use of a variable file so that we do not have to hardcode in our playbook information that may be used by several playbooks, such as the provider variable.

This variable file will be inside a folder called group_vars and will be called arista.yml, it will have the provider variable,  needed to establish an SSH/API connection.

---

conn_eapi:
  username: "{{ username }}"
  password: "{{ password }}"
  transport: eapi
  validate_certs: no

conn_ssh:
  username: "{{ username }}"
  password: "{{ password }}"
  transport: cli

Once we have all the above, we can start creating our playbook.

This will connect to an Arista switch using either eAPI or SSH, run the command show interface counters, and copy the output of such command in a text file called eod.txt

We could either use the Arista eAPI or use SSH, and take advantage of the Arista’s capability of converting the commands’ output into JSON format by just adding the following after the standard command: “| json”. For instance, if we want to get the JSON output of the command “show interface counters” we just need to type this: “show interface counters | json”.

Therefore, using eAPI, our playbook will look like the below:

---

- name: Check interface drops
  hosts: switch1
  gather_facts: false

  tasks:
    - name: Show command using eAPI
      eos_command:
         provider: "{{ conn_eapi }}"
         commands: show interfaces counters discards
      register: show_command

    - name: Print output of the show command
      debug:
         msg: "{{ show_command.stdout_lines }}"

    - name: Copy output to a txt file
      copy:
         content: "{{ show_command.stdout_lines[0] }}"
         dest: "/home/iserghini/EOD/eod.txt"

Here we can see the output:

(py27_venv)[iserghini@test EOD]$ ansible-playbook eod.yml -i hosts

PLAY [Check interface drops] ***********************************************************************************************

TASK [Show commands] ***************************************************************************************
ok: [switch1]

TASK [Print output of the show command] ********************************************************************
ok: [switch1] => {
    "msg": [
        {
            "inDiscardsTotal": 0,
            "interfaces": {
                "Ethernet1": {
                    "inDiscards": 0,
                    "outDiscards": 0
                },
                "Ethernet2": {
                    "inDiscards": 0,
                    "outDiscards": 0
                },
                "Ethernet3": {
                    "inDiscards": 0,
                    "outDiscards": 0
                },
                "Ethernet4": {
                    "inDiscards": 0,
                    "outDiscards": 0
                },
                "Ethernet5": {
                    "inDiscards": 0,
                    "outDiscards": 0
                },
                "Ethernet6": {
                    "inDiscards": 0,
                    "outDiscards": 0
                },
                "Ethernet7": {
                    "inDiscards": 0,
                    "outDiscards": 0
                },
                "Management1": {
                    "inDiscards": 0,
                    "outDiscards": 0
                }
            },
            "outDiscardsTotal": 0
        }
    ]
}

TASK [Copy output to a txt file] ***************************************************************************
changed: [switch1]

PLAY RECAP *************************************************************************************************
switch1                  : ok=3    changed=1    unreachable=0    failed=0

If we were to use SSH instead of eAPI to connect to the switch, we would need to change the provider variable and add the “| json” filter to the command as per below:

  tasks:
    - name: Show command using SSH
      eos_command:
         provider: "{{ conn_ssh }}"
         commands: show interfaces counters discards | json
      register: show_command

Please note that if you are using eAPI, you must type the full command, i.e. do not use abbreviations.

Finally, we could get the final output in two different ways. Either dumping the JSON output of the command directly into a text file and then process it using python with the JSON library or directly filtering what we need in Ansible.

Going for the former first: As shown above, we have the output of the command already on a text file called eod.txt, so we just need to run the below python script, which will read the file as JSON rather than simple .txt, so that we can iterate over the dictionary and get our report on a nice human-readable format.

import json

with open(r'/home/iserghini/EOD/eod.txt') as f:
    raw_show_command = f.read()

json_show_command = json.loads(raw_show_command)

##Access to the specific dictionary we'll need to iterate over
eod = json_show_command['stdout_lines'][0]['interfaces']

for k,v in eod.items():
    print("Interface {}: {} output discards".format(k,v['outDiscards']))

Output:

Interface Management1: 0 output discards
Interface Ethernet2: 0 output discards
Interface Ethernet3: 0 output discards
Interface Ethernet1: 0 output discards
Interface Ethernet6: 0 output discards
Interface Ethernet7: 0 output discards
Interface Ethernet4: 0 output discards
Interface Ethernet5: 0 output discards

On the other hand, if we prefer not to use python to extract the values we care about, we could iterate over the most inner dictionary (called eod in the above’s python script), directly in Ansible and copy the output to a text file.

---

- name: Check interface drops
  hosts: switch1
  gather_facts: false

  tasks:
   - name: Create the txt file and add a header description
     copy:
      content: "Interface Output Discards"
      dest: "/home/iserghini/EOD/eod3.txt"

    - name: Show command using eAPI
      eos_command:
         provider: "{{ conn_eapi }}"
         commands: show interfaces counters discards
      register: show_command

    - name: Writing output into a file
      lineinfile:
         dest: "/home/iserghini/EOD/eod.txt"
         line: "Interface {{ item.key }}: {{item.value.outDiscards}} output discards"
      with_dict: "{{ show_command['stdout_lines'][0]['interfaces'] }}"
      #when: item.value.outDiscards != 0

Output:


(py27_venv)[iserghini@testswitch1 EOD]$ ansible-playbook eod3.yml -i hosts

PLAY [Check interface drops] *********************************************************************************

TASK [Create the txt file and add a header description] ***********************************************************************************
changed: [switch1]

TASK [Show command using eAPI] *******************************************************************************
ok: [switch1]

TASK [Writing output into a file] ****************************************************************************
changed: [switch1] => (item={'key': u'Management1', 'value': {u'inDiscards': 0, u'outDiscards': 0}})
changed: [switch1] => (item={'key': u'Ethernet2', 'value': {u'inDiscards': 0, u'outDiscards': 0}})
changed: [switch1] => (item={'key': u'Ethernet3', 'value': {u'inDiscards': 0, u'outDiscards': 0}})
changed: [switch1] => (item={'key': u'Ethernet1', 'value': {u'inDiscards': 0, u'outDiscards': 0}})
changed: [switch1] => (item={'key': u'Ethernet6', 'value': {u'inDiscards': 0, u'outDiscards': 0}})
changed: [switch1] => (item={'key': u'Ethernet7', 'value': {u'inDiscards': 0, u'outDiscards': 0}})
changed: [switch1] => (item={'key': u'Ethernet4', 'value': {u'inDiscards': 0, u'outDiscards': 0}})
changed: [switch1] => (item={'key': u'Ethernet5', 'value': {u'inDiscards': 0, u'outDiscards': 0}})

PLAY RECAP ***************************************************************************************************
switch1                  : ok=3    changed=2    unreachable=0    failed=0

Text file:

(py27_venv)[iserghini@test EOD]$ cat eod3.txt
Interface Output Discards
Interface Management1: 0 output discards
Interface Ethernet2: 0 output discards
Interface Ethernet3: 0 output discards
Interface Ethernet1: 0 output discards
Interface Ethernet6: 0 output discards
Interface Ethernet7: 0 output discards
Interface Ethernet4: 0 output discards
Interface Ethernet5: 0 output discards

If we wanted to write into the file just the non-zero values, we just need to uncomment the last line of the playbook (#when: item.value.outDiscards != 0).

You can find the full code in my Github repository here.

All the above is very interesting but doesn’t say how to build a report of multiple devices in a nicer format than a text file. In the third part (and last), of this series, I will talk about how to build a template for the report using Jinja2 as well as how to run it on multiple devices.

Using templates will give us the flexibility to add anything we want to the report as well as having it independent of our playbook.

Advertisements

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