I imagine the progression for you, the reader, will be something like this in the first six- or seven-hundred milliseconds after reading the title: Oh cool! Wait, what? Don’t we already have like two libraries for python? Really, a third library for python? Yes. An emphatic yes. The first iteration of pycontrol (pc1) was based on the zsi library, which hasn’t been updated in years and was abandoned with the development of the second iteration, pycontrol v2 (pc2), which switched to the active and well-maintained suds library. Bigsuds, like pycontrol v2, is also based on the suds library. So why bigsuds? There are several advantages to using the bigsuds library.

No need to specify which WSDLs to download

In pycontrol v2, any iControl interface you wish to work with must be specified when you instantiate the BIG-IP, as well as specifying the local directory or loading from URL for the WSDLs. In bigsuds, just specify the host, username, and password (username and password optional if using test box defaults of admin/admin) and you’re good to go. Currently in pycontrol v2:

>>> import pycontrol.pycontrol as pc 
>>> b = pc.BIGIP( 
...     hostname = '192.168.6.11', 
...     username = 'admin', 
...     password = 'admin', 
...     fromurl = True, 
...     wsdls = ['LocalLB.Pool']) 
>>> b.LocalLB.Pool.get_list() 
[/Common/p1, /Common/p2, /Common/p3, /Common/p5] 

And here in bigsuds:

>>> import bigsuds 
>>> b = bigsuds.BIGIP(hostname = '192.168.6.11') 
>>> b.LocalLB.Pool.get_list() 
['/Common/p1', '/Common/p2', '/Common/p3', '/Common/p5'] 
>>> b.GlobalLB.Pool.get_list() 
['/Common/p2', '/Common/p1']

No need to define the typefactory for write operations.

This was the most challenging aspect of pycontrol v2 for me personally. I would get them correct sometimes. Often I’d bang my head against the wall wondering what little thing I missed to prevent success. The cool thing with bigsuds is you are just passing lists for sequences and lists of dictionaries for structures. No object creation necessary before making the iControl calls. It’s a thing of beauty.

Creating a two member pool in pycontrol v2:

lbmeth = b.LocalLB.Pool.typefactory.create('LocalLB.LBMethod')

# This is basically a stub holder of member items that we need to wrap up.
mem_sequence = b.LocalLB.Pool.typefactory.create('Common.IPPortDefinitionSequence')

# Now we'll create some pool members.
mem1 = b.LocalLB.Pool.typefactory.create('Common.IPPortDefinition')
mem2 = b.LocalLB.Pool.typefactory.create('Common.IPPortDefinition')

# Note how this is 'pythonic' now. We set attributes agains the objects, then
# pass them in.
mem1.address = '1.2.3.4'
mem1.port = 80

mem2.address = '1.2.3.4'
mem2.port = 81

# Create a 'sequence' of pool members.
mem_sequence.item = [mem1, mem2]

# Let's create our pool.
name = 'PC2' + str(int(time.time()))

b.LocalLB.Pool.create(pool_names = [name], lb_methods = \
        [lbmeth.LB_METHOD_ROUND_ROBIN], members = [mem_sequence])

In contrast, here is a two member pool in bigsuds.

>>> b.LocalLB.Pool.create_v2(['/Common/Pool1'],['LB_METHOD_ROUND_ROBIN'],[[{'port':80, 'address':'1.2.3.4'},{'port':81, 
'address':'1.2.3.4'}]])

Notice above that I did not use the method parameters. They are not required in bigsuds, though you can certainly include them. This could be written in the long form as:

>>> b.LocalLB.Pool.create_v2(pool_names = ['/Common/Pool1'],lb_methods = ['LB_METHOD_ROUND_ROBIN'], members = [[{'port':80, 'address':'1.2.3.4'},{'port':81, 
'address':'1.2.3.4'}]])

Standard python data types are returned

There’s no more dealing with data returned like this:

>>> p2.LocalLB.Pool.get_statistics(pool_names=['/Common/p2']) 
(LocalLB.Pool.PoolStatistics){ 
   statistics[] = 
      (LocalLB.Pool.PoolStatisticEntry){ 
         pool_name = "/Common/p2" 
         statistics[] = 
            (Common.Statistic){ 
               type = "STATISTIC_SERVER_SIDE_BYTES_IN" 
               value = 
                  (Common.ULong64){ 
                     high = 0 
                     low = 0 
                  } 
               time_stamp = 0 
            }, 
            (Common.Statistic){ 
               type = "STATISTIC_SERVER_SIDE_BYTES_OUT" 
               value = 
                  (Common.ULong64){ 
                     high = 0 
                     low = 0 
                  } 
               time_stamp = 0 
            },

Data is standard python types: strings, lists, dictionaries. That same data returned by bigsuds:

>>> b.LocalLB.Pool.get_statistics(['/Common/p1']) 
{'statistics': [{'pool_name': '/Common/p1', 'statistics': [{'time_stamp': 0, 'type': 'STATISTIC_SERVER_SIDE_BYTES_IN', 'value': {'high': 0, 'low': 0}}, {'time_stamp': 0, 'type': 'STATISTIC_SERVER_SIDE_BYTES_OUT', 'value': {'high': 0, 'low': 0}}

Perhaps not as readable in this form as with pycontrol v2, but far easier to work programmatically.

Better session and transaction support

George covered the benefits of sessions in his v11 iControl: Sessions article in fine detail, so I’ll leave that to the reader. Regarding implementations, bigsuds handles sessions with a built-in utility called with_session_id. Example code:

>>> bigip2 = b.with_session_id() 
>>> bigip2.System.Session.set_transaction_timeout(99) 
>>> print b.System.Session.get_transaction_timeout() 
5 
>>> print bigip2.System.Session.get_transaction_timeout() 
99

Also, with transactions, bigsuds has built-in transaction utilities as well. In the below sample code, creating a new pool that is dependent on a non-existent pool being deleted results in an error as expected, but also prevents the pool from the previous step from being created as show in the get_list method call.

>>> try: 
...     with bigsuds.Transaction(bigip2): 
...             bigip2.LocalLB.Pool.create_v2(['mypool'],['LB_METHOD_ROUND_ROBIN'],[[]]) 
...             bigip2.LocalLB.Pool.delete_pool(['nonexistent']) 
... except bigsuds.OperationFailed, e: 
...     print e 
... 
Server raised fault: 'Exception caught in System::urn:iControl:System/Session::submit_transaction() 
Exception: Common::OperationFailed 
        primary_error_code   : 16908342 (0x01020036) 
        secondary_error_code : 0 
        error_string         : 01020036:3: The requested pool (/Common/nonexistent) was not found.' 
>>> bigip2.LocalLB.Pool.get_list() 
['/Common/Pool1', '/Common/p1', '/Common/p2', '/Common/p3', '/Common/p5', '/Common/Pool3', '/Common/Pool2']

F5 maintained

Community member L4L7, the author of the pycontrol v2 library, is no longer with F5 and just doesn’t have the cycles to maintain the library going forward. Bigsuds author Garron Moore, however, works in house and will fix bugs and enhance as time allows. Note that all iControl libraries are considered experimental and are not officially supported by F5 Networks. Library maintainers for all the languages will do their best to fix bugs and introduce features as time allows. Source is provided though, and bugs can and are encouraged to be fixed by the community!

Installing bigsuds

Make sure you have suds installed and grab a copy of bigsuds (you’ll need to log in) and extract the contents. You can use the easy setup tools to install it to python’s site-packages library like this:

jrahm@jrahm-dev:/var/tmp$ tar xvfz bigsuds-1.0.tar.gz 
bigsuds-1.0/ 
bigsuds-1.0/setup.py 
bigsuds-1.0/bigsuds.egg-info/ 
bigsuds-1.0/bigsuds.egg-info/top_level.txt 
bigsuds-1.0/bigsuds.egg-info/requires.txt 
bigsuds-1.0/bigsuds.egg-info/SOURCES.txt 
bigsuds-1.0/bigsuds.egg-info/dependency_links.txt 
bigsuds-1.0/bigsuds.egg-info/PKG-INFO 
bigsuds-1.0/setup.cfg 
bigsuds-1.0/bigsuds.py 
bigsuds-1.0/MANIFEST.in 
bigsuds-1.0/PKG-INFO 
jrahm@jrahm-dev:/var/tmp$ cd bigsuds-1.0/ 
jrahm@jrahm-dev:/var/tmp/bigsuds-1.0$ python setup.py install

Doing it that way, you can just enter the python shell (or run your script) with a simple ‘import bigsuds’ command. If you don’t want to install it that way, you can just extract the bigsuds.py from the download and drop it in a directory of your choice and make a path reference in the shell or script:

>>> import bigsuds 
Traceback (most recent call last): 
  File "<stdin>", line 1, in <module> 
ImportError: No module named bigsuds 
>>> import sys 
>>> sys.path.append(r'/home/jrahm/dev/bigsuds-1.0') 
>>> import bigsuds 
>>>

Conclusion

Garron Moore's bigsuds contribution is a great new library for python users. There is work to be done to convert your pycontrol v2 samples, but the flexibility and clarity in the new library makes it worth it in this guy’s humble opinion. A new page in the iControl wiki has been created for bigsuds developments. Please check it out, community! For now, I’ve converted a few scripts to bigsuds, linked in the aforementioned page as well as directly below:

Comments on this Article
Comment made 09-Nov-2012 by mhite 509
Awesome news! Thanks.
0
Comment made 29-Aug-2013 by Brian Gibson 347
Jason,

Is the get_destination_v2 method in bigsuds? When I try to call it interactively I get the following...

Traceback (most recent call last):
File "", line 1, in
host.LocalLB.VirtualServer.get_destination_v2(Vertica-vs)
File "/usr/lib/python2.6/site-packages/bigsuds-1.0.1-py2.6.egg/bigsuds.py", line 364, in __getattr__
method = getattr(self._client.service, attr)
File "/usr/lib/python2.6/site-packages/suds/client.py", line 299, in __getattr__
return getattr(port, name)
File "/usr/lib/python2.6/site-packages/suds/client.py", line 403, in __getattr__
return getattr(m, name)
File "/usr/lib/python2.6/site-packages/suds/client.py", line 494, in __getattr__
return self[name]
File "/usr/lib/python2.6/site-packages/suds/client.py", line 507, in __getitem__
raise MethodNotFound, qn
MethodNotFound: Method not found: 'LocalLB.VirtualServer.LocalLB.VirtualServerPort.get_destination_v2'

1
Comment made 12-Nov-2013 by wcollins 4
@Brian Gibson

Not sure if this was answered -- This is probably a result of trying to utilize this with something older than BIG-IP_v11.0.0. Some of the older calls say 'depreciated' however they still work. You may want to use one of those.
0
Comment made 12-Nov-2013 by Brian Gibson 347
Yup. I was testing on a 10.2.4 machine and it was puking. Got it working. Thanks though!
-1
Comment made 25-Nov-2013 by Rich W. 28
Can BigSuds use local WSDLs like pycontrol2 did?
0
Comment made 25-Nov-2013 by Jason Rahm
yes, there is a cachedir option in the class definition:

def __init__(self, hostname, username='admin', password='admin',
debug=False, cachedir=None)
0
Comment made 25-Nov-2013 by Rich W. 28
Jason,

Thank you for taking the time to answer my question.

I read that in the code, but the comments seem to suggest that the "cachedir" param was for cache'ing WSDLs once they were downloaded from the device.

Did I read this wrong?

Thanks again.
0
Comment made 25-Nov-2013 by Jason Rahm
yes, that's true. however, I believe it works to store WSDLs offline there as well. Are you not seeing that behavior?
0
Comment made 25-Nov-2013 by Rich W. 28
I only saw BigSuds cache'ing the WSDLs per device and, according to the code, have a TTL of 1 day. Sometimes I have to plow through 600+ devices with versions ranging form 9.4 to 11.1.

My goal is to have a local set of up-to-date WSDLs that I could read once and use on all the devices. This would speed up execution time of my scripts since they wouldn't have to re-fetch/re-parse the WSDLs every time.

The F5 Ruby gem has a set of WSDLs, but the gem is using an out-of-date SOAP library for the currernt version of Ruby and only loads the WSDLs needed for the task.

I'm switching to Python because it seems to be much better supported and more widely used.

Thanks again for your help
0
Comment made 25-Nov-2013 by Jason Rahm
ok, let me check into this and get back to you.
0
Comment made 05-Dec-2013 by Phil Middleton 0
I guess I am still very novice with Python and with F5, for a school project I have to create a VIP, create/modify a LTM pool, etc. I was able to create/modify a LTM pool with bigsuds fairly easily but I am unsure of how to create a VIP with it. If possible could you provide some guidance?
0
Comment made 06-Dec-2013 by Jason Rahm
Hi Phil! With bigsuds, a sequence (in the API docs as []) is represented as a dictionary like so:

[{'key': 'val', 'key2': 'val2'}]

and a sequence-sequence (in the API docs as [][]) just wrapped in one more list:

[[{'key': 'val', 'key2': 'val2'}] ]

So to create a virtual server, either of these methods will work:

b.LocalLB.VirtualServer.create( \
definitions = [{'name': '/Common/vip10', 'address': '172.16.5.5', 'port': 80, 'protocol': 'PROTOCOL_TCP'}], \
wildmasks = ['255.255.255.255'], \
resources = [{'type': 'RESOURCE_TYPE_POOL', 'default_pool_name': '/Common/testpool'}], \
profiles = [[{'profile_context': 'PROFILE_CONTEXT_TYPE_ALL', 'profile_name': '/Common/tcp'}]] \
)

b.LocalLB.VirtualServer.create( \
[{'name': '/Common/vip11', 'address': '172.16.5.6', 'port': 80, 'protocol': 'PROTOCOL_TCP'}], \
['255.255.255.255'], \
[{'type': 'RESOURCE_TYPE_POOL', 'default_pool_name': '/Common/testpool'}], \
[[{'profile_context': 'PROFILE_CONTEXT_TYPE_ALL', 'profile_name': '/Common/tcp'}]] \
)

0
Comment made 06-Dec-2013 by Phil Middleton 0
Jason, this makes so much more sense now! Thank you, I really appreciate it!
0
Comment made 16-Jan-2014 by Rich W. 28
Will BigSuds work with legacy devices such as an old 3dns running v4?
0
Comment made 27-Mar-2014 by Matthias Gruber 0
Hi!

Quite nice, that lib, just seeking for some sort of API-Documentation?
Try to get Pool-Member on and offline

cheers
Matthias
0
Comment made 27-Mar-2014 by Matthias Gruber 0
All Fine, got it...
0
Comment made 02-May-2014 by Brian Gibson 347
Hi Jason,

So I'm trying to make sure I'm clear. In a situation like using create_user_3 the value you would submit is a would be adictionary(user, password, permissions,login_shell)?

So it would be something like

info = {"user":{"name":"Joe","fullname":"Joe Smith"},"password":{"isencrypted":"yes","[password":"12345"},"permissions":{"role":"admin","partition":"main"} }

These nested variables are tricky without knowing the syntax prior.
0
Comment made 02-May-2014 by JRahm
that's correct, you need a dictionary.
0
Comment made 18-Dec-2014 by aaaa 173
Hi Jason, Thank you for the article. I have followed the instructions and its been going great so far. Couple of questions though; How can i view Virtual Servers in multiple partitions, and not just Common? Will this https://devcentral.f5.com/wiki/iControl.APIReference.ashx be the right API reference to refer to for creating client scripts using the python bigsuds lib?
0
Comment made 06-Mar-2015 by arjunnambiartc 2
bigsuds does not have timeout parameter in its class definition and by default uses the suds 90 seconds timeout..it should be simple enough to add a timeout attribute..are there any plans to do this ?
0
Comment made 25-Mar-2015 by stpython 0
i've no idea about this --------------------------------------------------------------------------- ConnectionError Traceback (most recent call last) in () ----> 1 a.LocalLB.Pool.get_list() /home/vagrant/py279_f5/lib/python2.7/site-packages/bigsuds-1.0.1-py2.7.egg/bigsuds.pyc in __getattr__(self, attr) 311 if attr.startswith('__'): 312 return getattr(super(_Namespace, self), attr) --> 313 client = self._client_creator('%s.%s' % (self._name, attr)) 314 setattr(self, attr, client) 315 return client /home/vagrant/py279_f5/lib/python2.7/site-packages/bigsuds-1.0.1-py2.7.egg/bigsuds.pyc in _create_client(self, wsdl_name) 140 # One situation that raises TransportError is when credentials are bad. 141 except (urllib2.URLError, TransportError), e: --> 142 raise ConnectionError(str(e)) 143 return self._create_client_wrapper(client, wsdl_name) 144 ConnectionError:
0
Comment made 03-Apr-2015 by rmd1023 150
The LTM pool status script is great! How can I have it poll pools in all the partitions?
0
Comment made 26-May-2015 by Jason Antman 5
BigSuds has now been published to pypi, the Python software repository. Installing it is now as simple as "pip install bigsuds"
0
Comment made 08-Oct-2015 by felix001 13
Is there anyway to use bigsuds or icontrol to configure HA in v10.
0