Sunday, January 3, 2021

Python to interact with the Cisco SD-WAN REST API

 

Step 1: Login and authenticate with Python code

Postman is great to start interacting with and discovering APIs, but to automate and program the infrastructure, you need to build code that can be reused and applications that extend the fabric.

You've seen how Postman can generate code in Python and other programming languages. Now you'll build dedicated functions and classes based on the Postman generated code, and in the next Learning Lab you'll use those functions and classes to build Python applications. These functions and classes will authenticate and interact with the vManage REST API with GET and POST calls.

You can find complete code for the functions and the classes in the code for the learning lab Getting Started with Cisco SD-WAN GitHub repository.

Building the authentication function

In the Postman lab, you saw that the first step was to authenticate to the DevNet SD-WAN sandbox vManage instance. You will now use the Postman code generator for the authentication API call to build your first Python function.

  1. First you need to specify the endpoint, https://{{vmanage}}:{{port}} and then the login resource, /j_security_check. You will store each one of them in individual variables:

    • The base_url_str variable contains the vManage endpoint in string format.
    • The login_action variable contains the login resource.
  2. Next you need to specify the username and password and store it in another variable that we'll call login_data. This will be the payload data organized as key value pairs in JSON format that you send to the login resource.

    So far you have the three variables defined:

    base_url_str = 'https://%s:8443/'%vmanage_ip
    
    login_action = '/j_security_check'
    
    login_data = {'j_username' : username, 'j_password' : password}
    

    The endpoint and resource are split into two different variables. If either of them change, you only need to change them in one place.

  3. Next you will combine these two variables to build the complete login URL. Name the variable login_url and define it as a combination of base_url_str and login_action. This defines the login URL as a combination of endpoint and resource and the payload as a JSON file containing the j_username and j_password values.

  4. Next you will use the session method of the requests library to open a new session. Use the POST method of the session object to send the request to the login_url, with a payload of login_data. You don't want to check the authenticity of the self-signed certificate so the verify option is set to False.

    login_url = base_url_str + login_action
    
    sess = requests.session()
    
    login_response = sess.post(url=login_url, data=login_data, verify=False)
    
  5. The function needs to determine if the login attempt was successful. A successful authentication returns a status of 200 OK but does not return any data. However, the presence of an <html> tag will indicate a failed attempt. If the authentication fails, Python will return a message notifying the user that the Login Failed and exit the function.

    if b'<html>' in login_response.content:
       print ("Login Failed")
       sys.exit(0)
    

Reviewing the complete authentication function

By combining all these components, you have built a Python function to login and authenticate to a Cisco SD-WAN vManage REST API. This function takes the following value as input: the vManage IP address, the username and password.

The following code shows an example of a complete authentication function:

def login(vmanage_ip, username, password):
        """Login to vmanage"""
        base_url_str = 'https://%s:8443/'%vmanage_ip

        login_action = '/j_security_check'

        #Format data for loginForm
        login_data = {'j_username' : username, 'j_password' : password}

        #Url for posting login data
        login_url = base_url_str + login_action

        sess = requests.session()
        #If the vmanage has a certificate signed by a trusted authority change verify to True
        login_response = sess.post(url=login_url, data=login_data, verify=False)

        if b'<html>' in login_response.content:
            print ("Login Failed")
            sys.exit(0)

In the next section you will build ßadditional Python functions for getting data from the API (get_request) and posting and creating new data (post_request).

Note: After you have completed this Learning Lab, you are welcome to experiment with adding more functions for PUTDELETEPATCH, and others. For the purposes of your application that we'll develop in the next Learning Lab, being able to GET and POST new data is enough.

Step 2: GET requests in Python

In this step you will create a new function that will GET data from the vManage REST API.

For the purposes of this Lab, the function name will be get_request(). This function will receive two parameters as input: the vManage IP address and the resource from which you are trying to obtain the data. This resource will be called a mount_point.

  1. You need to define the URL to which you will issue your GET request. All the REST API resources can be found after https://{{vmanage_ip}}:{{port}}/dataservice/. With this information, build the url as follows:

    url = "https://%s:8443/dataservice/%s"%(vmanage_ip, mount_point)
    

    The input two variables for the get_request() function, vmanage_ip and mount_point, are passed as string values in the process of building the URL.

  2. Use the request method to perform a GET on the url. The results of the request will be restored in a variable named response and returned to the user:

    response = requests.request("GET", url, verify=False)
    data = response.content
    return data
    

    Note: In this Learning Lab example, you do not verify the authenticity of the SSL certificate. In a production environment you should always verify if the SSL certificate returned by the vManage instance is valid.

  3. You can now combine these components to create the get_request() function:

    def get_request(vmanage_ip, mount_point):
       """GET request"""
       url = "https://%s:8443/dataservice/%s"%(vmanage_ip, mount_point)
    
       response = requests.request("GET", url, verify=False)
       data = response.content
       return data
    

You will use this function whenever you want to perform a GET request from the vManage REST API. Next, you will build a POST function that creates new data in the API.

Step 3: POST requests in Python

You've built two functions for the vManage REST API: login(vmanage_ip, username, password) and get_request(vmanage_ip, mount_point). Next, you'll build the function to perform POST calls and create new data in the API. This function will be called post_request().

For the purposes of this Lab, the function name will be post_request(). This function receives the following parameters as input:

  • The vManage IP address
  • The resource to which the POST call will be sent.
  • The payload that will be sent to the endpoint.
  • The Content-Type header that will be enforced as application/json.
  1. Build the URL to which the request will be sent. This variable is exactly the same as the one you used for the GET function. The resources that you can send the POST request to, are all to be found after https://{{vmanage_ip}}:{{port}}/dataservice/.

  2. The payload data that will be sent with the request is taken from the input of the function, and is JSON encoded and stored in the payload variable:

    def post_request(vmanage_ip, mount_point, payload, headers={'Content-Type': 'application/json'}):
       url = "https://%s:8443/dataservice/%s"%(vmanage_ip, mount_point)
       payload = json.dumps(payload)
    
  3. Create the POST operation. Use the request and specify that this is a POST operation. You will also include the endpoint and resource represented by the URL you defined above. The actual data that will be sent with this call is stored in the payload variable, and the Content-Type headers and the SSL verification is disabled. The result of the request is stored in the response variable. The json() method is called on the response object and the JSON format of the response is returned to the user.

    response = requests.request("POST", url, data=payload, headers=headers, verify=False)
    data = response.json()
    return data
    
  4. You can now combine these components to create the post_request() function:

    def post_request(vmanage_ip, mount_point, payload, headers={'Content-Type': 'application/json'}):
       """POST request"""
       url = "https://%s:8443/dataservice/%s"%(vmanage_ip, mount_point)
       payload = json.dumps(payload)
    
       response = requests.request("POST", url, data=payload, headers=headers, verify=False)
       data = response.json()
       return data

Step 4: rest_api_lib Python class

You have now built three functions that you will re-use extensively in your interactions with the vManage REST API:

  • login()
  • get_request()
  • post_request()

In this step you will create your first Python class.

About Python classes

Classes in Python provide a method for bundling data and functionality. Creating a new class creates a new type of object that can then be instantiated. Each class instance can have attributes attached to it for state maintenance and methods for modifying its state.

The __init__ method is a reserved method in Python classes and is called a constructor. With it you can initialize the attributes of the class. self represents the instance of a class and with it you can access the attributes and the methods of the class.

Constructing the rest_api_lib class.

You will initialize the constructor __init__ method with the attributes for the vManage IP address, an empty dictionary for the REST API session and you will also initialize the login function.

Next, you will define the methods that the rest_api_lib class will expose when an instance of it is created. To define the methods, use the functions that you defined for loginget_request() and post_request.

You will need to make some adjustments to these functions to adapt to the Python class. Each method in a Python class needs to have the self parameter passed as input. You will also preserve the session that gets established after you login into the API and use this session in the other methods of the class.

When you combine these functions and parameters, the rest_api_lib class code should be similar to the following:

Note: The following code sample may be missing some underscore characters. Refer to the code in the Getting Started with Cisco SD-WAN GitHub repository.

class rest_api_lib:
    def __init__(self, vmanage_ip, username, password):
        self.vmanage_ip = vmanage_ip
        self.session = {}
        self.login(self.vmanage_ip, username, password)

    def login(self, vmanage_ip, username, password):
        """Login to vmanage"""
        base_url_str = 'https://%s:8443/'%vmanage_ip

        login_action = '/j_security_check'

        #Format data for loginForm
        login_data = {'j_username' : username, 'j_password' : password}

        #Url for posting login data
        login_url = base_url_str + login_action
        url = base_url_str + login_url

        sess = requests.session()
        #If the vmanage has a certificate signed by a trusted authority change verify to True
        login_response = sess.post(url=login_url, data=login_data, verify=False)


        if b'<html>' in login_response.content:
            print ("Login Failed")
            sys.exit(0)

        self.session[vmanage_ip] = sess

    def get_request(self, mount_point):
        """GET request"""
        url = "https://%s:8443/dataservice/%s"%(self.vmanage_ip, mount_point)
        #print url
        response = self.session[self.vmanage_ip].get(url, verify=False)
        data = response.content
        return data

    def post_request(self, mount_point, payload, headers={'Content-Type': 'application/json'}):
        """POST request"""
        url = "https://%s:8443/dataservice/%s"%(self.vmanage_ip, mount_point)
        payload = json.dumps(payload)
        print (payload)

        response = self.session[self.vmanage_ip].post(url=url, data=payload, headers=headers, verify=False)
        data = response.json()
        return data

Summary

If you are overwhelmed by the amount of information in this Learning Lab, you may want to spend some time with the functions and the class you created so far on your own. Copy and paste the code into Python (.py) files, run them in a Python interpreter and see the error messages you get. Try to solve the error messages and become comfortable with all the concepts you discussed in this Learning Lab.

Note: You can also find all the functions and the class created in this Learning Lab in the functions folder in the Getting Started with Cisco SD-WAN GitHub repository.

In the next Learning Lab in this module you will use this Python class as a foundation to build a CLI application that interacts with the vManage REST API, extracts data using GET requests, creates new data using POST requests and displays it to the user in an interactive manner.



 

No comments:

Post a Comment