VMware {code} Community
EmmEff
Contributor
Contributor
Jump to solution

Anyone using suds (Python) SOAP client with vSphere Web Services?

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"?

Reply
0 Kudos
1 Solution

Accepted Solutions
stumpr
Virtuoso
Virtuoso
Jump to solution

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 )

Reuben Stump | http://www.virtuin.com | @ReubenStump

View solution in original post

Reply
0 Kudos
10 Replies
stumpr
Virtuoso
Virtuoso
Jump to solution

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 )

Reuben Stump | http://www.virtuin.com | @ReubenStump
Reply
0 Kudos
EmmEff
Contributor
Contributor
Jump to solution

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.

Reply
0 Kudos
stumpr
Virtuoso
Virtuoso
Jump to solution

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.

Reuben Stump | http://www.virtuin.com | @ReubenStump
Reply
0 Kudos
fruers
Contributor
Contributor
Jump to solution

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.

Reply
0 Kudos
EmmEff
Contributor
Contributor
Jump to solution

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.

Reply
0 Kudos
stumpr
Virtuoso
Virtuoso
Jump to solution

Very cool. When I get some down time I'll give your bindings a try. Looking forward to trying them out though.

Reuben Stump | http://www.virtuin.com | @ReubenStump
Reply
0 Kudos
stello
Contributor
Contributor
Jump to solution

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

Reply
0 Kudos
AndyThirtover
Contributor
Contributor
Jump to solution

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

Reply
0 Kudos
stumpr
Virtuoso
Virtuoso
Jump to solution

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. 

Reuben Stump | http://www.virtuin.com | @ReubenStump
Reply
0 Kudos
AndyThirtover
Contributor
Contributor
Jump to solution

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

Reply
0 Kudos