Arista and Ansible using pyeapi

Author: Kirk Byers
Date: 2015-05-07

Arista recently created a library called pyeapi and they have integrated this library into their Ansible modules.

pyeapi itself is fairly staightforward to use. The main gotcha is that you need to create a .eapi.conf file in your home directory. This file contains information about the connection:

[connection:pynet-sw3]
username: admin
password: test123
host: 10.10.10.10
port: 8443
transport: https

[connection:pynet-sw4]
username: admin
password: test123
host: 10.10.10.10
port: 8543
transport: https

You can then enter the Python shell and make a connection to these devices:

>>> import pyeapi
>>> 
>>> pynet_sw3 = pyeapi.connect_to("pynet-sw3")
>>> pynet_sw4 = pyeapi.connect_to("pynet-sw4")

and send commands down the API channel:

>>> pynet_sw3.enable("show version")
[{'command': 'show version', 'result': {u'memTotal': 1001284, u'version': u'4.12.1-1356975.vEOS4123 (engineering build)', u'internalVersion': u'4.12.1-1356975.vEOS4123', u'serialNumber': u'', u'systemMacAddress': u'52:54:00:92:13:bb', u'bootupTimestamp': 1245724506.12415, u'memFree': 258592, u'modelName': u'vEOS', u'architecture': u'i386', u'internalBuildId': u'57cbbdaf-f64d-4492-87eb-6cd4fc157125', u'hardwareRevision': u''}, 'encoding': 'json'}]

>>> pynet_sw4.enable("show version")
[{'command': 'show version', 'result': {u'memTotal': 1001284, u'version': u'4.12.1-1356975.vEOS4123 (engineering build)', u'internalVersion': u'4.12.1-1356975.vEOS4123', u'serialNumber': u'', u'systemMacAddress': u'52:54:00:01:37:37', u'bootupTimestamp': 1245724571.1481102, u'memFree': 223504, u'modelName': u'vEOS', u'architecture': u'i386', u'internalBuildId': u'57cbbdaf-f64d-4492-87eb-6cd4fc157125', u'hardwareRevision': u''}, 'encoding': 'json'}]

Note, enable() is a bit of strange name for this method--it just executes one or more commands in enable mode.

See the following for more information on Arista's pyeapi: Introducing the Python Client for eAPI (pyeapi) GitHub pyeapi

So that is pyeapi—but how can we use the Arista-Ansible modules that depend upon pyeapi?

First, you obviously have to install pyeapi and the Arista-Ansible modules themselves (note, below I am using the 'develop' branch for both pyeapi and for the Ansible-Arista modules).

$ cd ~
$ git clone https://github.com/arista-eosplus/pyeapi.git
Cloning into 'pyeapi'...
remote: Counting objects: 1187, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 1187 (delta 12), reused 0 (delta 0), pack-reused 1149
Receiving objects: 100% (1187/1187), 336.37 KiB | 387.00 KiB/s, done.
Resolving deltas: 100% (766/766), done.

$ cd pyeapi
$ python setup.py install
...

$ cd ~
$ git clone https://github.com/arista-eosplus/ansible-eos.git
Cloning into 'ansible-eos'...
remote: Counting objects: 879, done.
remote: Compressing objects: 100% (342/342), done.
remote: Total 879 (delta 252), reused 0 (delta 0), pack-reused 519
Receiving objects: 100% (879/879), 1.77 MiB | 1.68 MiB/s, done.
Resolving deltas: 100% (578/578), done.

Now I will create a new directory to work in:

$ cd ~
$ mkdir ARISTA_NEW
$ mkdir ARISTA_NEW/library

And copy in all of the Arista-Ansible libraries into the new library directory:

$ cd ARISTA_NEW/library/
$ cp ~/ansible-eos/library/eos_* .

Now let me try to execute a test Arista-Ansible playbook. This playbook simply executes a 'show version' via the API:

---
- name: Arista Ansible testing
  hosts: arista
  gather_facts: false

  tasks:
    - name: Testing command (not idempotent)
      eos_command: 
        commands="show version" 
        username={{ username }}
        password={{ password }}
        host={{ host }}
        port={{ port }}
        transport={{ transport }}
      register: show_version

    - debug: var=show_version

The variable names above, enclosed by {{braces}}, are being obtained from the Ansible inventory file. Note, the names of the parameters above have changed from how Arista previously defined them; Arista used to define eapi_username, eapi_password, eapi_hostname, and eapi_port.

In my example, transport is set to 'https', 'host' is the IP address of the Arista switch, and port is '8443' (I am using port address translation).

$ ansible-playbook arista-test2.yml 

PLAY [Arista Ansible testing] ************************************************* 

TASK: [Testing command (not idempotent)] ************************************** 
changed: [pynet-sw3]

TASK: [debug var=show_version] ************************************************ 
ok: [pynet-sw3] => {
    "var": {
        "show_version": {
            "changed": true, 
            "invocation": {
                "module_args": "commands=\"show version\" username=admin password=test123 host=10.10.10.10 port=8443 transport=https", 
                "module_name": "eos_command"
            }, 
            "output": [
                {
                    "command": "show version", 
                    "encoding": "json", 
                    "result": {
                        "architecture": "i386", 
                        "bootupTimestamp": 1245724506.117476, 
                        "hardwareRevision": "", 
                        "internalBuildId": "57cbbdaf-f64d-4492-87eb-6cd4fc157125", 
                        "internalVersion": "4.12.1-1356975.vEOS4123", 
                        "memFree": 235144, 
                        "memTotal": 1001284, 
                        "modelName": "vEOS", 
                        "serialNumber": "", 
                        "systemMacAddress": "52:54:00:92:13:bb", 
                        "version": "4.12.1-1356975.vEOS4123 (engineering build)"
                    }
                }
            ]
        }
    }
} 

PLAY RECAP ******************************************************************** 
pynet-sw3                   : ok=2     changed=1     unreachable=0    failed=0

So that all worked correctly.

Now one other interesting aspect of using the pyeapi libraries with Ansible is that I can move the Arista specific variables from the Ansible inventory file to the ~/.eapi.conf file.

Here I define ~/.eapi.conf to be the following:

[connection:pynet-sw3]
username: admin
password: test123
host: 10.10.10.10
port: 8443
transport: https

I then update my playbook and remove the username, password, host, port, and transport parameters. My playbook now looks as follows:

---
- name: Arista Ansible testing
  hosts: arista
  gather_facts: false

  tasks:
    - name: Testing command (not idempotent)
      eos_command: commands="show version" connection='pynet-sw3'
      register: show_version

Note, I added the connection='pynet-sw3' argument to the eos_command. This tells pyeapi which entry to use in the .eapi.conf file.

Now executing this playbook yields the following:

$ ansible-playbook arista-test3.yml 

PLAY [Arista Ansible testing] ************************************************* 

TASK: [Testing command (not idempotent)] ************************************** 
changed: [pynet-sw3]

TASK: [debug var=show_version] ************************************************ 
ok: [pynet-sw3] => {
    "var": {
        "show_version": {
            "changed": true, 
            "invocation": {
                "module_args": "commands=\"show version\" connection='pynet-sw3'", 
                "module_name": "eos_command"
            }, 
            "output": [
                {
                    "command": "show version", 
                    "encoding": "json", 
                    "result": {
                        "architecture": "i386", 
                        "bootupTimestamp": 1245724506.1203039, 
                        "hardwareRevision": "", 
                        "internalBuildId": "57cbbdaf-f64d-4492-87eb-6cd4fc157125", 
                        "internalVersion": "4.12.1-1356975.vEOS4123", 
                        "memFree": 235020, 
                        "memTotal": 1001284, 
                        "modelName": "vEOS", 
                        "serialNumber": "", 
                        "systemMacAddress": "52:54:00:92:13:bb", 
                        "version": "4.12.1-1356975.vEOS4123 (engineering build)"
                    }
                }
            ]
        }
    }
} 

PLAY RECAP ******************************************************************** 
pynet-sw3                  : ok=2    changed=1    unreachable=0    failed=0

You can see that the playbook ran correctly even though the Arista specific arguments came from the ~/.eapi.conf file and not from the Ansible inventory.

Kirk Byers

@kirkbyers

You might also be interested in: