Arista and Ansible using pyeapi
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