The Cisco ACI

The Cisco Application Centric Infrastructure (ACI) is meant to provide a centralized approach to all of the network components. In the data center context, it means that the centralized controller is aware of and manages the spine, leaf, and top of rack switches, as well as all the network service functions. This can be done through GUI, CLI, or API. Some might argue that the ACI is Cisco's answer to the broader controller-based software-defined networking.

One of the somewhat confusing points for ACI is the difference between ACI and APIC-EM. In short, ACI focuses on data center operations while APIC-EM focuses on enterprise modules. Both offer a centralized view and control of the network components, but each has its own focus and share of tool sets. For example, it is rare to see any major data center deploy a customer-facing wireless infrastructure, but a wireless network is a crucial part of enterprises today. Another example would be the different approaches to network security. While security is important in any network, in the data center environment, lots of security policies are pushed to the edge node on the server for scalability. In enterprise security, policies are somewhat shared between the network devices and servers.

Unlike NETCONF RPC, ACI API follows the REST model to use the HTTP verb (GET, POST, DELETE) to specify the operation that's intended.

We can look at the cisco_apic_em_1.py file, which is a modified version of the Cisco sample code on lab2-1-get-network-device-list.py ( https://github.com/CiscoDevNet/apicem-1.3-LL-sample-codes/blob/master/basic-labs/lab2-1-get-network-device-list.py).

The abbreviated version without comments and spaces are listed in the following section.

The first function named getTicket() uses HTTPS POST on the controller with the path of /api/v1/ticket with a username and password embedded in the header. This function will return the parsed response for a ticket that is only valid for a limited time:

  def getTicket():
url = "https://" + controller + "/api/v1/ticket"
payload = {"username":"usernae","password":"password"}
header = {"content-type": "application/json"}
response= requests.post(url,data=json.dumps(payload), headers=header, verify=False)
r_json=response.json()
ticket = r_json["response"]["serviceTicket"]
return ticket

The second function then calls another path called /api/v1/network-devices with the newly acquired ticket embedded in the header, then parses the results:

url = "https://" + controller + "/api/v1/network-device"
header = {"content-type": "application/json", "X-Auth-Token":ticket}

This is a pretty common workflow for API interactions. The client will authenticate itself with the server in the first request and receive a time-based token. This token will be used in subsequent requests and will be served as a proof of authentication. 

The output displays both the raw JSON response output as well as a parsed table. A partial output when executed against a DevNet lab controller is shown here:

    Network Devices =
{
"version": "1.0",
"response": [
{
"reachabilityStatus": "Unreachable",
"id": "8dbd8068-1091-4cde-8cf5-d1b58dc5c9c7",
"platformId": "WS-C2960C-8PC-L",
<omitted>
"lineCardId": null,
"family": "Wireless Controller",
"interfaceCount": "12",
"upTime": "497 days, 2:27:52.95"
}
]
}
8dbd8068-1091-4cde-8cf5-d1b58dc5c9c7 Cisco Catalyst 2960-C Series
Switches
cd6d9b24-839b-4d58-adfe-3fdf781e1782 Cisco 3500I Series Unified
Access Points
<omitted>
55450140-de19-47b5-ae80-bfd741b23fd9 Cisco 4400 Series Integrated
Services Routers
ae19cd21-1b26-4f58-8ccd-d265deabb6c3 Cisco 5500 Series Wireless LAN
Controllers

As you can see, we only query a single controller device, but we are able to get a high-level view of all the network devices that the controller is aware of. In our output, the Catalyst 2960-C switch, 3500 Access Points, 4400 ISR router, and 5500 Wireless Controller can all be explored further. The downside is, of course, that the ACI controller only supports Cisco devices at this time.