Fixing pyeapi’s AS truncation error

UPDATE

In the pull request one of the contributors suggested rewriting the code to better reachability, once done he would approve the pull request. the changes look like this:

Figure 6: Commit 6fe6190 implementing the suggested changes

Getting started

I have been playing around with aristas eAPI lately, and thought I check out pyeapi. Getting pyeapi up and running is super easy. First, you need an eos node with eapi enabled. The configuration would look like:

management api http-commands
  shutdown
  !
  vrf mgmt
      no shutdown

Installing pyeapi is as easy as pip3 install pyeapi. I also personally like to install ipython (also with pip) as interactive command line interpreter. Once installed, you can begin exploring. First, you need to create a connection to a switch with eapi enabled.

import pyeapi
eapi_param = {'host': '<hostname>', 'username': '<username>', 'password': '<password>'}
eapi = pyeapi.connect(**eapi_param)
node = pyeapi.client.Node(eapi)

Fixing asdot truncation in api bgp module

A thing i noticed pretty early when poking around, the bgp api module would truncate an ASN if it is in asdot notation (EOS: bgp asn notation asdot). I dont have the original screenshots anymore, but I have all the infos I need in a reddit post i made about this. So what was going on? Assume you have following configuration on an eos device:

router bgp 65001.10
  bgp asn notation asdot
  <snip>

Trying to retrieve the own local AS via eAPI would look something like this:

import pyeapi
eapi_param = {'host': '<hostname>', 'username': '<username>', 'password': '<password>'}
eapi = pyeapi.connect(**eapi_param)
node = pyeapi.client.Node(eapi)

node.api('bgp').get['bgp_as']
Figure 1: pyeapi api bgp module returning wrong AS value

As you can see, the AS returned is not correct. 65001 != 65001.10. Why does this happen? Can we retrieve the AS with correct value somehow? According to my notes, this is how i did it:

import re
configStringIncludingAS = re.findall(r'router bgp .*', node.running_config)[0]
print(configStringIncludingAS)

This would return 65001.10, however i was not able to get this working while writing this post. Anyway, we know now that the value we want is definitely there and can be retrieved. Checking their github i quickly found why this is happening:

Figure 2: the code responsible for the incorrect value for local-as being returned (pyeapi/api/gbp.py)

The regex in use ^router bgp (\d+) would match 65001 but not 65001.10. Editing the regex to something like ^router bgp (\d+).(\d+) does match the correct value, but the value gets converted to an integer dict(bgp_as=int(match.group(1)))
To fix this, I have created a fork that does have an edited regex to match both, regular and asdot. It then checks if the value retrieved is an integer or string, and returns it as such.

Figure 3: Edited code with correct behaviour for local-as (pyeapi/api/gbp.py)

As of the moment of writing this, there is an open pull request to merge these changes into the official pyeapi repository. However, if you want to check my version, you can install it like:

git clone git@github.com:bh-rr/pyeapi.git
pip3 install -e pyeapi/

I quickly came accross the same truncation issue when retrieving the AS for a neighbor, and fixed it as well:

Figure 4: Code returning truncated remote-as (pyeapi/api/bgp.py)

Fixing was pretty straight forward as its almost the same as the code for the own AS:

Figure 5: Edited code with correct behaviour for remote-as (pyeapi/api/gbp.py)

As I am still playing around with eAPI and pyeapi, I currently dont have much more to write, but I will keep this post updated or create a new one ones my scripts (creating vrf’s, generating bgp reports etc) are done. I will then also make the repo public and link it here.

Leave a Reply

Cookie Consent Banner by Real Cookie Banner