Using Python 2.4.3 with python-suds-0.3.9-1.el5, I am trying RetrieveServiceContent using the following code:
#!/usr/bin/env python from suds.client import Client import logging logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.DEBUG) logging.getLogger('suds.wsdl').setLevel(logging.DEBUG) url = 'https://192.168.0.111/sdk/vimService?wsdl' client = Client(url) client.set_options(location='https://192.168.0.111/sdk') o = client.factory.create('ns0:ManagedObjectReference') o._type = 'ServiceInstance' result = client.service.RetrieveServiceContent(o)
I am getting the following failure...
DEBUG:suds.client:http failed:
Since this is supposed to be an anonymous operation, why is it failing with "The session is not authenticated"?
So, I dug around.
Basically what I'm seeing is that Python suds doesn't really expect you to have an XML element with both an attribute and some node text.
For example, a RetrieveServiceContent call looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <RetrieveServiceContent xmlns="urn:vim25"><_this type="ServiceInstance">ServiceInstance</_this> </RetrieveServiceContent></soapenv:Body></soapenv:Envelope>
The suds call ends up looking like this:
<SOAP-ENV:Envelope xmlns:ns0="urn:vim25" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header></SOAP-ENV:Header> <ns1:Body> <ns0:RetrieveServiceContent> <ns0:_this type="ServiceInstance"></ns0:_this> </ns0:RetrieveServiceContent> </ns1:Body> </SOAP-ENV:Envelope>
It looks like you should be able to create your ManagedObjectReference like this:
o = client.factory.create('ns0:ManagedObjectReference') o._type = 'ServiceInstance' o.value = 'ServiceInstance'
However, it won't handle this for some reason. This does work:
o = Property('ServiceInstance') o._type = 'ServiceInstance' result = client.service.RetrieveServiceContent(o)
I think you may only hit this snag with the ManagedObjectReference suds object. But don't hold me too it. You'll have to custom create your managed object references to your calls using the Property class.
Here's a working example:
from suds.client import Client from suds.sudsobject import Property import logging logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.DEBUG) logging.getLogger('suds.wsdl').setLevel(logging.DEBUG) url = 'https://172.16.50.11/sdk/vimService?wsdl' client = Client(url) client.set_options(location='https://172.16.50.11/sdk') mo_ServiceInstance = Property('ServiceInstance') mo_ServiceInstance._type = 'ServiceInstance' result = client.service.RetrieveServiceContent(mo_ServiceInstance) mo_SessionManager = Property(result.sessionManager.value) mo_SessionManager._type = 'SessionManager' result = client.service.Login(mo_SessionManager, 'root', 'VMware1!') print "Login Time: {0}".format( result.loginTime )
So, I dug around.
Basically what I'm seeing is that Python suds doesn't really expect you to have an XML element with both an attribute and some node text.
For example, a RetrieveServiceContent call looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <RetrieveServiceContent xmlns="urn:vim25"><_this type="ServiceInstance">ServiceInstance</_this> </RetrieveServiceContent></soapenv:Body></soapenv:Envelope>
The suds call ends up looking like this:
<SOAP-ENV:Envelope xmlns:ns0="urn:vim25" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header></SOAP-ENV:Header> <ns1:Body> <ns0:RetrieveServiceContent> <ns0:_this type="ServiceInstance"></ns0:_this> </ns0:RetrieveServiceContent> </ns1:Body> </SOAP-ENV:Envelope>
It looks like you should be able to create your ManagedObjectReference like this:
o = client.factory.create('ns0:ManagedObjectReference') o._type = 'ServiceInstance' o.value = 'ServiceInstance'
However, it won't handle this for some reason. This does work:
o = Property('ServiceInstance') o._type = 'ServiceInstance' result = client.service.RetrieveServiceContent(o)
I think you may only hit this snag with the ManagedObjectReference suds object. But don't hold me too it. You'll have to custom create your managed object references to your calls using the Property class.
Here's a working example:
from suds.client import Client from suds.sudsobject import Property import logging logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.DEBUG) logging.getLogger('suds.wsdl').setLevel(logging.DEBUG) url = 'https://172.16.50.11/sdk/vimService?wsdl' client = Client(url) client.set_options(location='https://172.16.50.11/sdk') mo_ServiceInstance = Property('ServiceInstance') mo_ServiceInstance._type = 'ServiceInstance' result = client.service.RetrieveServiceContent(mo_ServiceInstance) mo_SessionManager = Property(result.sessionManager.value) mo_SessionManager._type = 'SessionManager' result = client.service.Login(mo_SessionManager, 'root', 'VMware1!') print "Login Time: {0}".format( result.loginTime )
Thank you so much for this! I am now able to proceed with my development.
I am running into what appears to be a similar issue when building a PropertyFilter.
The exception is as follows:
TypeNotFound: Type not found: '_type' Uncaught exception. Entering post mortem debugging Running 'cont' or 'step' will restart the program > /usr/lib/python2.4/site-packages/suds/mx/literal.py(87)start() -> raise TypeNotFound(content.tag) (Pdb) p content (Content){ tag = "_type" value = "PropertySpec" type = None } (Pdb)
The code to generate the PropertySpec object:
propspecary = propspecary[0]._type = 'PropertySpec' propspecary[0].all = False propspecary[0].type = 'ManagedEntity' propspecary[0].pathSet =
Since you mentioned having to do the Property() "trick" with only managed objects, I tried the following to no avail:
propspecary = [client.factory.create('ns0:PropertySpec')]
Sorry to be a bother, but can you shed some light on this? I am starting to think that rolling my own SOAP requests might make this more clear to me.
PropertySpec does not have an attribute called _type. The _type property was specific to the ManagedObjectReference.
You will need to leverage the Property trick I posted above for any ManagedObjectReference. You can use the client.factory.create method for the other VI SDK objects. I think our ManagedObjectReference is likely the only odd case.
Here's some more code (by the way, my Python isn't as rusty as I thought ;] )
from suds.client import Client from suds.sudsobject import Property import logging logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.DEBUG) logging.getLogger('suds.wsdl').setLevel(logging.DEBUG) url = 'https://172.16.50.25/sdk/vimService?wsdl' client = Client(url) client.set_options(location='https://172.16.50.25/sdk') mo_ServiceInstance = Property('ServiceInstance') mo_ServiceInstance._type = 'ServiceInstance' ServiceContent = client.service.RetrieveServiceContent(mo_ServiceInstance) mo_SessionManager = Property(ServiceContent.sessionManager.value) mo_SessionManager._type = 'SessionManager' SessionManager = client.service.Login(mo_SessionManager, 'administrator', 'VMware1!') print "Login Time: {0}".format( SessionManager.loginTime ) # Traversal Specs FolderTraversalSpec = client.factory.create('ns0:TraversalSpec') DatacenterVMTraversalSpec = client.factory.create('ns0:TraversalSpec') FolderSelectionSpec = client.factory.create('ns0:SelectionSpec') DatacenterVMSelectionSpec = client.factory.create('ns0:SelectionSpec') FolderSelectionSpec.name = "FolderTraversalSpec" DatacenterVMSelectionSpec.name = "DatacenterVMTraversalSpec" DatacenterVMTraversalSpec.name = "DatacenterVMTraversalSpec" DatacenterVMTraversalSpec.type = "Datacenter" DatacenterVMTraversalSpec.path = "vmFolder" DatacenterVMTraversalSpec.skip = True FolderTraversalSpec.name = "FolderTraversalSpec" FolderTraversalSpec.type = "Folder" FolderTraversalSpec.path = "childEntity" FolderTraversalSpec.skip = True DatacenterVMTraversalSpec.selectSet = [FolderSelectionSpec] FolderTraversalSpec.selectSet = [DatacenterVMSelectionSpec, FolderSelectionSpec] # Property Spec propSpec = client.factory.create('ns0:PropertySpec') propSpec.all = False propSpec.pathSet = propSpec.type = "VirtualMachine" # Object Spec mo_RootFolder = Property(ServiceContent.rootFolder.value) mo_RootFolder._type = 'Folder' objSpec = client.factory.create('ns0:ObjectSpec') objSpec.obj = mo_RootFolder objSpec.selectSet = [ FolderTraversalSpec, DatacenterVMTraversalSpec ] # PropertyFilterSpec propFilterSpec = client.factory.create('ns0:PropertyFilterSpec') propFilterSpec.propSet = [ propSpec ] propFilterSpec.objectSet = [ objSpec ] # RetrieveProperties mo_PropertyCollector = Property(ServiceContent.propertyCollector.value) mo_PropertyCollector._type = 'PropertyCollector' objContent = client.service.RetrieveProperties(mo_PropertyCollector, propFilterSpec) # print results def properties_to_dict(entity): props = {} props = entity.obj._type props = entity.obj.value for dynProp in entity.propSet: props[http://dynProp.name|http://dynProp.name] = dynProp.val return props virtual_machines = map(properties_to_dict, objContent) for vm in virtual_machines: print "Virtual Machine: {0} (PowerState: {1})".format(vm, vm)
Hopefully you won't hit too hard of a wall with TraversalSpecs, which can be a bit confusing if you haven't read through the Programming Guide or worked with them before.
You will find using the Perl SDK to be much easier. The view functions will abstract the TraversalSpecs and you won't have to work around the quirks of suds. But you may have a project requirement to use Python. You could also look into using JPython against the Java SDK. It isn't something I have tried, but I've been told it works.
In any event I tested the snippet above in my laptop lab (tm), so it should form a good foundation for moving your project forward on Python.
FORUM MANGLE WARNING:
Looks like the forum is mangling some of the code in the properties_to_dict function. I've attached the script as a text file so you can see the unedited version.
With stumpr's info on getting suds working with vSphere, I've started a project to provide Python bindings for the vSphere SDK.
Check it out:
http://jkinred.bitbucket.org/psphere/
It's pre-alpha but I think that it's a worthwhile project and any contributors would be welcome. Even what is already there will be a big help for anyone wanting to use Python to access the vSphere API.
Once again, thanks to stumpr for all the help! I've been working on other more pressing issues since but am hoping to get back to it.
I would certainly like to contribute to the vSphere Python bindings as well but don't have the time right now. It looks like a very useful project.
Very cool. When I get some down time I'll give your bindings a try. Looking forward to trying them out though.
Hi fruers,
I've developed a couple of years ago some python bindings for vSphere using ZSI (http://pywebsvcs.sourceforge.net/zsi.html). I wanted to try suds so I migrated part of my lib to use it for two main reasons:
1) ZSI project is not active since 2005, I even had to make some fixes to it and bundle it into my lib to make it work.
2) suds is more pythonistic, the code I got using it is shorter and much more legible.
3) I'm experiencing some issues with my lib when using threads.
However I found ZSI to be about 10 times faster, even providing suds with a local wsdl and enabling cache settings. E.g Loging In in a Virtual Center takes about 9 seconds using suds and less than 1 second with ZSI.
I believe the main reason is that ZSI supports code generation from a wsdl file so it doesn't need to generate objects and it's properties on runtime.
Any clues on how can I make suds work faster? Do you know if it is thread-safe?
Thanks!
Sebastian Tello
Dear Mr Stumpr
Did you go on to write psphere ?
Anyway, I've been trying to get suds to extract the ntp servers from an ESXi host without much luck.
Regards
Andy
No, that wasn't me. I did look over the project page and it looks good, I see they have a solution for getting specific entity properties. I haven't tried pshpere myself, however.
Thanks stumpr.
Actually psphere is pretty useful once one gets one's head round it. Thinking of changing the way it uses sys.exit()
have posted on jkinkred's bit bucket site, last known activity Oct 2011
Will stick with psphere for the moment.
Regards
Andy