In this blog article, we’re going to look further into using
the Python requests module to interface with REST APIs. In particular, we’ll look at Cisco Nexus
NX-API.
Blog Series
Python for Network Engineers - Part 1 - Introduction
Python for Network Engineers - Part 2 - Making REST calls
Python for Network Engineers - Part 3 - Using Cisco Nexus NX-API
Python for Network Engineers - Part 4 - Using Arista EOS eAPI
Python for Network Engineers - Part 5 - Using Junos NETCONF interface
Python for Network Engineers - Part 6 - Using Cisco Nexus NETCONF interface
Python for Network Engineers - Part 7 - Using Palo Alto Networks XML API
Python for Network Engineers - Part 1 - Introduction
Python for Network Engineers - Part 2 - Making REST calls
Python for Network Engineers - Part 3 - Using Cisco Nexus NX-API
Python for Network Engineers - Part 4 - Using Arista EOS eAPI
Python for Network Engineers - Part 5 - Using Junos NETCONF interface
Python for Network Engineers - Part 6 - Using Cisco Nexus NETCONF interface
Python for Network Engineers - Part 7 - Using Palo Alto Networks XML API
Python for Network Engineers - Part 2 - Making REST calls
Python for Network Engineers - Part 3 - Using Cisco Nexus NX-API
Python for Network Engineers - Part 4 - Using Arista EOS eAPI
Python for Network Engineers - Part 5 - Using Junos NETCONF interface
Python for Network Engineers - Part 6 - Using Cisco Nexus NETCONF interface
Python for Network Engineers - Part 7 - Using Palo Alto Networks XML API
Cisco NX-API
For this example, I’m using a Cisco Nexus 7000 with NX-OS 7.2
and Ubuntu 16.04 Linux with Python. Please see the previous blog article (part2) for details of how to install the requests module
Cisco Setup
On the Nexus switch then all we have to do is the following
from the configuration prompt:
feature nxapi
If you wish to also use the NX-API sandbox, do the following additional command:
nxapi sandbox
you can now point a web browser at you nexus switch (i.e. http://10.1.1.1)
Python Bit
Next let’s open an interactive Python session and create a
REST connection to the Nexus switch. In
the first instance we’ll just run a show command. The “s” object is the session to the Nexus
switch and the “r” object is the response data.
import requests, json
uname = upass = 'admin'
uri = 'http://10.1.1.1/ins/'
s = requests.session()
s.auth = (uname,upass)
s.verify = False
s.headers.update({'Content-Type' :
'application/json'})
data = {'ins_api': {'chunk': '0',
'version': '1.2', 'sid': '1', 'input': 'show version', 'type': 'cli_show',
'output_format': 'json'}}
r = s.request('post', uri,
data=json.dumps(data))
As described in the previous blog we can now do some checks against the session and response data and see if it ran as expected:
s.cookies
r.status_code
r.text
r.headers
One thing to note is that in the response headers set a cookie and the requests library has automatically added it to the session data for future requests. Next we’ll look at the response data payload:
print json.dumps(r.json(),
indent=2)
print
json.dumps(r.json()['ins_api']['outputs'], indent=2)
Example 1
For the next example I’ll just make a small change to the
previous JSON payload and run the REST call again. This time I’ve also shown the output:
data['input'] = 'show vlan brief'
r = s.request('post', uri,
data=json.dumps(data))
print json.dumps(r.json()['ins_api']['outputs'],
indent=2)
{
"output": {
"msg": "Success",
"input": "show vlan brief",
"code": "200",
"body": {
"TABLE_vlanbriefxbrief": {
"ROW_vlanbriefxbrief": {
"vlanshowbr-vlanid":
16777216,
"vlanshowbr-vlanid-utf": 1,
"vlanshowbr-vlanname":
"default",
"vlanshowbr-vlanstate":
"active",
"vlanshowbr-shutstate":
"noshutdown"
}
}
}
}
}
As you can see on my switch there
is only the default vlan.
Example 2
For the next example we’ll add a new vlan. As this is a configuration command then we
need to update the JSON to reflect this
data['type'] = 'cli_conf'
data['input'] = 'vlan 99'
r = s.request('post', uri,
data=json.dumps(data))
print json.dumps(r.json()['ins_api']['outputs'],
indent=2)
{
"output": {
"msg": "Success",
"body": {},
"code": "200"
}
}
Now if we run the show command again (changing the JSON back to a show command) we can see the new VLAN has been created:
data['type'] = 'cli_show'
data['input'] = 'show vlan brief'
r = s.request('post', uri,
data=json.dumps(data))
print
json.dumps(r.json()['ins_api']['outputs'], indent=2)
{
"output": {
"msg": "Success",
"input": "show vlan brief",
"code": "200",
"body": {
"TABLE_vlanbriefxbrief": {
"ROW_vlanbriefxbrief": [
{
"vlanshowbr-vlanid":
16777216,
"vlanshowbr-vlanid-utf":
1,
"vlanshowbr-vlanname":
"default",
"vlanshowbr-vlanstate":
"active",
"vlanshowbr-shutstate":
"noshutdown"
},
{
"vlanshowbr-vlanid":
1660944384,
"vlanshowbr-vlanid-utf":
99,
"vlanshowbr-vlanname":
"VLAN0099",
"vlanshowbr-vlanstate":
"active",
"vlanshowbr-shutstate":
"noshutdown"
}
]
}
}
}
}
Example 3
In the last example, we ran a configuration command under the
global context. However what if we want
to run a command under a specific interface or other sub-prompt? In this example, we’ll show how to run these
commands using a semi-colon delimiter. To be clear we need to separate commands with a space, semi-colon and another space as shown in the example below:
data['type'] = 'cli_conf'
data['input'] = 'vlan 199 ; name
REST_API_TEST'
r = s.request('post', uri,
data=json.dumps(data))
print
json.dumps(r.json()['ins_api']['outputs'], indent=2)
{
"output": [
{
"msg": "Success",
"body": {},
"code": "200"
},
{
"msg": "Success",
"body": {},
"code": "200"
}
]
}
Now if we run the show command again (changing the JSON back to a show command) we can see the new VLAN has been created with the correct name:
data['type'] = 'cli_show'
data['input'] = 'show vlan brief'
r = s.request('post', uri,
data=json.dumps(data))
print
json.dumps(r.json()['ins_api']['outputs'], indent=2)
{
"output": {
"msg": "Success",
"input": "show vlan brief",
"code": "200",
"body": {
"TABLE_vlanbriefxbrief": {
"ROW_vlanbriefxbrief": [
{
"vlanshowbr-vlanid":
16777216,
"vlanshowbr-vlanid-utf":
1,
"vlanshowbr-vlanname":
"default",
"vlanshowbr-vlanstate":
"active",
"vlanshowbr-shutstate":
"noshutdown"
},
{
"vlanshowbr-vlanid":
1660944384,
"vlanshowbr-vlanid-utf":
99,
"vlanshowbr-vlanname":
"VLAN0099",
"vlanshowbr-vlanstate":
"active",
"vlanshowbr-shutstate":
"noshutdown"
},
{
"vlanshowbr-vlanid":
3338665984,
"vlanshowbr-vlanid-utf":
199,
"vlanshowbr-vlanname":
"REST_API_TEST",
"vlanshowbr-vlanstate":
"active",
"vlanshowbr-shutstate":
"noshutdown"
}
]
}
}
}
}
Recap
To conclude the basic JSON data structure for NX-OS is:
data = {'ins_api': {'chunk': '0',
'version': '1.2', 'sid': '1', 'output_format': 'json'}}
Then to run a show or a configuration command, add either of the following keys:
data['type'] = 'cli_show'
data['type'] = 'cli_conf'
And then add a key with the command or commands you wish to run:
data['input'] = 'show vlan brief'
data['input'] = 'vlan 199 ; name
REST_API_TEST'
So as long as you know what you want to do on the Cisco cli it's very straight forward to run this from a script, get a response code to say if it ran well and capture the output in a structured way to pull out individual parameters.
Resources
About the Author
The author of this blog works for Vanguard IT who provide a range of professional services and managed services
For more information go to https://vanguard-it.net
No comments:
Post a Comment