Automation is going to be fundamental in all networking products. I’ve been working a lot on integrating Juniper products in existing and standard software. There are many different ways to automate something on a network running Junos. Using REST (or RESTful) APIs is one way of doing this. The reason I’m using REST is that it’s fairly easy to understand, but the best thing is that a large amount of existing products supports REST to integrate with it.
The goal of this blog is to explain how Junos products support REST, compatibility with older versions and how it scales.
What is REST?
REST (REpresentational State Transfer) is a simple stateless architecture that generally runs over HTTP. There are 4 commonly supported commands. When you issue a command your input data consists of a URL, HTTP headers and a body holding the data.
HTTP Headers are used for things like Authentication and a Content Type to let the application know what data format the body will contain.
The URL specifies which data you want to receive from the application or you want to change.
The body is empty in a request for data, when you want to change some data this is typically XML or JSON data (defined by the Content-Type HTTP Header).
The commonly supported commands are:
GET – Request data from the application
PUT – Change/Update data
POST – Add new data
DELETE – Delete existing data It’s very important to know which commands your application supports.
It could be that an application only supports PUT commands instead of POST, so data you submit will override any existing entries (as PUT is a Change/Update action).
To test commands on a REST API there are many great Browser plugins that will let you create a REST call step-by-step. Below are 2 free and great plugins:
Junos and REST
There are 2 options to use REST on Junos products. The first one is to run it against Junos itself. Starting in Junos 14.2 there is full support for any feature on a box to be accessed through the REST API. In this blog I will not focus on this, because I want to look at a more scalable solution that is also compatible with older versions. All information regarding the Junos REST API is available on the public documentation page: Junos 14.2 REST API Guide
The second option which supports any Junos version is by using the Juniper network management platform: Junos Space.
Junos Space is a platform that hosts applications that manage your Juniper network devices. Any Juniper device running Junos is supported. Applications like Security Director, Network Director, etc. are applications by Juniper, but there are also applications written by partners for various other purposes. Applications have to be installed separately. In this blog I will be using the foundation: Network Management Platform (or NMP).
This platform will connect to all of your devices running Junos and will use NETCONF as a southbound protocol to communicate. It will detect which version of Junos the device is running and will select the correct schema. A schema consists of all possible configuration for that particular hardware platform and software version. The REST API of the NMP in Junos Space covers 100% of the commands that you can access in the GUI as well, so I have a full features management platform that I can access with a REST API and access my Junos devices through it. Very scalable and easily managed.
Let’s issue our first REST command to our Junos Space platform:
We first need to authenticate ourselves, just like we would on the GUI. We do this by adding a Authentication HTTP header. Your REST Client should support encoding the credentials for you and generating the header.
After I added my credentials we see that I have access to all kinds of different services.
If I want to dive deeper I just follow the link given in the service.
Device Management
As an example I want to take a look at the devices currently registered to my Junos Space platform. I follow the link towards Device management and then Devices.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <devices uri="/api/space/device-management/devices" size="3"> <device href="/api/space/device-management/devices/131087" uri="/api/space/device-management/devices/131087" key="131087"> <deviceFamily>junos-es</deviceFamily> <OSVersion>12.1X46-D10.2</OSVersion> <platform>SRX210H-POE</platform> <serialNumber>XXXXXXX</serialNumber> <connectionStatus>up</connectionStatus> <ipAddr>172.22.1.4</ipAddr> <managedStatus>In Sync</managedStatus> <name>MaverickSRX</name> <domain-id>2</domain-id> <domain-name>Global</domain-name> </device> <device href="/api/space/device-management/devices/131095" uri="/api/space/device-management/devices/131095" key="131095"> <deviceFamily>junos</deviceFamily> <OSVersion>14.1R2.12</OSVersion> <platform>VMX</platform> <connectionStatus>up</connectionStatus> <ipAddr>172.22.1.151</ipAddr> <managedStatus>In Sync</managedStatus> <name>vMX1</name> <domain-id>2</domain-id> <domain-name>Global</domain-name> </device> <device href="/api/space/device-management/devices/131099" uri="/api/space/device-management/devices/131099" key="131099"> <deviceFamily>junos</deviceFamily> <OSVersion>14.1R2.12</OSVersion> <platform>VMX</platform> <connectionStatus>up</connectionStatus> <ipAddr>172.22.1.152</ipAddr> <managedStatus>In Sync</managedStatus> <name>vMX2</name> <domain-id>2</domain-id> <domain-name>Global</domain-name> </device> </devices>
The output given by default is in XML format. If you like to work with JSON instead, this is supported as well. We just have to add another header. In a typical REST API I have a generic Content Type (in PUT/POST) or Accept (in GET) header for this called usually: application/xml or application/json. Junos Space however, requires a specific string for each request depending on what you want to see. To look this specific string up you can check the online documentation which is extremely well written and detailed! Junos Space REST API Guide Device Management
In the guide we find that we have to specify an Accept header of: application/vnd.net.juniper.space.device-management.devices+json;version=1.
Then we issue the same request again, but now with the Accept header added.
Request
GET /api/space/device-management/devices HTTP/1.1 Host: maverickspace.maverick.local Authorization: Basic XXXXXX= Accept: application/vnd.net.juniper.space.device-management.devices+json;version=1 Cache-Control: no-cache
Response
{ "devices": { "@uri": "/api/space/device-management/devices", "@size": "3", "device": [ { "@href": "/api/space/device-management/devices/131087", "@uri": "/api/space/device-management/devices/131087", "@key": "131087", "deviceFamily": "junos-es", "OSVersion": "12.1X46-D10.2", "platform": "SRX210H-POE", "serialNumber": "XXXXX", "connectionStatus": "up", "ipAddr": "172.22.1.4", "managedStatus": "In Sync", "name": "MaverickSRX", "domain-id": 2, "domain-name": "Global" }, { "@href": "/api/space/device-management/devices/131095", "@uri": "/api/space/device-management/devices/131095", "@key": "131095", "deviceFamily": "junos", "OSVersion": "14.1R2.12", "platform": "VMX", "connectionStatus": "up", "ipAddr": "172.22.1.151", "managedStatus": "In Sync", "name": "vMX1", "domain-id": 2, "domain-name": "Global" }, { "@href": "/api/space/device-management/devices/131099", "@uri": "/api/space/device-management/devices/131099", "@key": "131099", "deviceFamily": "junos", "OSVersion": "14.1R2.12", "platform": "VMX", "connectionStatus": "up", "ipAddr": "172.22.1.152", "managedStatus": "In Sync", "name": "vMX2", "domain-id": 2, "domain-name": "Global" } ] } }
Tags and Filtering
The reason I’m using Junos Space is because I want to be scalable. I want to be able to apply a certain piece of configuration or I want to get a certain show command from a list of devices. That device list can change over time when I add more nodes to my network. So I need a flexible and scalable way of talking to a group of devices. Within Junos Space I can specify one or more tags on a Device which I can then use to filter on in my REST request.
I can add Private and Public tags. Private tags are only visible for your username. Public tags are visible for everyone.
I’m going to add a private tag called: ‘RESTtest‘ to one of my devices.
Now I can leverage this tag to filter on devices and find the right devices that I want a certain piece of information from. To filter I use a simple query string: ?filter=(TAG eq ‘RESTtest’). When I want to filter on Public tags I query them using ?filter=(TAG eq ‘RESTtest:public‘). The documentation will explain in detail how tags can be used to filter and on which places in the API: Junos Space REST API Guide Tag Management.
Now I filter on the newly created tag and the output now shows just a single device.
Request
GET /api/space/device-management/devices?filter=(TAG eq 'RESTtest') HTTP/1.1 Host: maverickspace.maverick.local Authorization: Basic XXXXXXX= Cache-Control: no-cache
Response
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <devices uri="/api/space/device-management/devices" size="1"> <device href="/api/space/device-management/devices/131087" uri="/api/space/device-management/devices/131087" key="131087"> <deviceFamily>junos-es</deviceFamily> <OSVersion>12.1X46-D10.2</OSVersion> <platform>SRX210H-POE</platform> <serialNumber>XXXXXX</serialNumber> <connectionStatus>up</connectionStatus> <ipAddr>172.22.1.4</ipAddr> <managedStatus>In Sync</managedStatus> <name>MaverickSRX</name> <domain-id>2</domain-id> <domain-name>Global</domain-name> </device> </devices>
Summary
REST is a very powerful tool for all kinds of integrations that you want to build. Stay tuned for other blogs where I will use the Junos Space REST API to integrate with other networking products. Junos Space is a great tool for your Juniper devices to maintain and manage them, but most of all to have a central location where you can communicate with all Junos devices through REST and use tags to run commands on multiple devices without having to know the exact device details. It provides a great abstraction layer for your Junos based network.