APIC-EM REST API Learning Labs

Part III - Policy Labs

This Lab is based on the GA release 1.3. The url for API call in "DevNet APIC-EM GA 1.3 always on sandbox" is https://devnetapi.cisco.com/sandbox/apic_em. This url is used for API call only, not for UI access.

If you are not familiar with APIC-EM APIs we recommend strongly you start form Part I - The Basics

Getting Started

If you are using Cisco-provided hardware at a Cisco event:

  • Lab files are already downloaded into working directory: C:\apicem-1.3-LL-sample-codes\policy-labs
  • If you cannot find downloaded sample codes you can create your working directory by typing "mkdir \apicem-1.3-LL-sample-codes\policy-labs\".

If you are working from your own laptop, please take the following steps to set up your system:

  • Install Python 3 and Git on your computer. See How To Set up Your Own Computer at the top of this page.
  • Download and install Git. The download URL is https://git-scm.com/downloads
  • Download the lab files from GitHub :

    cd <your working directory>
    

    If you are in the DevNet Zone at a Cisco Live Event open the Git Command window by either clicking on the 'Git CMD' icon on the Task Bar or in the Run bar type 'git cmd'. In the git command window type the command below.

    git clone https://github.com/CiscoDevNet/apicem-1.3-LL-sample-codes
    

    After the git clone completes, you will have all of the Python files that the lab steps use.

  • In order to run the Python scripts outside of a Cisco event, you need to set the ip variable to the IP address of the Cisco APIC-EM controller that you want the scripts to call. This variable is in the apicem_config.py file.
    For example:

    ip = 'devnetapi.cisco.com/sandbox/apic_em'
    

Executing Lab Examples

To execute the scripts, take the following steps:

  1. Open a terminal and switch to the directory that holds the learning lab sample code. Typically, the\apicem-1.3-LL-sample-codes\policy-labsis your working directory.

  2. Invoke Python3 as appropriate for your OS:

Python version 3.x is required to run sample scripts

  • Mac OS or Linux: type: python3 programName
  • Windows: type: py –3 programName. Or type: python programName

Note:

Alternatively, you can use Python IDE - IDLE.
In Mac OS Terminal just type "idle3" that will bring up IDLE for Pyhton3.
In Windows you can start IDLE from Start menu. See the following figure.

Figure

If you have finished Part I - The Basics or Part II you can skip to Sample scripts section.

Overview

The APIC-EM Controller provides REST-based API access to Enterprise, WAN and Campus networks. Network programmability and automated network control helps IT to respond more rapidly to changing network conditions and related business opportunities.

The APIC-EM has a southbound interface that speaks directly to the network control plane. Southbound interfaces are not exposed directly but are used to execute the commands that you specify with via the Northbound (NB) REST API. Thus, you can use the Northbound REST API to APIC-EM to develop your own custom controller or to add dynamic SDN functionality directly into your own applications.

About this Learning Lab

This learning lab demonstrates basic usage of the Cisco APIC-EM Northbound REST API.

What You Should Know Already

If you are not familiar with the following topics, you can complete the Coding 101: REST API Basics Lab to learn about REST and JSON before returning to this lab.

This lab assumes you are familiar with the following:

  • REST (Representational State Transfer)
    Representational State Transfer (REST) is a programming model that is based on the HTTP request-response model. A REST request is similar to the text that you type into your Web browser's address bar to go to a Web site.
  • JSON (JavaScript Object Notation)
    JavaScript Object Notation (JSON) represents REST data in a human-readable block format that looks similar to JavaScript.

  • Python programming language
    You don't have to be a Python expert to work through this lab, but some familiarity with Python or another high-level programming language is necessary.

Structure of Learning Lab Code Examples

Each lab provides a code example that consists of three main sections:

  • Code: The Python code that executes a particular REST request
  • Output: The complete result of executing the code example. Note that your result may not match this Web page exactly.
  • Explanation: A description that interleaves code and output to describe how the code works, what the output means, and any other points of interest, such as things to keep in mind when writing your own code.

Shorthand Notation of APIC-EM NB REST API URLs

A complete Northbound REST request to the Cisco APIC-EM controller takes the form of a URL like the following example:

https://fqdn-Or-IPofController/api/v1/request_details
This part of the URL, called the Base URL, i.e https://fqdn-Or-IPofController, is common to all requests sent to a particular controller:

About APIC-EM Northbound (NB) REST API Version Numbers

Every Cisco APIC-EM request URL includes a version number. The GA release of Cisco APIC-EM provides version 1 of the NB REST API; calls to this controller must include v1 in the URL. For the most part, the Learning Labs use GA 1.0 Cisco APIC-EM controllers and v1 of the NB REST API.

Example: api/v1/host

Issuing HTTP Requests from Python

HTTP methods used in APIC-EM REST API

The APIC-EM Northbound REST API uses standard HTTP methods to CRUD (Create, Read, Update, Delete) data.

HTTP Operation
POST Create new data
GET Read (Retrieve) existing data
PUT Update existing data
DELETE Delete existing data

The following code snippets show how to use the Python requests library to issue each of these HTTP requests. You can use these snippets as templates for issuing your own HTTP requests in this lab.

These examples rely on the following conventions:

  • apicem_ip is the IP address or fully-qualified domain name (FQDN) of the Cisco APIC-EM controller to which you are sending the request. See "Getting Started" for more information.

  • request_name is the portion of the NB REST API that you are calling

GET

A GET request retrieves existing data.

import requests
url = "https://apicem_ip/api/v1/request_name"
response = requests.get(url,verify=False)

POST

A POST request creates new data. For security reasons, the Northbound REST API to APIC-EM always places POST request parameters and arguments in the JSON body.

import requests
import json

json_obj = {
"key":"value"
}
url = "https://apicem_ip/api/v1/request_name"
# need to specify content type -json- for POST request #
headers = {'content-type': 'application/json'}
response = requests.post(url, json.dumps(json_object), headers=headers,verify=False)

PUT

A PUT request modifies existing data. For security reasons, the NB REST API to APIC-EM always places PUT request parameters and arguments in the JSON body.

import requests
import json

json_obj = {
"key":"value_to_change"
}
url = "https://apicem_ip/api/v1/api_itself"
# need to specify content type -json- for PUT request #
headers = {'content-type': 'application/json'}
response = requests.put(url, json.dumps(json_object), headers=headers,verify=False)

DELETE

A DELETE request removes existing data.

import requests
url = "https://apicem_ip/api/v1/request_name"
response = requests.delete(url,verify=False)

APIC-EM REST API Reference

For reference treatment of all NB REST APIs to the Cisco APIC-EM controller, see the APIC-EM API Reference Docs

APIC-EM server in this lab

This lab uses the Cisco APIC-EM controller that the Cisco DevNet Always-On Sandbox provides. To use a different controller, set the apicem_ip variable in the apicem_config.py file appropriately. For more information, see the "Getting Started" section of this lab.

Sample scripts

Same as in previous sessions, all Python sample scripts are working in a flat directory. The apicem_config.py is used for configuring parameters in different environment. Those parameters are APIC-EM IP (including port number), username, password and the apic-em API version number. If you are using your own APIC-EM this is the file you need to modify. And every script needs to import apicem.py.
But this time we want to program apicem.py in different way. We want to turn it into an object. We will create a class called apicem. We then make all functions become the methods of apicem object.

Here shows apicem.py script:

apicem.py - Click to expand

"""
This script provides the same functions as in previous leaning lab
but using Python class.
"""

import requests   # We use Python external "requests" module to do HTTP query
import json
import sys

# All APIC-EM configuration is in apicem_config.py
import apicem_config  # APIC-EM IP is assigned in apicem_config.py
from tabulate import tabulate # Pretty-print tabular data in Python

requests.packages.urllib3.disable_warnings() # Disable warning message
# It's used to get rid of certificate warning messages when using Python 3.
# For more information please refer to: https://urllib3.readthedocs.org/en/latest/security.html

class apicem(object):
    """ An object to provide easy RESTful request for APIC-EM APIs"""

    def init(self, host = apicem_config.APICEM_IP,username = apicem_config.USERNAME,
                 password = apicem_config.PASSWORD,version= apicem_config.VERSION,kwargs):
        """      --apicem object initializer--

        When a class defines an special init() method,
        class instantiation automatically invokes init() for the newly-created class instance.

        Taking apic-em IP, login, password and version number from apicem_config.py as default
        To overwrite enter IP,username and password when initialize the instance

        Parameters
        ----------
        self: a reference to the class instance
        host (str): apic-em routable DNS address or ip
        username (str): user name to authenticate with
        password (str): password to authenticate with
        version (str): apic-em version
        kwargs: arbitrary number of keyword arguments (optional, use as needed)

        Will use default value from apicem_config.py for host, username, password and version
        if there are not assigned during creating apicem instance.

        Methods:
        ----------
        get_X_auth_token: get token
        get_url: get the complete url i.e. 'https://myapicem.mycompany.com/api/v1/'
        get: simplify requests.get
        post: simplify requests.post
        put: simplify requests.put
        delete: simplify requests.delete
        prettyPrint: pretty print raw response

        Note:
        -----
        port number can be configured in apicem_config.py as part of 'apicem_ip' string

        """

        self.dict.update(kwargs)
        self.api_url = "https://%s/api/%s/%s" # host, version and api
        self.host = host
        self.version = version
        self.username = username
        self.password = password
        self.headers = {"content-type":"application/json"}

        # Get authentication when initializing instant, also add token into the self.headers
        # So in get,post,put and delete methods don't need to get service ticket again
        if self.username is not None:
            self.get_X_auth_token()
        else:
            print ("need to provide username")

    def get_X_auth_token(self):
        """
        This function returns a new service ticket.
        In this function we also assign header value which is used in the get/post/put/delete functions

        Return:
        ----------
        str: APIC-EM authentication token
        """
        # All APIC-EM REST API query and response content type is JSON
        # JSON input for the post ticket API request

        r_json = {"username": self.username,"password": self.password}

        # Post ticket API request
        try:
            r = requests.post(self.get_url("ticket"),json.dumps(r_json),headers=self.headers,verify = False)
            response_json = r.json()

            # Adding 'X-Auth-Token' to header
            self.headers['X-Auth-Token'] = response_json["response"]["serviceTicket"]
            return (response_json["response"]["serviceTicket"])
        except:
            # Something wrong, cannot get service ticket
            print ("Status: %s"%r.status_code)
            print ("Response: %s"%r.text)
            sys.exit ()


    def get_url(self, api):
        """
        get the complete url path for the request

        Parameters
        ----------
        api (str): APIC-EM API

        Return:
        str: url for REST request
        """

        complete_url = self.api_url % (self.host, self.version, api)
        return complete_url

    def get(self, api, params='', printOut=False):
        """
        To simplify requests.get with default configuration.Return is the same as requests.get

        Parameters
        ----------
        api (str): api without prefix
                   example: for https://10.10.10.10/api/v1/host just use "host"
        params (str): optional parameters for the GET request
        printOut (boolean): to pretty print raw response (set True to print)

        Return:
        -------
        object: an instance of the Response object(of requests module)

        Authentication token is obtained during the object initialization and assigned to self.headers
        when calling get_X_auth_token()
        """
        try:
            url = self.get_url(api)
            print ("\nExecuting GET '%s'\n"%url)
            r = requests.get(url,headers=self.headers,params=params, verify = False)
            print ("GET '%s' Status: "%api,r.status_code,'\n') # This is the http request status
            if printOut:
                self.prettyPrint("Response:\n", r)
            return r
        except:
            print ("Something wrong to GET /",api)
            sys.exit()

    def post(self,api,data=None,params='',printOut=False):
        """
        To simplify requests.post with default configuration. Return is the same as requests.post

        Parameters
        ----------
        api (str): api without prefix
             example: for https://10.10.10.10/api/v1/policy just use "policy"
        data (JSON): JSON object for the POST request
        printOut (boolean): to pretty print raw response (set True to print)

        Return:
        -------
        object: an instance of the Response object(of requests module)

        Authentication token is obtained during the object initialization and assigned to self.headers
        when calling get_X_auth_token()
        """

        try:
            url = self.get_url(api)
            print ("\nExecuting POST '%s'\n"%url)
            r = requests.post(url, json.dumps(data), headers=self.headers,params=params,verify = False)
            print ("POST '%s' Status: "%api,r.status_code,'\n') # This is the http request status
            if printOut:
                self.prettyPrint("Response:\n", r)
            return r
        except:
            print ("Something wrong to POST /",api)
            sys.exit()


    def put(self, api, data=None, printOut=False):
        """
        To simplify requests.post with default configuration. Return is the same as requests.put

        Parameters
        ----------
        api (str): api without prefix
             example: for https://10.10.10.10/api/v1/policy just use "policy"
        data (JSON): JSON object for the POST request
        printOut (boolean): to pretty print raw response (set True to print)

        Return:
        -------
        object: an instance of the Response object(of requests module)

        Authentication token is obtained during the object initialization and assigned to self.headers
        when calling get_X_auth_token()
        """

        try:
            url = self.get_url(api)
            print ("\nExecuting PUT '%s'\n"%url)
            r = requests.put(url, data, headers=self.headers,verify = False)
            print ("PUT '%s' Status: "%api,r.status_code,'\n') # This is the http request status
            if printOut:
                self.prettyPrint("Response:\n", r)
            return r
        except:
            print ("Something wrong to PUT /",api)
            sys.exit()

    def delete(self, api, params='',printOut=False):
        """
        To simplify requests.get with default configuration.Return is the same as requests.delete
        Parameters
        ----------
        api (str): api without prefix
             example: for https://10.10.10.10/api/v1/policy just use "policy"
        params (str): optional parameters for the GET request
        printOut (boolean): to pretty print raw response (set True to print)

        Return:
        -------
        object: an instance of the Response object(of requests module)

        Authentication token is obtained during the object initialization and assigned to self.headers
        when calling get_X_auth_token()
        """
        try:
            url = self.get_url(api)
            print ("\nExecuting DELETE '%s'\n"%url)
            r = requests.delete(url, headers=self.headers, params=params, verify = False)
            print ("DELETE '%s' Status: "%api,r.status_code,'\n') # This is the http request status
            if printOut:
                self.prettyPrint("Response:\n", r)
            return r
        except:
            print ("Something wrong to DELETE /",api)
            sys.exit()

    def prettyPrint(self,text="",json_object=None):
        """
        Parameters
        ----------
        text (str) : message to print out
        json_object (Response object): an instance of the Response object(of requests module)

        Return:
        -------
        None
        """
        resp = json_object.json() # Get the json-encoded content from response
        print (text,json.dumps(resp,indent=4))    # This is the entire response from the query

What's next?

The following lab sessions create simple Python applications that interact with the Cisco APIC-EM controller by means of the NB REST API. We recommend strongly that you run the scripts in each lab session to see the live responses from APIC-EM server.

  • Lab 1: EasyQoS and related APIs - Create Policy Tag
  • Lab 2: EasyQoS and related APIs - Create Policy Tag Association
  • Lab 3: EasyQoS and related APIs - Create Custom NBAR2 Application
  • Lab 4: EasyQoS and related APIs - Policy Preview - New API in GA 1.3
  • Lab 5: EasyQoS and related APIs - Create and Apply Policy
  • Lab 6: EasyQoS and related APIs - Delete Policy,Custom NBAR2 Application,Policy Tag Association and Policy Tag