Forum Discussion

bknotwell_12713's avatar
bknotwell_12713
Historic F5 Account
May 29, 2004

the factory pattern and SOAP proxies

Writing numerous small shells to chat iControl with a BIGIP, I've ended up writing a

 

proxy factory object to make things more uniform.

 

 

I've always had tons of ugliness like so:

 

 

 
 from SOAPpy import SOAPProxy 
 SOAP.broken_href_workaround = 1 
  
 ns = 'urn:iControl:ITCMLocalLB/Global' 
 action = 'get_validate_l7_checksum' 
 url = 'https://uname:passwd@myhost/iControl/iControlPortal.cgi' 
 server = SOAPProxy(url,namespace=ns,soapaction=ns+""+action,noroot = 1) 
 

 

 

Let's face it, that's ugly the first time and gets progressively more heinous. There's two things that'll show up everytime--configuration information and corresponding proxy creation.

 

 

I'll explain the globally (ok, mostly global) applicable problem solution first--abstracting proxy creation with a ProxyFactory functor.

 

 

 
 from SOAPpy import SOAPProxy 
 from socket import gethostbyname,inet_aton 
  
 class ProxyFactory: 
     def __init__(self,user,passwd,address,proto='https'): 
         ''' 
            authentication information 
            address must be a straight-ip or succeed a host lookup 
  
            a functor to partially specialize a proxy 
         ''' 
         assert(user != '' and passwd != '' and proto in ['https','http']) 
         try: 
             inet_aton(address) 
         except: 
             try: 
                 address = gethostbyname(address) 
             except: 
                 raise 
  
         self.url = proto + '://' + user + ':' + passwd + '@' + address 
         self.url = self.url + '/iControl/iControlPortal.cgi' 
  
     def __call__(self,interface): 
         ''' 
           the interface (eg ITCMLocalLB/Global) 
         ''' 
         return SOAPProxy(self.url,namespace='urn:iControl:'+interface) 
 

 

 

After creating a ProxyFactory object, you call the object with the actual interface to create your object. It'd look something like this:

 

 

 
 from F5Proxy import ProxyFactory 
  
 myProxyFactory = ProxyFactory('a_user','a_passwd','mybigip.cooldomain.org') 
 myServicesProxy= myProxyFactory('ITCMSystem/Services') 
 mySystemInfoProxy = myProxyFactory('ITCMSystem/SystemInfo') 
 

 

 

Using the factory pattern, you've made your code cleaner. Particularly so if you need to access multiple interfaces in a single program.

 

 

Now, how do I keep from including configuration information all over my programs? Well, I normally work in an interpreter so I just do the following:

 

 

1) create an environment file (iControl.env for this example) that looks like so:

 

 

 
 user = 'myuser' 
 passwd = 'mypasswd' 
 host = '192.168.20.20' 
 protocol = 'http' 
 

 

 

2) have the interpreter compile/evaluate the file. NB: depending on your interpreter, you should have worries about namespacing. Since it's what I have on hand, I've included some relevant python code below:

 

 

 
 def loadEnv(filename,global_env,local_env): 
     '''  
        load a configuration file  
        called from your main program in the following manner: 
            
            loadEnv('myconfigfile',globals(),locals()) 
   
        This will add named varibles to your environment 
     ''' 
     codeObj = compile(open(filename).read(),'/dev/null','exec') 
     eval(codeObj,global_env,local_env) 
 

 

 

The previous function is called at the beginning of your main program in the following manner:

 

 

 
 loadEnv('./iControl.env',globals(),locals()) 
 

 

 

In this case, user,passwd,host and protocol will be added to my global namespace *as if I had defined them myself* in the current program.

 

 

As an aside, while the loadEnv code is shorter, it required far more thought to understand the relevant scoping. This is probably why the Lisp guys recommend avoiding eval.
No RepliesBe the first to reply