Getting Started with Cisco Application Centric Infrastructure (ACI) Programmability

The Cisco ACI programmability model allows complete programmatic access to the application centric infrastructure. With this access, customers can integrate network deployment into management and monitoring tools, and deploy new workloads programmatically. ACI Fabric is configured using an abstract policy model on the Cisco Application Policy Infrastructure Controller (APIC). The APIC has a rich and complete object model that is accessible through a programmatic REST API. The API accepts and returns HTTP or HTTPS messages that contain JavaScript Object Notation (JSON) or Extensible Markup Language (XML) documents. You can use any programming language, to generate messages and JSON or XML documents that contain the API methods or Managed Object (MO) descriptions. In addition to the standard REST interface, Cisco provides several open source tools or frameworks such as ACI toolkit, Cobra (Python), ACIrb (Ruby), Puppet, and Ansible to automate and program the APIC.

TIP: Try the interactive tutorial at Cisco Learning Lab: Introduction to ACI Programmability

Throttling

APIC will actively throttle password-based authenticated connection rates over a specific threshold. This is as part of an anti-DDOS measure with ACI using password-based authentication using signature-based authentication is recommended.

  • Using Username and Password for API authentication is typically fine when developing scripts and using REST client tools like Postman.
  • To use SSH or X509 user authentication, refer to the Cisco APIC Basic Configuration Guide

NOTE: In Production ready code it is advisable to use signature-based authentication with ACI as it not only prevents connection-throttling, but also improves general performance ACI API performance.

APIC Configuration

This section introduces the user to perform basic APIC configuration usecases such as Physical domain configuration, VLAN pool configuration, and Tenant configuration.

Authentication

POST http://APIC-IP/api/aaaLogin.json HTTP/1.1
Content-Type: application/json

{
    "aaaUser" : {
        "attributes" : {
            "name" : "APIC_USER",
            "pwd" : "APIC_PASSWORD"
        }
    }
}

Procedure to configure APIC

  1. Login to the CLI, to execute a request. A cookie is generated and stored for subsequent execution.
  2. In the URL, replace the APIC-IP with the IP or hostname of the APIC server.

Note: If you do not have access to an ACI environment, you can use the ACI Simulator in the DevNet Sandbox.

Configure ACI using Postman:

Postman is a Google Chrome Browser application to make REST API calls. If you are using GUI, use Postman.

Executing ACI-REST using Postman for first time:

  1. Enter the IP address of the APIC server in your browser and accept the certificate if asked.
  2. Copy POST URL mentioned in Authentication section, and then replace APIC-IP with IP address of APIC.
  3. Select method as POST.
  4. Open raw JSON section.
  5. Copy BODY JSON to raw JSON body section of Postman.
  6. Replace APIC_USERNAME with apic user.
  7. Replace APIC_PASSWORD with apic password.
  8. Click Send button.

Note: If the cookie gets expired, perform the above steps again.

For subsequent REST call:

  1. Copy POST URL, and then replace APIC-IP with IP address of APIC.
  2. Select method as POST.
  3. Open raw JSON section.
  4. Copy BODY JSON to raw JSON body section of Postman.
  5. Click Send button.

Using ACI Toolkit

See the Documentation for the ACI Toolkit.

If you are ready to start programming, download and install the ACI Toolkit.

Environment Pre-requisities:

Downloading

If you have Git installed, clone the repository.

git clone https://github.com/datacenter/acitoolkit.git

Installing

After downloading, install using setuptools.

cd acitoolkit
python setup.py install

If you plan to modify the actual toolkit files, you should install the developer environment that will link the package installation to your development directory.

 cd acitoolkit
 python setup.py develop

ACI Toolkit Samples

This directory contains sample scripts that use the python library.

Set up

In order to use the examples in this directory, it is important to set the PYTHONPATH variable to include the path to the ACI toolkit or have installed the acitoolkit using setup.py.

credentials.py

Many of the samples in this directory use the file credentials.py to login to the APIC. Before running, edit the credentials.py with the username, password, and IP address for your environment.

To execute the sample files

  1. cd samples
  2. vi example.py (Copy the script here)
  3. Execute the script. example: python example.py

Sample scripts

For additional examples, see the Documentation for the ACI Toolkit.

Physical Domain Configuration

This section describes how to configure physical domain and attach VLAN pool to it. The physical domain profile stores the physical resources (ports and port-channels) and encapsulate resources (VLAN/VXLAN) that should be used for endpoint groups associated with this domain. The following example shows the creation of the physical domain by attaching AEP and VLAN pools.

POST http://APIC-IP/api/node/mo/uni.json HTTP/1.1
Content-Type: application/json
Cache-Control: no-cache

{
    "physDomP": {
        "attributes": {
            "name": "test_phy_dmn",
            "dn": "uni/phys-test_phy_dmn"
        },
        "children": [{
            "infraRsVlanNs": {
                "attributes": {
                    "tDn": "uni/infra/vlanns-[test_vlan]-dynamic"
                }
            }
        }]
    }
}
import acitoolkit.acitoolkit as aci

# Define static values to pass (edit these if you wish to set differently)
DEFAULT_PHY_DOMAIN_NAME = 'test_phy_dmn'

def main():
    """
    Main create tenant routine
    :return: None
    """
    # Get all the arguments
    description = 'It logs in to APIC and will create the physical domain.'
    creds = aci.Credentials('apic', description)
    creds.add_argument('-p', '--phy_domain',
                       help='The name of physical domain',
                       default=DEFAULT_PHY_DOMAIN_NAME)
    args = creds.get()

    # Login to the APIC
    session = aci.Session(args.url, args.login, args.password)
    resp = session.login()
    if not resp.ok:
        print('%% Could not login to APIC')

    # Create the physical Domain
    phy_dmn = aci.PhysDomain(args.phy_domain)

    # Push the physical domain to the APIC
    resp = session.push_to_apic(phy_dmn.get_url(),
                                phy_dmn.get_json())
    if not resp.ok:
        print('%% Error: Could not push configuration to APIC')
        print(resp.text)


if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass

VLAN Pool Configuration

This section describes how to

  • configure VLAN Pool with VLAN range
  • manage and configure VLAN-pool on APIC using different configuration management code snippet

The provider access function is defined when the hypervisor uses an encapsulation protocol such as VxLAN/NVGRE, and provides the policies to impact VxLAN/NvGRE packets from NVGRE. You do not need to provide the encapsulation VLAN and endpoint for the provider access function. The system uses the Infra VLAN (provided during APIC bootup) as the encapsulation, and associates it to the default endpoint group under the default tenant.

POST http://APIC-IP/api/node/mo/uni/infra/vlanns-[test_vlan]-dynamic.json HTTP/1.1
Content-Type: application/json
Cache-Control: no-cache

{
    "fvnsVlanInstP":{
        "attributes":{
            "name":"test_vlan"
        },
        "children":[
            {
                "fvnsEncapBlk":{
                    "attributes":{
                        "from":"vlan-222",
                        "to":"vlan-223"
                    }
                }
            }
        ]
    }
}
import acitoolkit.acitoolkit as aci

# Define static values to pass (edit these if you wish to set differently)
DEFAULT_VLAN_NAME = 'test_vlan'

def main():
    """
    Main create tenant routine
    :return: None
    """
    # Get all the arguments
    description = 'It logs in to the APIC and will create the vlan pool.'
    creds = aci.Credentials('apic', description)
    creds.add_argument('-v', '--vlan', help='The name of vlan pool',
                       default=DEFAULT_VLAN_NAME)
    args = creds.get()

    # Login to the APIC
    session = aci.Session(args.url, args.login, args.password)
    resp = session.login()
    if not resp.ok:
        print('%% Could not login to APIC')

    # Create the VLAN pool
    vlan_pool = aci.NetworkPool(args.vlan, 'vlan', '222', '223', 'dynamic')

    # Push the VLAN pool to the APIC
    resp = session.push_to_apic(vlan_pool.get_url(),
                                vlan_pool.get_json())
    if not resp.ok:
        print('%% Error: Could not push configuration to APIC')
        print(resp.text)


if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass

Tenant Configuration

This section describes how to manage and configure tenant on APIC using different configuration management code snippet. A tenant is a logical container for application policies that enable an administrator to exercise domain-based access control. A tenant represents a unit of isolation from a policy perspective, but it does not represent a private network. Tenants can represent a customer in a service provider setting, an organization or domain in an enterprise setting, or just a convenient grouping of policies.

POST http://APIC-IP/api/mo/uni.json HTTP/1.1
Content-Type: application/json
Cache-Control: no-cache

{
    "fvTenant": {
        "attributes": {
            "name": "test_tenant"
        }
    }
}
import acitoolkit.acitoolkit as aci

# Define static values to pass (edit these if you wish to set differently)
DEFAULT_TENANT_NAME = 'test_tenant'

def main():
    """
    Main create tenant routine
    :return: None
    """
    # Get all the arguments
    description = 'It logs in to the APIC and will create the tenant.'
    creds = aci.Credentials('apic', description)
    creds.add_argument('-t', '--tenant', help='The name of tenant',
                       default=DEFAULT_TENANT_NAME)

    args = creds.get()

    # Login to the APIC
    session = aci.Session(args.url, args.login, args.password)
    resp = session.login()
    if not resp.ok:
        print('%% Could not login to APIC')

    # Create the Tenant
    tenant = aci.Tenant(args.tenant)

    # Push the tenant to the APIC
    resp = session.push_to_apic(tenant.get_url(),
                                tenant.get_json())
    if not resp.ok:
        print('%% Error: Could not push configuration to APIC')
        print(resp.text)


if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass