vrandom yet another random IT blog

NSX Python - Part 2 - Transport Zones - vdnScope

Overview

In this post we will create a helper function to retrieve the vdnScope’s in our environment. This is important as a large number of calls we make to NSX will require a ‘scopeId’.

vdnScope - aka Transport Zones

We are going to look at how to retrieve the scopeId for a given Transport Zone, and late store this in a helper function. First lets review the test script we created to list the Transport Zones when we setup our python environment:

from creds import *
from nsxramlclient.client import NsxClient
import pprint
pp = pprint.PrettyPrinter(indent=4)

nsxraml_file = 'nsxraml/nsxvapiv614.raml'
client_session = NsxClient(nsxraml_file, nsx_manager, nsx_username, nsx_password)

vdn_scopes = client_session.read('vdnScopes', 'read')
pp.pprint(vdn_scopes['body'])

What does this output when its run:

(venv) [alex@web01 nsxlab]$ python nsx_test.py 
{'vdnScopes': {'vdnScope': {'clientHandle': None,
                            'clusters': {'cluster': [{'cluster': {'clientHandle': None,
                                                                  'extendedAttributes': None,
                                                                  'isUniversal': 'false',
                                                                  'name': 'n54l',
                                                                  'nodeId': '4218115B-03A8-B552-9491-FCB8981E6E51',
                                                                  'objectId': 'domain-c21',
                                                                  'objectTypeName': 'ClusterComputeResource',
                                                                  'revision': '10',
                                                                  'scope': {'id': 'datacenter-2',
                                                                            'name': 'lab1',
                                                                            'objectTypeName': 'Datacenter'},
                                                                  'type': {'typeName': 'ClusterComputeResource'},
                                                                  'universalRevision': '0',
                                                                  'vsmUuid': '4218115B-03A8-B552-9491-FCB8981E6E51'}},
                                                     {'cluster': {'clientHandle': None,
                                                                  'extendedAttributes': None,
                                                                  'isUniversal': 'false',
                                                                  'name': 'gen8',
                                                                  'nodeId': '4218115B-03A8-B552-9491-FCB8981E6E51',
                                                                  'objectId': 'domain-c7',
                                                                  'objectTypeName': 'ClusterComputeResource',
                                                                  'revision': '22',
                                                                  'scope': {'id': 'datacenter-2',
                                                                            'name': 'lab1',
                                                                            'objectTypeName': 'Datacenter'},
                                                                  'type': {'typeName': 'ClusterComputeResource'},
                                                                  'universalRevision': '0',
                                                                  'vsmUuid': '4218115B-03A8-B552-9491-FCB8981E6E51'}}]},
                            'controlPlaneMode': 'UNICAST_MODE',
                            'description': None,
                            'extendedAttributes': None,
                            'id': 'vdnscope-1',
                            'isUniversal': 'false',
                            'name': 'lab1',
                            'nodeId': '4218115B-03A8-B552-9491-FCB8981E6E51',
                            'objectId': 'vdnscope-1',
                            'objectTypeName': 'VdnScope',
                            'revision': '0',
                            'type': {'typeName': 'VdnScope'},
                            'universalRevision': '0',
                            'virtualWireCount': '1',
                            'vsmUuid': '4218115B-03A8-B552-9491-FCB8981E6E51'}}}

Above you can see we have a Transport Zone named ‘lab1’ with a scopeId ‘vdnscope-1’. Let make our script output that information a little more nicely:

from creds import *
from nsxramlclient.client import NsxClient
import pprint
pp = pprint.PrettyPrinter(indent=1)

nsxraml_file = 'nsxraml/nsxvapiv614.raml'
client_session = NsxClient(nsxraml_file, nsx_manager, nsx_username, nsx_password)

vdn_scopes = client_session.read('vdnScopes', 'read')['body']
print "Transport Zone:", vdn_scopes['vdnScopes']['vdnScope']['name']
print "ID:", vdn_scopes['vdnScopes']['vdnScope']['id']
(venv) [alex@web01 nsxlab]$ python print_vdnscope.py 
Transport Zone: lab1
ID: vdnscope-1

Perfect, we’re done, that was easy! Err no… Unfortunately not, lets add another Transport Zone to our environment and re-run the script: vdn

(venv) [alex@web01 nsxlab]$ python print_vdnscope.py 
Transport Zone:
Traceback (most recent call last):
  File "print_vdnscope.py", line 10, in <module>
    print "Transport Zone:", vdn_scopes['vdnScopes']['vdnScope']['name']
TypeError: list indices must be integers, not str

Re-running the first pretty print script will reveal what has changed here:

(venv) [alex@web01 nsxlab]$ python nsx_test.py 
{'vdnScopes': {'vdnScope': [{'clientHandle': None,
                             'clusters': {'cluster': {'cluster': {'clientHandle': None,
                                                                  'extendedAttributes': None,
                                                                  'isUniversal': 'false',
                                                                  'name': 'gen8',
                                                                  'nodeId': '4218115B-03A8-B552-9491-FCB8981E6E51',
                                                                  'objectId': 'domain-c7',
                                                                  'objectTypeName': 'ClusterComputeResource',
                                                                  'revision': '24',
                                                                  'scope': {'id': 'datacenter-2',
                                                                            'name': 'lab1',
                                                                            'objectTypeName': 'Datacenter'},
                                                                  'type': {'typeName': 'ClusterComputeResource'},
                                                                  'universalRevision': '0',
                                                                  'vsmUuid': '4218115B-03A8-B552-9491-FCB8981E6E51'}}},
                             'controlPlaneMode': 'UNICAST_MODE',
                             'description': None,
                             'extendedAttributes': None,
                             'id': 'vdnscope-3',
                             'isUniversal': 'false',
                             'name': 'test1',
                             'nodeId': '4218115B-03A8-B552-9491-FCB8981E6E51',
                             'objectId': 'vdnscope-3',
                             'objectTypeName': 'VdnScope',
                             'revision': '0',
                             'type': {'typeName': 'VdnScope'},
                             'universalRevision': '0',
                             'virtualWireCount': '0',
                             'vsmUuid': '4218115B-03A8-B552-9491-FCB8981E6E51'},
                            {'clientHandle': None,
                             'clusters': {'cluster': [{'cluster': {'clientHandle': None,
                                                                   'extendedAttributes': None,
                                                                   'isUniversal': 'false',
                                                                   'name': 'n54l',
                                                                   'nodeId': '4218115B-03A8-B552-9491-FCB8981E6E51',
                                                                   'objectId': 'domain-c21',
                                                                   'objectTypeName': 'ClusterComputeResource',
                                                                   'revision': '12',
                                                                   'scope': {'id': 'datacenter-2',
                                                                             'name': 'lab1',
                                                                             'objectTypeName': 'Datacenter'},
                                                                   'type': {'typeName': 'ClusterComputeResource'},
                                                                   'universalRevision': '0',
                                                                   'vsmUuid': '4218115B-03A8-B552-9491-FCB8981E6E51'}},
                                                      {'cluster': {'clientHandle': None,
                                                                   'extendedAttributes': None,
                                                                   'isUniversal': 'false',
                                                                   'name': 'gen8',
                                                                   'nodeId': '4218115B-03A8-B552-9491-FCB8981E6E51',
                                                                   'objectId': 'domain-c7',
                                                                   'objectTypeName': 'ClusterComputeResource',
                                                                   'revision': '24',
                                                                   'scope': {'id': 'datacenter-2',
                                                                             'name': 'lab1',
                                                                             'objectTypeName': 'Datacenter'},
                                                                   'type': {'typeName': 'ClusterComputeResource'},
                                                                   'universalRevision': '0',
                                                                   'vsmUuid': '4218115B-03A8-B552-9491-FCB8981E6E51'}}]},
                             'controlPlaneMode': 'UNICAST_MODE',
                             'description': None,
                             'extendedAttributes': None,
                             'id': 'vdnscope-1',
                             'isUniversal': 'false',
                             'name': 'lab1',
                             'nodeId': '4218115B-03A8-B552-9491-FCB8981E6E51',
                             'objectId': 'vdnscope-1',
                             'objectTypeName': 'VdnScope',
                             'revision': '2',
                             'type': {'typeName': 'VdnScope'},
                             'universalRevision': '0',
                             'virtualWireCount': '3',
                             'vsmUuid': '4218115B-03A8-B552-9491-FCB8981E6E51'}]}}

vdn vdnScope has changed to return a list not a dictionary. Armed with this information lets change our script to check whether ‘vdnScopes’ is a list or a dictionary and process them accordingly:

from creds import *
from nsxramlclient.client import NsxClient
import pprint
pp = pprint.PrettyPrinter(indent=1)

nsxraml_file = 'nsxraml/nsxvapiv614.raml'
client_session = NsxClient(nsxraml_file, nsx_manager, nsx_username, nsx_password)

vdn_scopes = client_session.read('vdnScopes', 'read')['body']
if not isinstance(vdn_scopes['vdnScopes']['vdnScope'], list):
    print "Only one Transport Zone"
    print "Transport Zone:", vdn_scopes['vdnScopes']['vdnScope']['name']
    print "ID:", vdn_scopes['vdnScopes']['vdnScope']['id']
else:
    print "Multiple Transport Zones"
    for tz in vdn_scopes['vdnScopes']['vdnScope']:
        print "Transport Zone:", tz['name']
        print "ID:", tz['id']

Result:

(venv) [alex@web01 nsxlab]$ python print_all_vdnscope.py 
Multiple Transport Zones
Transport Zone: test1
ID: vdnscope-3
Transport Zone: lab1
ID: vdnscope-1
(venv) [alex@web01 nsxlab]$ python print_all_vdnscope.py 
Only one Transport Zone
Transport Zone: lab1
ID: vdnscope-1

So now we’re handling whether multiple or single vdnScope’s are returned.

Making it useful

Lets turn this simple script into some re-usable code. Firstly lets decide what we’ll want our code to do:

  • Return a list of all vdnScope ID’s and names
  • Search for vdnScope ID by name
from creds import *
from nsxramlclient.client import NsxClient
import pprint
pp = pprint.PrettyPrinter(indent=1)

nsxraml_file = 'nsxraml/nsxvapiv614.raml'
client_session = NsxClient(nsxraml_file, nsx_manager, nsx_username, nsx_password)

def all_vdn_scopes(client_session):
    scopes = []
    vdn_scopes = client_session.read('vdnScopes', 'read')['body']
    if not isinstance(vdn_scopes['vdnScopes']['vdnScope'], list):
        print "all_vdn_scopes: Only one Transport Zone"
        print "all_vdn_scopes: Transport Zone:", vdn_scopes['vdnScopes']['vdnScope']['name']
        print "all_vdn_scopes: ID:", vdn_scopes['vdnScopes']['vdnScope']['id']
        scopes.append(  {
                'id': vdn_scopes['vdnScopes']['vdnScope']['id'],
                'name': vdn_scopes['vdnScopes']['vdnScope']['name'],
                })
    else:
        print "all_vdn_scopes: Multiple Transport Zones"
        for tz in vdn_scopes['vdnScopes']['vdnScope']:
            print "all_vdn_scopes: Transport Zone:", tz['name']
            print "all_vdn_scopes: ID:", tz['id']
            scopes.append(  {
                    'id': tz['id'],
                    'name': tz['name'],
                    })
    return scopes

def get_vdn_scope(client_session, name):
    vdn_scopes = client_session.read('vdnScopes', 'read')['body']
    if not isinstance(vdn_scopes['vdnScopes']['vdnScope'], list):
        print "get_vdn_scope: Only one Transport Zone"
        if vdn_scopes['vdnScopes']['vdnScope']['name'] == name:
            return  {
                'id': vdn_scopes['vdnScopes']['vdnScope']['id'],
                'name': vdn_scopes['vdnScopes']['vdnScope']['name'],
                }
    else:
        print "get_vdn_scope: Multiple Transport Zones"
        for tz in vdn_scopes['vdnScopes']['vdnScope']:
            if tz['name'] == name:
                return  {
                    'id': tz['id'],
                    'name': tz['name'],
                    }
    return None

all = all_vdn_scopes(client_session)
lab1 = get_vdn_scope(client_session, "lab1")
lab2 = get_vdn_scope(client_session, "lab2")
test1 = get_vdn_scope(client_session, "test1")


print "***Results***"
print "all_vdn_scopes:"
pp.pprint(all)
print "get_vdn_scope lab1:"
pp.pprint(lab1)
print "get_vdn_scope lab2:"
pp.pprint(lab2)
print "get_vdn_scope test1:"
pp.pprint(test1)

What have we done here?

Firstly we’ve created a function called ‘all_vdn_scopes’ which retrieves all Transport Zones defined in NSX, and returns a list of dictionaries with the ‘id’ and ‘name’ of the Zone.

Secondly we’ve created a ‘get_vdn_scope’ function, this retrieves all the Transport Zones defined in NSX, then returns the first which matches the ‘name’ argument passed to it. It uses the same dictionary format as the previous function (but returns a single entry, not a list)

Okay, so what does that give us when we run it?

(venv) [alex@web01 nsxlab]$ #with only one transport zone
(venv) [alex@web01 nsxlab]$ python vdnscope.py 
all_vdn_scopes: Only one Transport Zone
all_vdn_scopes: Transport Zone: lab1
all_vdn_scopes: ID: vdnscope-1
get_vdn_scope: Only one Transport Zone
get_vdn_scope: Only one Transport Zone
get_vdn_scope: Only one Transport Zone
***Results***
all_vdn_scopes:
[{'id': 'vdnscope-1', 'name': 'lab1'}]
get_vdn_scope lab1:
{'id': 'vdnscope-1', 'name': 'lab1'}
get_vdn_scope lab2:
None
get_vdn_scope test1:
None
(venv) [alex@web01 nsxlab]$ #with two transport zones
(venv) [alex@web01 nsxlab]$ python vdnscope.py 
all_vdn_scopes: Multiple Transport Zones
all_vdn_scopes: Transport Zone: lab2
all_vdn_scopes: ID: vdnscope-5
all_vdn_scopes: Transport Zone: lab1
all_vdn_scopes: ID: vdnscope-1
get_vdn_scope: Multiple Transport Zones
get_vdn_scope: Multiple Transport Zones
get_vdn_scope: Multiple Transport Zones
***Results***
all_vdn_scopes:
[{'id': 'vdnscope-5', 'name': 'lab2'}, {'id': 'vdnscope-1', 'name': 'lab1'}]
get_vdn_scope lab1:
{'id': 'vdnscope-1', 'name': 'lab1'}
get_vdn_scope lab2:
{'id': 'vdnscope-5', 'name': 'lab2'}
get_vdn_scope test1:
None

vdn

So now we have two functions, all_vdn_scopes and get_vdn_scope which we can use to return our data in a consistent form. Lets split the above into two files:

  • vdnscope.py - this will contain the above functions and is where we will add other functions relating to Transport Zones
  • part2.py - this will be the script we execute, it will call the functions from vdnscope.py

vdnscope.py:

def all_vdn_scopes(client_session):
    scopes = []
    vdn_scopes = client_session.read('vdnScopes', 'read')['body']
    if not isinstance(vdn_scopes['vdnScopes']['vdnScope'], list):
        print "all_vdn_scopes: Only one Transport Zone"
        print "all_vdn_scopes: Transport Zone:", vdn_scopes['vdnScopes']['vdnScope']['name']
        print "all_vdn_scopes: ID:", vdn_scopes['vdnScopes']['vdnScope']['id']
        scopes.append(  {
                'id': vdn_scopes['vdnScopes']['vdnScope']['id'],
                'name': vdn_scopes['vdnScopes']['vdnScope']['name'],
                })
    else:
        print "all_vdn_scopes: Multiple Transport Zones"
        for tz in vdn_scopes['vdnScopes']['vdnScope']:
            print "all_vdn_scopes: Transport Zone:", tz['name']
            print "all_vdn_scopes: ID:", tz['id']
            scopes.append(  {
                    'id': tz['id'],
                    'name': tz['name'],
                    })
    return scopes

def get_vdn_scope(client_session, name):
    vdn_scopes = client_session.read('vdnScopes', 'read')['body']
    if not isinstance(vdn_scopes['vdnScopes']['vdnScope'], list):
        print "get_vdn_scope: Only one Transport Zone"
        if vdn_scopes['vdnScopes']['vdnScope']['name'] == name:
            return  {
                'id': vdn_scopes['vdnScopes']['vdnScope']['id'],
                'name': vdn_scopes['vdnScopes']['vdnScope']['name'],
                }
    else:
        print "get_vdn_scope: Multiple Transport Zones"
        for tz in vdn_scopes['vdnScopes']['vdnScope']:
            if tz['name'] == name:
                return  {
                    'id': tz['id'],
                    'name': tz['name'],
                    }
    return None

part2.py:

from creds import *
from vdnscope import *
from nsxramlclient.client import NsxClient
import pprint
pp = pprint.PrettyPrinter(indent=1)

nsxraml_file = 'nsxraml/nsxvapiv614.raml'
client_session = NsxClient(nsxraml_file, nsx_manager, nsx_username, nsx_password)

all = all_vdn_scopes(client_session)
lab1 = get_vdn_scope(client_session, "lab1")
lab2 = get_vdn_scope(client_session, "lab2")
test1 = get_vdn_scope(client_session, "test1")

print "***Results***"
print "all_vdn_scopes:"
pp.pprint(all)
print "get_vdn_scope lab1:"
pp.pprint(lab1)
print "get_vdn_scope lab2:"
pp.pprint(lab2)
print "get_vdn_scope test1:"
pp.pprint(test1)

results

You’ll see we get the exact same output, however we’ve moved out Transport Zone related functions into a re-usable python module. I’ve left all the debug print statements in there to help visualise what calls are being made, but you’d want to remove them in your project once you’re satisfied your code is working.

 Summary

In this post we have learnt how to explore the Transport Zones definied in NSX, and in doing so have created some re-usable functions which we will use when calling other NSX function in later posts.

References

FIN