ACI REST API with Ansible and Python

Create a tenant using the REST API

Alt text

General

ACI consists of multiple managed-objects that are using the JSON format. You can do a REST Call with your JSON Syntax and create anything you want without relying on ACI libraries like the acitoolkit or the Cisco.Aci libraries from Ansible.

API inspector

When you are in the APIC GUI in the right corner click on the settings wheel. Here is the option show API inspector. it will open a popup window which translates every action you do in the GUI to the appropriate REST call.

Alt text

In this picture it shows that we created the tenant TNT1. Every entity in ACI is a managed object which is declared in a json file. We can copy the url and the payload and paste it in our REST call.

Ansible

The ACI-REST Module is part of the Ansible-ACI collection. To install it you can use following command.

ansible-galaxy collection install cisco.aci

You can also download the tarball from the Ansible-ACI website and install it offline using following command.

ansible-galaxy collection install cisco-aci-2.6.0.tar.gz

Here is the inventory file I use apic.

[apic:vars]
username=admin
password=cisco123
ansible_python_interpreter="/usr/bin/python3"

[apic]
192.168.15.81

Now you can reference the ACI-REST module by typing cisco.aci.aci_rest in your tasks.

Lets copy/paste the url and payload from the API inspector to our playbook create_tenant.yml.

---
- name: Create Tenant
  hosts: apic
  connection: local
  gather_facts: false
  tasks:
    - name: Create Tenant
      cisco.aci.aci_rest:
        host: "{{ inventory_hostname }}"
        username: "{{ username }}"
        password: "{{ password }}"
        validate_certs: false
        path: /api/node/mo/uni/tn-TNT1.json
        method: post
        content: { fvTenant: { attributes: { dn: uni/tn-TNT1, name: TNT1, rn: tn-TNT1, status: created }, children: [] } }

You can use jsonlint if you do not like to have all attributes in one line. I used Ansible-Lint to remove the inverted commas.


Now if we issue ansible-playbook -i apic create_tenant.yml command we will get the following output. We successfully created a tenant called TNT1.

PLAY [Create Tenant] *****************************************************************************************************************************

TASK [Create Tenant] *****************************************************************************************************************************
changed: [192.168.15.81]

PLAY RECAP ***************************************************************************************************************************************
192.168.15.81              : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Python

It is a little bit trickier to create a REST Call with Python but it is more efficient since python keeps the session alive while Ansible needs to login to ACI for every task it does.


We need to install the requests library.

You can do this with the command python -m pip install requests.

The json library is a built-in package of python.


Now we can create aci_login.py to login to ACI.

import requests
import json

def get_token():  
   url = "https://192.168.15.81/api/aaaLogin.json"

   payload = {
      "aaaUser": {
         "attributes": {
            "name":"admin",
            "pwd":"cisco123"
         }
      }
   }

   headers = {
      "Content-Type" : "application/json"
   }

   requests.packages.urllib3.disable_warnings()
   response = requests.post(url,data=json.dumps(payload), headers=headers, verify=False).json()

   token = response['imdata'][0]['aaaLogin']['attributes']['token']
   return token

def main():
   token = get_token()
   print("The token is: " + token)

if __name__ == "__main__":
   main()

Then we will again copy the same json payload and url from API-Inspector we did before in Ansible and do a REST call in create_tenant.py

import requests
import json
from aci_login import get_token

tenant_name = "Tenant_Python"

def create_tenant():
  
   token = get_token()

   url = "https://192.168.15.81/api/mo/uni.json"
   
   payload = {"fvTenant":{"attributes":{"dn":"uni/tn-TNT1","name":"TNT1","rn":"tn-TNT1","status":"created"},"children":[]}}

   headers = {
      "Cookie" : f"APIC-Cookie={token}", 
   }

   requests.packages.urllib3.disable_warnings()
   response = requests.post(url,data=json.dumps(payload), headers=headers, verify=False)

   if (response.status_code == 200):
      print("Successfully created tenant")
   else:
      print("Issue with creating tenant")

def get_tenant():
   return tenant_name



if __name__ == "__main__":
   create_tenant()

When we now issue the python create_tenant.py command we will create the Tenant.


Thanks for reading my article. If you have any questions or recommendations you can message me via arvednetblog@gmail.com.