Creating a Connection Object

We have the helper modules ready and fixed, so finally we are going to actually communicate with our load balancer via SOAP API.

Before we can continue, we need to import all our methods that we generated with wsdl2py:

import NSStat_services

Initializing the locator and service access objects is very simple and can be achieved with only two lines of code. First we're creating the actual Locator object, which contains information about the web service location:

locator = NSStat_services.NSStatServiceLocator()

Then we call the method that will return us the binding object, already initialized with service URL:

soap = locator.getNSStatPort()

The locator object has only two methods, one to read the URL from WSDL and another to initialize and return a binding object.

The binding object (in our example initialized as the variable soap) contains all methods that are available on our web service (in this instance Citrix Netscaler Statistics API). It acts like a proxy, mapping object methods to API functions.

Before we continue let's see how we can fix the Netscaler invalid URL issue. As you already know, you can interrogate the Locator object and request an endpoint URL. You can also force getNSStatPort to use a custom URL instead of the generated one. So what we are going to do is to get the URL, replace the bogus string with the IP of our load balancer, and then generate a binding object with the correct URL. Listing 2-10 shows the code.

Listing 2-10. Substituting the load balancer address MY_NS_IP = '192.168.1.1'

locator = NSStat_services.NSStatServiceLocator() bad_url = locator.getNSStatPortAddress()

good_url = re.sub('netscaler_ip', MY_NS_IP, bad_url) soap = locator.getNSStatPort(url=good_url)

As you can see, here I used the getNSStatPortAddress Locator method to retrieve the URL string, which I then modified using a regular expression and replaced the netscaler_ip string with the load balancer's IP. Finally I asked the Locator to create my SOAP binding object with my new (correct) URL.

This approach is more flexible than changing automatically generated module. If for whatever reason (an Ns OS upgrade would be one example) you decide to generate a new module, you will lose the changes that you have made. That other approach also requires you to remember that you have to change the code. Overriding the IP in the code that makes a request is more obvious, and will not interfere with other tools that might reuse the same helper modules.

So this was a quick way of creating our connection object, but how are we going to fit this into our required structure that we have defined earlier? Remember, we decided to have one generic class with initialization and logging facilities, and then derive two different classes from it: one for statistics and monitoring module and one for management and configuration module. You can see the class inheritance in the Figure 2-1 below.

Figure 2-1. Class inheritance diagram.

This poses an immediate problem, because we will need to use different Locator objects for each service, so we cannot initialize them in the NSSoapApi class, because we do not know what type of Locator object, Stat or Config, we will need to use.

The generic class needs to be able to identify which module it is supposed to use as a service locator, so I will pass a module object from NSStatApi or NSConfigApi as a parameter to NSSoapApi, which will then use this parameter to initialize the appropriate Locator and perform the login call using the specific module call. It may sound complicated, but it really isn't at all. Listing 2-11 shows the code that implements this.

Listing 2-11. Defining a generic class class NSSoapApi(object):

def __init__(self, module=None, hostname=None, username=None, password=None):

self.username = username self.password = password self.hostname = hostname self.module = module if self.module.__name__ == 'NSStat_services':

self.locator = self.module.NSStatServiceLocator() bad_url = self.locator.getNSStatPortAddress() good_url = re.sub('netscaler_ip', self.hostname, bad_url) self.soap = self.locator.getNSStatPort(url=good_url)

self.locator = self.module.NSConfigServiceLocator() bad_url = self.locator.getNSConfigPortAddress() good_url = re.sub('netscaler_ip', self.hostname, bad_url) self.soap = self.locator.getNSConfigPort(url=good_url)

else:

self.login()

req = self.module.login() req._username = self.username req._password = self.password [...]

This generic class expects a module object to be passed into it, so it can

• Call generic methods such as login directly from whichever module is passed

• Depending on the module, call specific methods or refer to module-specific classes, such as NSStatServiceLocator vs NSConfigServiceLocator

Our subclasses will pass the module object on to the superclass, as shown in Listing 2-12.

Listing 2-12. Passing a module object to a generic class class NSStatApi(NSSoapApi):

def __init__(self, hostname=None, username=None, password=None):

super(NSStatApi, self).__init__(hostname=hostname, username=username, password=password, module=NSStat_services)

class NSConfigApi(NSSoapApi):

def __init__(self, hostname=None, username=None, password=None):

super(NSConfigApi, self).__init__(hostname=hostname, username=username, password=password, module=NSConfig_services)

Was this article helpful?

0 0

Post a comment