VimWrap
From IronPython Cookbook
The code for VMware convenience wrapper. see description in my blog for more details.
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).
import clr
clr.AddReference('VimService2005')
import VimApi
clr.AddReference('System.Web.Services')
import System.Web.Services
clr.AddReference('System.Xml')
import System.Xml
from System.Net import CookieContainer
#########################################################
# VimException
#########################################################
class VimException(Exception):
"""Extracts the relevant information from the soap exception thrown natively by VimApi"""
def __init__(self,e):
try:
self.msg = e.Message
self.name = 'GenericError'
self.element = None
for c in e.Detail.ChildNodes:
if isinstance(c,System.Xml.XmlElement):
self.name = c.Name
if self.name.endswith('Fault'):
self.name = self.name[:-5]
self.element = c
break
except Exception,err:
self.name = 'UnexpectedExceptionError'
def __str__(self):
return 'VimException(%s: %s)' % (self.name,self.msg)
#########################################################
# ServiceWrapper
#########################################################
class ServiceWrapper(object):
"""Convenience wrapper over VMware's VimService and ServiceContent classes.
Also designed to work naturally with the ManagedObject class.
"""
def __init__(self,url,user,pswd):
self.url = url
self.user = user
self.pswd = pswd
self.b_connected = False
self.service = VimApi.VimService(
Url = self.url,
CookieContainer = CookieContainer(),
)
self.service_instance = self.wrap(VimApi.ManagedObjectReference(
type="ServiceInstance",
Value="ServiceInstance",
))
def wrap(self,x):
if isinstance(x,VimApi.ManagedObjectReference):
return ManagedObject(x,self)
if isinstance(x,System.Array): # XXX - seems this is the only sequence type we need to handle
return [self.wrap(i) for i in x]
return x
def unwrap(self,x):
if isinstance(x,ManagedObject):
return x.moref
if isinstance(x,tuple): # XXX - seems this is the only sequence type we need to handle
return tuple(self.unwrap(i) for i in x)
return x
def connect(self):
content = self.service_instance.RetrieveServiceContent()
for propname in [p.Name for p in clr.GetClrType(VimApi.ServiceContent).GetProperties()]:
if propname in ['dynamicProperty','dynamicType']:
continue # these are boilerplate fields for SOAP protocol. ignore them
prop = getattr(content,propname)
obj = self.wrap(prop)
setattr(self,propname,obj)
self.b_connected = True
def login(self):
if not self.b_connected:
self.connect()
self.sessionManager.Login(self.user,self.pswd,None)
def invoke(self,moref,method_name,*a):
mth = getattr(self.service,method_name)
a = [self.unwrap(x) for x in a]
try:
res = mth(moref,*a)
except System.Web.Services.Protocols.SoapException, e:
raise VimException(e)
return self.wrap(res)
def get_property(self,moref,name):
# Create a filter spec with the specified object and property spec
fs = VimApi.PropertyFilterSpec()
# create a property spec (describes what we want retrieved)
ps = VimApi.PropertySpec()
ps.type = moref.type
ps.all = False
ps.pathSet = (name,)
fs.propSet = (ps,)
# the search starting point
os = VimApi.ObjectSpec()
os.obj = moref
fs.objectSet = (os,)
# run the query
raw_res = self.propertyCollector.RetrieveProperties((fs,))
# translate the result
if raw_res is None:
return None
propSet = raw_res[0].propSet
if propSet is None:
return None
res = propSet[0].val
return self.wrap(res)
#########################################################
# ManagedObject
#########################################################
class ManagedObject(object):
"""Object oriented wrapper over VMware's ManagedObjectReference (an opaque handle)"""
def __init__(self,moref,service):
self.moref = moref
self.service = service # service wrapper
def __repr__(self):
return '%s(%s)' % (self.moref.type,self.moref.Value)
def __getattr__(self,name):
if hasattr(self.service.service,name): # it's a method
def wrapped(*a):
return self.service.invoke(self.moref,name,*a)
wrapped.__name__ = name
return wrapped
else: # not a method - assume it's a property
try:
return self.service.get_property(self.moref,name)
except VimException, e:
if e.name == 'InvalidProperty':
raise AttributeError(name)
else:
raise
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)
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.stat
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.
Back to Contents.

