cancel
Showing results for 
Search instead for 
Did you mean: 
cancel

Five APIC-EM API to improve network engineer productivity – part 2

1629
Views
6
Helpful
0
Comments
Cisco Employee

This blog series looks at the most useful API for a network engineer who is getting started with scripting and API on APIC-EM.  The first blog covered the /network-device API.


When APIC-EM discovers the network, it builds an inventory of network-devices, interfaces and hosts. Those network-devices can have locations and tags.

api map.png

This blog covers the interfaces and hosts connected to a network-device.

#2 interfaces and hosts on a network-device

One of the other tables kept by the controller is "/interface".  This table contains every interface on every network device.  While you can get a list of all interfaces via the API call, it is often more useful to get a subset of them…  for example those that are attached to a specific network-device.

As with previous blogs we will cover both the coding and non-coding way of exploring the API. Swagger is a tool built into the APIC-EM that lets you explore and run live API calls without needing to code. If you are comfortable with python, you can skip straight to the code section.

First a bit about swagger

The "API" button in the top right brings up the swagger pages.  The great thing is you can click on the "try it out" button for an API and run the REST API call directly on the controller. You get to see that REST call that was made plus the full response.    To access the always on sandbox at https://sandboxapic.cisco.com  User: devnetuser, Password: Cisco123!

Swagger-API.png

Once in swagger, scroll to the "interface" API.  We need to look up the interfaces for a specific network-device.  We know from blog1 that a network-device ID is going to be required.  The API will be "/interface/network-device/{deviceid}".

interface-network-device-id.png

Scroll down a little further until you see the parameters part and use the deviceId from example #1  "24ac6aa8-7759-44d5-90a3-00c83e96583d".

Set the scope "ALL".

Press "Try it Out"

You will see the following result.  Which shows all the interfaces connected to this device.   In the script section we will discuss the attributes and what they mean.

host-by-network-device-integrated.png

To see the hosts connected to this network-device, navigate to the "/host" URL

host-hostIp-param.png

Scroll down to the parameters section, and input the "connectedDeviceIP" parameter of "212.1.10.1".  This is the IP address of the switch.  Scope of "ALL" and press, "Try it Out"

The output below shows a host connected to interface "gi1/0/47" and has an IP address of "212.1.10.20".

host-connected-device-result.png

Script

Blog 1 contained instructions for downloading the sample scripts from Github.

The "02_interface_device.py" script is a utility to display all of the interfaces for a network-device.  It requires an IP for the network-device.  Some points to look at:

  • The interfaces are displayed in a "naturally sorted" order.    There is a natural sort algorithm to do this in the code
  • If a host is connected to the device, it is also displayed.  This is another API call, but just a single call for the entire network-device (i.e. one call per device).
  • If the interface has an IP address assigned to it that is also displayed.
  • Physical and Virtual interfaces (e.g. VLAN SVI) are displayed.

$ python 02_interface_device.py 212.1.10.1

https://sandboxapic.cisco.com/api/v1/network-device/ip-address/212.1.10.1

https://sandboxapic.cisco.com/api/v1/interface/network-device/24ac6aa8-7759-44d5-90a3-00c83e96583d

https://sandboxapic.cisco.com/api/v1/host?connectedDeviceIp=212.1.10.1

Interface Name           :Speed     Status Type      Vlan Other

GigabitEthernet0/0       :1000000   down Physical        

GigabitEthernet1/0/1     :1000000 up     Physical  1 trunk Connected to Dist1

GigabitEthernet1/0/2     :1000000 up     Physical  1 trunk

GigabitEthernet1/0/3     :1000000 down   Physical  1     

GigabitEthernet1/0/4     :1000000 down   Physical  1     

GigabitEthernet1/0/5     :1000000 down   Physical  1     

GigabitEthernet1/0/6     :1000000 down   Physical  1     

GigabitEthernet1/0/7     :1000000 down   Physical  1     

GigabitEthernet1/0/8     :1000000 down   Physical  1     

GigabitEthernet1/0/9     :1000000 down   Physical  1     

GigabitEthernet1/0/10    :1000000 down   Physical  1     

GigabitEthernet1/0/11    :1000000 down   Physical  1     

GigabitEthernet1/0/12    :1000000 down   Physical  1     

GigabitEthernet1/0/13    :1000000 down   Physical  1     

GigabitEthernet1/0/14    :1000000 down   Physical  1     

GigabitEthernet1/0/15    :1000000 down   Physical  1     

GigabitEthernet1/0/16    :1000000 down   Physical  1     

GigabitEthernet1/0/17    :1000000 down   Physical  1     

GigabitEthernet1/0/18    :1000000 down   Physical  1     

GigabitEthernet1/0/19    :1000000 down   Physical  1     

GigabitEthernet1/0/20    :1000000 down   Physical  1     

GigabitEthernet1/0/21    :1000000 down   Physical  1     

GigabitEthernet1/0/22    :1000000 down   Physical  1     

GigabitEthernet1/0/23    :1000000 down   Physical  1     

GigabitEthernet1/0/24    :1000000 down   Physical  1     

GigabitEthernet1/0/25    :1000000 down   Physical  1     

GigabitEthernet1/0/26    :1000000 up     Physical  400   

GigabitEthernet1/0/27    :1000000 down   Physical  1     

GigabitEthernet1/0/28    :1000000 down   Physical  1     

GigabitEthernet1/0/29    :1000000 down   Physical  1     

GigabitEthernet1/0/30    :1000000 down   Physical  1     

GigabitEthernet1/0/31    :1000000 down   Physical  1     

GigabitEthernet1/0/32    :1000000 down   Physical  1     

GigabitEthernet1/0/33    :1000000 down   Physical  1     

GigabitEthernet1/0/34    :1000000 down   Physical  1     

GigabitEthernet1/0/35    :1000000 down   Physical  1     

GigabitEthernet1/0/36    :1000000 down   Physical  1     

GigabitEthernet1/0/37    :1000000 down   Physical  1     

GigabitEthernet1/0/38    :1000000 down   Physical  1     

GigabitEthernet1/0/39    :1000000 down   Physical  1     

GigabitEthernet1/0/40    :1000000 down   Physical  1     

GigabitEthernet1/0/41    :1000000 down   Physical  1     

GigabitEthernet1/0/42    :1000000 down   Physical  1     

GigabitEthernet1/0/43    :1000000 down   Physical  1     

GigabitEthernet1/0/44    :1000000 down   Physical  1     

GigabitEthernet1/0/45    :1000000 down   Physical  1     

GigabitEthernet1/0/46    :1000000 down   Physical  1     

GigabitEthernet1/0/47    :1000000 up     Physical  200    212.1.10.20/e8:9a:8f:7a:22:99

GigabitEthernet1/0/48    :1000000 up     Physical  500   

GigabitEthernet1/1/1     :1000000 down   Physical  0     

GigabitEthernet1/1/2     :1000000 down   Physical  0     

GigabitEthernet1/1/3     :1000000 down   Physical  0     

GigabitEthernet1/1/4     :1000000 down   Physical  0     

TenGigabitEthernet1/1/1  :10000000 down   Physical  1     

TenGigabitEthernet1/1/2  :10000000 down   Physical  1     

TenGigabitEthernet1/1/3  :10000000 down   Physical  1     

TenGigabitEthernet1/1/4  :10000000 down   Physical  1     

Vlan1                    :1000000   down Virtual   1     

Vlan200                  :1000000   up Virtual   200    212.1.10.1/255.255.255.0

Vlan300                  :1000000 up     Virtual   300 212.1.20.1/255.255.255.252

Vlan400                  :1000000   up Virtual   400    55.1.1.1/255.255.255.0

Vlan500                  :1000000   up Virtual   500    172.28.97.155/255.255.255.0

Utilization:8%, Total ports:57, Total up:5

Looking at the code

Let's take a look at how the code works.  The snippets below are from the "02_interface_device.py" python source code.

  The code for this script starts to get a little more sophisticated.  There are two helper functions for the natural sort.  Some pretty advanced python to do this in a few lines, but remember, this is the reason the interface list is nicely sorted!

# helper for natural sort
def atoi(text):
return int(text) if text.isdigit() else text

# natural sort for interfaces
def natural_sort(interfacelist):
return sorted(interfacelist, key=lambda port: [ atoi(c) for c in re.split('(\d+)', port['portName'])])

There is also a helper function to take a network-device IP address and return a UUID.  Internally network-devices are referenced by their UUID, to make this easier to use we map IP->UUID.

def ip_to_id(ip):
return get_url("network-device/ip-address/%s" % ip)['response']['id']

  There are two different REST API calls.

  1. "interface/network-device/<deviceid>" – this is all interfaces on the network-device with UUID of <deviceid>. From the first example, we know the network-device with IP of "212.1.10.1" has an id (UUID) of  "24ac6aa8-7759-44d5-90a3-00c83e96583d".
  2. "host?connectedDeviceIp=%s" – a parameterized search of the host table returning any hosts that are connected to the network-device (based on the network-device IP address).  This could be done by the UUID.

You are probably wondering why the first call is by UUID and the second can use either IP address (an absolute) or reference (UUID)?  The second call is a parameterized search, so can use attributes (of which there are quite a few options).  We will cover some more options for the parameterised search in blog 4 of this series.

def get_interfaces(id):
return get_url("interface/network-device/%s" % id)

def get_hosts(ip):
return get_url("host?connectedDeviceIp=%s" % ip)

The rest of the code just makes things look pretty.  There is an "if" statement to display things like trunks, connected hosts, IP address.

One thing you might find interesting is the python dictionary comprehension to speed up the process of looking up the interface the host is connected to.  It takes the list of hosts that are connected to this network-device and turns them into a python dictionary.  This allows a lookup by interfaceId to determine if a host is connected to the interface.

def print_info(interfaces,hosts):
# this is a hash of the interface_id and hosts that are connected, so can do a lookup
id_to_host = {host['connectedInterfaceId'] : (host['hostIp'], host['hostMac']) for host in hosts['response']}

There is also a section of code to count the total number of physical ports, and the number of physical ports that are up.  This gives a switchport utilization.

if interface['interfaceType'] == "Physical":

     total_ports +=1

     if interface['status'] == "up":

         total_up+=1

There are a number of useful tools built with these API calls:

  • network wide switchport utilization based on physical ports that are up/down.  I have shown you one device, but you could easily make this multiple devices.
  • a list of configured IP networks by looking at all interfaces with an IP address/netmask (useful for validating IP address management - IPAM)
  • identifying all the trunk points in the network

What Next?

This blog covered the /interface.  API The next blog in the series will look at /license and a tool for displaying all of the license information on a network-device.


In the meantime, if you would like to learn more about APIC-EM, you could visit Cisco Devnet.  All of the code samples can be found in the  Github repository.


Thanks for reading


@adamradford123

This widget could not be displayed.