Forum Discussion
bknotwell_12713
May 29, 2004Historic F5 Account
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
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects