The Arista EOS command API, or eAPI, has been maturing ever since EOS 4.12. Recently, I started to look into ways to use this API for information retrieval. In this article, I am sharing what I learned exploring the eAPI using a library called pyeapi.


Enabling the API

To enable the API on the device and allow access from a vrf called lab, I used the following configuration:

management api http-commands
   no shutdown
   !
   vrf labmgmt
      no shutdown

You can verify that the API is enabled using show management api http-commands. The resulting output is pretty self-explanatory:

lr.lon01#show management api  http-commands
Enabled:            Yes
< output omitted >
VRFs:               lab


Connecting to the device

After installing pyeapi using pip install pyeapi, we can use the following to send a command to the device:

import pyeapi
import pprint

eapi_param = pyeapi.client.connect(
    transport='https',
    host='lr.lon01',
    username='salt',
    password='salt123',
    port=443,
)
eapi = pyeapi.client.Node(eapi_param)

version_info = eapi.run_commands(['show version',])
pprint.pprint(version_info)

Here, we pass the eapi_param to pyeapi.client.Node(). As a result, we can use the eapi object to communicate with the device. Then we call the run_commands method and use it to send the show version command to a device. The output is stored in version_info which is then printed to screen.

Running the script gives us the following output:

[{u'architecture': u'i386',
  u'bootupTimestamp': 1527495886.66,
  u'hardwareRevision': u'11.00',
  u'internalBuildId': u'54acf3af-762b-4cc0-83b7-3b2060a5c8c1',
  u'internalVersion': u'4.18.0F-4224134.4180F',
  u'isIntlVersion': False,
  u'memFree': 5346020,
  u'memTotal': 8008976,
  u'modelName': u'DCS-7260CX-64-F',
  u'serialNumber': u'JPE18280004',
  u'systemMacAddress': u'44:4c:a8:42:5e:45',
  u'version': u'4.18.0F'}]

Structured data, great! No more need to create textfsm templates.

When I started out, the thing I was most interested in was verifying the mlag status in a script. So the first thing I did after show version was add show mlag:

mlag_info = eapi.run_commands(['show mlag',])
pprint.pprint(mlag_info)

The resulting output from this addition to the script was the following:

[{u'configSanity': u'consistent',
  u'domainId': u'lr01',
  u'localInterface': u'Vlan4000',
  u'localIntfStatus': u'up',
  u'mlagPorts': {u'Active-full': 7,
                 u'Active-partial': 1,
                 u'Configured': 0,
                 u'Disabled': 0,
                 u'Inactive': 3},
  u'negStatus': u'connected',
  u'peerAddress': u'192.254.1.2',
  u'peerLink': u'Port-Channel10',
  u'peerLinkStatus': u'up',
  u'portsErrdisabled': False,
  u'reloadDelay': 300,
  u'reloadDelayNonMlag': 300,
  u'state': u'active',
  u'systemId': u'47:3c:b8:44:11:29'}]

Familiarity with the CLI will allow you to quickly add whatever you need. Another thing worth noting is that you can use | json on the CLI to figure out the response from the eAPI in advance:

lr.lon01#show mlag | json 
{
    "localInterface": "Vlan4000",
    "systemId": "47:3c:b8:44:11:29",
    "domainId": "lr01",
    "peerLink": "Port-Channel10",
    "localIntfStatus": "up",
    "peerLinkStatus": "up",
    "peerAddress": "192.254.1.2",
    "configSanity": "consistent",
    "portsErrdisabled": false,
    "state": "active",
    "reloadDelay": 300,
    "reloadDelayNonMlag": 300,
    "negStatus": "connected",
    "mlagPorts": {
        "Disabled": 0,
        "Active-partial": 1,
        "Inactive": 3,
        "Configured": 0,
        "Active-full": 7
    }
}
lr.lon01#

This is a nice way to see what return value you will be dealing with.


Using the API module

In addition to sending CLI commands to the device, the eAPI also offers API modules to inspect and change configuration. Let’s look at an example script where we check out the MLAG configuration of a device:

import pyeapi
import pprint

eapi_param = pyeapi.client.connect(
    transport='https',
    host='lr.lon01',
    username='salt',
    password='salt123',
    port=443,
)
eapi = pyeapi.client.Node(eapi_param)

mlag = eapi.api('mlag')
mlag_d = mlag.get()
pprint.pprint(mlag_d)

We call the api method for mlag using mlag = eapi.api('mlag'). This mlag object in turn gives us several new methods to work with. You can check here to find out about all of the methods. Right now, we simply use get to check the configuration of the mlag using mlag_d = mlag.get().

When we run the script, we get the following:

{'config': {'domain_id': None,
            'local_interface': 'Vlan4000',
            'peer_address': '192.254.1.2',
            'peer_link': 'Port-Channel10',
            'shutdown': False},
 'interfaces': {'Port-Channel11': {'mlag_id': '11'},
                'Port-Channel12': {'mlag_id': '12'},
                'Port-Channel13': {'mlag_id': '13'},
                'Port-Channel14': {'mlag_id': '14'},
                'Port-Channel15': {'mlag_id': '15'},
                'Port-Channel16': {'mlag_id': '16'},
                'Port-Channel17': {'mlag_id': '17'},
                'Port-Channel18': {'mlag_id': '18'},
                'Port-Channel5': {'mlag_id': '5'},
                'Port-Channel6': {'mlag_id': '6'},
                'Port-Channel7': {'mlag_id': '7'}}}

This gives us the MLAG configuration as a dictionary.

There are plenty of other API modules available to us in addition to mlag and you can find them here.

Some insight into how easy it is to use the get method on the other APIs:

ospf = eapi.api('ospf')
ospf_d = ospf.get()

bgp = eapi.api('bgp')
bgp_d = bgp.get()

acl = eapi.api('acl')
acl_d = acl.getall()


Closing thoughts

The eAPI looks pretty neat. Using it to scan through configuration is very easy and I like how simple it is to translate your CLI routines into a script. If you have some basic understanding of Python and some exposure to the Arista CLI, you should be able build interesting scripts quickly.


Note: according to the documentation, pyeapi support for Python 3 is in the works. For now though, it is Python 2.7 only.