VMware {code} Community
KSymmonds
Contributor
Contributor
Jump to solution

vSphere (4.1) API and PHP

Hi all,

I'm tearing my hair out here. I can successfully connect to the API via SOAP using PHP and calling the "ServiceInstance" method, I can get the following:

stdClass Object
(
    [returnval] => stdClass Object
        (
            [rootFolder] => stdClass Object
                (
                    [_] => ha-folder-root
                    [type] => Folder
                )
            [propertyCollector] => stdClass Object
                (
                    [_] => ha-property-collector
                    [type] => PropertyCollector
                )
            [viewManager] => stdClass Object
                (
                    [_] => ViewManager
                    [type] => ViewManager
                )
            [about] => stdClass Object
                (
                    [name] => VMware ESXi
                    [fullName] => VMware ESXi 4.1.0 build-260247
                    [vendor] => VMware, Inc.
                    [version] => 4.1.0
                    [build] => 260247
                    [localeVersion] => INTL
                    [localeBuild] => 000
                    [osType] => vmnix-x86
                    [productLineId] => embeddedEsx
                    [apiType] => HostAgent
                    [apiVersion] => 4.1
                    [licenseProductName] => VMware ESX Server
                    [licenseProductVersion] => 4.0
                )
            [setting] => stdClass Object
                (
                    [_] => HostAgentSettings
                    [type] => OptionManager
                )
            [userDirectory] => stdClass Object
                (
                    [_] => ha-user-directory
                    [type] => UserDirectory
                )
            [sessionManager] => stdClass Object
                (
                    [_] => ha-sessionmgr
                    [type] => SessionManager
                )
            [authorizationManager] => stdClass Object
                (
                    [_] => ha-authmgr
                    [type] => AuthorizationManager
                )
            [perfManager] => stdClass Object
                (
                    [_] => ha-perfmgr
                    [type] => PerformanceManager
                )
            [eventManager] => stdClass Object
                (
                    [_] => ha-eventmgr
                    [type] => EventManager
                )
            [taskManager] => stdClass
However, I try to invoke a login call, but keep getting the following error message:
Uncaught SoapFault exception: [ServerFaultCode] The session is not authenticated
If I try and change ommit the userName or password nodes, I get the following (expected) error:
SOAP-ERROR: Encoding: object has no 'userName' property
This is my XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:vim25">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:Login>
         <urn:_this type="SessionManager">SessionManager</urn:_this>
         <urn:userName>redacted</urn:userName>
         <urn:password>redacted</urn:password>
      </urn:Login>
   </soapenv:Body>
</soapenv:Envelope>
Any pointers greatly appreciated 🙂
Tags (3)
0 Kudos
1 Solution

Accepted Solutions
stumpr
Virtuoso
Virtuoso
Jump to solution

Ok, I don't know how you even got past the first RetrieveServiceContent call successfully.  Maybe it's the SDK version or the version of the SoapClient in use.  I'm on 5.3.6 using the default SoapClient (OS X Lion default installation of PHP).

It also seems the version I'm using is successfully handling cookies automatically for me, at least it was performing a logout successfully.  I didn't dive any deeper, however.

The first issue was in the construction of the "_this" argument (or more specifically, ManagedObjectReferences) to the soap calls.  The SoapVar construction doesn't seem to include attributes.  I had to use a manual array for it, so that the type attribute could be set properly.  I was unable to make any calls to the SDK until I did so.

$soapmsg["_this"] = array( "_" => "ServiceInstance", "type" => "ServiceInstance");

This is similar to the issues I've seen with other soap clients (nusoap) and some Python libraries.  The following example is working for me.

<?php

$client = new SoapClient("https://172.16.254.10/sdk/vimService.wsdl",

   array("trace" => 1, "location" => "https://172.16.254.10/sdk/") );


$soapmsg["_this"] = array( "_" => "ServiceInstance", "type" => "ServiceInstance");


$result = $client->RetrieveServiceContent($soapmsg);


$ServiceContent = $result->returnval;


$soapmsg = NULL;

$soapmsg["_this"] = $ServiceContent->sessionManager;

$soapmsg["userName"] = "administrator";

$soapmsg["password"] = "******!";


$result = $client->Login($soapmsg);


$UserSession = $result->returnval;

echo "User, " . $UserSession->userName . ", successfully logged in!\n";


$soapmsg = NULL;

$soapmsg["_this"] = $ServiceContent->sessionManager;


$result = $client->Logout($soapmsg);

?>

$ php -f client.php

User, VLAB\Administrator, successfully logged in!

I suspect you'll be turning this into a web page, so you'll likely need to disable exceptions during the SoapClient constructor, or wrap the SDK calls in try...catch blocks.  I didn't do any error handling for brevity and out of laziness.

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

View solution in original post

0 Kudos
11 Replies
stumpr
Virtuoso
Virtuoso
Jump to solution

Cookies.  Are you using and sending the sessionId cookie value you got in your initial call to the sdk throughout all the calls in that session?

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

Hi Stumpr,

Thanks, but this is the intial call. I was lead to believe that I would get a session ID returned with the response. Are you saying I need to create a session first, before logging in?

Thanks in advance.

0 Kudos
stumpr
Virtuoso
Virtuoso
Jump to solution

I'm not 100% sure about just jumping to Login.  It would depend on how the session is managed internally.  I would recommend you call RetrieveServiceContent.  During this call, save the cookie value returned from the SDK.  Then you can invoke Login, sending the cookie value.  The UserSession sessionId is not what's used for authentication, it's the sessionId in the cookie value.    When you login, this elevates your privileges to the login credentials specified.  You continue to use that cookie sessionId until you opt to Logout or the session is destroyed by timeout or admin intervention.

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

Hi Stumpr.

OK, so here's the process I have so far...

** Code Start **

$connection = new SoapClient("https://172.20.0.11/sdk/vimService.wsdl", array("trace" => 1, "location"=>"https://172.20.0.11/sdk/"));
$soapmsg["_this"] = new SoapVar("ServiceInstance", XSD_STRING, "ServiceInstance");
$result = $connection->RetrieveServiceContent($soapmsg);
// Retrieve the session ID from the call (Removes the double-quotes also)...
$cookieVal = str_replace('"','', $connection->_cookies['vmware_soap_session'][0]);
$connection->__setCookie("vmware_soap_session", $cookieVal);
//Reset the SOAP message array..
unset($soapmsg);
$soapmsg["_this"] = new SoapVar("SessionManager", XSD_STRING, "SessionManager");
$soapmsg["userName"] = "redacted";
$soapmsg["password"] = "redacted";
$result = $connection->Login($soapmsg);
** Code End **
But I still get this:
Fatal error:
Uncaught SoapFault exception: [ServerFaultCode] The session is not authenticated. test.php:30
Stack trace:
#0 test.php(30): SoapClient->__call('Login', Array)
#1 test.php(30): SoapClient->Login(Array)
#2 {main} thrown in test.php on line 30
Thanks again in advance.
Keith.


0 Kudos
stumpr
Virtuoso
Virtuoso
Jump to solution

Ok, I don't know how you even got past the first RetrieveServiceContent call successfully.  Maybe it's the SDK version or the version of the SoapClient in use.  I'm on 5.3.6 using the default SoapClient (OS X Lion default installation of PHP).

It also seems the version I'm using is successfully handling cookies automatically for me, at least it was performing a logout successfully.  I didn't dive any deeper, however.

The first issue was in the construction of the "_this" argument (or more specifically, ManagedObjectReferences) to the soap calls.  The SoapVar construction doesn't seem to include attributes.  I had to use a manual array for it, so that the type attribute could be set properly.  I was unable to make any calls to the SDK until I did so.

$soapmsg["_this"] = array( "_" => "ServiceInstance", "type" => "ServiceInstance");

This is similar to the issues I've seen with other soap clients (nusoap) and some Python libraries.  The following example is working for me.

<?php

$client = new SoapClient("https://172.16.254.10/sdk/vimService.wsdl",

   array("trace" => 1, "location" => "https://172.16.254.10/sdk/") );


$soapmsg["_this"] = array( "_" => "ServiceInstance", "type" => "ServiceInstance");


$result = $client->RetrieveServiceContent($soapmsg);


$ServiceContent = $result->returnval;


$soapmsg = NULL;

$soapmsg["_this"] = $ServiceContent->sessionManager;

$soapmsg["userName"] = "administrator";

$soapmsg["password"] = "******!";


$result = $client->Login($soapmsg);


$UserSession = $result->returnval;

echo "User, " . $UserSession->userName . ", successfully logged in!\n";


$soapmsg = NULL;

$soapmsg["_this"] = $ServiceContent->sessionManager;


$result = $client->Logout($soapmsg);

?>

$ php -f client.php

User, VLAB\Administrator, successfully logged in!

I suspect you'll be turning this into a web page, so you'll likely need to disable exceptions during the SoapClient constructor, or wrap the SDK calls in try...catch blocks.  I didn't do any error handling for brevity and out of laziness.

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

Thanks Stumpr.

Using your excellent example, I have connected and can retieve the object fine and interregation of which reveals the following as expected:

<snip>

stdClass Object
(
    [rootFolder] => stdClass Object
        (
            [_] => ha-folder-root
            [type] => Folder
        )
    [propertyCollector] => stdClass Object
        (
            [_] => ha-property-collector
            [type] => PropertyCollector
        )
    [viewManager] => stdClass Object
        (
            [_] => ViewManager
            [type] => ViewManager
        )
    [about] => stdClass Object
        (
            [name] => VMware ESXi
            [fullName] => VMware ESXi 4.1.0 build-260247
            [vendor] => VMware, Inc.
            [version] => 4.1.0
            [build] => 260247
            [localeVersion] => INTL
            [localeBuild] => 000
            [osType] => vmnix-x86
            [productLineId] => embeddedEsx
            [apiType] => HostAgent
            [apiVersion] => 4.1
            [licenseProductName] => VMware ESX Server
            [licenseProductVersion] => 4.0
        )
Etc...

</snip>

However, wanting to move on and perform simple tasks such as list VM's, etc, I'm still having trouble. I know I need to invoke the 'rootFolder' method (ManagedObjectReference:Folder), but every permitation I've tried still doesn't work 😕

Am I still missing something? May I ask how, using the example you have kindly given, how you would get the API to return the "ha-folder-root"??

Thanks in advance,

Keith

0 Kudos
stumpr
Virtuoso
Virtuoso
Jump to solution

The root folder is a property of ServiceContent and you can always get it once you've logged in.

$RootFolder = $ServiceContent->rootFolder;

print var_dump($RootFolder) . "\n";

You can pass this object in as needed for your queries.

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

Hey Stumpr.

Yes, I get that 🙂 I didn't explain myself, possibly.

I know that on the Host I'm connecting too returns a "Managed Object ID : ha-folder-root".

One of the properties, "childEntity" has a value of "ha-datacenter".

If I invoke the "Managed Object OD: ha-datacenter", one of the properties of this is "vmFolder". This has a value "ha-folder-vm"

In turn, "Managed Object ID: ha-folder-vm" has a property "childEntity" whose values are the VM's running on that host.

What I'm trying to do, is use your PHP example to get to return the "ha-folder-vm" object.

I do get the feeling that I might be over complicating things though 🙂

Thanks again in advance.

Keith.

0 Kudos
KSymmonds
Contributor
Contributor
Jump to solution

Hi All,

I attended the London VMUG yesterday (17th May 2012) and was re-energised to get this thing moving again. A lot has to be attributed to Ricky El-Qasem who gave a talk about his experiences with the API.

So, I'm posting the code here that works for the connection, retrieving the info and login:

<?php
/* Set the Host Connection Details */
$serviceHost = '192.168.96.131'; // Your host IP or FDQ.
$serviceUser = 'username'; // Your host user ('root' if you've not set one up in your test rig).
$servicePass = 'password'; // Your host password (or again the 'root' password if you've not set one up).
/* Set Host to connect */
$viConnection = new SoapClient("https://".$serviceHost."/sdk/vimService.wsdl", array("trace" => 1, "location" => "https://".$serviceHost."/sdk/"));
$soapmsg["_this"] = array( "_" => "ServiceInstance", "type" => "ServiceInstance");
$result = $viConnection->RetrieveServiceContent($soapmsg);
$ServiceContent = $result->returnval;
echo "<pre>";
print_r($ServiceContent);
echo "</pre>";
$soapmsg = NULL; // Reset the $soapmsg array..
$soapmsg["_this"] = $ServiceContent->sessionManager;
$soapmsg["userName"] = $serviceUser;
$soapmsg["password"] = $servicePass;
$result = $viConnection->Login($soapmsg);
$UserSession = $result->returnval;
echo "User, " . $UserSession->userName . ", successfully logged in!<br />";
$soapmsg = NULL; // Reset the $soapmsg array..
$soapmsg["_this"] = $ServiceContent->sessionManager;
$result = $viConnection->Logout($soapmsg);
?>

OK, so run this in your browser and compare with what you have in the Managed Object Browser (https://your_host/mob) and there you have it. So, my problem (or as I suspect, I'm missing something *really* simple) how do I pass the moID (traverse the API to get to the object I want) in this example like I can via the browser.

Aaaaaaaargh! (LOL)

Thanks in advance all.

0 Kudos
uffe81
Contributor
Contributor
Jump to solution

Hi!

Did you manage to get it working? I have the same problem as you.

Thanks.

0 Kudos
stumpr
Virtuoso
Virtuoso
Jump to solution

You'll need to review the traversal spec and property retrieval methods for the SDK.  You can look through the API Programming Guide.

The basic issue with PHP is that there is no official SDK toolkit for it, so you have to do the low level SOAP construction.  For login/logout this is fairly simple (see the above example).  For more complex operations (querying inventory data, performance metrics, etc) you'll have to build nested, complex SOAP objects by hand and deal with some quirks like the ManagedObjectReference slightly non-expected XML attributes (like ServiceInstance in above example).

I would encourage you to use an official toolkit vs PHP for this reason (you'll find all utility functions to retrieve objects are pre-built for you).  If it's to be web embedded, Perl has several options and is officially supported.  The non-supported Python bindings were released as well: https://github.com/vmware/pyvmomi

There were some PHP kits the community put together, but I can't speak to their current status or how complete they were.  I did explore the PHP process years ago, but ultimately abandoned it.  It was too time consuming.  I was able to make much faster and more robust progress with Perl +  HTML::Mason (which provides PHP like embedded Perl with inheritance). 

For example, using the above thread, if you wanted to get all the VMs of a specific datacenter in Perl:

$my_dc_vms = Vim::find_entity_views(view_type => "VirtualMachine", begin_entity => $my_dc);

To do the same in the lower level API calls, you'd have to build TraversalSpecs, PropertySpecs, and ObjectSpecs using the SOAP constructions in PHP.  However, if you do build these Specs, you can do very advanced filtering and searching on the SDK inventory efficiently. 

But for a simple VM retrieval, learning the complete SDK inventory traversal operation and hand building the SOAP in PHP can be difficult, particularly if you're not already familiar with the VI SDK SOAP model.

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