I've been working with the iControl REST interface on a few different things trying to get comfortable with the new kid on the block. One of the things I really like about the SOAP interface is the clear definition of objects. Whether or not you want all the fields for a given object, you're going to get them. This is not the case with the REST interface. For default attributes on objects, the fields may not be returned. For example, with the self IP, the json data returned from the BIG-IP does not include the allowService attribute if the default of "none" is set.

 

#snippet of json data with default allowService setting
u'trafficGroup': u'/Common/traffic-group-local-only', u'unit': 0
#snippet of json data with non-default allowService setting
u'trafficGroup': u'/Common/traffic-group-local-only', u'allowService': u'all', u'unit': 0

If you are just printing the entire object, this is not a problem. But if your code is looking for a particular attribute and it is not there, it will fail. Unless, of course, you build in exception handling. This is not my strong suit as I write mostly throwaway scripts to meet a specific need. My first thought was just to go ahead and iterate through every key value pair and print them all. But I really only wanted to print the name, address, vlan, and services. So I got cute with some conditions and a boolean:

 

for k, v in x.items():
  if k == 'allowService':
    isPresent = True

if isPresent:
  print("\tName: %s\n\t\tAddress: %s\n\t\tVlan: %s\n\t\tAllow Service: %s\n" % (x['name'], x['address'], x['vlan'], x['allowService']))
else:
  print("\tName: %s\n\t\tAddress: %s\n\t\tVlan: %s\n\t\tAllow Service: none\n" % (x['name'], x['address'], x['vlan']))

This code iterates through all the keys and sets the variable to true if the key is present, then on the true condition for that variable, will print with the allow service present. This works fine, but is a little verbose and unnecessary. Instead, I can use the try/except method:

 

try:
  print("\tName: %s\n\t\tAddress: %s\n\t\tVlan: %s\n\t\tAllow Service: %s\n" % (x['name'], x['address'], x['vlan'], x['allowService']))
except Exception, e:
  print("\t%s" % e)
  print("\tName: %s\n\t\tAddress: %s\n\t\tVlan: %s\n\t\tAllow Service: none\n" % (x['name'], x['address'], x['vlan']))

This is a simple exception handling case that results in the following output (from the larger python function logic)

 

	'allowService'
	Name: self.rd10
		Address: 10.10.1.1%10/24
		Vlan: /Common/vlan_r10
		Allow Service: none

	Name: self.vmnet2
		Address: 192.168.100.5/24
		Vlan: /Common/vmnet2
		Allow Service: all

	Name: self.golgotha_net
		Address: 10.10.10.5/24
		Vlan: /Common/golgotha_net
		Allow Service: all

	Name: self.vmnet3
		Address: 192.168.101.5/24
		Vlan: /Common/vmnet3
		Allow Service: all

Notice that the only one to trigger on the exception is the self.rd10 self IP. Given that the information for the allow service is not returned, I fill that manually in the print string as none. For the other cases, there were no exceptions and so the code supplies the value from x['allowService'].

A few things to note about further use of the try/except logic in python should you want to investigate:

  • The except statement can be a generic and will handle all exceptions
  • Multiple except statements are allowed to handle specific exceptions like IOError or ValueError. The python docs site defines the built-in exceptions.
  • You can use an else condition to catch any unhandled error in your except statements, but this is generally frowned upon.
  • You can use a finally condition that will execute regardless. This cannot be used with the except blocks. It's either/or.

References