Cisco DNA REST API calls using SDK

There are various methods of interacting with the Cisco DNA Center. In the previous articles, I’ve shown you how to execute REST API calls by using Postman software and Python’s requests library. This time, I’ll use an SDK dedicated for the DNA Center.

Tools

To run REST API calls we will use Python3 with the Cisco DNA Center SDK library. It’s not installed by default, so make sure it’s present before jumping further.

Environment

For the purpose of this article, we will use a Cisco DNA Center Always-on Lab. It’s a free lab environment that everybody can access to test various functionalities.

The URL to the Cisco DNA Center is https://sandboxdnac.cisco.com/

API calls

In this article, we will examine one script, that has various functionalities. The final result accomplished by using SDK is very similar to one presented in previous article about the requests library.

You can find source code down below and on a GitLab page.

from dnacentersdk import api

dnac = api.DNACenterAPI(username="devnetuser",
                        password="Cisco123!",
                        base_url="https://sandboxdnac.cisco.com",
                        verify=False)

devices = dnac.devices.get_device_list()

for device in devices['response']:
    print('Hostname: {hostname}, Type: {type}, MAC: {mac}, Serial: {serial}'.format(serial=device['serialNumber'],
hostname=device['hostname'],type=device['type'],mac=device['macAddress']))

device_mapping = {}

for device in devices['response']:
    device_mapping[device['id']] = device['hostname']


interfaces = dnac.devices.get_all_interfaces()
interfaces_by_device = {}

for interface in interfaces['response']:
    if interface['deviceId'] in interfaces_by_device.keys():
        interfaces_by_device[interface['deviceId']].append(interface)
    else:
        interfaces_by_device[interface['deviceId']] = [interface]

for device in interfaces_by_device:
    print('Interfaces on {hostname}:'.format(hostname=device_mapping[device]))
    for interface in interfaces_by_device[device]:
        print('\tName: {name}, Status: {status}, Port mode: {portMode}, '
              'Speed: {speed}'.format(name=interface['portName'],
                                      status=interface['status'],
                                      portMode=interface['portMode'],
                                      speed=interface['speed']))


ospf_interfaces = dnac.devices.get_ospf_interfaces()

ospf_interfaces_by_device = {}

for interface in ospf_interfaces['response']:
    if interface['deviceId'] in ospf_interfaces_by_device.keys():
        ospf_interfaces_by_device[interface['deviceId']].append(interface)
    else:
        ospf_interfaces_by_device[interface['deviceId']] = [interface]

for device in ospf_interfaces_by_device:
    print('Interfaces with enabled OSPF on {hostname}:'.format(hostname=device_mapping[device]))
    for interface in ospf_interfaces_by_device[device]:
        print('\t Name: {name}, IP: {ip}'.format(name=interface['portName'],
                                                 ip=interface['ipv4Address']))

API usage

To use the Cisco DNA Center SDK, first of all, we have to import it to our script. After that, we’re creating a connection object. As arguments, we have to pass:

  • authorization details – username and password
  • Cisco DNA Center URL

In this case, we’re passing also a verify variable, so the server’s TLS certificate won’t be verified.

If you’re familiar with Cisco DNA Center API, you could be surprised, because there is no token mentioned in the authorization part. SDK takes care of that automatically.

From now on, we’re ready to work with API by using our newly created object.

Devices

To gather a list of network devices present in the Cisco DNA Center, we have to interact with the dnac variable. The object structure is hierarchical. The get_device_list() method can be found in the devices section.

You can find a structure and list of available methods in the documentation.

The response from the API call is saved in the devices variable. In the following screenshot, you can find the structure of this object.

As we can see, it’s a MyDict object, which behaves like a standard Python dictionary. Inside, we can find a response key with a list of network devices. From now on, we can easily print desirable information. In the presented for loop, we’re printing a hostname, type, mac address, and serial of each asset.

Hostname: asr1001-x, Type: Cisco ASR 1001-X Router, MAC: 00:c8:8b:80:bb:00, Serial: FXS1932Q1SE
Hostname: cat_9k_1.abc.inc, Type: Cisco Catalyst 9300 Switch, MAC: f8:7b:20:67:62:80, Serial: FCW2136L0AK
Hostname: cat_9k_2, Type: Cisco Catalyst 9300 Switch, MAC: f8:7b:20:71:4d:80, Serial: FCW2140L039
Hostname: cs3850, Type: Cisco Catalyst38xx stack-able ethernet switch, MAC: cc:d8:c1:15:d2:80, Serial: FOC1833X0AR

In the Cisco DNA Center word, each device has its own unique id. This id is widely used as a reference – more on that later in this article. For scripts, it’s a good solution, but let’s be honest, for us, humans it would cause a headache if we would have to recognize devices based on ids. That’s why in the second for loop, we’re creating a mapping between the unique id of each device, and its hostname. This dictionary will be used later to identify devices based on the id. The complete structure of the device_mapping variable is following.

{'1cfd383a-7265-47fb-96b3-f069191a0ed5': 'asr1001-x', 
'21335daf-f5a1-4e97-970f-ce4eaec339f6': 'cat_9k_1.abc.inc', 
'3e48558a-237a-4bca-8823-0580b88c6acf': 'cat_9k_2', 
'de6477ad-22a2-4daa-9941-eb61cecefb34': 'cs3850'}

Interfaces

Let’s now list the interfaces of each device. To get a list of all interfaces, we can use a get_all_interfaces() method. After issuing a call, the complete list will be available in the interfaces variable.

Okay, we have a full list of interfaces, but how do we recognize which interface belongs to which device?

As you probably guessed, we will make use of the device id mappings. Each interface has a deviceId key with a corresponding device id value. Using values of the device_mapping variable, we can easily decode id to the hostname.

Before printing interface data, we will group them by the device. In the for loop, we’re iterating through each interface and based on the deviceId value, we’re appending this interface to the corresponding device in the interfaces_by_device dictionary.

From now on, we’re ready to print desired information. The output is shown below.

Interfaces on asr1001-x:
	Name: TenGigabitEthernet0/0/1, Status: up, Port mode: routed, Speed: 10000000
	Name: GigabitEthernet0/0/5, Status: down, Port mode: routed, Speed: 1000000
	Name: GigabitEthernet0/0/0, Status: down, Port mode: routed, Speed: 1000000
	Name: GigabitEthernet0, Status: down, Port mode: routed, Speed: 1000000
[...]
Interfaces on cat_9k_1.abc.inc:
	Name: TenGigabitEthernet1/1/3, Status: down, Port mode: dynamic_auto, Speed: 10000000
	Name: TenGigabitEthernet1/0/6, Status: down, Port mode: dynamic_auto, Speed: 10000000
	Name: GigabitEthernet1/1/4, Status: down, Port mode: dynamic_auto, Speed: 1000000
	Name: TenGigabitEthernet1/0/12, Status: down, Port mode: dynamic_auto, Speed: 10000000
[...]
Interfaces on cat_9k_2:
	Name: TenGigabitEthernet1/1/7, Status: down, Port mode: dynamic_auto, Speed: 10000000
	Name: TenGigabitEthernet1/0/24, Status: up, Port mode: access, Speed: 1000000
	Name: GigabitEthernet1/1/2, Status: down, Port mode: dynamic_auto, Speed: 1000000
	Name: GigabitEthernet1/1/4, Status: down, Port mode: dynamic_auto, Speed: 1000000
[...]
Interfaces on cs3850:
	Name: GigabitEthernet1/0/8, Status: down, Port mode: dynamic_auto, Speed: 1000000
	Name: GigabitEthernet1/0/13, Status: down, Port mode: dynamic_auto, Speed: 1000000
	Name: GigabitEthernet1/0/42, Status: down, Port mode: dynamic_auto, Speed: 1000000
	Name: GigabitEthernet1/1/2, Status: down, Port mode: dynamic_auto, Speed: 1000000
[...]

OSPF interfaces

As the last example, we will examine how to get a list of OSPF-enabled interfaces. The method to gather information from the DNA Center is get_ospf_interfaces(). The response from the call is stored in the ospf_interfaces variable. The next step is to sort interfaces by the device. It’s done in the same way as before. After that, we’re ready to print the information.

Interfaces with enabled OSPF on cat_9k_2:
	 Name: Vlan1, IP: 10.10.22.113
	 Name: TenGigabitEthernet1/1/1, IP: 10.10.22.70
Interfaces with enabled OSPF on cat_9k_1.abc.inc:
	 Name: Vlan1, IP: 10.10.22.97
	 Name: TenGigabitEthernet1/1/1, IP: 10.10.22.66
Share

Leave a Reply

Your email address will not be published. Required fields are marked *