Getting Started with pyControl

I've been dying to spend some time digging in to python, iControl, &GTM--why not combine all three into a single article?  Done.  This article will walk you through the iControl methods (in python, yea!) necessary to grab wideIP and pool statistics from the GTM.

Prerequisites

In order to use pyControl, you'll need to prepare your environment.  Obviously, you'll need python.  You'll also need the Zolera Soap Infrastructure (ZSI) and pyControl eggs.  For the detailed installation instructions (and the pyControl egg), head over to the pyControl Labs page.

GTM iControl Methods

In this initial article, we're going to stick with some basic methods, mostly because my python and iControl skills need work.  The methods we'll be tackling are:

  • get_list
  • get_object_status
  • get_all_statistics

Note that these methods exist in both the interfaces we'll access, GlobalLB::WideIP and GlobalLB::Pool.  This is great, as once we write the code for one, the other is easily adapted.  I highly recommend spending time combing the interfaces over in the online iControl SDK.  All the keywords necessary to extract the goodies are in there.

Firing up Python

I'm new to Python.  I still don't understand some most of the conventions.  This isn't to say Python isn't easy.  I just haven't put enough into it yet to make a judgement.  Anyway, I'm using Komodo Edit to write the code in, and iPython when working through issues with compilation or undesired outcomes, of which I had several of each.

The Main Loop

As I've seen in most of Joe's iControl script efforts, as well as other places, its common to keep the main loop fairly light and shift most of the processing out to functions.  To that end, I'll demonstrate the function approach, both locally within the script and calling the function from another file.  I'll put the wideip/pool status functions in another file that I'll import, and stats functions will remain in the script. 

Main
if __name__ == "__main__":
     import pycontrol.pyControl as pc
     from pycontrol.Utils import get_wideips, get_pools
     import getpass
     from sys import argv
     #Require Command-line arguments
     if len(argv) != 3:
          exit("Usage: GTMstats.py  ")
     host = argv[1]
     uname = argv[2]
     print "%s, enter your " % getpass.getuser(),
     upass = getpass.getpass()
     b = pc.BIGIP(
          hostname = host, 
          username   = uname, 
          password   = upass, 
          wsdl_files = ['GlobalLB.WideIP', 'GlobalLB.Pool']
          )
     w  = b.GlobalLB_WideIP
     p  = b.GlobalLB_Pool
     print "Fetching wideip info...\n"
     get_wideips(w)
     print "Fetching wideip stats...\n"
     get_wideip_stats(w)
     print "Fetching pool info...\n"
     get_pools(p)
     print "Fetching pool stats...\n"
     get_pool_stats(p) 

In the main loop, I've imported pyControl as pc, so when I call BIGIP, I can just use pc.BIGIP instead of pycontrol.pyControl.BIGIP.  It's just a shortcut, either is acceptable.  I've also created two functions I've moved to the Utils file called get_wideips & get_pools, so in order to use them, I imported them.  You'll note that I only imported those functions, not all of Utils, as only those two are necessary.  Same with argv from sys.  After collecting the hostname, username, & password, I define the BIGIP call and the wsdl files I want to load.  Since I only need methods from GlobalLB::WideIP and GlobalLB::Pool, there's no reason to load more.  After creating another shortcut for the interfaces (w & p), it's time to call some functions.

WideIP and Pool Status

 You'll notice that the functions below are remarkably similar.  In fact, except for comments, the get_object_status parameter, and printed value (WideIP or Pool), they are identical.  This should speed up development, once you've figured out the method call, repeating it just takes looking up the different parameters.  get_list returns a list of wideIPs, and get_object_status returns the availability status, the enabled status, and the status description.  The python zip function returns a list of parallel item tuples, which in my case marries wideIP to its status.

WideIP & Pool Status Functions

 

def get_wideips(obj):
     ''' Shows the wideips configured on the GTM '''
     try:
          wideips = obj.get_list()['return']
          status = obj.get_object_status(wide_ips = wideips)['return']
     except:
          "Unable to fetch wideip list or get status - check trace log"
     combined = zip(wideips,status)
     for x in combined:
          print "WideIP: ", x[0]
          print "\t",  x[1]['availability_status']
          print "\t",  x[1]['enabled_status']
          print "\t",  x[1]['status_description']
          print "\n"*2
def get_pools(obj):
     '''Shows the pools configured, LTM or GTM'''
     try:
          pools = obj.get_list()['return']
          status = obj.get_object_status(pool_names = pools)['return']
     except:
          "Unable to fetch pool list or get status - check trace log"
     combined = zip(pools, status)
     for x in combined:
          print "Pool: ", x[0]
          print "\t",     x[1]['availability_status']
          print "\t",     x[1]['enabled_status']
          print "\t",     x[1]['status_description']
          print "\n"*2

 

WideIP and Pool Statistics

Now that I know the statuses of the wideIPs and pools, I'll look at the statistics by calling the get_all_statistics method.  Again, you'll notice these functions are near identical, just a different parameter for a different interface.  Different in this function, however, is that I need a nested loop, one for the wideIPs, then one for each of the statistics within that wideIP.  Because the BIG-IP returns 64-bit values for statistics in the form of a high and low 32-bit structure, I need to extract those values from the (in python) dictionary, then do some bitwise operations (highlighted below) to return the true 64-bit value for each statistic.

WideIP & Pool Statistics Functions

 

def get_wideip_stats(obj):
     try:
          stats = obj.get_all_statistics()['return']
     except:
          "Unable to fetch wideip list or get statistics - check trace log"
     for x in stats['statistics']:
          print "WideIP: ", x['wide_ip']
          print "\n"*2
          for y in x['statistics']:
               value = y.get('value')
               high = value.get('high')
               low = value.get('low')
               value64 = (high<<32)|low
               print "\t", y.get('type') , value64
def get_pool_stats(obj):
     try:
          stats = obj.get_all_statistics()['return']
     except:
          "Unable to fetch pool list or get statistics - check trace log"
     for x in stats['statistics']:
          print "Pool: ", x['pool_name']
          print "\n"*2
          for y in x['statistics']:
               value = y.get('value')
               high = value.get('high')
               low = value.get('low')
               value64 = (high<<32)|low
               print "\t", y.get('type') , value64

 

And now that I have all the pieces in place, running the script results in the desired outcomes:

C:\dev\pyScripts>GTMstats.py 10.10.100.5 admin
jrahm, enter your Password:
 Loading WSDL: GlobalLB.WideIP.wsdl
Loading WSDL: GlobalLB.Pool.wsdl
Fetching wideip info...

WideIP:  test.wip.com
        AVAILABILITY_STATUS_RED
        ENABLED_STATUS_ENABLED
        Wide IP test.wip.com: No enabled pools available

 

Fetching wideip stats...

WideIP:  test.wip.com

 

        STATISTIC_GTM_WIDEIP_REQUESTS 39
        STATISTIC_GTM_WIDEIP_RESOLUTIONS 39
        STATISTIC_GTM_WIDEIP_PERSISTED 0
        STATISTIC_GTM_WIDEIP_PREFERRED_LB_METHODS 39
        STATISTIC_GTM_WIDEIP_ALTERNATE_LB_METHODS 0
        STATISTIC_GTM_WIDEIP_FALLBACK_LB_METHODS 0
        STATISTIC_GTM_WIDEIP_DROPPED_CONNECTIONS 0
        STATISTIC_GTM_WIDEIP_EXPLICIT_IP 0
        STATISTIC_GTM_WIDEIP_RETURN_TO_DNS 0
Fetching pool info...

Pool:  gpool2
        AVAILABILITY_STATUS_RED
        ENABLED_STATUS_ENABLED
        Pool gpool2: No enabled pool members available

 

Pool:  gpool1
        AVAILABILITY_STATUS_RED
        ENABLED_STATUS_ENABLED
        Pool gpool1: No enabled pool members available

 

Fetching pool stats...

Pool:  gpool2

 

        STATISTIC_GTM_POOL_PREFERRED_LB_METHODS 27
        STATISTIC_GTM_POOL_ALTERNATE_LB_METHODS 0
        STATISTIC_GTM_POOL_FALLBACK_LB_METHODS 0
        STATISTIC_GTM_POOL_DROPPED_CONNECTIONS 0
        STATISTIC_GTM_POOL_EXPLICIT_IP 0
        STATISTIC_GTM_POOL_RETURN_TO_DNS 0
Pool:  gpool1

 

        STATISTIC_GTM_POOL_PREFERRED_LB_METHODS 12
        STATISTIC_GTM_POOL_ALTERNATE_LB_METHODS 0
        STATISTIC_GTM_POOL_FALLBACK_LB_METHODS 0
        STATISTIC_GTM_POOL_DROPPED_CONNECTIONS 0
        STATISTIC_GTM_POOL_EXPLICIT_IP 0
        STATISTIC_GTM_POOL_RETURN_TO_DNS 0

Obviously not the cleanest look, and not that useful as is.  This is a foundation, however, that I can build upon to provide some quick and dirty real-time graphs.  Check back in as I work my way through the pyControl library.  The full script is available here in the codeshare.  Since I'm the only user with get_pools & get_wideips in the Utils.py file, I moved those functions back into the script in the codeshare and removed the import functions shown above.

 

Published May 27, 2009
Version 1.0
  • Nice work! I'm open to porting in any functions into the Utils module, so if there's interest in adding these it'll be no problem.

     

     

    -Matt
  • hi Matt, when i try to run the script on windows,i got an error messeage as below,please help me on this, thanks very much!

     

     

    >>> Fetching wideip info...

     

     

    Traceback (most recent call last): File "C:\Python27\GTMstats.py", line 128, in get_wideips(w) File "C:\Python27\GTMstats.py", line 44, in get_wideips combined = zip(wideips,status) UnboundLocalError: local variable 'wideips' referenced before assignment

     

     

     

     

    best regards, david

     

  • are you running pycontrol v1 or v2? This script here is v1.
  • hi jason,

     

    i'm runing pycontrol v2,so it won't be support that,all right? thanks!
  • I was just looking at using the LocalLB.VirtualServer.get_statistics() method, but it doesn't seem to return anything in the statistics object (where I'd expect a type of VirtualServerStatisticEntry):

     

     

    https://clouddocs.f5.com/api/icontrol-soap/LocalLB__VirtualServer__VirtualServerStatistics.html

     

    https://clouddocs.f5.com/api/icontrol-soap/LocalLB__VirtualServer__VirtualServerStatisticEntry.html

     

     

    I used virtual_server = 'x.x.x.x', where the stats were returned for that host when calling LocalLB.VirtualServer.get_all_statistics()

     

     

    Does this work in python 2.6 + suds + pycontrol2? Or am i missing something?

     

     

    Thanks to everyone who is supporting iControl and pycontrol2... it's full of awesomeness.

     

  • Yep, should work fine. Need to pass a list of virtual servers to the get_statistics() method:

     

     

    server_list = b.LocalLB.VirtualServer.get_list()

     

    server_stats = b.LocalLB.VirtualServer.get_statistics(virtual_servers = server_list)

     

     

  • Ah. that was the issue, forgot the list bracket around the single 'x.x.x.x', suds nor pycontrol seemed to complain that the virtual_servers parameter wasn't of type list.

     

     

    Thanks Jason.