In ArubaOS 8.x Aruba introduced a new feature to their architecture: a REST-API to interact in a more automated way with the single components of the infrastructure. Together with the Mobility-Master architecture it is a key component of their SND (Software Defined Network) agenda. In this blog post I want to give a small introduction to the API itself and some of its key-features.
About the API
The API itself is a REST-API. REST stands for REpresentational State Transfer. This translated means, that you interface this API through normal web-based requests like GET and POST. For example, if you type an URL into your browser, this is a GET-request. A REST-API works the same way. For now I only make API-calls to the Mobility-Master, as it has the configuration of all managed devices. If you want to try it yourself you can open the following link in a browser. I use Firefox, as it’s possible to show the returned JSON file in a proper way.
Congratulations! You just made your first API-Call to the Aruba-API. The returned data is in the JSON format, which is basically a machine-readable data format. This is cool, as we can easily write a python-script, which can work with the data returned by the API. We’ll come back at that later.
As a result of our GET-request the API returns data. The request we did above is to authenticate yourself (or the script) to the API. After a successful login the API returns three values: status, status_str and UIDARUBA. The first two simply tell you that your login was successful and only the third one is interesting for further requests. For all future requests we have to include this key into our API-call instead of sending a username/password every time.
At this point I should mention, that I discovered a strange thing in the API I don’t fully understand at this point: At the point you get the API-response with the session-id a cookie is created, which contains the IP-Address/Domain of the Mobility-Master and the session-id. Anyway you always need the session-id in your request AND in this cookie. With only one out of two you get an error. I’m not quite sure, why you would do such a thing.
Getting Configuration out of the API
With the new Mobility-Master architecture introduced in ArubaOS 8 there is also a new way the configuration is organized. Of cause this is included in the API. If we add the attribute „config_path“ to our request we can get the configuration from a certain point in the hierarchy. In the API the configuration is organized in different, so called, containers. If you want a full list of all available containers with a description simply open the following link in your browser. It will return all available containers:
or if you want the list as JSON:
For example, if we want all information about the configured interfaces on the level „/md“, we simply write „/Interfaces“ between the URL and the question mark in it. This returns all of the configuration. At this point the API gets a bit messy. In the returned JSON file is a field called „vlan_id“, which contains a sorted list of vlans.
WARNING: The list is not sorted numerical, but alphabetically. This means vlan-id 1985 comes before vlan-id 220, which is also before vlan-id 29. This is a bit messed up, but I already opened a support-case on that.
a small python3-library to talk to the API
Now, that we know how to use the API, we can start to script the commands. The easiest way to do this is to use python3, because it already has a module to parse JSON. You can find the code here: https://github.com/do9xe/aruba_api_caller/ Please excuse the quality of the code, I’m not the biggest coder and just started learning python.
Basically the class „api_session“ contains seven functions, you can call. The „__init__“ function is used to create an object with the needed properties for an API-call. You have to pass the MMs IP-Address, the username, the password and a wether you want to check the ssl-certificate of the MM. You can find an example-script on GitHub, which I will explain later in this post.
The second Function „login“ needs no arguments, as we passed them already during the creation of the object. It does the login and saves the api-token to the object. The function „logout“ does -surprise- a logout at the API.
The function „write_memory“ is similar to the cli command. It only takes a configuration path as an argument, e.g. „/md“ or „/mm/mynode“ and so on.
The most important functions are „get“ and „post“. if you call the „get“-function you have to provide an API-path, in this implementation this means everything after „/v1/“ and before „?“. So for the GET we performed earlier this means we need to pass „configuration/container“ as an argument. Optionally you can pass a configuration path. The function returns the API-output as JSON.
I would love to say more about the „post“ function, but this would kill this blog-post, so I’ll talk about it in another post.
Example-Script using the python3-library
The example-script in the repository simply reads all configured VLANs from the „/md“ level and prints them in a readable manner. Well, the numbers are still not sorted the nice way, but we already knew that.
The first two lines import the JSON and requests module, you maybe need to install them first. Then we import everything from the python-library I wrote.
After that we create an object and start an API-session with the login-function. We execute a get-call to the API and write the results into „VLANS“. Now we run a for-loop over this JSON data and print every VLAN-ID with its description, if there is one. In the end we log out and end the API-session.
I like the API, as we can automate a lot of stuff at work with it. Right now I am trying to write some custom ansible interfaces, so we can deploy some systems easier. What I would like to see is a way to get monitoring data out of the API, so we can finally get further to kill SNMP, sadly the closest thing is the API-call for the show-command, but it seems like the API just delivers the output of the cli command, including all white-spaces. As you might know this makes it really hard to parse with a script. Maybe this feature will be introduced in a future release. For now I’m quite happy.