diff --git a/src/Requests/SoapRequest.php b/src/Requests/SoapRequest.php
index 6884241..adf6924 100644
--- a/src/Requests/SoapRequest.php
+++ b/src/Requests/SoapRequest.php
@@ -19,14 +19,14 @@ trait SoapRequest
/**
* @return stdClass
*/
- public function request(string $method, array $requestBody, bool $convertToSoap = true)
+ public function request(string $method, array $requestBody, bool $withXMLAttributes = false, bool $convertToSoap = true)
{
try {
$response = $this->soapClient->$method($convertToSoap ? $this->arrayToSoapVar($requestBody) : $requestBody);
RequestEvent::dispatch(
- property_exists($this->soapClient, '__last_request') ? $this->soapClient->__last_request : '',
- property_exists($this->soapClient, '__last_response') ? $this->soapClient->__last_response : '',
+ $this->soapClient->__getLastRequest() ?? '',
+ $this->soapClient->__getLastResponse() ?? '',
true
);
@@ -34,17 +34,19 @@ public function request(string $method, array $requestBody, bool $convertToSoap
Log::info(
'SOAP REQUEST SUCCESS:'.
"\nSOAP method: ".$method.
- property_exists($this->soapClient, '__last_request')
- ? "\nSOAP request start***".preg_replace('#.+#', '*****', $this->soapClient->__last_request).'***SOAP request end'
+ $this->soapClient->__getLastRequest()
+ ? "\nSOAP request start***".preg_replace('#.+#', '*****', $this->soapClient->__getLastRequest()).'***SOAP request end'
: ''
);
}
- return $response;
+ return ($withXMLAttributes)
+ ? $this->parseXMLResponse($this->soapClient->__getLastResponse())
+ : $response;
} catch (\Exception $exception) {
RequestEvent::dispatch(
- property_exists($this->soapClient, '__last_request') ? $this->soapClient->__last_request : '',
- property_exists($this->soapClient, '__last_response') ? $this->soapClient->__last_response : '',
+ $this->soapClient->__getLastRequest() ?? '',
+ $this->soapClient->__getLastResponse() ?? '',
false
);
@@ -66,21 +68,21 @@ public function request(string $method, array $requestBody, bool $convertToSoap
]);
$this->soapClient->__setCookie('vmware_soap_session', $sessionInfo['vmware_soap_session']);
- return $this->request($method, $requestBody, $convertToSoap);
+ return $this->request($method, $requestBody, $withXMLAttributes, $convertToSoap);
}
}
$message = "SOAP REQUEST FAILED:\nMessage: ".$exception->getMessage().
"\nSOAP method: ".$method.
(
- property_exists($this->soapClient, '__last_request')
- ? "\nSOAP request start***".preg_replace('#.+#', '*****', $this->soapClient->__last_request).'***SOAP request end'
+ $this->soapClient->__getLastRequest()
+ ? "\nSOAP request start***".preg_replace('#.+#', '*****', $this->soapClient->__getLastRequest()).'***SOAP request end'
: ''
- ).(
- property_exists($this->soapClient, '__last_response')
- ? "\nSOAP response start***: ".$this->soapClient->__last_response.'***SOAP response end'
+ ).(
+ $this->soapClient->__getLastResponse()
+ ? "\nSOAP response start***: ".$this->soapClient->__getLastResponse().'***SOAP response end'
: ''
- );
+ );
// "\nTrace: ".json_encode($exception->getTrace());
Log::error($message);
@@ -103,4 +105,61 @@ private function vmRequest(string $method, string $vmId, array $requestBody = []
return $this->request($method, $soapMessage);
}
+
+ /*
+ * Totally not stolen from https://stackoverflow.com/a/46349713
+ */
+ private function parseXMLResponse(string $xmlResponse)
+ {
+ $previous_value = libxml_use_internal_errors(true);
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->preserveWhiteSpace = false;
+ $dom->loadXml($xmlResponse);
+ libxml_use_internal_errors($previous_value);
+
+ if (libxml_get_errors()) {
+ return [];
+ }
+
+ return $this->domToArray($dom);
+ }
+
+ private function domToArray($root) {
+ $result = [];
+
+ if ($root->hasAttributes()) {
+ $attrs = $root->attributes;
+ foreach ($attrs as $attr) {
+ $result['@attributes'][$attr->name] = $attr->value;
+ }
+ }
+
+ if ($root->hasChildNodes()) {
+ $children = $root->childNodes;
+ if ($children->length == 1) {
+ $child = $children->item(0);
+ if (in_array($child->nodeType,[XML_TEXT_NODE,XML_CDATA_SECTION_NODE])) {
+ $result['_value'] = $child->nodeValue;
+ return count($result) == 1
+ ? $result['_value']
+ : $result;
+ }
+
+ }
+ $groups = [];
+ foreach ($children as $child) {
+ if (!isset($result[$child->nodeName])) {
+ $result[$child->nodeName] = $this->domToArray($child);
+ } else {
+ if (!isset($groups[$child->nodeName])) {
+ $result[$child->nodeName] = [$result[$child->nodeName]];
+ $groups[$child->nodeName] = 1;
+ }
+ $result[$child->nodeName][] = $this->domToArray($child);
+ }
+ }
+ }
+
+ return $result;
+ }
}
diff --git a/src/Traits/Soap/SoapImportApis.php b/src/Traits/Soap/SoapImportApis.php
new file mode 100644
index 0000000..95f2d45
--- /dev/null
+++ b/src/Traits/Soap/SoapImportApis.php
@@ -0,0 +1,285 @@
+ [
+ '_' => 'OvfManager',
+ 'type' => 'OvfManager',
+ ],
+ 'ovfDescriptor' => file_get_contents($ovfPath),
+ 'pdp' => new OvfParseDescriptorParams([
+ 'locale' => '',
+ 'deploymentOption' => '',
+ ]),
+ ];
+ return $this->request('ParseDescriptor', $body);
+ }
+
+ public function createImportSpec(string $ovfPath, string $resourcepool, string $datastore, array $networkMapping = null)
+ {
+ $body = [
+ '_this' => [
+ '_' => 'OvfManager',
+ 'type' => 'OvfManager',
+ ],
+ 'ovfDescriptor' => file_get_contents($ovfPath),
+ 'resourcePool' => $resourcepool,
+ 'datastore' => $datastore,
+ 'cisp' => new OvfCreateImportSpecParams([
+ 'locale' => '',
+ 'entityName' => '',
+ 'deploymentOption' => '',
+ 'networkMapping' => $networkMapping,
+ ]),
+ ];
+
+ return $this->request('CreateImportSpec', $body, true);
+ }
+
+ public function importVApp(string $resourcePoolId, $entityConfig, $instantiationOst, $configSpec, $folder = null, $host = null)
+ {
+ $extraConfig = [];
+ if (isset($configSpec->extraConfig)) {
+ // sometimes there is only one level of nesting
+ if (property_exists($configSpec->extraConfig, 'key')) {
+ $extraConfig['key'] = $configSpec->extraConfig->key;
+ $extraConfig['value:string'] = $configSpec->extraConfig->value->_value ?? '';
+ // but sometimes there are several
+ } else {
+ foreach ($configSpec->extraConfig as $i => $config) {
+ $extraConfig[$i]['key'] = $config->key;
+ $extraConfig[$i]['value:string'] = $config->value->_value ?? '';
+ }
+ }
+ }
+
+ // devices may vary from one VM to another, therefore we can not explicitly set those params manually
+ $deviceChange = [];
+ if (isset($configSpec->deviceChange) && \count($configSpec->deviceChange) > 0) {
+ foreach ($configSpec->deviceChange as $i => $deviceObj) {
+ $deviceConfig = json_decode(json_encode($deviceObj), true);
+ $deviceChange[$i] = $this->build($deviceConfig, []);
+ }
+ }
+
+ $body = [
+ '_this' => [
+ '_' => $resourcePoolId,
+ 'type' => 'ResourcePool',
+ ],
+ 'spec' => new VirtualMachineImportSpec([
+ 'entityConfig' => new VAppEntityConfigInfo([
+ 'key' => $entityConfig->key ?? null,
+ 'tag' => $entityConfig->tag ?? null,
+ 'startOrder' => $entityConfig->startOrder ?? null,
+ 'startDelay' => $entityConfig->startDelay ?? null,
+ 'waitingForGuest' => $entityConfig->waitingForGuest ?? null,
+ 'startAction' => $entityConfig->startAction ?? null,
+ 'stopDelay' => $entityConfig->stopDelay ?? null,
+ 'stopAction' => $entityConfig->stopAction ?? null,
+ 'destroyWithParent' => $entityConfig->destroyWithParent ?? null,
+ ]),
+ 'instantiationOst' => new OvfConsumerOstNode([
+ 'id' => $instantiationOst->id ?? null,
+ 'type' => $instantiationOst->type ?? null,
+ 'section' => $instantiationOst->section ?? null,
+ 'child' => $instantiationOst->child ? [
+ 'id' => $instantiationOst->child->id ?? null,
+ 'type' => $instantiationOst->child->type ?? null,
+ ] : null,
+ 'entity' => $instantiationOst->entity ?? null,
+ ]),
+ 'configSpec' => new VirtualMachineConfigSpec([
+ 'name' => $configSpec->name ?? null,
+ 'version' => $configSpec->version ?? null,
+ 'uuid' => $configSpec->uuid ?? null,
+ 'guestId' => $configSpec->guestId ?? null,
+ 'files' => $configSpec->files ? new VirtualMachineFileInfo([
+ 'vmPathName' => $configSpec->files->vmPathName ?? null,
+ 'snapshotDirectory' => $configSpec->files->snapshotDirectory ?? null,
+ 'suspendDirectory' => $configSpec->files->suspendDirectory ?? null,
+ 'logDirectory' => $configSpec->files->logDirectory ?? null,
+ 'ftMetadataDirectory' => $configSpec->files->ftMetadataDirectory ?? null,
+ ]) : null,
+ 'tools' => $configSpec->tools ? new ToolsConfigInfo([
+ 'toolsVersion' => $configSpec->tools->toolsVersion ?? null,
+ 'toolsInstallType' => $configSpec->tools->toolsInstallType ?? null,
+ 'afterPowerOn' => $configSpec->tools->afterPowerOn ?? null,
+ 'afterResume' => $configSpec->tools->afterResume ?? null,
+ 'beforeGuestStandby' => $configSpec->tools->beforeGuestStandby ?? null,
+ 'beforeGuestShutdown' => $configSpec->tools->beforeGuestShutdown ?? null,
+ 'beforeGuestReboot' => $configSpec->tools->beforeGuestReboot ?? null,
+ 'toolsUpgradePolicy' => $configSpec->tools->toolsUpgradePolicy ?? null,
+ 'pendingCustomization' => $configSpec->tools->pendingCustomization ?? null,
+ 'customizationKeyId' => $configSpec->tools->customizationKeyId ?? null,
+ 'syncTimeWithHostAllowed' => $configSpec->tools->syncTimeWithHostAllowed ?? null,
+ 'syncTimeWithHost' => $configSpec->tools->syncTimeWithHost ?? null,
+ 'lastInstallInfo' => $configSpec->tools->lastInstallInfo ?? null,
+
+ ]) : null,
+ 'flags' => $configSpec->flags ? new VirtualMachineFlagInfo([
+ 'disableAcceleration' => $configSpec->flags->disableAcceleration ?? null,
+ 'enableLogging' => $configSpec->flags->enableLogging ?? null,
+ 'useToe' => $configSpec->flags->useToe ?? null,
+ 'runWithDebugInfo' => $configSpec->flags->runWithDebugInfo ?? null,
+ 'monitorType' => $configSpec->flags->monitorType ?? null,
+ 'htSharing' => $configSpec->flags->htSharing ?? null,
+ 'snapshotDisabled' => $configSpec->flags->snapshotDisabled ?? null,
+ 'snapshotLocked' => $configSpec->flags->snapshotLocked ?? null,
+ 'diskUuidEnabled' => $configSpec->flags->diskUuidEnabled ?? null,
+ 'virtualMmuUsage' => $configSpec->flags->virtualMmuUsage ?? null,
+ 'virtualExecUsage' => $configSpec->flags->virtualExecUsage ?? null,
+ 'snapshotPowerOffBehavior' => $configSpec->flags->snapshotPowerOffBehavior ?? null,
+ 'recordReplayEnabled' => $configSpec->flags->recordReplayEnabled ?? null,
+ 'faultToleranceType' => $configSpec->flags->faultToleranceType ?? null,
+ 'cbrcCacheEnabled' => $configSpec->flags->cbrcCacheEnabled ?? null,
+ 'vvtdEnabled' => $configSpec->flags->vvtdEnabled ?? null,
+ 'vbsEnabled' => $configSpec->flags->vbsEnabled ?? null,
+ ]) : null,
+ 'numCPUs' => $configSpec->numCPUs ?? null,
+ 'numCoresPerSocket' => $configSpec->numCoresPerSocket ?? null,
+ 'memoryMB' => $configSpec->memoryMB ?? null,
+ 'memoryHotAddEnabled' => $configSpec->memoryHotAddEnabled ?? null,
+ 'cpuHotAddEnabled' => $configSpec->cpuHotAddEnabled ?? null,
+ 'cpuHotRemoveEnabled' => $configSpec->cpuHotRemoveEnabled ?? null,
+ 'virtualICH7MPresent' => $configSpec->virtualICH7MPresent ?? null,
+ 'virtualSMCPresent' => $configSpec->virtualSMCPresent ?? null,
+ 'deviceChange' => $deviceChange,
+ 'memoryAllocation' => isset($configSpec->memoryAllocation) ? [
+ 'reservation' => $configSpec->memoryAllocation->reservation ?? null,
+ 'expandableReservation' => $configSpec->memoryAllocation->expandableReservation ?? null,
+ 'limit' => $configSpec->memoryAllocation->limit ?? null,
+ 'shares' => $configSpec->memoryAllocation->shares ? [
+ 'shares' => $configSpec->memoryAllocation->shares->shares ?? null,
+ 'level' => $configSpec->memoryAllocation->shares->level ?? null,
+ ] : null,
+ ] : null,
+ 'extraConfig' => \count($extraConfig) > 0 ? $extraConfig : null,
+ 'bootOptions' => $configSpec->bootOptions ? [
+ 'bootDelay' => $configSpec->bootOptions->bootDelay ?? null,
+ 'enterBIOSSetup' => $configSpec->bootOptions->enterBIOSSetup ?? null,
+ 'efiSecureBootEnabled' => $configSpec->bootOptions->efiSecureBootEnabled,
+ 'bootRetryEnabled' => $configSpec->bootOptions->bootRetryEnabled ?? null,
+ 'bootRetryDelay' => $configSpec->bootOptions->bootRetryDelay ?? null,
+ 'bootOrder' => $configSpec->bootOptions->bootOrder ?? null,
+ 'networkBootProtocol' => $configSpec->bootOptions->networkBootProtocol ?? null,
+ ] : null,
+ 'vAppConfig' => [
+ 'product' => $configSpec->vAppConfig->product ? [
+ 'operation' => $configSpec->vAppConfig->product->operation ?? null,
+ 'info' => $configSpec->vAppConfig->product->info ? [
+ 'key' => $configSpec->vAppConfig->product->info->key ?? null,
+ 'classId' => $configSpec->vAppConfig->product->info->classId ?? null,
+ 'instanceId' => $configSpec->vAppConfig->product->info->instanceId ?? null,
+ 'name' => $configSpec->vAppConfig->product->info->name ?? null,
+ 'vendor' => $configSpec->vAppConfig->product->info->vendor ?? null,
+ 'version' => $configSpec->vAppConfig->product->info->version ?? null,
+ 'fullVersion' => $configSpec->vAppConfig->product->info->fullVersion ?? null,
+ 'vendorUrl' => $configSpec->vAppConfig->product->info->vendorUrl ?? null,
+ 'productUrl' => $configSpec->vAppConfig->product->info->productUrl ?? null,
+ 'appUrl' => $configSpec->vAppConfig->product->info->appUrl ?? null,
+ ] : null,
+ ] : null,
+ 'installBootRequired' => $configSpec->vAppConfig->installBootRequired ?? null,
+ 'installBootStopDelay' => $configSpec->vAppConfig->installBootStopDelay ?? null,
+ ],
+ 'firmware' => $configSpec->firmware ?? null,
+ 'nestedHVEnabled' => $configSpec->nestedHVEnabled ?? null,
+ 'sgxInfo' => isset($configSpec->sgxInfo) ? [
+ 'epcSize' => $configSpec->sgxInfo->epcSize ?? null,
+ 'flcMode' => $configSpec->sgxInfo->flcMode ?? null,
+ 'lePubKeyHash' => $configSpec->sgxInfo->lePubKeyHash ?? null,
+ ] : null,
+ 'sevEnabled' => $configSpec->sevEnabled ?? null,
+ ]),
+ ]),
+ 'folder' => $folder,
+ 'host' => $host,
+ ];
+
+ return $this->request('ImportVApp', $body);
+ }
+
+ private function build($data, $arrayToBuild, $object = null)
+ {
+ if ($object) {
+ foreach ($data as $key => $value) {
+ if (!is_array($value)) {
+ $object->$key = $value;
+ } else if (is_array($value) && array_key_exists('@attributes', $value)) {
+ $className = "Xelon\\VmWareClient\\Types\\".$value['@attributes']['type'];
+ $newObj = (new $className);
+ unset($value['@attributes']);
+
+ $object->$key = $this->build($value, [], $newObj);
+ } else if (is_array($value)) {
+ $object->$key = $this->build($value, []);
+ }
+ }
+
+ return $object;
+ }
+
+ foreach ($data as $key => $value) {
+ if (!is_array($value)) {
+ $arrayToBuild[$key] = $value;
+ } else if (is_array($value) && array_key_exists('@attributes', $value)) {
+ $className = "Xelon\\VmWareClient\\Types\\".$value['@attributes']['type'];
+ $newObj = (new $className);
+ unset($value['@attributes']);
+
+ $arrayToBuild[$key] = $this->build($value, [], $newObj);
+ } else if (is_array($value)) {
+ $arrayToBuild[$key] = $this->build($value, []);
+ }
+ }
+
+ return $arrayToBuild;
+ }
+
+ public function httpNfcLeaseProgress($httpNfcLease, int $percent)
+ {
+ $body = [
+ '_this' => [
+ '_' => $httpNfcLease->returnval->_,
+ 'type' => 'HttpNfcLease',
+ ],
+ 'percent' => $percent,
+ ];
+
+ return $this->request('HttpNfcLeaseProgress', $body);
+ }
+
+ public function httpNfcLeaseComplete($httpNfcLease)
+ {
+ $body = [
+ '_this' => [
+ '_' => $httpNfcLease->returnval->_,
+ 'type' => 'HttpNfcLease',
+ ],
+ ];
+
+ return $this->request('HttpNfcLeaseComplete', $body);
+ }
+}
\ No newline at end of file
diff --git a/src/Traits/Soap/SoapVmApis.php b/src/Traits/Soap/SoapVmApis.php
index 670fc5e..28d1faf 100644
--- a/src/Traits/Soap/SoapVmApis.php
+++ b/src/Traits/Soap/SoapVmApis.php
@@ -30,8 +30,8 @@ public function getObjectInfo(string $objectId, string $objectType, string $path
} catch (\Exception $exception) {
Log::error(
"SOAP REQUEST FAILED:\nMessage: ".$exception->getMessage().
- "\nSOAP request: ".$this->soapClient->__last_request.
- "\nSOAP response: ".$this->soapClient->__last_response ?? ''
+ "\nSOAP request: ".($this->soapClient->__getLastRequest() ?? '').
+ "\nSOAP response: ".($this->soapClient->__getLastResponse() ?? '')
);
if (array_keys(json_decode(json_encode($exception->detail), true))[0] === 'ManagedObjectNotFoundFault') {
diff --git a/src/Transform/SoapTransform.php b/src/Transform/SoapTransform.php
index 84ca982..b409acb 100644
--- a/src/Transform/SoapTransform.php
+++ b/src/Transform/SoapTransform.php
@@ -22,6 +22,11 @@ public function arrayToSoapVar(array $array): array
$typeName = null;
$data = [];
foreach ($array as $key => $value) {
+ if (str_contains($key, ':')) {
+ $keyString = explode(':', $key);
+ $key = $keyString[0];
+ $type = $keyString[1];
+ }
if (is_array($value) || $value instanceof DynamicData) {
if ($value instanceof DynamicData) {
$typeName = (new \ReflectionClass($value))->getShortName();
@@ -75,7 +80,9 @@ public function arrayToSoapVar(array $array): array
$typeName = null;
} elseif (! is_null($value)) {
- $data[$key] = new SoapVar($value, null, null, null, $key);
+ $encoding = isset($type) ? XSD_STRING : null;
+ $typeName = isset($type) ? 'xsd:string' : null;
+ $data[$key] = new SoapVar($value, $encoding, $typeName, null, $key);
}
}
diff --git a/src/Types/Core/ExtensibleManagedObject.php b/src/Types/Core/ExtensibleManagedObject.php
new file mode 100644
index 0000000..dd5ee98
--- /dev/null
+++ b/src/Types/Core/ExtensibleManagedObject.php
@@ -0,0 +1,8 @@
+soapClient->Login($loginMessage);
- if (isset($this->soapClient->_cookies)) {
- $soapSessionToken = $this->soapClient->_cookies['vmware_soap_session'][0];
+ if (array_key_exists('vmware_soap_session', $this->soapClient->__getCookies())) {
+ $soapSessionToken = $this->soapClient->__getCookies()['vmware_soap_session'][0];
} else {
- $responseHeaders = $this->soapClient->__last_response_headers;
+ $responseHeaders = $this->soapClient->__getLastResponseHeaders();
$string = strstr($responseHeaders, 'vmware_soap_session');
$string = strstr($string, '"');