Modern networking devices expose REST API to provide a standard and consistent way to interact with the devices, simplifying configuration, monitoring, and management tasks.
Many vendor switches are capable of exposing REST API. Some examples are:
- Cisco:
- Cisco Nexus Series: Nexus 9000, 7000, 3000, and 2000 series.
- Cisco Catalyst Series: Catalyst 9000, 3850, 3650, and 2960 series.
- Cisco Meraki: All Meraki switches have REST API support through the Meraki Dashboard.
- Arista Networks:
- Arista 7000 Series: 7500R, 7280R, 7050X, and 7020R series.
- Juniper Networks:
- Juniper EX Series: EX9200, EX4600, EX4300, and EX2300 series.
- Juniper QFX Series: QFX10000, QFX5200, and QFX5100 series.
Cisco APIC REST API Overview
Cisco Nexus 9000 can operate in ACI mode, of the SDDC (Software-Defined Data Center) solutions provided by Cisco. The Cisco Nexus 9000 switches are part of an ACI Fabric and are configured, monitored, and managed by the Application Policy Infrastructure Controller (APIC). The APIC can be a physical or virtual machine that facilitates network provisioning and control based on application needs, providing a unified operations model and simplifying management. It offers northbound REST APIs and operates as a distributed system with multiple controller instances. The APIC REST API accepts and returns HTTP or HTTPS messages that contain JavaScript Object Notation (JSON) or Extensible Markup Language (XML) documents.
APIC Log in via REST API
Before starting to use the APIC REST API for any purpose, it is a must first log in with the name and password of a configured user. In the section Authenticating and Maintaining an API Session it is possible to find all the details about APIC REST API for login.
When a login message is accepted, the API returns a data structure that includes a session timeout period in seconds and a token that represents the session. The default session timeout period is 10 minutes, which means that after 10 minutes of inactivity, the session is terminated. The token is also returned as a cookie in the HTTP response header.
In the next paragraphs, we explore 2 practical examples of how to use the REST API with CURL and POSTMAN. Then a Python class example is provided which can be used for further automation. Finally, a basic setup for APIC login and configuration with Ansible is shown.
Login with CURL
We need to use the POST method aaaLogin which logs in a user and opens a session. The message body contains an aaa:User object with the name and password attributes in XML format payload.
curl -X POST -k https://APIC_IP_ADDRESS/api/aaaLogin.xml -d '<aaaUser name="USERNAME" pwd="PASSWORD"/>' -c cookie.txt
The APIC controller returns a token stored in a cookie.txt file. It will last for 10 minutes. The cookie must be used to run any following REST API.
Example
For example, the REST API that uses XML format payload and creates a new Tenant, a new Application Profile, and a new EPG will look like this:
curl -b cookie.txt -X POST -k https://APIC_IP_ADDRESS/api/node/mo/uni.xml -d '<polUni> <fvTenant name="TENANT-NAME" descr="TENANT-NAME-DESC" status=""> <fvAp name="APP-PROF-NAME"> <fvAEPg name="NEW-EPG-NAME" > </fvAEPg> </fvAp> </fvTenant> </polUni>' -c cookie.txt
Login with POSTMAN
The login with PostMan will need to use these settings:
Method: POST
Body RAW, Type XML:
https://IP_ADDRESS_APIC/api/mo/aaaLogin.xml
<aaaUser name='USERNAME' pwd='PASSWORD'/>
You will receive a token stored in a cookie which PostMan will store for you, it will last 10 minutes.
PostMan usage example
PostMan Variable settings
After that, you can run REST API.
Example
Method: GET
https://IP_ADDRESS_APIC/api/class/datetimeNtpProvider.xml
To get all the NTP providers configured in the fabric.
If you prefer JSON format, then change REST URL to:
Method: GET
https://IP_ADDRESS_APIC/api/class/datetimeNtpProvider.json
Login and Automation with Python
For automating the REST API usage with Python the class Session can be used, which is also available on GitHub.
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
class Session(object):
def __init__(self, apic_ip, apic_port, user, passwd):
self.ip = apic_ip
self.port = apic_port
self.user = user
self.passwd = passwd
self.cookie = ''
def set_cookie(self, cookie):
self.cookie = cookie
def get_cookie(self):
try:
auth_url = "https://%s:%s/api/aaaLogin.json" % (self.ip, self.port)
auth_json = '{"aaaUser": {"attributes": {"name": "%s", "pwd": "%s"}}}' % (self.user, self.passwd)
print("Getting cookie from %s" % self.ip)
session = requests.post(auth_url, data=auth_json, verify=False, timeout=5)
session_json = session.json()
token = session_json["imdata"][0]["aaaLogin"]["attributes"]["token"]
return {'APIC-cookie': token}
except requests.exceptions.Timeout:
print("APIC %s timed out " % (self.ip))
except requests.exceptions.ConnectionError:
print("Connection error can't log in to APIC %s with user %s" % (self.ip, self.user))
def apic_json_get(self, url):
get_json_url = "https://%s:%s/api/class/%s.json" % (self.ip, self.port, url)
json_get = requests.get(get_json_url, cookies=self.cookie, verify=False)
print(get_json_url)
if json_get.status_code != 200:
print(json_get.text)
else:
return json_get.text
def apic_json_post(self, url, data):
post_json_url = "https://%s:%s/%s.json" % (self.ip, self.port, url)
json_post = requests.post(post_json_url, cookies=self.cookie, data=data, verify=False)
print(post_json_url)
if json_post.status_code != 200:
print(json_post.text)
else:
return json_post.text
The Session class allows users to login with the APIC and interact with it using GET and POST methods with JSON format payload and the cookie provided by the login. It uses the Python requests library.
Usage Example
apic_ip = 'APIC_IP_ADDRESS'
apic_port = '443' # Default port for APIC for HTTPS
username = 'USERNAME'
password = 'PASSWORD'
# Create a session instance
session = Session(apic_ip, apic_port, username, password)
# Get the cookie
cookie = session.get_cookie()
# Set the cookie in the session
session.set_cookie(cookie)
# URL for the POST request
url = 'api/node/mo/uni/'
# Data for the POST request (JSON format)
data = '''
{
"polUni": {
"fvTenant": {
"attributes": {
"name": "TENANT-NAME",
"descr": "TENANT-NAME-DESC",
"status": ""
},
"children": [
{
"fvAp": {
"attributes": {
"name": "APP-PROF-NAME"
},
"children": [
{
"fvAEPg": {
"attributes": {
"name": "NEW-EPG-NAME"
}
}
}
]
}
}
]
}
}
}
'''
# Perform the POST request using the session
response = session.apic_json_post(url, data)
print(response)
Authentication and Configuration with Ansible
The Ansible ACI modules provide a user-friendly interface for managing the ACI Fabric environment using Ansible playbooks. On my GitHub a repository is available with a practical example.
In most cases, Ansible modules for network devices do not run on the network devices or controller but talk directly to the APIC's REST interface. This is also the case of the APIC.
Using aci_rest Module
A lot of ACI modules exist in the Ansible distribution, and the most common actions can be performed with these existing modules, there's always something that may not be possible with off-the-shelf modules.
For this purpose, the aci_rest module provides direct access to the APIC REST API and enables you to perform any task not already covered by the existing modules.
The aci_rest module accepts the native XML and JSON payloads and can accept the inline YAML payload. The XML payload requires you to use a path ending with .xml whereas JSON or YAML require the path to end with .json.
Modifications require the use of POST or DELETE methods, whereas doing just queries requires the GET method.
Password-based authentication is very simple to work with, but it is not the most efficient form of authentication from ACI's point-of-view as it requires a login every time an Ansible task is executed and an open session to work. Password-based authentication may trigger anti-DoS measures in recent ACI versions that result in HTTP 503 errors and login failures. To avoid this, it is possible to use the more efficient Signature-based authentication.
Example
The Ansible playbook is written in YAML. It creates a tenant using signature-based authentication and querying it afterward using password authentication:
- name: ACI Configuration
hosts: localhost
gather_facts: no
vars:
apic_host: 'APIC_IP_ADDRESS'
apic_username: 'USERNAME'
apic_password: 'PASSWORD'
apic_private_key: 'pki/admin.key'
apic_validate_certs: false
tasks:
- name: Add a tenant using inline YAML
cisco.aci.aci_rest:
host: '{{ apic_host }}' # The IP address or hostname of your APIC
username: '{{ apic_username }}' # The username for authentication
private_key: '{{ apic_private_key }}' # The private key of the user for authentication
validate_certs: false # Whether to validate SSL certificates
path: /api/mo/uni.json # The API endpoint for creating a tenant
method: post # The HTTP method to use
content: # The content of the request, in YAML format
fvTenant:
attributes:
name: TENANT-NAME # The name of the tenant to create
descr: TENANT-NAME-DESC # The description of the tenant
delegate_to: localhost # Run this task on the local machine
- name: Get tenants using password authentication
cisco.aci.aci_rest:
host: '{{ apic_host }}' # The IP address or hostname of your APIC
username: '{{ apic_username }}' # The username for authentication
password: '{{ apic_password }}' # The password for authentication
method: get # The HTTP method to use
path: /api/node/class/fvTenant.json # The API endpoint for querying tenants
delegate_to: localhost # Run this task on the local machine
register: query_result # Register the output of the query in a variable
Note that the SSL certificate has nothing to do with the authentication certificate.
SSL certificate is used between APIC and client for secure communication between them by encrypting the data transmitted over the network. The parameter apic_validate_certs set to false avoid the client to validate the certificate provided by the APIC against a trusted CA.
An authentication certificate is used to verify the client's identity to the APIC without using a password. The APIC contains the self-signed certificate for that specific local user. The ansible task uses the user's private key for authentication. The APIC challenges the client by asking to encrypt data by using its private key contained in the file pki/admin.key. The client sends the encrypted data to the APIC. The APIC can decrypt the data with the user public key in the admin.crt file.
Usage
Save the playbook to a file, for example, aci_config.yml.
Run the playbook using the ansible-playbook command:
# ansible-playbook aci_config.yml