In Python you could write the code to interact with the ACI library directly without the need of a library. Yet the advantage of some of these libraries is that another person has provided a foundation that is easier to work with than going at it alone. The Requests Library is a very popular library available in Python that really helps you when doing REST calls using Python.
The best description for Requests is available on their site as: "Requests is the only Non-GMO HTTP library for Python, safe for human consumption."
As we had mentioned we will be using this web based IDE. You have complete view of the files in the working directory ltrdcn-3225. From here you can create files in the different directories we will create for the different components in the lab.
To create a file you just use the IDE itself.
And name the file
req-aci.py
For our simple request script we are going to just interact directly with the fabric. We have to get the request library imported into our script, and then work with the authentication to the ACI fabric like we did in the Postman section of the lab.
On the first line of req-aci.py you will add:
import requests, json
This will import into our script the request library and the JSON library to be able to construct the ReST API calls to the ACI fabric.
Then add some crude credentials to login to the APIC.
import requests, json
apic_ip = '10.0.226.41'
apic_username = 'aciproglab04'
apic_password = 'cisco.123'
With these now you will create a dictionary that will contain the structure of authentication into the APIC. This is a standard Python dictionary data structure that is the same for all authentication requests. You can also utilize XML to see the request and that request would look as:
<aaaUser name="admin" pwd="cisco.123"/>
but we will stick to JSON format for this lab.
import requests, json
apic_ip = '10.0.226.41'
apic_username = 'aciproglab04'
apic_password = 'cisco.123'
credentials = {'aaaUser':
{'attributes':
{'name': apic_username, 'pwd': apic_password }
}
}
Now that you have the structure of the authentication request, you have to build the code to send
the request to the APIC controller. The first thing is to set the base URL that we will use to
make the request against the AAA object models of the fabric to gain a authentication token. For better
results we will create two variables. base_url
and login_url
where we can append to that
base string, base_url
, with the specific object we want to reach in the fabric.
If you remember when we talked about the API, you can see the structure was like:
So what we do is set a variable to be the protocol, APIC host and the API that is standard across all references of the ACI fabric.
import requests, json
apic_ip = '10.0.226.41'
apic_username = 'aciproglab04'
apic_password = 'cisco.123'
credentials = {'aaaUser':
{'attributes':
{'name': apic_username, 'pwd': apic_password }
}
}
base_url = 'https://%s/api/' % apic_ip
login_url = base_url + 'aaaLogin.json'
With the login_url
built for this fabric, we have to convert the dictionary for the
credentials information to JSON. Using the JSON library that
is part of Python, we will take the dictionary that we built for Python and create a variable that will be
called json_credentials
that is what will be sent to the APIC in the REST request using the
request library.
import requests, json
apic_ip = '10.0.226.41'
apic_username = 'aciproglab04'
apic_password = 'cisco.123'
credentials = {'aaaUser':
{'attributes':
{'name': apic_username, 'pwd': apic_password }
}
}
base_url = 'https://%s/api/' % apic_ip
login_url = base_url + 'aaaLogin.json'
json_credentials = json.dumps(credentials)
With the credentials in JSON format, you can proceed to create the POST request to the ACI fabric. Since we are going to be sending data to the ACI fabric we will be using a REST POST request.
Now, the request library needs to invoke the POST request and the answer from the APIC
will be injected into the post_response
variable. We add a print message for the response to see what
is the response from the APIC.
You may notice in the following section that we have added the parameter to the request call verify = False. This is to tell requests library to ignore the self signed certificate that is on the APIC controller.
import requests, json
apic_ip = '10.0.226.41'
apic_username = 'aciproglab04'
apic_password = 'cisco.123'
credentials = {'aaaUser':
{'attributes':
{'name': apic_username, 'pwd': apic_password }
}
}
base_url = 'https://%s/api/' % apic_ip
login_url = base_url + 'aaaLogin.json'
json_credentials = json.dumps(credentials)
post_response = requests.post(login_url, data=json_credentials, verify=False)
print(post_response)
At this point make sure you have saved your file. Then, return to your Terminal window.You will now execute the script in the terminal. Make sure you are in the correct directory.
cd ~/ltrdcn-3225/requests
And then run the Python script.
python3 req-aci.py
The output of the command should be similar to the following output:
InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See:
https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
<Response [200]>
The following table shows you just a couple of the various response codes to assist you understanding this concept.
CODE | Description |
---|---|
200 | The request has succeeded. |
202 | The request has been accepted, but processing hasn't completed |
400 | Bad request. The request could not be understood by the server due to malformed syntax. |
401 | Unauthorized. The request requires user authentication. |
403 | Forbidden. The server understood the request, but is refusing to fulfill it. |
404 | Not found. The server has not found anything matching the Request-URI |
500 | Internal Server Error. The server encountered an unexpected condition which prevented it from fulfilling the request. |
The key in that output is going to be the proper Response code, that should be 200 for OK.
In the response object created by the requests library is the authentication token that we are looking for
to gain access to the APIC controller API. The simple print command that we did print(post_response)
was to validate the response. You can extract more details on the response by simply doing a print to the same
object but invoking the text method of the object print(post_response.text)
.
The output will be EXTENSIVE as the text of the response is printed in itself. You can make this change if you wish to see the output. If not you can jump straight to the code that we are interested in that would extract the token from the response directly. What we are looking for is the authentication token that is needed for you to issue commands into the ACI fabric in itself.
First, we have to take the response that the APIC sent back and convert that into a dictionary
that Python can process. The response is in essence just text inside the response object
of the request library. Using the json.loads
command, the string response
will be converted into a Python dictionary. At that point you can easily extract
the login attributes field from the response to get the token.
Then you have to parse the object in return to extract the token. The response dictionary will look as follows (ordering of fields is different every time):
Return to your editor. To extract that value you have to select exactly the right position in the dictionary to get
the value. In
this case post_response_json['imdata'][0]['aaaLogin']['attributes']
import requests, json
apic_ip = '10.0.226.41'
apic_username = 'aciproglab04'
apic_password = 'cisco.123'
credentials = {'aaaUser':
{'attributes':
{'name': apic_username, 'pwd': apic_password }
}
}
base_url = 'https://%s/api/' % apic_ip
login_url = base_url + 'aaaLogin.json'
json_credentials = json.dumps(credentials)
post_response = requests.post(login_url, data=json_credentials, verify=False)
post_response_json = json.loads(post_response.text)
login_attributes = post_response_json['imdata'][0]['aaaLogin']['attributes']
With that you can extract the token directly as the token would be in
login_attributes['token']
and we can built the cookie dictionary that will
be needed for further connections.
import requests, json
apic_ip = '10.0.226.41'
apic_username = 'aciproglab04'
apic_password = 'cisco.123'
credentials = {'aaaUser':
{'attributes':
{'name': apic_username, 'pwd': apic_password }
}
}
base_url = 'https://%s/api/' % apic_ip
login_url = base_url + 'aaaLogin.json'
json_credentials = json.dumps(credentials)
post_response = requests.post(login_url, data=json_credentials, verify=False)
post_response_json = json.loads(post_response.text)
login_attributes = post_response_json['imdata'][0]['aaaLogin']['attributes']
cookies = {}
cookies['APIC-Cookie'] = login_attributes['token']
print(cookies)
With that, make sure you save your Python file again and return to your Terminal window. Then, execute the script and see the cookie definition.
python3 req-aci.py
{'APIC-Cookie': u'IP2IOcGIqUuf3u7Jb3EItLeZDDRknypcQPruHzVV25p5iveE/nACcT2jiTV56G
N051ZU61WGhj21tAM5sb5uSzOUgzjtt2hntR5MV7+em6Fgj7CEkni+4bWjAVi/Hlw9czDJp2hCCj
oOjuqZ5MExCmqHw4RNR+PXFPxLaSn0csTY+W4Kpyn2mIsLfWwfsXqsLydk4i+iiHgsZNxxKxL0H1
Woj4e6cRdBFX37W7b6ZP/RJ0Wlz1hDEd6+D+yUQQnZ0BCYrtYBWvf8q6ZsiOoR6g=='}
And with that token, all future requests to the ACI fabric can be performed. The token will expire over time, but you can write your code in such a way that it can execute all the sequence of requests to the fabric using the same authentication token. Then when completed, that token can expire and you would re-execute the authentication code to refresh and get a new token.