Getting Started with pyControl
I've been dying to spend some time digging in to python, iControl, >M--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.
Mainif __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.
- L4L7_53191NimbostratusNice 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.
- e71joy_25623Nimbostratushi 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!
- JRahmAdminare you running pycontrol v1 or v2? This script here is v1.
- e71joy_25623Nimbostratushi jason,
- JRahmAdmincorrect. It'll need to be updated for pc2.
- JRahmAdminHmm, looks like I already did it a while back:
- ives_39316NimbostratusI 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. 
- JRahmAdminYep, should work fine. Need to pass a list of virtual servers to the get_statistics() method:
- ives_39316NimbostratusAh. 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.
- L4L7_53191NimbostratusGood work getting it going, glad you like pycontrol!