API symbol


Working as a network consultant and engineer I am often faced with very specific requirements from my customers. One of the latest requests was to support the implementation of a security framework by providing extensive information about the network. At first, a list of all switches was needed. Following that, my customer needed to know which VLAN is configured on which port – for all devices.

The network of that customer consists of more than 50 switches, so both tasks would have been a challenge for a manual approach. Luckily, Extreme Management Center (XMC) is in productive use. However, even with this help at hand, manually gathering all required data would have been a pa…laborious.


Hello, my Name is GraphQL

While XMC has provided API functionality for quite some time, the GraphQL-based API is relatively new. GraphQL itself is not an API per se – it is nothing more but a query language developed by Facebook. That language has been designed to be simple and human-readable in the frontend, while allowing specific queries to a database in the backend.

File cabinet

Using GraphQL to access the XMC database makes sense. First of all, XMC stores a lot of data. Everything you see in the frontend, from the plain list of devices, to port states, to configurations – it all needs to be configured respectively fetched and stored before it can be displayed. Secondly, most of the data is internally stored in a standard SQL database that uses a multitude of tables. There is no public documentation on how to use that database.

GraphQL solves these two issues by providing a standardized and documented way to access the stored data, and only the data that you actually want to fetch – keeping users sane and minimizing the amount of transferred data.


I Need Some REST

Within XMC, GraphQL is used to fetch data from XMC or to initiate actions. In either case, the result is returned as a JSON object. Queries are passed to XMC via GET requests, the result is returned in the message body.

Effectively this means that XMC provides a REST API that uses GraphQL for requests and JSON for results – the modern standard for APIs. That combination of GraphQL and JSON has officially been named the Northbound Interface (NBI) of XMC.


First Contact

Extreme Networks has not only worked on providing a new API, efforts to keep the learning curve as low as possible have also been made. The result is an API interface for Machine-to-Machine (M2M) communication and another interface that can easily be used by humans: The NBI Explorer.

Using the NBI Explorer actually was my first contact with the Northbound Interface. What you get is a two pane view, with a text field to enter your query on the left and the result on the right side. In addition, you can access your query history and, more importantly, a complete documentation of the underlying GraphQL schema.

Screenshot of NBI Explorer

When talking about „querying the API" it should be noted that this can mean a real query, e.g. retrieving data, or triggering an action, called mutation. While real queries, defined by the „query" type in the API, are safe, mutations, defined by the „mutation" type, should be tested in a lab environment first.

From now on „query" will translate to a query-type API call, while „mutation" will translate to a mutation-type API call.


Getting a List of Devices

The first task I got from my customer was to hand over a list of all switches in the customer’s network. Using NBI Explorer, I played around with queries and finally settled on one that provided everything I needed.

query {
  network {
    devices {
      up
      ip
      sysName
      deviceData {
        vendor
        family
        subFamily
      }
    }
  }
}

Breaking down the query, here is what I requested:

  • Query all devices from the network context.
  • For each device, retrieve whether it is up, the IP used for managing the device and the system name.
  • Going deeper into the device data, also retrieve the vendor, family and subfamily name.

Having what I needed, I just copied the JSON result from the right side pane and pasted it into a text file. I transformed this into a CSV file with a few lines of Python, handing over the CSV file to the customer accomplished the job. Easy!


What About VLANs?

The second task I got was to deliver a list of VLANs per device, preferably per port. „Easy," I thought, „that can be fetched from the API in no time."

Oh, how wrong I was.

As with the list of devices I started to fiddle around with the query in NBI Explorer. Using the integrated documentation, I came up with a rather simple query variant (which includes too much data, by the way):

query {
  network {
    devices {
      id
      sysName
      name
      nickName
      deviceData {
        vendor
        sysDescr
        serialNumber
        macAddress
        firmware
        mgmtInterface
        mgmtInterfaceVlan
        mgmtInterfaceOutOfBand
        ipAddress
        gateway
        vlans {
          name
          vid
          networkAddress
          networkPrefixLength
          networkDefaultGateway
        }
        physicalPortCount
        ports {
          ifIndex
          portAlias
          portName
          portAdmin
          portSpeed
          portDuplex
          tagged
          untagged
        }
      }
    }
  }
}

However, looking at the results I got, something seemed wrong. It was a gut feeling at first, but when I digged into the results and compared them against CLI output of some switches it became clear: There is something wrong here. The information returned from the API was incorrect because VLANs were listed in the JSON that were not configured on the switch.

Working through that issue with Extreme’s Global Technical Assistance Center (GTAC) it turned out that the query was wrong. In order to get a correct VLANs per port association the right context must be queried. Which is only possible on a per-device basis, so each device must be queried individually as well. This turned the generic query into a specific one.

query {
  network {
    device(ip: "10.0.0.1") {
      deviceData {
        physicalPortCount
        serialNumber
      }
      sysName
      nickName
      firmware
      baseMac
      ip
      entityData {
        allPorts {
          ifIndex
          ifName
          ifOperStatus
          ifSpeed
          vlanList
        }
      }
    }
    deviceVlans(ip: "10.0.0.1") {
      name
      vid
      primaryIp
      netmask
      ipForward
    }
  }
}

Rise of the Mutants

While the query was corrected, the result was still wrong, returning VLANs that were not configured on my test device. At this point mutations joined the game.

XMC’s API does not use real time data from the devices you query. Instead, cached data from the database is used. That cached data may be correct or not, depending on the configuration. Luckily, you can trigger a refresh by using mutations. However, they come with caveats:

  1. Mutations need to be triggered separately per device.
  2. Triggering a mutation will most likely return a „success" response. That success only means that the refresh was queued by XMC, not that the refresh has successfully been done.
  3. It may take up to 15 minutes for the actual refresh to happen.

With that in mind, we worked out the following mutation to refresh my test device.

mutation {
  network {
    rediscoverDevices(input: {devices: [{ipAddress: "10.0.0.1"}]}) {
      status
      message
    }
  }
}

The state can be monitored in the operations view within XMC. I ran my query again once the refresh had happened, et voilá, the result was finally correct!


Diversity is a Game Changer

Having tried and tested the necessary mutation and my query I moved over to the customer environment, testing both on a productive switch. Expecting a certain result, I was surprised to see yet another unexpected behaviour: The list of VLANs returned per port was quite long, way longer than it should be, based on CLI output.

In my test environment I was working on EXOS (native Extreme Networks) switches only, but the first switch I ran my mutation and query on in the customer environment was an EOS (Enterasys legacy) device. While both are fully manageable by XMC, the result returned from the API when querying them differs.

  • For EXOS switches only the VLANs that are configured for the port in question are returned by the API.
  • For EOS switches every VLAN configured on the switch is returned for every port, along with an information „no egress" for those VLANs that are not configured for the port in question.

While this is not a bug it is important to know that difference, because those „no egress" VLANs need to be filtered out of the result for correct reporting. On a side note, this behaviour will be changed in future XMC releases, so that EOS switches also only return actually configured VLANs for each port.


Data, Where Are You?

Finally thinking that we had everything figured out I ran my query in the customer environment again a few days later in order to analyze the data structure of the result. Looking at the result I was shocked: There was no VLAN data at all. Everything just gone.

Faded computer

Contacting GTAC about this issue revealed another important aspect about the caching behaviour of XMC: If the XMC server is rebooted, some pieces of information – for example VLAN data – are deleted from the database. That data will be retrieved during the next regular refresh or whenever a refresh is triggered manually.

A single mutation later VLAN data was available again and correct.


Combining the Pieces

Up to this point, I had found out quite substantial and important pieces of information. I had:

  • A mutation to refresh XMC’s data for a single device.
  • A correct and working query to fetch the data my customer wanted on a per-device basis.
  • Gained the knowledge that mutation and query have to be done separately for each device.
  • Gained the knowledge that it can take up to 15 minutes between the mutation and the actual data refresh.
  • Gained the knowledge that „no egress" VLANs needed to be filtered out of the dataset for my customer.

The only problem I had left was that I was no longer able to run a single query, copy a single result and parse it with a simple script. I either had to do the mutate-query-copy-parse process for 50+ devices manually or find a way to automate this.

Remember the M2M API interface?


Building an API Client

Automation was the way I wanted to go. Unfortunately, I was unable to find example implementations for using the XMC API from an external program. Even documentation was hard to find. With a bit of luck and try-and-error I finally found out that …

  • … the M2M API endpoint is reachable at /nbi/graphql on a XMC server.
  • … a GET request with a „query" parameter is used to interact with the M2M API endpoint.
  • … each request needs to be authenticated using HTTP Basic Auth, utilizing any user that has the Northbound Interface rights within XMC.

That knowledge allowed me to build a customer specific tool that:

  1. Fetches a list of active devices (state == up) from XMC.
  2. Triggers a refresh for each active device.
  3. Waits for 15 minutes after the last mutation.
  4. Fetches the required data for each device.
  5. Parses the combined results and prints CSV data to the CLI.

Job done! And thanks to having a tool available now, the job can easily be repeated whenever necessary.


Recap

My job for the customer is done, but I am still in contact with Extreme GTAC and Engineering regarding the overall state of the GraphQL-based XMC API.

Communication tower

On the positive side, the API is available right now and it works. And it is quite easy to use: You can test and try everything using the NBI Explorer, and once you are done with testing just transfer your findings to an API client – if you need such a client at all. Writing such a client is sufficiently easy again, because it uses standard methods and data formats everywhere.

On the negative side documentation needs to be mentioned. While there is a lot of information contained within NBI Explorer, you will see that some pieces of data can be fetched from multiple contexts. Unfortunately, there is no hint on which context is right. And for all of us who want to write an API client there is virtually no documentation available at all.

After all, getting to the point where I am right now took a lot of work. But using the API also spared a lot of manual work. In the end, I am happy that the API is available – and with the continued development Extreme Networks is putting into the API I am sure that it will only get better.


Sharing is Caring

As all of the above took quite some time to figure out I have written generic API clients in the meantime. They are publicly available on GitLab for everyone who is interested; as of now, Python and Go variants have been published.

This article was originally published on Medium.