You are on page 1of 11

Introduction to Cisco DNA Center

Northbound APIs
In this learning lab we will get a list of all network devices that are being managed by the Cisco DNA
Center cluster that is running in the DevNet Sandbox. We will use both Postman and Python code to
accomplish this.

Objectives
The objective of this training is to learn:

1. How to use the Postman collection provided with this learning lab to get a list of all network
devices managed by Cisco DNA Center.
2. How to write Python code to get a list of all network devices using the Cisco DNA Center REST
API.
3. To be ready to automate day to day network tasks using network programmability and Cisco DNA
Center.

Prerequisites
To complete this lab you need:

 A development environment with typical tools and applications. If you are at a DevNet Event
using a provided workstation, you are ready to go. If you are working from your own workstation,
please review the "How to setup your own computer" link at the top of this page.
 Lab infrastructure to target API calls and code. These labs and code examples are written to
leverage the DevNet Cisco DNA Center Always On Sandbox. This lab is available for anyone to
use, with only access to the Internet as a requirement.

You should also have an understanding of these foundational topics:

 The previous labs in the "Introduction to Cisco DNA Center Programmability" Learning Lab
Module.
 Ability to read and understand Python code samples and scripts. You can explore the
"Programming Fundamentals" labs available on DevNet.
 Ability to leverage Postman to make REST API requests. This includes the use of Collections and
Environments. Check out the REST API Fundamentals labs available on DevNet.

More reasons to learn this topic


As you have seen in the previous learning lab in this module Cisco DNA Center is the next generation
Cisco SDN controller for the enterprise. By using the REST APIs that Cisco DNA Center exposes we can
start automating the network from the design phase through installation, configuration, management and
monitoring. Using the abstractions that Cisco DNA Center provides to end users and developers it is now
easier than ever to start automating day to day tasks and how we manage networks. From getting a list of
all the network devices that are being managed by Cisco DNA Center, to a list of all the end users and
how they connect to the network to integrating with third party REST APIs like Cisco Spark we will show
you in this learning lab how easy it is to get started with network programmability and Cisco DNA Center.

Next up, Step 1: Postman collection, environment and Cisco DNA Center token

Step 1: Postman collection, environment


and Cisco DNA Center token
Following the instructions in the BYOD section at the top of this learning lab you should have successfully
imported the Postman collection and environment. If everything went well you should see the following
image:

Make sure the collection and environment you just imported are selected as active in Postman. If you
don't see the new environment listed in the drop down you might need to restart Postman.

The collection has only 2 tasks. One named 1.Ticket and a second one named 2.Network Device.
The one named Ticket contains only one POST request
to https://{{dnac}}:{{port}}/dna/system/api/v1/auth/token. {{dnac}} and {{port}} a
re variables defined in the environment file. In this case we are using sandboxdnac.cisco.com as our
Cisco DNA Center appliance and the port is 443.

We are using Basic Auth as the authorization method and get the variables defined in the environment file
for {{username}} and {{password}}.

The purpose of this request is to get an authentication token that we can use to authenticate all our
subsequent API calls.

Select this first task and then press the Send button. After a few seconds the Cisco DNA Center REST
API responds with a code of 200 OK and in the body of the response we get a JSON containing the
token similar to the one below:

The token is automatically saved in the environment for us so in the next step we don't need to specify it
again. This is done by creating a new environment variable that will store the value of the token. Postman
will reference this environment variable whenever the token is needed in an API call.

Next: Step 2. List of network devices in Postman


Step 2: List of network devices in
Postman
After we successfully authenticated and obtained the token it is now time to explore the API. In the
second task from the collection we will use a GET call to get a list of all the network devices that are being
managed by Cisco DNA Center.

Select the GET call under the second task and press Send. You should get back a JSON list of all the
network devices that are being managed by this instance of Cisco DNA Center similar to the image
below:

The JSON file contains a lot of information for each device as you can see in the sample below:

JSON output sample


With this we have concluded the Postman part of this learning lab. We have seen how to get an
authentication token and then used that token to get a list of all network devices managed by Cisco DNA
Center in Postman. In the next steps we will accomplish the same but using Python scripts.

Next: Step 3. Cisco DNA Center authentication in Python


Step 3: Cisco DNA Center
authentication in Python
In order to get the authentication token in Python, we build a function
called get_auth_token. Obtaining an authentication token is a common operation when
interacting with REST APIs so we decided to follow best practices and build a function that we
can re-use in the next learning lab. This function takes as input three variables: the Cisco DNA
Center IP address and the username and the password that will be used to connect to the
controller.

The login_url variable contains the URI that we will send our authentication request to. Just
like in Postman we will do a POST call to this URI and we will use the
Python requests library to accomplish this. The requests library also provides support for
a variety of authentication methods. We will use Basic Auth just as we did in Postman. The
third parameter we pass to the post method is verify=False. This is needed because we have
a self-signed certificate on the Cisco DNA Center appliance and we want the requests call to
ignore the fact that the certificate was not obtained from a CA. In a production
environment you would of course want to use verify=True.

We store the result of the POST request into a variable aptly named result. We
use raise_for_status() to make sure the request was successful. If there were any
problems with the request and there was any response code different than 200 OK then
raise_for_status() will exit out the script and display a Traceback message indicating what was
the problem with the request.

The result will contain JSON data similar to the output below:

{
"Token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1YTU4Y2QzN2UwNW
JiYTAwOGVmNjJiOTIiLCJhdXRoU291cmNlIjoiaW50ZXJuYWwiLCJ0ZW5hbnROYW1lIjoiVE5UMCI
sInJvbGVzIjpbIjVhMzE1MTYwOTA5MGZiYTY5OGIyZjViNyJdLCJ0ZW5hbnRJZCI6IjVhMzE1MTlk
ZTA1YmJhMDA4ZWY2MWYwYSIsImV4cCI6MTUyMjc5NDQ0OCwidXNlcm5hbWUiOiJkZXZuZXR1c2VyI
n0.BEtIiPTiwwqrQJ2ZFBpYwyMnDNl_NPUM5p3wC0ySNQ4"
}

In the next step we extract the authentication token that was returned by Cisco DNA Center and
store it into a variable named token.

The get_auth_token() function will return a JSON containing two key:value pairs. The
first one will contain the Cisco DNA Center controller IP address and the second one will be the
authentication token.

The function should look similar to the one below:


def get_auth_token(controller_ip=DNAC, username=DNAC_USER, password=DNAC_PASS
WORD):
""" Authenticates with controller and returns a token to be used in subse
quent API invocations
"""

login_url = "https://{0}:{1}/dna/system/api/v1/auth/token".format(control
ler_ip, DNAC_PORT)
result = requests.post(url=login_url, auth=HTTPBasicAuth(DNAC_USER, DNAC_
PASSWORD), verify=False)
result.raise_for_status()

token = result.json()["Token"]
return {
"controller_ip": controller_ip,
"token": token
}

Next: Step 4. Helper functions

Step 4: Helper functions


Next we will create some additional functions to help us build the Python script. First we have
the create_url() function that we will use to build the URIs for API requests. This function takes two
parameters: the API path and the Cisco DNA Center IP address. It is a very simple one line function that
just appends the path parameter to https://controller-ip:port/api/v1/. This function will be
useful when the next version of the API will be released for example. Instead of going through the script
and updating all the API requests individually to the new URI which might be https://controller-
ip:port/api/v2 you will have to update the new value in only one place: the create_url() function.
We will also re-use this function in the next learning lab.

def create_url(path, controller_ip=DNAC):


""" Helper function to create a DNAC API endpoint URL
"""

return "https://%s:%s/api/v1/%s" % (controller_ip, DNAC_PORT, path)

The second helper function is called get_url(). This function builds on the previous two functions
that we've created so far: get_auth_token() and create_url(). The main purpose is to do all GET
REST APIs calls in our script using this function. It takes only one input parameter: the url relative
to https://controller-ip:port/api/v1/.
You've seen how you can check on the status of a REST API request with raise_for_status() in the
previous step. In this function we use a different way of checking for errors: try except. Error handling with
a try except block of code is very common in Python. After we create the URI, get the token
using get_auth_token() and build the X-auth-token header containing the token, we do GET
using again the requests library. In case there are any exceptions generated by the GET request, the
except block will catch them and exit the script in a controlled manner and will print out the exception. If
everything went fine with the request the function will return the response in JSON format.

def get_url(url):

url = create_url(path=url)
print(url)
token = get_auth_token()
headers = {'X-auth-token' : token['token']}
try:
response = requests.get(url, headers=headers, verify=False)
except requests.exceptions.RequestException as cerror:
print("Error processing request", cerror)
sys.exit(1)

return response.json()

The third and last helper function that we will use is called list_network_devices(). The main
purpose of this function is to build the URI for: https://controller-ip:port/api/v1/network-
device. It uses the get_url() function which at its turn uses
the create_url() and get_auth_token()
functions to build the URI and perform the GET call to get a list of all network devices managed by Cisco
DNA Center. The list_network_devices()function looks like:

def list_network_devices():
return get_url("network-device")

Next: Step 6. Bringing it all together

Step 5: Bringing it all together


Because we've been so far very diligent and built our functions in a modular way the main function of our
script can contain only one line to get the same output we've seen in Postman:

response = list_network_devices()
The response variable will contain a JSON list of all the network devices managed by Cisco DNA
Center. We will take it a step further and extract and pretty print from the JSON output some specific data
that we find useful: the hostname of the device, the management IP address, the serial number,
the platform ID, the software version and the uptime.

if __name__ == "__main__":
response = list_network_devices()
print("{0:42}{1:17}{2:12}{3:18}{4:12}{5:16}{6:15}".
format("hostname","mgmt IP","serial",
"platformId","SW Version","role","Uptime"))

for device in response['response']:


uptime = "N/A" if device['upTime'] is None else device['upTime']
print("{0:42}{1:17}{2:12}{3:18}{4:12}{5:16}{6:15}".
format(device['hostname'],
device['managementIpAddress'],
device['serialNumber'],
device['platformId'],
device['softwareVersion'],
device['role'],uptime))

When importing all the third party libraries and having all the functions described in this learning lab so far
your final version of the script should be similar to the one below:

Complete Python script

#!/usr/bin/env python
"""DNAv3 - DNAC Northbound API - Hands on exercise 01
In this exercise we create helper functions to get an auth token
from DNAC - get_auth_token() and also get_url(), create_url() and
list_network_devices() to get a list of all network devices managed
by Cisco DNA Center. In the main function we extract some data we find useful
and pretty print the result.

Copyright (c) 2018 Cisco and/or its affiliates.

Permission is hereby granted, free of charge, to any person obtaining a copy


of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in al
l
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import sys
import json
import requests
import os
from requests.auth import HTTPBasicAuth
requests.packages.urllib3.disable_warnings()

DNAC=os.environ.get('DNAC','sandboxdnac.cisco.com')
DNAC_PORT=os.environ.get('DNAC_PORT',443)
DNAC_USER=os.environ.get('DNAC_USER','devnetuser')
DNAC_PASSWORD=os.environ.get('DNAC_PASSWORD','Cisco123!')

# -------------------------------------------------------------------
# Helper functions
# -------------------------------------------------------------------
def get_auth_token(controller_ip=DNAC, username=DNAC_USER, password=DNAC_PASS
WORD):
""" Authenticates with controller and returns a token to be used in subse
quent API invocations
"""

login_url = "https://{0}:{1}/dna/system/api/v1/auth/token".format(control
ler_ip, DNAC_PORT)
result = requests.post(url=login_url, auth=HTTPBasicAuth(DNAC_USER, DNAC_
PASSWORD), verify=False)
result.raise_for_status()

token = result.json()["Token"]
return {
"controller_ip": controller_ip,
"token": token
}

def create_url(path, controller_ip=DNAC):


""" Helper function to create a DNAC API endpoint URL
"""

return "https://%s:%s/dna/intent/api/v1/%s" % (controller_ip, DNAC_PORT,


path)

def get_url(url):

url = create_url(path=url)
print(url)
token = get_auth_token()
headers = {'X-auth-token' : token['token']}
try:
response = requests.get(url, headers=headers, verify=False)
except requests.exceptions.RequestException as cerror:
print("Error processing request", cerror)
sys.exit(1)

return response.json()

def list_network_devices():
return get_url("network-device")

if name == "main":
response = list_network_devices()
print("{0:42}{1:17}{2:12}{3:18}{4:12}{5:16}{6:15}".
format("hostname","mgmt IP","serial",
"platformId","SW Version","role","Uptime"))

for device in response['response']:


uptime = "N/A" if device['upTime'] is None else device['upTime']
print("{0:42}{1:17}{2:12}{3:18}{4:12}{5:16}{6:15}".
format(device['hostname'],
device['managementIpAddress'],
device['serialNumber'],
device['platformId'],
device['softwareVersion'],
device['role'],uptime))

Once you run the script the output should be similar to the one below:

https://sandboxdnac.cisco.com:443/api/v1/network-device
hostname mgmt IP serial platfo
rmId SW Version role Uptime
asr1001-x.abc.inc 10.10.22.74 FXS1932Q1SE ASR100
1-X 16.6.1 BORDER ROUTER 96 days, 2:36:28.13
cat_9k_1.abc.inc 10.10.22.66 FCW2136L0AK C9300-
24UX 16.6.1 ACCESS 96 days, 3:31:44.49
cat_9k_2.abc.inc 10.10.22.70 FCW2140L039 C9300-
24UX 16.6.1 ACCESS 96 days, 3:18:05.83
cs3850.abc.inc 10.10.22.69 FOC1833X0AR WS-C38
50-48U-E 16.6.2s CORE 92 days, 14:29:44.09

Next: Summary

Summary
In this learning lab we've explored the Northbound REST API available with Cisco DNA Center and were
able to authenticate and get a list of all network devices being managed by Cisco DNA Center using both
Postman and a Python script we've developed from scratch.

You might also like