Friday, June 27, 2008

client side soap timeout

I was getting timeouts working with VMware API. Most of their commands that can take a long time have an async interface, but some don't, and I was getting frequent timeouts for one of the new commands I started using.

Took me a while to find out the timeout was actually coming from my .net soap proxy and not from the VMware at all.

Seems .net proxies have a client side timeout which is set to 1:40 minutes by default (100,000 msecs). Changing it is just a matter of setting the Timeout property on the proxy.

I still wish VMware would provide an async API for all their long commands, but now at least the problem shifts to making things run concurrently instead of not failing.

just in case I'm not the last person to have to figure this out...

Monday, June 9, 2008

Making VMware API friendlier

I've had very little time in the last week, and am expecting it to stay that way for the next few weeks :-(. Still, wanted to get this one out.

For the last year I've been working with VMware's ESX and VirtualCenter servers. The core product is great. The API for using it is, well, not as great...

For example, here's what you need to do if you have a managed object reference (a handle) to a virtual machine and want to get its name:
def get_name(vm_moref):
# Create a filter spec with object and property specs
fs = VimApi.PropertyFilterSpec()

# create a property spec (describes what we want retrieved)
ps = VimApi.PropertySpec()
ps.type = 'VirtualMachine'
ps.all = False
ps.pathSet = ('name',)
fs.propSet = (ps,)

# the search starting point
os = VimApi.ObjectSpec()
os.obj = vm_moref
fs.objectSet = (os,)

# run the query
# (assumes you have service object and property collector moref)
raw_res = service.RetrieveProperties(property_collector_moref,(fs,))

# translate the result
if raw_res is None:
return None
propSet = raw_res[0].propSet
if propSet is None:
return None
return propSet[0].val

yep, not so great :-(

In the .net parts of their 2.0 SDK they had a code generation tool written in XSLT that provided an object oriented wrapper over the basic API that was much more usable.
Unfortunately, with version 2.5 it seems to no longer be supported.

Luckily, it's pretty easy to write an equivalent wrapper in IronPython.
Here's an example usage:
from vimwrap import ServiceWrapper
svc = ServiceWrapper(url,user,pswd)
svc.login()

f = svc.searchIndex.FindByInventoryPath('.../my_folder')
print 'Folder: %s' % f
print 'Children:'
for child in f.childEntity:
print '\t%s: %s' % (child.name,child)

sample output (names and places changed to protect the innocent):
Folder: Folder(group-v205)
Children:
RonnieTest: Folder(group-v13059)
Staging: Folder(group-v12431)
Testing: Folder(group-v12432)
MockWin2k3: VirtualMachine(vm-12697)
Apache: VirtualMachine(vm-12603)
...

Here's another example - powering on a machine, and checking task progress:
vm =  svc.searchIndex.FindByInventoryPath('.../test_machine')
task = vm.PowerOnVM_Task(None)
ti = task.info # call VMware to get updated task info
print 'powering on... state=%s, progress=%s' % (ti.state,ti.progress)


The vimwrap module is about 150 lines of code. I put it on the ironpython cookbook.
The code works with API versions 2.0 and 2.5 (ESX 3.0 and 3.5 respectively) - just make sure you use the right version of the VimService2005 assembly (part of the SDK).
Let me know if you find this useful.

note of caution:

This is great for exploration and basic tasks. However, once you need to go over larger configurations, you will need to use methods like RetrieveProperties directly to get only the data you need and get all of it in one call. I suggest writing a wrapper for that API too - it's still much more complex and boilerplate than it needs to be.