Integrating vSphere and NSX API's with Python (1/2)

It is common knowledge that NSX has great orchestration capabilities when leveraging API's. Everything you can do via the GUI can be achieved through API calls, and further integrated into some scripts. If you plan to move down this road (and you should, really!!), there are two questions you may ask yourself:

  • How can I  manually test my API calls before wrapping them in a script?
  • What scripting language should I use?

The simplest way to test your API calls is to use a web browser add-on. I can recommend RESTClient for Firefox and Postman for Chrome. You just need a couple of steps before playing with the API's and messing up with your fresh NSX install. This is an example with RESTClient:

First, create your authentication credentials, ie. the admin user credentials for NSX Manager:

NSX_API_1

NSX_API_2

Then create custom headers to set application/xml as the MIME type for your requests:

NSX_API_3

NSX_API_4

OK, now let's try our first GET operation to check that NSX manager answers a basic request. We're just going to ask for some vCenter information:

NSX_API_5

The response includes some vCenter details, such as the IP address, the user name used for the registration as well as the SSL certificate thumbprint. (The comprehensive API documentation for NSX can be found here)

If you remember my Disaster Recovery scenario, we had a couple of tasks to achieve for the recovered VMs to get connectivity:

  1. Disconnect the Logical Switch in DC1.
  2. Create a new Logical Switch in DC2.
  3. Add one interface to a DLR in DC2, with the same IP address as previously used by the DLR that was connecting the Logical Switch in DC1. In this way, we don't have to change the default gateway of the recovered VMs.
  4. Connect this interface to the Logical Switch just created.
  5. Recover VMs in DC2.
  6. Connect VMs to the new Logical Switch.
  7. Boot VMs and test connectivity.
  8. Check route updates on the physical network.

My goal is to show you some Python snippets to perform these tasks. I'll be using pyVmomi for vSphere related tasks and the Requests library (here for full documentation) for REST API calls and NSX related tasks. PyVmomi is the Python wrapper for vSphere native APIs. It doesn't have any powerful high level methods like the Perl SDK, so you need to spend some time reading through the vSphere API documentation. But Shawn Hartsock (@hartsock) who maintains pyVmomi, is quite reactive if you still need information after visiting the github repository. Also, if you need some introduction to Python, I encourage you to visit Code Academy!

Please note that I won’t include any error catching in the scripts, as my goal is only to provide you with an introduction to pyVmomi and NSX API’s management. But feel free to improve the code and share back !

Install Requests and create a basic script

I'm assuming here that you've already installed Python 2.7.9. Then just use pip to install Requests:

$ pip install requests

The basic script you can create to perform the query we've made earlier with RESTClient is the following:


#!/usr/bin/env python

import requests

MANAGER = 'https://10.100.1.122'
USER = 'admin'
PASS = 'vmware'

rheaders = {'Content-Type': 'application/xml'}
r = requests.get(MANAGER + '/api/2.0/services/vcconfig’, auth = (USER, PASS), verify = False, headers = rheaders)
print r.text

You should get the same response as the response body returned by RESTClient:

<pre><code class=xml><?xml version=1.0 encoding=UTF-8?>
<vcInfo><ipAddress>10.100.1.113</ipAddress>
<userName>root</userName>
<certificateThumbprint>52:09:2D:2A:0D:D8:65:8C:67:63:4B:60:69:5F:9D:E5:4E:7D:66:2B</certificateThumbprint>
<assignRoleToUser><strong>false</assignRoleToUser>
<vcInventoryLastUpdateTime>1426272968570</vcInventoryLastUpdateTime>
</vcInfo>
</code></pre>
Disconnect a Logical Switch

To perform this task I'm just going to delete the interface of the DLR that is connected to the Logical Switch. The DELETE request would be:

NSX<em>API</em>9

Where Index=10 is the interface index of the DLR that is connected to the Logical Switch you want to recover at the second data center. To determine this index, you can use the following subsequent GET requests:

NSX<em>API</em>8
In the response body, locate the following:

<edgeSummary>
<objectId><strong>edge-11</objectId>
<objectTypeName>Edge</objectTypeName>
<vsmUuid>420849F0-39A6-21BE-3D8E-44827202CF25</vsmUuid>
<revision>131</revision>
<type>
<typeName>Edge</typeName>
</type>
<name><strong>DC1_lrouter</name>

This request allows you to find the DLR id corresponding to the name of the DLR you're looking for, e.g. edge-11.
Then you can execute:

NSX_API_10

In the response body, locate the Logical Switch name you’re interested in:

<interface>
<label>75649ae60000000a</label>
<name>int_net01</name>
<addressGroups>
<addressGroup>
<primaryAddress>192.168.0.254</primaryAddress>
<subnetMask>255.255.255.0</subnetMask>
<subnetPrefixLength>24</subnetPrefixLength>
</addressGroup>
</addressGroups>
<mtu>1500</mtu>
<type>internal</type>
<isConnected>true</isConnected>
<strong><index>10</index>
<connectedToId>virtualwire-1</connectedToId>
<connectedToName><strong>ls_vm_net01</connectedToName>
</interface>

This part helps you identify the interface that is connected to the Logical Switch you’re looking for, e.g 10. Once you've determined the interface index (index=10 in my case), you can integrate that in your Python script:

#!/usr/bin/env python

import requests

MANAGER = 'https://10.100.1.122'
USER = 'admin'
PASS = 'vmware'

rheaders = {'Content-Type': 'application/xml'}
r = requests.delete(MANAGER + '/api/4.0/edges/edge-11/interfaces/?index=10', auth = (USER, PASS), verify = False, headers = rheaders)
Create a new Logical Switch

This task requires a body in your POST request, with the following skeleton:

<virtualWireCreateSpec>
<Name><strong>drls_DC2_01</name>
<tenantId><strong>DC2</tenantId>
</virtualWireCreateSpec>

The tenant id is purely informative and doesn't really have any impact, so you can choose something explicit.

The POST syntax to create the Logical Switch is:

NSX<em>API</em>15

The required scope id (vdnscope-2 in my example)basically reprensents your transport zone. To get the corresponding id, you can perform the following GET request:

NSX<em>API</em>12

In the response body, look for the object id field that is located close to your transport zone name (u_z02 in my case), e.g. vdnscope-2

<interfaces>
<interface>
<Name>dr_interface_net_01</name>
<addressGroups>
<addressGroup>
<primaryAddress>192.168.0.254</primaryAddress>
<subnetMask>255.255.255.0</subnetMask>
</addressGroup>
</addressGroups>
<mtu>1500</mtu>
<type>internal</type>
<isConnected>true</isConnected>
<ConnectedToId>virtualwire-60</connectedToId>
</interface>
</interfaces><vdnScope>
<objectId>vdnscope-2</objectId>
<objectTypeName>VdnScope</objectTypeName>
<vsmUuid>420849F0-39A6-21BE-3D8E-44827202CF25</vsmUuid>
<revision>0</revision>
<type>
<typeName>VdnScope</typeName>
</type>
<name>u_z02</name>

We've now identified all the components we need to create our Python snippet. The whole body can be defined as a string variable in Python:


#!/usr/bin/env python

import requests

MANAGER = 'https://10.100.1.122'
USER = 'admin'
PASS = 'vmware'
xml_LS01 = '''
<virtualWireCreateSpec>
<name>drls_DC2_01</name>
<tenantId>DC2</tenantId>
</virtualWireCreateSpec>
'''

rheaders = {'Content-Type': 'application/xml'}
r = requests.delete(MANAGER + '/api/4.0/edges/edge-11/interfaces/?index=10', auth = (USER, PASS), verify = False, headers = rheaders)
r = requests.post(MANAGER + '/api/2.0/vdn/scopes/vdnscope-2/virtualwires', data = xml_LS01, auth = (USER, PASS), verify = False, headers = rheaders)
connectedToID = r.text

Create a DLR interface and connect it to the Logical Switch

This task requires a body in the POST request, with the following skeleton:

<interfaces>
<interface>
<Name>dr_interface_net_01</name>
<addressGroups>
<addressGroup>
<primaryAddress>192.168.0.254</primaryAddress>
<subnetMask>255.255.255.0</subnetMask>
</addressGroup>
</addressGroups>
<mtu>1500</mtu>
<type>internal</type>
<isConnected>true</isConnected>
<ConnectedToId>virtualwire-60</connectedToId>
</interface>
</interfaces>

The only thing we need to know from previous operations is the VXLAN backed port-group that our DLR interface is going to connect to. This is represented by the tag. You can easily identify the value of this variable as it's returned by the http response when creating the Logical Switch. (Hence the “connectedToID = r.text” as the last line of the previous snippet)

In addition, we need to know the POST request to create the DLR interface, which is:

NSX<em>API</em>13

Where "edge-13" represents the DLR id at the recovery site. It can be obtained by running the following GET request:

NSX<em>API</em>14

As previously, the response lists all DLR’s and ESG’s already created. You can find the corresponding id by looking for the tag a couple of lines before the name of the DLR you’re looking for, e.g. edge-13. This id is also accessible via the GUI, in the NSX Edges menu.

The corresponding Python code is the following:

#!/usr/bin/env python

import requests

MANAGER = 'https://10.100.1.122'
USER = 'admin'
PASS = 'vmware'
xml_LS01 = '''
<virtualWireCreateSpec>
<name>drls_DC2_01</name>
<tenantId>DC2</tenantId>
</virtualWireCreateSpec>
'''
dr_EdgeId = 'edge-13'

rheaders = {'Content-Type': 'application/xml'}
r = requests.delete(MANAGER + '/api/4.0/edges/edge-11/interfaces/?index=10', auth = (USER, PASS), verify = False, headers = rheaders)
r = requests.post(MANAGER + '/api/2.0/vdn/scopes/vdnscope-2/virtualwires', data = xml_LS01, auth = (USER, PASS), verify = False, headers = rheaders)
connectedToID = r.text

xml_Int = '''
    <interfaces>
    <interface>
    <name>dr_interface_net_01</name>
    <addressGroups>
    <addressGroup>
    <primaryAddress>192.168.0.254</primaryAddress>
    <subnetMask>255.255.255.0</subnetMask>
    </addressGroup>
    </addressGroups>
    <mtu>1500</mtu>
    <type>internal</type>
    <isConnected>true</isConnected>
    <connectedToId>''' + connectedToID + '''</connectedToId>
    </interface>
    </interfaces>
    '''

r = requests.post(MANAGER + '/api/4.0/edges/' + dr_EdgeId + '/interfaces/?action=patch', data = xml_Int, auth = (USER, PASS), verify = False, headers = rheaders)

I think this is enough for this post, I'll address the 4 last tasks, which are going to be more focused on pyVmomi, in my next article. Hopefully you're now a little bit more familiar with managing NSX API's through Python.

Comments

comments powered by Disqus