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.
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!
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}".
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.
To see the hosts connected to this network-device, navigate to the "/host" URL
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".
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.
- "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".
- "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