Hi
I know this topic has been discussed quite a lot recently, but unfortunately I haven't been able to find a solution to my problem. I am currently running ESX Server 3.5. I have no problems accessing it via the SDK using Java and Perl. However, I am trying to get a simple C++ program working that can connect to it and do something useful. First of all, I changed the proxy.xml file on the ESX Server so that the sdk can be accessed via both http and https.
Second, on my client machine (64-bit AMD Athlon running Ubuntu 8.10) I have installed gsoap-2.7 to convert the WSDL files into stubs necessary to communicate with the server. I use the various gsoap programs to convert the vimService.wsdl file in the directory SDK/wsdl/vim/ as follows:
wsdl2h -x -s vimService.wsdl
soapcpp2 -i -C -I/home/ashok/gsoap-2.7/gsoap/import vimService.h
This generates soapH.h, soapStub.h, soapC.cpp, as well as soapVimBindingProxy.{h,cpp}.
Here is my simple test.cpp driver program that tries to access the ESX Server and create a snapshot of one of the VMs (note that I've specified http and not https in the URL):
-
#include "soapH.h"
#include "VimBinding.nsmap"
#include "soapVimBindingProxy.h"
int main() {
VimBindingProxy service;
service.soap_endpoint = "http://<server ip address>:443/sdk";
ns2__ManagedObjectReference mor;
ns2__CreateSnapshotRequestType req;
ns2_CreateSnapshotResponse resp;
req._USCOREthis = &mor;
req.name = "ashok_linux_1";
req.memory = false;
req.quiesce = false;
if (service.CreateSnapshot(&req, &resp) == SOAP_OK) {
std::cout << "OK"<< std::endl;
}
else
}
-
I compile this and run as follows:
g++ *.cpp -Wall -DWITH_OPENSSL -lgsoap++
ashok@ashok-desktop: ./a.out
BAD
Error -1 fault: SOAP-ENV:Client
"End of file or no input: Connection reset by peer"
The message "Error -1 fault: SOAP-ENV:Client " is something that I always get, regardless of the SDK function that I invoke. Has anyone figured out this problem, specifically using the C++ stub functions auto-generated by gsoap? If so, please tell me what I'm doing wrong as I'm close to pulling my hair out!
Ashok
I think I'm going to write up a tutorial for C++ & gsoap to get people started. I got a working setup that will build libraries and use the advanced C++ proxy option. This generates more OO like code that (in my opinion) reads and is easier to code with. I'll post it up in this thread if I do get to it this week.
First thing is you'll need to login first. You won't be able to call most of the functions in the SDK until you do.
You'll also need to keep the compile flags consistent for all the objects. You'll need at least -DWITH_COOKIES. Without cookies you'll end up with permission errors as you end up regenerating a new SessionID for each call.
Can you also post up all the steps in your compile process? It wasn't clear if you compiled and linked in your soapC.
Here's a very simple example you can work from. I don't call a login in this one, but you can use it to get a working program and start to build on it. It does use SSL so you can see how that's handled.
#include "soapVimBindingProxy.h"
#include "VimBinding.nsmap"
#include <time.h>
#include <iostream>
#include <typeinfo>
using namespace std;
void sigpipe_handle(int x) { cout << "sigpipe: " << x << endl; }
int main(int argc, char* argv[])
{
VimBinding vim;
ns1__ManagedObjectReference ManagedObjectRef;
ns1__RetrieveServiceContentRequestType RetrieveServiceContentReq;
_ns1__RetrieveServiceContentResponse RetrieveServiceContentRes;
ns1__ServiceContent *ServiceContent;
ns1__AboutInfo *AboutInfo;
if (argc != 2)
{
cout << "Usage: " << argv[0] << " <service url>" << endl;
exit(1);
}
string service_url(argv[1]);
vim.endpoint = service_url.c_str();
soap_ssl_init();
if (soap_ssl_client_context(
vim.soap,
SOAP_SSL_NO_AUTHENTICATION,
NULL,
NULL,
NULL,
NULL,
NULL ))
{
cout << "SSL:";
soap_print_fault(vim.soap, stderr);
soap_done(vim.soap);
soap_end(vim.soap);
exit(1);
}
ManagedObjectRef.__item = "ServiceInstance";
ManagedObjectRef.type = new string("ServiceInstance");
RetrieveServiceContentReq._USCOREthis = &ManagedObjectRef;
if ( vim.__ns1__RetrieveServiceContent(&RetrieveServiceContentReq, &RetrieveServiceContentRes) == SOAP_OK )
{
cout << "RetrieveServiceContent - OK" << endl;
}
else
{
delete ManagedObjectRef.type;
soap_print_fault(vim.soap,stderr);
soap_done(vim.soap);
soap_end(vim.soap);
exit(1);
}
ServiceContent = RetrieveServiceContentRes.returnval;
if (ServiceContent && ServiceContent->about)
{
AboutInfo = ServiceContent->about;
cout << "fullName: " << AboutInfo->fullName << endl;
cout << " name: " << AboutInfo->name << endl;
cout << " build: " << AboutInfo->build << endl;
cout << " version: " << AboutInfo->version << endl;
cout << " apiType: " << AboutInfo->apiType << endl;
cout << " productLineId: " << AboutInfo->productLineId << endl;
}
delete ManagedObjectRef.type;
soap_done(vim.soap);
soap_end(vim.soap);
return 0;
}
Thank you very much for your response. I am looking forward to reading your C++/gsoap "Getting Started" tutorial. I will try working with the template code you provided, but I first tried adding login capability to my original test program. My program (test.cpp) now looks like this:
-
#include :443/sdk";
// Invoke Login API
ns2__LoginRequestType login_request;
ns2_LoginResponse login_response;
login_request._USCOREthis = &mor;
login_request.userName = "root";
login_request.password = "";
if (service.Login(&login_request, &login_response) == SOAP_OK) {
std::cout << "login ok" << std::endl;
}
else
// Invoke RetrieveServiceContent API
ns2__RetrieveServiceContentRequestType service_request;
ns2_RetrieveServiceContentResponse service_response;
service_request._USCOREthis = &mor;
if (service.RetrieveServiceContent(&service_request, &service_response) == SOAP_OK)
else
}
-
This is how I compiled the code:
ashok@ashok-desktop:g++ -DWITH_OPENSSL -DWITH_COOKIES test.cpp soapC.cpp soapVimBindingProxy.cpp /home/ashok/gsoap-2.7/gsoap/stdsoap2.cpp -lssl -lcrypto
Unfortunately, I get both "not ok" messages when I run the executable. Looking at this code, is it obvious to you what I'm not doing correctly?
Thanks
Ashok
You'll need your ServiceContent first. You'll need it for most of the method calls against the SDK and should get it first. You also need to do a bit more setup on the ManagedObject reference.
You should setup the ManagedObjectReference with the "ServiceInstance" string. I updated it below. Call this before the login, you'll need the ServiceContent response for login.
// Invoke RetrieveServiceContent API
ns2__RetrieveServiceContentRequestType service_request;
_ns2__RetrieveServiceContentResponse service_response;
mor.__item = "ServiceInstance";
mor.type = new string("ServiceInstance");
service_request._USCOREthis = &mor;
if (service.RetrieveServiceContent(&service_request, &service_response) == SOAP_OK)
{
std::cout << "retrieve ok" << std::endl;
}
else
{
std::cout << "retrieve not ok" << std::endl;
service.soap_print_fault(stdout);
}
delete mor.type;
The login function is from the SessionManager object, so you'll need that to set up your Login call:
ns2__ServiceContent *ServiceContent;
ServiceContent = service_response.returnval;
// Invoke Login API
ns2__LoginRequestType login_request;
_ns2__LoginResponse login_response;
login_request._USCOREthis = ServiceContent->sessionManager;
login_request.userName = "root";
login_request.password = "<my root passwd>";
if (service.Login(&login_request, &login_response) == SOAP_OK)
{
std::cout << "login ok" << std::endl;
}
else
{
std::cout << "login not ok" << std::endl;
service.soap_print_fault(stdout);
}
I finally got your test program (from your prior post) to build and run properly. Thanks so much for your help! In case anyone is interested, here are the exact sequence of steps I took to get things working. Note that I have installed both gsoap-2.7 and the VI SDK in my home directory /home/ashok:
1) Copy over the vim25 WSDL file:
cp /home/ashok/vi_sdk/SDK/wsdl/vim25/vim.wsdl .
2) Build .h and .cpp files from WSDL:
wsdl2h -o vim25.h vim.wsdl
soapcpp2 -x -C vim25.h -I/home/ashok/gsoap-2.7/gsoap/import
3) Put test program in file test.cpp
4) Build executable:
g++ -DWITH_OPENSSL -DWITH_COOKIES test.cpp soapC.cpp soapClient.cpp /home/ashok/gsoap-2.7/gsoap/stdsoap2.cpp -lssl -lcrypto
5) Run executable
ashok@ashok-desktop:~/vi_gsoap$ ./a.out https://:443/sdk
RetrieveServiceContent - OK
fullName: VMware ESX Server 3.5.0 build-123630
name: VMware ESX Server
build: 123630
version: 3.5.0
apiType: HostAgent
productLineId: esx
I can use the property collector to get the ManagedObjectReference corresponding to a specific VirtualMachine. However, I'm having trouble getting the MOR corresponding to a snapshot of the VM. Given the name of a VM and the name of a snapshot within the VM, could you please tell me the general algorithm I need to follow to get a hold of the ManagedObjectReference for this snapshot?
Thanks
Ashok
If you're getting your VM ManagedObject from RetrieveProperties, you should also just get the snapshot property. The currentSnapshot from this property will have a ManagedObjectReference to the snapshot. You can use this to the snapshot task methods or you can RetrieveProperties again to get the snapshot info.
I might be able to get you some code examples in a bit.
Stumpr
Sorry to bother you with more questions. So I have no problems using the PropertyCollector to iterate over all the VirtualMachine objects. For each VM object, I can easily grab the Snapshot MORs associated with it as well as get info about all the virtual disk files that comprise the VM. What I would like to do now is to use the PropertyCollector to iterate over all the Datastore objects and for each Datastore, find out which VirtualMachines map to the datastore. I took your original traversal code and modified it slightly (I changed the datacenter traversal path and propertyspec type). My changes are marked with ***:
-
FolderTraversalSelectionSpec.name = new string("FolderTraversalSpec");
DataCenterVMTraversalSelectionSpec.name = new string("DataCenterVMTraversalSpec");
DataCenterVMTraversalSpec.name = new string("DataCenterVMTraversalSpec");
DataCenterVMTraversalSpec.type = "Datacenter";
DataCenterVMTraversalSpec.path = "datastoreFolder"; ***
DataCenterVMTraversalSpec.skip = &xsd_true;
FolderTraversalSpec.name = new string("FolderTraversalSpec");
FolderTraversalSpec.type = "Folder";
FolderTraversalSpec.path = "childEntity";
FolderTraversalSpec.skip = &xsd_true;
DataCenterVMTraversalSpec.selectSet.push_back(&FolderTraversalSelectionSpec);
FolderTraversalSpec.selectSet.push_back(&DataCenterVMTraversalSelectionSpec);
FolderTraversalSpec.selectSet.push_back(&FolderTraversalSelectionSpec);
PropertySpec.type = "Datastore"; ***
PropertySpec.all = &xsd_true; ***
ObjectSpec.obj = ServiceContent->rootFolder;
ObjectSpec.skip = &xsd_true;
ObjectSpec.selectSet.push_back(&FolderTraversalSpec);
ObjectSpec.selectSet.push_back(&DataCenterVMTraversalSpec);
PropertyFilterSpec.propSet.push_back(&PropertySpec);
PropertyFilterSpec.objectSet.push_back(&ObjectSpec);
RetrievePropertiesReq._USCOREthis = ServiceContent->propertyCollector;
RetrievePropertiesReq.specSet.push_back(&PropertyFilterSpec);
-
When I invoke the RetrieveProperties function:
if ( vim.__ns1__RetrieveProperties(&RetrievePropertiesReq, &RetrievePropertiesRes) == SOAP_OK )
the ESX server responds with a fault:
SOAP 1.1 fault: "":ServerFaultCode
""
Detail:
Is this something you have seen before?
Thanks
Ashok
I don't think there is a folder for the Datastore. You will probably need to just do your call to get the Datacenter object(s) and then enumerate their datastores...using the string "datastoreFolder" is likely the cause of your serverFaultCode.
FolderTraversalSelectionSpec.name = new string("FolderTraversalSpec");
DataCenterVMTraversalSelectionSpec.name = new string("DataCenterVMTraversalSpec");
DataCenterVMTraversalSpec.name = new string("DataCenterVMTraversalSpec");
DataCenterVMTraversalSpec.type = "Datacenter";
DataCenterVMTraversalSpec.path = "vmFolder"; // Change this back
DataCenterVMTraversalSpec.skip = &xsd_true;
FolderTraversalSpec.name = new string("FolderTraversalSpec");
FolderTraversalSpec.type = "Folder";
FolderTraversalSpec.path = "childEntity";
FolderTraversalSpec.skip = &xsd_true;
DataCenterVMTraversalSpec.selectSet.push_back(&FolderTraversalSelectionSpec);
FolderTraversalSpec.selectSet.push_back(&DataCenterVMTraversalSelectionSpec);
FolderTraversalSpec.selectSet.push_back(&FolderTraversalSelectionSpec);
PropertySpec.type = "Datacenter"; // Change this to Datacenter
PropertySpec.all = &xsd_false; // Change this to false, just get the Datastore property -- will be faster
PropertySpec.pathSet.push_back("name"); // Get the name in case you have multiple datacenters in your inventory
PropertySpec.pathSet.push_back("datastore"); // Get the datastore property
ObjectSpec.obj = ServiceContent->rootFolder;
ObjectSpec.skip = &xsd_true;
ObjectSpec.selectSet.push_back(&FolderTraversalSpec);
ObjectSpec.selectSet.push_back(&DataCenterVMTraversalSpec);
PropertyFilterSpec.propSet.push_back(&PropertySpec);
PropertyFilterSpec.objectSet.push_back(&ObjectSpec);
RetrievePropertiesReq._USCOREthis = ServiceContent->propertyCollector;
RetrievePropertiesReq.specSet.push_back(&PropertyFilterSpec);
You can read up on TraversalSpecs in the VI SDK Programming guide. I sort of take the lazy method of just using a sort of 'generic all' TraversalSpec, but you'll want to review it to understand what inventory objects you can query that way.
What will really start to drive you crazy is when you have to deal with the DynamicProperty data type you get back from your calls. You'll end up with a lot of conditional code using either dynamic_cast or typeid calls. I've been thinking of creating a class, say Entity, that would parse the properties data and build a hash_map similar to how the perl toolkit get_view* and find_entity_view* calls work.
Thank you very much. I'll give this a try and let you know what happens. What I find confusing is that when I access the MOB for my ESX server over the web, I see that the Datacenter object type has a property called 'datastoreFolder' and the value of this property is 'ha-folder-datastore'.
One other thing: I have created 2 VMs on two different ESX servers -- one runs ESX Server 3.5 and the other runs the 4.0 Beta. I can successfully issue a PowerOn command to the ESX 4.0 server using the call: vim->__ns1__PowerOnVM(&powerOnReq, &powerOnRes) (where the powerOnReq object contains a pointer to the VM MOR corresponding to the VM I created). However, when I issue the same command to the ESX 3.5 server, I get the SOAP_FAULT error that I reported previously:
SOAP 1.1 fault: "":ServerFaultCode no subcode
""
Detail:
I am certain I am accessing the VM MOR properly on the ESX 3.5 server because I can print out the correct properties of this machine. I just can't power it on/off, take snapshots, etc. Do you have any idea why the 3.5 server won't allow me to issue these commands? Could it be some kind of permission issue?
ashok
Could be, do you have full admin rights on 3.5?
Hi Ashok,
Let me try to understand what you did with the ESX server, you call the following line of code but supplied a MOR to your host. Am I right?
vim->__ns1__PowerOnVM(&powerOnReq, &powerOnRes)
If so, you for sure got the error message. Basically the PowerOnVM is only applicable for the virtual machine managed object. If you want to power on a host, you want to use... Wait a second, you cannot power on a host using VI SDK at all. But if you want to power it off, then you can use ShutdownHost_Task() method. Check out more @ http://pubs.vmware.com/vi-sdk/visdk250/ReferenceGuide/vim.HostSystem.html
Final note, if you use higher level API like VI Java API, you will not get this problem at all. The compile will enforce the type checking. Find it more at http://vijava.sf.net.
Steve JIN, VMware Engineering
Creator of VMware Infrastructure Java(Jython) API. VI Java API 2.0 --- 15 times faster than AXIS in loading, 4+ faster in deserialization; only 1/4 of the size required by AXIS. More importantly, the freedom to redistribute it with your applications. (Download, Samples, DocWiki, RSS Feed)
Get Connected with Other Developers in the Community?
I didn't get that impression. He stated he had a moref from a VM he created (and used it to populate his PowerOnReq object), then got a fault only when trying to power on the VM on an ESX 3.5 server, his beta 4 worked properly. If it isn't a permission issue Ashok, post up some code. Might be able to see if there is anything off in the call.
I wasn't sure what he did... You are right, sharing more code definitely helps.
Steve JIN, VMware Engineering
Creator of VMware Infrastructure Java(Jython) API. VI Java API 2.0 --- 15 times faster than AXIS in loading, 4+ faster in deserialization; only 1/4 of the size required by AXIS. More importantly, the freedom to redistribute it with your applications. (Download, Samples, DocWiki, RSS Feed)
Get Connected with Other Developers in the Community?
Steve and stumpr:
(stumpr: what is your real name by the way?)
I am attaching the small test program that I've been using to power on / power off a specified VM. To recap, I can use this program to manipulate a VM on an ESX 4.0 beta server, but not a VM on an ESX 3.5 server. I am pretty certain that this has nothing to do with permissions on the 3.5 server. The reason for this is that I can powerOn/powerOff a VM on the ESX 3.5 machine using the Java sample program VMpowerOps.java, but I cannot do this with my C++ program. In both programs, I login using the same username ("root") and password.
Here is the command I issue to get the Java program working (note that I use the "--ignorecert" option):
ashok@ashok-ubuntu-vm:~/vi_sdk/SDK/samples/Axis/java$ ./run.sh com.vmware.samples.vm.VMpowerOps --url https:// --vmname ashok_linux_1 --operation poweroff --ignorecert
./run.sh: 48: pushd: not found
RUNNING
Started
Powering off virtualmachine 'ashok_linux_1'
Virtual Machine ashok_linux_1 powered off successfuly
Ended VMpowerOps
Why would the powerOn/powerOff operation work correctly from the Java application, but not the C++ app?
It's sort of an issue with the gsoap code generation, but I found an answer after a comparing a few packet captures.
So there are actually two functions created after parsing the VMware vim25 wsdl matching PowerOnVM. One is the PowerOnVM function you used. However, this will send the method name to the VIM instance as PowerOnVM which is the VIM service returns as unsupported. This in turn generates the fault code you were seeing.
There is another function, PowerOnVM_USCORETask. You'll need to use this version (and I suspect you'll need it for every _Task function). This will create the soap envelope with the function name as the VIM service expects.
I'm guessing that Beta 4 either is supports both (or just PowerOnVM).
It's actually an easy fix.
Update your powerVM function to match the following: (I put a "This line has changed" comment at the end of each line I changed)
static void
powerVM(VimBinding* vim, ns1__ServiceContent* serviceContent,
string vm_name, bool powerOn) {
ns1__ManagedObjectReference* vm_mor =
getVMManagedObjectRef(vim, serviceContent, vm_name);
if (powerOn) {
// Power-on the Virtual Machine.
ns1__PowerOnVMRequestType powerOnReq;
_ns1__PowerOnVM_USCORETaskResponse powerOnRes; // This line is changed
powerOnReq._USCOREthis = vm_mor;
if (vim->__ns1__PowerOnVM_USCORETask(&powerOnReq, &powerOnRes) == SOAP_OK) { // This line is changed
cout << "PowerOn of VM " << vm_name << " successful" << endl << endl;
}
else {
cout << "PowerOn of VM " << vm_name << " unsuccessful" << endl << endl;
soap_print_fault(vim->soap,stderr);
soap_done(vim->soap);
soap_end(vim->soap);
exit(1);
}
}
else {
// Power-off the Virtual Machine.
ns1__PowerOffVMRequestType powerOffReq;
_ns1__PowerOffVM_USCORETaskResponse powerOffRes; // This line is changed
powerOffReq._USCOREthis = vm_mor;
if (vim->__ns1__PowerOffVM_USCORETask(&powerOffReq, &powerOffRes) == SOAP_OK) { // This line is changed
cout << "PowerOff of VM " << vm_name << " successful" << endl << endl;
}
else {
cout << "PowerOff of VM " << vm_name << " unsuccessful" << endl << endl;
soap_print_fault(vim->soap,stderr);
soap_done(vim->soap);
soap_end(vim->soap);
exit(1);
}
}
}
I just verified that using the PowerOnVM_USCORETask function on the ESX 3.5 server works fine, thanks for your help! I will let you know if I run into any problems with the datastore object retrieval.
I'm curious as to why gsoap generates both PowerOnVM and PowerOnVM_USCORETask functions. It seems that we should always use the latter function. When would one use the former?
Ashok
Well, both are defined in the WSDL. In fact, the PowerOnVM worked for Beta 4 right?
They may have it in there as a place holder or just not have gotten around to implementing that version on the server side. Don't know. Does the PowerOnVM_Task work on Beta 4 as well? I don't have a b4 system to test against.
Stumpr is right that both methods are there in the WSDL. In the API ref, you only see the *_Task version. Please stick with the *_Task() since the * version may go away.
Steve JIN, VMware Engineering
Creator of VMware Infrastructure Java(Jython) API. VI Java API 2.0 --- 15 times faster than AXIS in loading, 4+ faster in deserialization; only 1/4 of the size required by AXIS. More importantly, the freedom to redistribute it with your applications. (Download, Samples, DocWiki, RSS Feed)
Get Connected with Other Developers in the Community?
Hi,
I have followed the same steps listed in this thread to traverse Managed objects to get the list of VMs in my C++ client with gsoap.
Login happened successfully. But RetrieveProperties() is returning zero objects.
(I am using ESX server 3.5.)
The following message appears in /var/log/vmware/hostd.log, whenever I run my client.
Event 10 : User root@127.0.0.1 logged in
_FetchPropertyPath got unexpected error of type N3Vim5Fault16NotAuthenticated9ExceptionE: vim.fault.NotAuthenticated, for ref=ha-folder-root, path=childEntity
Throw vim.fault.NotAuthenticated
(vim.fault.NotAuthenticated) {
dynamicType =
using namespace std;
struct soap *soap;
ostringstream server;
void sigpipe_handle(int x) {
cout << "sigpipe: " << x << endl;
}
int getCurrentVMMob(sduvisdk2__ServiceContent *ServiceContent) {
sduvisdk2__TraversalSpec DatacenterToVmFolderTraversalSpec, FolderToChildEntityTraversalSpec;
sduvisdk2__SelectionSpec DatacenterToVmFolderSelectionSpec, FolderToChildEntitySelectionSpec;
sduvisdk2__PropertySpec propertySpec;
sduvisdk2__ObjectSpec objectSpec;
sduvisdk2__PropertyFilterSpec propertyFilterSpec;
sduvisdk2__DynamicProperty dynamicProperty;
sduvisdk2__RetrievePropertiesRequestType retrievePropertiesReq;
sduvisdk2_RetrievePropertiesResponse retrievePropertiesRes;
sduvisdk2__ManagedObjectReference* vm_mor = NULL;
bool xsd_true = 1;
bool xsd_false = 0;
FolderToChildEntitySelectionSpec.name = new string("DatacenterToVmFolderTraversalSpec");
DatacenterToVmFolderSelectionSpec.name = new string("FolderToChildEntityTraversalSpec");
DatacenterToVmFolderTraversalSpec.name = new string("DatacenterToVmFolderTraversalSpec");
DatacenterToVmFolderTraversalSpec.type = "Datacenter";
DatacenterToVmFolderTraversalSpec.path = "vmFolder";
DatacenterToVmFolderTraversalSpec.skip = &xsd_true;
FolderToChildEntityTraversalSpec.name = new string("FolderToChildEntityTraversalSpec");
FolderToChildEntityTraversalSpec.type = "Folder";
FolderToChildEntityTraversalSpec.path = "childEntity";
FolderToChildEntityTraversalSpec.skip = &xsd_true;
DatacenterToVmFolderTraversalSpec.selectSet.push_back(&FolderToChildEntitySelectionSpec);
FolderToChildEntityTraversalSpec.selectSet.push_back(&DatacenterToVmFolderSelectionSpec);
FolderToChildEntityTraversalSpec.selectSet.push_back(&FolderToChildEntitySelectionSpec);
propertySpec.type = "VirtualMachine";
propertySpec.all = &xsd_false;
propertySpec.pathSet.push_back("name");
objectSpec.obj = ServiceContent->rootFolder;
objectSpec.skip = &xsd_true;
objectSpec.selectSet.push_back(&FolderToChildEntityTraversalSpec);
objectSpec.selectSet.push_back(&DatacenterToVmFolderTraversalSpec);
propertyFilterSpec.propSet.push_back(&propertySpec);
propertyFilterSpec.objectSet.push_back(&objectSpec);
retrievePropertiesReq._USCOREthis = ServiceContent->propertyCollector;
retrievePropertiesReq.specSet.push_back(&propertyFilterSpec);
soap_call___sduvisdk2__RetrieveProperties(soap, server.str().c_str(), "",
&retrievePropertiesReq, &retrievePropertiesRes);
if (soap->error) {
soap_print_fault(soap, stderr);
goto end_of_function;
}
cout << "Retrieved Properties: " << retrievePropertiesRes.returnval.size() << "\n";
for (unsigned int i = 0; i < retrievePropertiesRes.returnval.size(); i++) {
dynamicProperty = *retrievePropertiesRes.returnval[i]->propSet[0];
assert(dynamicProperty.name == "name");
xsd__string* name = (xsd__string*) dynamicProperty.val;
cout << "VM name: " << name->__item << endl;
}
end_of_function:
delete FolderToChildEntitySelectionSpec.name;
delete FolderToChildEntityTraversalSpec.name;
delete DatacenterToVmFolderSelectionSpec.name;
delete DatacenterToVmFolderTraversalSpec.name;
return soap->error;
}
int main(int argc, char *argv[])
{
int ret = 0;
sduvisdk2__RetrieveServiceContentRequestType SvcCont;
sduvisdk2_RetrieveServiceContentResponse Response;
sduvisdk2__ManagedObjectReference *Mobj;
sduvisdk2__ServiceContent *sc;
sduvisdk2__LoginRequestType login;
sduvisdk2_LoginResponse loginResponse;
sduvisdk2__LogoutRequestType logout;
sduvisdk2_LogoutResponse logoutResponse;
sduvisdk2__AboutInfo *about;
sduvisdk2__UserSession *returnval = NULL;
if (argc != 4) {
cout \n";
exit(1);
}
server << "https://" << argv[1] << ":443/sdk";
soap = soap_new();
soap_init(soap);
soap_set_namespaces(soap, namespaces);
Mobj = new sduvisdk2__ManagedObjectReference;
soap_ssl_init();
if (soap_ssl_client_context( soap, SOAP_SSL_NO_AUTHENTICATION, NULL, NULL, NULL, NULL, NULL))
Mobj->__item = "ServiceInstance";
Mobj->type = new string("ServiceInstance");
SvcCont._USCOREthis = Mobj;
ret = soap_call___sduvisdk2__RetrieveServiceContent(soap, server.str().c_str(), "", &SvcCont, &Response);
if(SOAP_OK == ret) {
cout << "Retrieve success\n";
} else {
cout << "Soap Errors " << soap->error
<< " " << soap->errnum;
soap_print_fault(soap, stderr);
goto end_of_function;
}
sc = Response.returnval;
if( !sc || !sc->sessionManager ) {
goto end_of_function;
}
about = sc->about;
cout << "----
\n"
<< "About Info: \n"
<< "Name :" << about->name << endl
<< "FullName :" << about->fullName << endl
<< "Vendor :" << about->vendor << endl
<< "version :" << about->version << endl
<< "build :" << about->build << endl
<< "osType :" << about->osType << endl
<< "productLineId :" << about->productLineId << endl
<< "apiType :" << about->apiType << endl
<< "apiVersion :" << about->apiVersion << endl
<< "----
\n";
login._USCOREthis = sc->sessionManager;
login.userName = argv[2];
login.password = argv[3];
soap_call___sduvisdk2__Login(soap, server.str().c_str(), "", &login, &loginResponse);
if(soap->error != SOAP_OK ) {
soap_print_fault(soap, stderr);
goto end_of_function;
}
returnval = loginResponse.returnval;
cout << "Login success, the details are:\n"
<< "\tUser: " << returnval->userName << endl
<< "\tFull Name: " << returnval->fullName << endl
<< "\tLocale: " << returnval->locale << endl;
ret = getCurrentVMMob(sc);
if (ret != SOAP_OK)
cout << "Failed to get CurrentVMMob\n";
cout << "\nNow Logging out\n";
logout._USCOREthis = sc->sessionManager;
ret = soap_call___sduvisdk2__Logout(soap, server.str().c_str(), "", &logout, &logoutResponse);
if( soap->error != SOAP_OK ) {
soap_print_fault(soap, stderr);
goto end_of_function;
}
cout << "Logout succesful\n";
end_of_function:
soap_done(soap);
soap_end(soap);
}
When I run this code:
$ ./DynamicClient 10.72.197.66 root XXXXX
Retrieve success
-
About Info:
Name :VMware ESX Server
FullName :VMware ESX Server 3.5.0 build-64607
Vendor :VMware, Inc.
version :3.5.0
build :64607
osType :vmnix-x86
productLineId :esx
apiType :HostAgent
apiVersion :2.5.0
-
Login success, the details are:
User: root
Full Name: root
Locale: en
Retrieved Properties: 0
Now Logging out
SOAP 1.1 fault: "":ServerFaultCode
"The session is not authenticated."
Detail:
Why is Logout() call failing. Please let me know if I am doing anything wrong in my client code.
Thanks!
