diff --git a/README.md b/README.md
index c5aa4d8..84a2ba8 100644
--- a/README.md
+++ b/README.md
@@ -1,70 +1,139 @@
[](https://supportukrainenow.org)
-
-# PHP API Client for VmWare
-
+
+# PHP API Client for VMWare
+
[![Latest Version on Packagist](https://img.shields.io/packagist/v/xelon-ag/vmware-php-client.svg?style=flat-square)](https://packagist.org/packages/xelon-ag/vmware-php-client)
-[![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/xelon-ag/vmware-php-client/run-tests?label=tests)](https://github.com/xelon-ag/vmware-php-client/actions?query=workflow%3Arun-tests+branch%3Amain)
[![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/xelon-ag/vmware-php-client/Check%20&%20fix%20styling?label=code%20style)](https://github.com/xelon-ag/vmware-php-client/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain)
[![Total Downloads](https://img.shields.io/packagist/dt/xelon-ag/vmware-php-client.svg?style=flat-square)](https://packagist.org/packages/xelon-ag/vmware-php-client)
-
-This is where your description should go. Limit it to a paragraph or two. Consider adding a small example.
-
-## Support us
-
-[](https://spatie.be/github-ad-click/vmware-php-client)
-
-We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).
-
-We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).
-
+
## Installation
-
+
You can install the package via composer:
-
+
```bash
composer require xelon-ag/vmware-php-client
```
-
+
You can publish the config file with:
-
+
```bash
php artisan vendor:publish --tag="vmware-php-client-config"
```
-
-This is the contents of the published config file:
-
+
```php
return [
+ 'session_ttl' => env('VMWARE_SESSION_TTL', 10),
+ 'enable_logs' => env('VMWARE_ENABLE_LOGS', true),
];
```
-
-
-## Usage
-
+
+
+## Getting started
+
+Create a connection to your hypervisor so that you can call the methods:
```php
-$vmWareClient = new Xelon\VmWareClient();
-echo $vmWareClient->echoPhrase('Hello, Xelon!');
+$vcenterClient = new Xelon\VmWareClient\VcenterClient(
+ 'https://10.20.30.40',
+ 'mylogin',
+ 'mypassword'
+);
+$vmInfo = $vcenterClient->getVmInfo('vm-123');
```
-
-
-## Changelog
-
-Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
-
-## Contributing
-
-Please see [CONTRIBUTING](https://github.com/gazhur94/.github/blob/main/CONTRIBUTING.md) for details.
-
-## Security Vulnerabilities
-
-Please review [our security policy](../../security/policy) on how to report security vulnerabilities.
-
+This lib can run in three modes: `rest`, `soap` and `both`. By default, it runs in `rest` mode, but you can set another mode in constructor:
+```php
+$vcenterClient = new Xelon\VmWareClient\VcenterClient(
+ 'https://10.20.30.40',
+ 'mylogin',
+ 'mypassword',
+ 'soap'
+);
+```
+Yet we recommend to use constants:
+```php
+$vcenterClient = new Xelon\VmWareClient\VcenterClient(
+ 'https://10.20.30.40',
+ 'mylogin',
+ 'mypassword',
+ Xelon\VmWareClient\VcenterClient::MODE_SOAP
+);
+```
+
+### `rest` mode
+
+With `rest` mode you can use REST methods which you can find in the [VMWare API developer center](https://developer.vmware.com/apis/vsphere-automation/latest/).
+For now, the lib has only some methods available. You can find full list of files in the `vendor/xelon-ag/vmware-php-client/src/Traits/Rest` folder.
+
+> We plan to add the full list of methods later.
+
+### `soap` mode
+
+Using `soap` mode allow you to use SOAP methods which you can find in [VMWare SOAP developer center](https://developer.vmware.com/apis/1192/vsphere).
+For now, the lib has only some methods available. You can find full list of files in the `vendor/xelon-ag/vmware-php-client/src/Traits/SOAP` folder.
+
+> We plan to add the full list of methods later.
+
+
+Here's how to make your first SOAP call:
+```php
+$folder = $vcenterClient->soap->createFolder('group-v3', 'foldername');
+```
+
+If you want to use both modes at one time you can set `both` mode (Xelon\VmWareClient\VcenterClient::MODE_BOTH).
+
+ If you want to run custom `soap` method, which you do not find in lib, you can run this method directly:
+```php
+$vcenterClient = new Xelon\VmWareClient\VcenterClient(
+ 'https://10.20.30.40',
+ 'mylogin',
+ 'mypassword',
+ Xelon\VmWareClient\VcenterClient::MODE_SOAP
+);
+
+$taskInfo = $vcenterClient->soap->request('ReconfigureComputeResource_Task', [
+ '_this' => [
+ '_' => 'domain-c33',
+ 'type' => 'ComputeResource',
+ ],
+ 'spec' => [
+ '@type' => 'ClusterConfigSpecEx',
+ 'drsConfig' => [
+ '@type' => 'ClusterDrsConfigInfo',
+ ],
+ 'rulesSpec' => [
+ '@type' => 'ClusterRuleSpec',
+ 'operation' => 'add',
+ 'info' => [
+ '@type' => 'ClusterAntiAffinityRuleSpec',
+ 'enabled' => true,
+ 'name' => 'VM-VM Affinity rule',
+ 'userCreated' => true,
+ 'vm' => [
+ ['_' => 'vm-133', 'type' => 'VirtualMachine'],
+ ['_' => 'vm-134', 'type' => 'VirtualMachine']
+ ]
+ ],
+ ],
+ 'dpmConfig' => [
+ '@type' => 'ClusterDpmConfigInfo',
+ ],
+
+ ],
+ 'modify' => false,
+])
+```
+
+> Order of parameters is very important. You can find the correct order in the [documentation]((https://developer.vmware.com/apis/1192/vsphere)), the `WSDL type definition` section for each object type.
+
## Credits
-
+
- [Andrii Hazhur](https://github.com/gazhur94)
-- [All Contributors](../../contributors)
-
+- [All Contributors](https://github.com/Xelon-AG/vmware-php-client/graphs/contributors)
+
+## Questions and feedback
+
+If you've got questions about setup or just want to chat with the developer, please feel free to reach out to a.hazhur@bitcat.agency.
+
## License
-
+
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
diff --git a/config/vmware-php-client.php b/config/vmware-php-client.php
index 9b22dfe..4a962ac 100644
--- a/config/vmware-php-client.php
+++ b/config/vmware-php-client.php
@@ -2,5 +2,6 @@
return [
// session ttl in minutes
- 'session_ttl' => env('VMWARE_SESSION_TTL', 120),
+ 'session_ttl' => env('VMWARE_SESSION_TTL', 10),
+ 'enable_logs' => env('VMWARE_ENABLE_LOGS', true),
];
diff --git a/src/Data/SoapData.php b/src/Data/SoapData.php
index 8fadb34..54dee9d 100644
--- a/src/Data/SoapData.php
+++ b/src/Data/SoapData.php
@@ -2,9 +2,31 @@
namespace Xelon\VmWareClient\Data;
+use Xelon\VmWareClient\Types\CustomizationAdapterMapping;
+use Xelon\VmWareClient\Types\CustomizationFixedIp;
+use Xelon\VmWareClient\Types\CustomizationFixedName;
+use Xelon\VmWareClient\Types\CustomizationGuiUnattended;
+use Xelon\VmWareClient\Types\CustomizationIdentification;
+use Xelon\VmWareClient\Types\CustomizationIPSettings;
+use Xelon\VmWareClient\Types\CustomizationPassword;
+use Xelon\VmWareClient\Types\CustomizationSysprep;
+use Xelon\VmWareClient\Types\CustomizationUserData;
+use Xelon\VmWareClient\Types\Description;
+use Xelon\VmWareClient\Types\DistributedVirtualSwitchPortConnection;
+use Xelon\VmWareClient\Types\SharesInfo;
+use Xelon\VmWareClient\Types\VirtualCdrom;
+use Xelon\VmWareClient\Types\VirtualCdromIsoBackingInfo;
+use Xelon\VmWareClient\Types\VirtualCdromRemoteAtapiBackingInfo;
+use Xelon\VmWareClient\Types\VirtualDeviceConnectInfo;
+use Xelon\VmWareClient\Types\VirtualDisk;
+use Xelon\VmWareClient\Types\VirtualDiskFlatVer2BackingInfo;
+use Xelon\VmWareClient\Types\VirtualEthernetCardDistributedVirtualPortBackingInfo;
+use Xelon\VmWareClient\Types\VirtualLsiLogicSASController;
+use Xelon\VmWareClient\Types\VirtualVmxnet3;
+
class SoapData
{
- public function findVmBody(string $vmId, string $pathSet = ''): array
+ public function objectInfoBody(string $objectId, string $objectType, string $pathSet = ''): array
{
return [
'_this' => [
@@ -13,15 +35,16 @@ public function findVmBody(string $vmId, string $pathSet = ''): array
],
'specSet' => [
'propSet' => [
- 'type' => 'VirtualMachine',
+ 'type' => $objectType,
'all' => ! $pathSet,
'pathSet' => $pathSet,
],
'objectSet' => [
'obj' => [
- '_' => $vmId,
- 'type' => 'VirtualMachine',
+ '_' => $objectId,
+ 'type' => $objectType,
],
+ 'skip' => false,
],
],
];
@@ -32,54 +55,62 @@ public function addVirtualDiskSpec(
int $unitNumber,
bool $isHdd = false,
string $name = 'New Hard disk'
- ): array {
- return [
- '@type' => 'VirtualDisk',
+ ): VirtualDisk {
+ return new VirtualDisk([
'key' => -101,
- 'deviceInfo' => [
- '@type' => 'Description',
+ 'deviceInfo' => new Description([
'label' => $name,
'summary' => $name,
- ],
- 'backing' => [
- '@type' => 'VirtualDiskFlatVer2BackingInfo',
+ ]),
+ 'backing' => new VirtualDiskFlatVer2BackingInfo([
'fileName' => '',
'diskMode' => 'persistent',
'thinProvisioned' => false,
'eagerlyScrub' => false,
- ],
+ ]),
'controllerKey' => 1000,
'unitNumber' => $unitNumber,
'capacityInKB' => $capacityInKB,
'capacityInBytes' => $capacityInKB * 1024,
'storageIOAllocation' => [
'limit' => $isHdd ? 3200 : -1,
- 'shares' => [
- '@type' => 'SharesInfo',
+ 'shares' => new SharesInfo([
'shares' => 1000,
'level' => 'normal',
- ],
+ ]),
],
- ];
+ ]);
}
- public function editVirtualDiskSpec(array $params): array
+ public function editVirtualDiskSpec(array $params): VirtualDisk
{
- return [
- '@type' => 'VirtualDisk',
+ return new VirtualDisk([
'key' => $params['key'],
- 'backing' => [
- '@type' => 'VirtualDiskFlatVer2BackingInfo',
+ 'backing' => new VirtualDiskFlatVer2BackingInfo([
'fileName' => $params['backing']['fileName'],
'diskMode' => $params['backing']['diskMode'] ?? 'persistent',
'thinProvisioned' => $params['backing']['thinProvisioned'] ?? false,
'eagerlyScrub' => $params['backing']['eagerlyScrub'] ?? false,
- ],
+ ]),
'controllerKey' => $params['controllerKey'],
'unitNumber' => $params['unitNumber'],
'capacityInKB' => $params['capacityInKB'],
'capacityInBytes' => $params['capacityInKB'] * 1024,
- ];
+ ]);
+ }
+
+ public function addBlockStorageSpec(string $blockStoragePath, int $capacityInKB, int $controllerKey = 1000): VirtualDisk
+ {
+ return new VirtualDisk([
+ 'key' => -1,
+ 'backing' => new VirtualDiskFlatVer2BackingInfo([
+ 'fileName' => $blockStoragePath,
+ 'diskMode' => 'independent_persistent',
+ ]),
+ 'controllerKey' => $controllerKey,
+ 'unitNumber' => -1,
+ 'capacityInKB' => $capacityInKB,
+ ]);
}
public function addNetworkSpec(
@@ -88,20 +119,18 @@ public function addNetworkSpec(
int $unitNumber,
int $controllerKey = 100,
int $key = -1
- ): array {
- return [
- '@type' => 'VirtualVmxnet3',
+ ): VirtualVmxnet3 {
+ return new VirtualVmxnet3([
'key' => $key,
- 'backing' => [
- '@type' => 'VirtualEthernetCardDistributedVirtualPortBackingInfo',
- 'port' => [
+ 'backing' => new VirtualEthernetCardDistributedVirtualPortBackingInfo([
+ 'port' => new DistributedVirtualSwitchPortConnection([
'switchUuid' => $switchUuid,
'portgroupKey' => $portgroupKey,
- ],
- ],
+ ]),
+ ]),
'controllerKey' => $controllerKey,
'unitNumber' => $unitNumber,
- ];
+ ]);
}
public function editNetworkSpec(
@@ -109,118 +138,104 @@ public function editNetworkSpec(
string $portgroupKey,
int $key,
?string $macAddress = null
- ): array {
- $data = [
- '@type' => 'VirtualVmxnet3',
+ ): VirtualVmxnet3 {
+ return new VirtualVmxnet3([
'key' => $key,
- 'backing' => [
- '@type' => 'VirtualEthernetCardDistributedVirtualPortBackingInfo',
- 'port' => [
+ 'backing' => new VirtualEthernetCardDistributedVirtualPortBackingInfo([
+ 'port' => new DistributedVirtualSwitchPortConnection([
'switchUuid' => $switchUuid,
'portgroupKey' => $portgroupKey,
- ],
- ],
+ ]),
+ ]),
'addressType' => 'generated',
'macAddress' => $macAddress,
- ];
-
- if ($macAddress) {
- $data['macAddress'] = $macAddress;
- }
-
- return $data;
+ ]);
}
- public function addSasControllerSpec()
+ public function addSasControllerSpec(): VirtualLsiLogicSASController
{
- return [
- '@type' => 'VirtualLsiLogicSASController',
+ return new VirtualLsiLogicSASController([
+ 'key' => 1000,
'busNumber' => 1,
'hotAddRemove' => true,
'sharedBus' => 'physicalSharing',
- ];
+ ]);
}
- public function mountVirtualCdRomSpec(string $fileName, int $key, int $controllerKey, string $datastore): array
+ public function mountVirtualCdRomSpec(string $fileName, int $key, int $controllerKey, string $datastore): VirtualCdrom
{
- return [
- '@type' => 'VirtualCdrom',
+ return new VirtualCdrom([
'key' => $key,
- 'backing' => [
- '@type' => 'VirtualCdromIsoBackingInfo',
+ 'backing' => new VirtualCdromIsoBackingInfo([
'fileName' => $fileName,
'datastore' => [
'type' => 'Datastore',
'_' => $datastore,
],
- ],
- 'connectable' => [
+ ]),
+ 'connectable' => new VirtualDeviceConnectInfo([
'startConnected' => true,
'allowGuestControl' => true,
'connected' => true,
- ],
+ ]),
'controllerKey' => $controllerKey,
- ];
+ ]);
}
- public function unmountVirtualCdRomSpec(int $key, int $controllerKey): array
+ public function unmountVirtualCdRomSpec(int $key, int $controllerKey): VirtualCdrom
{
- return [
- '@type' => 'VirtualCdrom',
+ return new VirtualCdrom([
'key' => $key,
- 'backing' => [
- '@type' => 'VirtualCdromRemoteAtapiBackingInfo',
+ 'backing' => new VirtualCdromRemoteAtapiBackingInfo([
'deviceName' => 'CDRom',
- ],
- 'connectable' => [
+ ]),
+ 'connectable' => new VirtualDeviceConnectInfo([
'startConnected' => false,
'allowGuestControl' => false,
'connected' => false,
- ],
+ ]),
'controllerKey' => $controllerKey,
- ];
+ ]);
}
- public function fixedIpAdapterSpec(string $ip, string $subnetMask, array $dnsServerList, array $gateway): array
+ public function fixedIpAdapterSpec(string $ip, string $subnetMask, array $dnsServerList, array $gateway): CustomizationAdapterMapping
{
- return [
- 'adapter' => [
- '@type' => 'CustomizationFixedIp',
- 'ipAddress' => $ip,
- ],
- 'subnetMask' => $subnetMask,
- 'dnsServerList' => $dnsServerList,
- 'gateway' => $gateway,
-
- ];
+ return new CustomizationAdapterMapping([
+ 'adapter' => new CustomizationIPSettings([
+ 'ip' => new CustomizationFixedIp([
+ 'ipAddress' => $ip,
+ ]),
+ 'subnetMask' => $subnetMask,
+ 'dnsServerList' => $dnsServerList,
+ 'gateway' => $gateway,
+ ]),
+ ]);
}
- public function customizationIdendity(string $hostname, string $license, string $password, string $name): array
+ public function customizationIdendity(string $hostname, string $license, string $password, string $name): CustomizationSysprep
{
- return [
- 'type' => 'CustomizationSysprep',
- 'guiUnattended' => [
- 'password' => [
+ return new CustomizationSysprep([
+ 'guiUnattended' => new CustomizationGuiUnattended([
+ 'password' => new CustomizationPassword([
'plainText' => true,
'value' => $password,
- ],
+ ]),
'timeZone' => 110,
'autoLogon' => true,
'autoLogonCount' => 1,
- ],
- 'userData' => [
+ ]),
+ 'userData' => new CustomizationUserData([
'fullName' => $name,
'orgName' => $name,
- 'computerName' => [
- '@type' => 'CustomizationFixedName',
+ 'computerName' => new CustomizationFixedName([
'name' => $hostname,
- ],
+ ]),
'productId' => $license,
- ],
- 'identification' => [
+ ]),
+ 'identification' => new CustomizationIdentification([
'joinWorkgroup' => 'workgroup',
- ],
- ];
+ ]),
+ ]);
}
}
diff --git a/src/Requests/ApiRequest.php b/src/Requests/ApiRequest.php
index 3582dfd..d847629 100644
--- a/src/Requests/ApiRequest.php
+++ b/src/Requests/ApiRequest.php
@@ -13,7 +13,13 @@ trait ApiRequest
private function request(string $method, string $uri, array $options = [])
{
try {
- return json_decode($this->guzzleClient->request($method, $uri, $options)->getBody());
+ $result = json_decode($this->guzzleClient->request($method, $uri, $options)->getBody());
+
+ if ($this->version < 7 && isset($result->value)) {
+ return $result->value;
+ }
+
+ return $result;
} catch (ConnectException $e) {
Log::error('Rest api Connect exception: '.$e->getMessage());
} catch (ServerException $e) {
@@ -24,7 +30,7 @@ private function request(string $method, string $uri, array $options = [])
return [
'isError' => true,
'code' => $e->getCode(),
- 'info' => json_decode($e->getResponse()->getBody()->getContents()),
+ 'info' => $this->transformErrorInfo(json_decode($e->getResponse()->getBody()->getContents(), true)),
];
} catch (ClientException $e) {
// if 401, create new session and reply attempt
@@ -32,4 +38,19 @@ private function request(string $method, string $uri, array $options = [])
Log::error('Rest api exception : '.$e->getMessage());
}
}
+
+ private function transformErrorInfo(array $info)
+ {
+ if ($this->version < 7) {
+ if (isset($info['value']['messages'])) {
+ $info['messages'] = $info['value']['messages'];
+ } elseif (isset($info['localizableMessages'])) {
+ $info['messages'] = $info['localizableMessages'];
+ }
+ } elseif (count($info['messages']) === 0) {
+ $info['messages'][0]['default_message'] = $info['error_type'];
+ }
+
+ return $info;
+ }
}
diff --git a/src/Requests/SoapRequest.php b/src/Requests/SoapRequest.php
index db5fa9f..5a7ba8d 100644
--- a/src/Requests/SoapRequest.php
+++ b/src/Requests/SoapRequest.php
@@ -2,8 +2,61 @@
namespace Xelon\VmWareClient\Requests;
+use Illuminate\Support\Facades\Log;
+use stdClass;
+use Xelon\VmWareClient\Transform\SoapTransform;
+
trait SoapRequest
{
+ use SoapTransform;
+
+ /**
+ * @param string $method
+ * @param array $requestBody
+ * @param bool $convertToSoap
+ * @return stdClass
+ */
+ public function request(string $method, array $requestBody, bool $convertToSoap = true)
+ {
+ try {
+ $response = $this->soapClient->$method($convertToSoap ? $this->arrayToSoapVar($requestBody) : $requestBody);
+
+ if (config('vmware-php-client.enable_logs')) {
+ Log::info(
+ 'SOAP REQUEST SUCCESS:'.
+ "\nSOAP method: ".$method.
+ property_exists($this->soapClient, '__last_request')
+ ? "\nSOAP request start***".$this->soapClient->__last_request.'***SOAP request end'
+ : ''
+ );
+ }
+
+ return $response;
+ } catch (\Exception $exception) {
+ $message = "SOAP REQUEST FAILED:\nMessage: ".$exception->getMessage().
+ "\nSOAP method: ".$method.
+ (
+ property_exists($this->soapClient, '__last_request')
+ ? "\nSOAP request start***".$this->soapClient->__last_request.'***SOAP request end'
+ : ''
+ ).(
+ property_exists($this->soapClient, '__last_request')
+ ? "\nSOAP response start***: ".$this->soapClient->__last_response.'***SOAP response end'
+ : ''
+ ).
+ "\nTrace: ".json_encode($exception->getTrace());
+
+ Log::error($message);
+ throw new \Exception($message);
+ }
+ }
+
+ /**
+ * @param string $method
+ * @param string $vmId
+ * @param array $requestBody
+ * @return stdClass
+ */
private function vmRequest(string $method, string $vmId, array $requestBody = [])
{
$soapMessage = [
@@ -14,6 +67,6 @@ private function vmRequest(string $method, string $vmId, array $requestBody = []
];
$soapMessage = array_merge($soapMessage, $requestBody);
- return $this->soapClient->$method($soapMessage);
+ return $this->request($method, $soapMessage);
}
}
diff --git a/src/Traits/Rest/CisApis.php b/src/Traits/Rest/CisApis.php
new file mode 100644
index 0000000..abd315b
--- /dev/null
+++ b/src/Traits/Rest/CisApis.php
@@ -0,0 +1,64 @@
+request(
+ 'post',
+ $this->version >= 7
+ ? '/api/cis/tagging/tag-association?action=list-attached-tags'
+ : '/rest/com/vmware/cis/tagging/tag-association?~action=list-attached-tags',
+ [
+ 'json' => [
+ 'object_id' => [
+ 'type' => 'VirtualMachine',
+ 'id' => $vmId,
+ ],
+ ],
+ ]
+ );
+ }
+
+ public function atachTagAssociation(string $vmId, string $tagId)
+ {
+ return $this->request(
+ 'post',
+ $this->version >= 7
+ ? "/api/cis/tagging/tag-association/$tagId?action=attach"
+ : "/rest/com/vmware/cis/tagging/tag-association/id:$tagId?~action=attach",
+ [
+ 'json' => [
+ 'object_id' => [
+ 'type' => 'VirtualMachine',
+ 'id' => $vmId,
+ ],
+ ],
+ ]
+ );
+ }
+
+ public function detachTagAssociation(string $vmId, string $tagId)
+ {
+ return $this->request(
+ 'post',
+ $this->version >= 7
+ ? "/api/cis/tagging/tag-association/$tagId?action=detach"
+ : "/rest/com/vmware/cis/tagging/tag-association/id:$tagId?~action=detach",
+ [
+ 'json' => [
+ 'object_id' => [
+ 'type' => 'VirtualMachine',
+ 'id' => $vmId,
+ ],
+ ],
+ ]
+ );
+ }
+}
diff --git a/src/Traits/Rest/IsoApis.php b/src/Traits/Rest/IsoApis.php
index f1262de..3c036e2 100644
--- a/src/Traits/Rest/IsoApis.php
+++ b/src/Traits/Rest/IsoApis.php
@@ -10,17 +10,27 @@ trait IsoApis
public function mountImage(string $vmId, string $libraryItem)
{
- return $this->request('post', '/api/vcenter/iso/image?action=mount', ['form_params' => [
- 'library_item' => $libraryItem,
- 'vm' => $vmId,
- ]]);
+ if ($this->version >= 7) {
+ $url = '/api/vcenter/iso/image?action=mount';
+ $params = ['library_item' => $libraryItem, 'vm' => $vmId];
+ } else {
+ $url = "/rest/com/vmware/vcenter/iso/image/id:$libraryItem?~action=mount";
+ $params = ['vm' => $vmId];
+ }
+
+ return $this->request('post', $url, ['form_params' => $params]);
}
public function unmountImage(string $vmId, string $cdRom)
{
- return $this->request('post', '/api/vcenter/iso/image?action=unmount', ['form_params' => [
- 'cdrom' => $cdRom,
- 'vm' => $vmId,
- ]]);
+ if ($this->version >= 7) {
+ $url = '/api/vcenter/iso/image?action=unmount';
+ $params = ['cdrom' => $cdRom, 'vm' => $vmId];
+ } else {
+ $url = "/rest/com/vmware/vcenter/iso/image/id:$vmId?~action=unmount";
+ $params = ['cdrom' => $cdRom];
+ }
+
+ return $this->request('post', $url, ['form_params' => $params]);
}
}
diff --git a/src/Traits/Rest/OfvApis.php b/src/Traits/Rest/OfvApis.php
new file mode 100644
index 0000000..e3ded32
--- /dev/null
+++ b/src/Traits/Rest/OfvApis.php
@@ -0,0 +1,66 @@
+ $data['network_port_group'],
+ 'key' => 'VM Network',
+ ];
+
+ if ($this->version < 7) {
+ $networkMappings = [$networkMappings];
+ }
+
+ $body = [
+ 'deployment_spec' => [
+ 'name' => $data['name'],
+ 'accept_all_EULA' => false,
+ 'default_datastore_id' => $data['default_datastore_id'],
+ 'storage_provisioning' => 'thin',
+ 'additional_parameters' => [
+ [
+ '@class' => 'com.vmware.vcenter.ovf.property_params',
+ 'type' => 'PropertyParams',
+ 'properties' => [
+ [
+ 'instance_id' => '',
+ 'class_id' => '',
+ 'description' => 'In order to fit into a xml attribute, this value is base64 encoded . It will be decoded, and then processed normally as user-data.',
+ 'id' => 'user-data',
+ 'label' => 'Encoded user-data',
+ 'category' => '',
+ 'type' => 'string',
+ 'value' => $data['user_data'],
+ 'ui_optional' => false,
+ ],
+ ],
+ ],
+ ],
+ 'network_mappings' => $networkMappings,
+ ],
+ 'target' => [
+ 'resource_pool_id' => $data['resource_pool_id'],
+ ],
+ ];
+
+ if (isset($data['folder_id'])) {
+ $body['target']['folder_id'] = $data['folder_id'];
+ }
+
+ return $this->request(
+ 'post',
+ $this->version >= 7
+ ? "/api/vcenter/ovf/library-item/$ovfLibraryItemId?action=deploy"
+ : "/rest/com/vmware/vcenter/ovf/library-item/id:$ovfLibraryItemId?~action=deploy",
+ ['json' => $body]
+ );
+ }
+}
diff --git a/src/Traits/Rest/VcenterApis.php b/src/Traits/Rest/VcenterApis.php
index 1af6b2f..3c67d91 100644
--- a/src/Traits/Rest/VcenterApis.php
+++ b/src/Traits/Rest/VcenterApis.php
@@ -3,34 +3,50 @@
namespace Xelon\VmWareClient\Traits\Rest;
use Xelon\VmWareClient\Requests\ApiRequest;
+use Xelon\VmWareClient\Transform\SoapTransform;
trait VcenterApis
{
use ApiRequest;
+ use SoapTransform;
public function createVm()
{
// TODO:
}
- public function getVmList()
+ public function getVmList(array $requestBody = [])
{
- return $this->request('get', '/api/vcenter/vm');
+ return $this->request(
+ 'get',
+ "$this->apiUrlPrefix/vcenter/vm",
+ ['query' => $this->getListFilterQuery($requestBody)]
+ );
}
public function getVmInfo(string $vmId)
{
- return $this->request('get', "/api/vcenter/vm/$vmId");
+ $result = $this->request('get', "$this->apiUrlPrefix/vcenter/vm/$vmId");
+
+ if ($this->version < 7) {
+ foreach ($result->disks as $disk) {
+ foreach ($disk->value as $key => $property) {
+ $disk->$key = $property;
+ }
+ }
+ }
+
+ return $result;
}
- public function deleteVm()
+ public function deleteVm(string $vmId)
{
- // TODO:
+ return $this->request('delete', "$this->apiUrlPrefix/vcenter/vm/$vmId");
}
public function cloneVm(array $requestBody)
{
- return $this->request('post', '/api/vcenter/vm?action=clone', ['body' => $requestBody]);
+ return $this->request('post', "$this->apiUrlPrefix/vcenter/vm?action=clone", ['json' => $requestBody]);
}
public function registerVm()
@@ -52,4 +68,13 @@ public function unregisterVm()
{
// TODO:
}
+
+ public function getNetworkList(array $requestBody = [])
+ {
+ return $this->request(
+ 'get',
+ "$this->apiUrlPrefix/vcenter/network",
+ ['query' => $this->getListFilterQuery($requestBody)]
+ );
+ }
}
diff --git a/src/Traits/Rest/VmApis.php b/src/Traits/Rest/VmApis.php
index e4f703d..b1b3884 100644
--- a/src/Traits/Rest/VmApis.php
+++ b/src/Traits/Rest/VmApis.php
@@ -35,22 +35,36 @@ public function getPower()
public function resetPower(string $vmId)
{
- return $this->request('post', "/api/vcenter/vm/$vmId/power?action=reset");
+ return $this->request(
+ 'post',
+ $this->version >= 7 ? "/api/vcenter/vm/$vmId/power?action=reset" : "/rest/vcenter/vm/$vmId/power/reset"
+ );
}
public function startPower(string $vmId)
{
- return $this->request('post', "/api/vcenter/vm/$vmId/power?action=start");
+ return $this->request(
+ 'post',
+ $this->version >= 7 ? "/api/vcenter/vm/$vmId/power?action=start" : "/rest/vcenter/vm/$vmId/power/start"
+ );
}
public function stopPower(string $vmId)
{
- return $this->request('post', "/api/vcenter/vm/$vmId/power?action=stop");
+ $a = 5;
+
+ return $this->request(
+ 'post',
+ $this->version >= 7 ? "/api/vcenter/vm/$vmId/power?action=stop" : "/rest/vcenter/vm/$vmId/power/stop"
+ );
}
public function suspendPower(string $vmId)
{
- return $this->request('post', "/api/vcenter/vm/$vmId/power?action=suspend");
+ return $this->request(
+ 'post',
+ $this->version >= 7 ? "/api/vcenter/vm/$vmId/power?action=suspend" : "/rest/vcenter/vm/$vmId/power/suspend"
+ );
}
public function getTools()
@@ -275,14 +289,21 @@ public function updateHardwareCpu(
bool $hotAddEnabled = false,
bool $hotRemoveEnabled = false
) {
- return $this->request('patch', "/api/vcenter/vm/$vmId/hardware/cpu", [
- 'json' => [
- 'cores_per_socket' => $coresPerSocket,
- 'count' => $count,
- 'hot_add_enabled' => $hotAddEnabled,
- 'hot_remove_enabled' => $hotRemoveEnabled,
- ],
- ]);
+ $requestBody = [
+ 'cores_per_socket' => $coresPerSocket,
+ 'count' => $count,
+ 'hot_add_enabled' => $hotAddEnabled,
+ 'hot_remove_enabled' => $hotRemoveEnabled,
+ ];
+
+ if ($this->version < 7) {
+ $requestBody = ['spec' => $requestBody];
+ }
+
+ return $this->request(
+ 'patch',
+ "$this->apiUrlPrefix/vcenter/vm/$vmId/hardware/cpu",
+ ['json' => $requestBody]);
}
public function listHardwareDisk()
@@ -292,7 +313,7 @@ public function listHardwareDisk()
public function createHardwareDisk(string $vmId, array $body)
{
- return $this->request('post', "/api/vcenter/vm/$vmId/hardware/disk", ['json' => $body]);
+ return $this->request('post', "$this->apiUrlPrefix/vcenter/vm/$vmId/hardware/disk", ['json' => $body]);
}
public function getHardwareDisk()
@@ -307,7 +328,7 @@ public function updateHardwareDisk()
public function deleteHardwareDisk(string $vmId, int $diskKey)
{
- return $this->request('delete', "/api/vcenter/vm/$vmId/hardware/disk/$diskKey");
+ return $this->request('delete', "$this->apiUrlPrefix/vcenter/vm/$vmId/hardware/disk/$diskKey");
}
public function listHardwareEthernet()
@@ -332,7 +353,7 @@ public function updateHardwareEthernet()
public function deleteHardwareEthernet(string $vmId, int $nicKey)
{
- return $this->request('delete', "/api/vcenter/vm/$vmId/hardware/ethernet/$nicKey");
+ return $this->request('delete', "$this->apiUrlPrefix/vcenter/vm/$vmId/hardware/ethernet/$nicKey");
}
public function connectHardwareEthernet()
@@ -387,12 +408,17 @@ public function getHardwareMemory()
public function updateHardwareMemory(string $vmId, int $size, bool $hotAddEnabled = false)
{
- return $this->request('patch', "/api/vcenter/vm/$vmId/hardware/memory", [
- 'json' => [
- 'hot_add_enabled' => $hotAddEnabled,
- 'size_MiB' => $size,
- ],
- ]);
+ $requestBody = ['hot_add_enabled' => $hotAddEnabled, 'size_MiB' => $size];
+
+ if ($this->version < 7) {
+ $requestBody = ['spec' => $requestBody];
+ }
+
+ return $this->request(
+ 'patch',
+ "$this->apiUrlPrefix/vcenter/vm/$vmId/hardware/memory",
+ ['json' => $requestBody]
+ );
}
public function listHardwareParallel()
diff --git a/src/Traits/Soap/SoapFileApis.php b/src/Traits/Soap/SoapFileApis.php
deleted file mode 100644
index c55aca1..0000000
--- a/src/Traits/Soap/SoapFileApis.php
+++ /dev/null
@@ -1,159 +0,0 @@
- 0) {
- foreach ($params as $key => $value) {
- $script = str_replace('{'.$key.'}', $value, $script);
- }
- }
-
- $body = [
- '_this' => [
- 'type' => 'GuestFileManager',
- '_' => 'guestOperationsFileManager',
- ],
- 'vm' => [
- 'type' => 'VirtualMachine',
- '_' => $vmId,
- ],
- 'auth' => [
- '@type' => 'NamePasswordAuthentication',
- 'interactiveSession' => true,
- 'username' => $username,
- 'password' => $password,
- ],
- 'guestFilePath' => "{$guestFilePath}",
- 'fileAttributes' => new \stdClass(),
- 'fileSize' => strlen($script),
- 'overwrite' => true,
- ];
-
- $response = $this->soapClient->InitiateFileTransferToGuest($this->arrayToSoapVar($body));
-
- $client = new GuzzleClient(['verify' => false]);
-
- try {
- if (is_string($response->returnval) && substr($response->returnval, 0, 4) !== 'http') {
- throw new Exception('File transfer invalid response url');
- }
- $client->request('PUT', $response->returnval, ['body' => $script]);
- } catch (Exception $e) {
- throw new Exception($e->getMessage());
- }
- }
-
- public function createTemporaryDirectoryInGuest(
- string $username,
- string $password,
- string $vmId,
- string $directoryPath,
- string $prefix = '',
- string $sufix = ''
- ) {
- $body = [
- '_this' => [
- 'type' => 'GuestFileManager',
- '_' => 'guestOperationsFileManager',
- ],
- 'vm' => [
- 'type' => 'VirtualMachine',
- '_' => $vmId,
- ],
- 'auth' => [
- '@type' => 'NamePasswordAuthentication',
- 'interactiveSession' => false,
- 'username' => $username,
- 'password' => $password,
- ],
- 'prefix' => $prefix,
- 'suffix' => $sufix,
- 'directoryPath' => $directoryPath,
- ];
-
- return $this->soapClient->CreateTemporaryDirectoryInGuest($this->arrayToSoapVar($body));
- }
-
- public function deleteDirectoryInGuest(
- string $username,
- string $password,
- string $vmId,
- string $directoryPath
- ) {
- $body = [
- '_this' => [
- 'type' => 'GuestFileManager',
- '_' => 'guestOperationsFileManager',
- ],
- 'vm' => [
- 'type' => 'VirtualMachine',
- '_' => $vmId,
- ],
- 'auth' => [
- '@type' => 'NamePasswordAuthentication',
- 'interactiveSession' => false,
- 'username' => $username,
- 'password' => $password,
- ],
- 'directoryPath' => $directoryPath,
- 'recursive' => true,
- ];
-
- return $this->soapClient->DeleteDirectoryInGuest($this->arrayToSoapVar($body));
- }
-
- public function startProgramInGuest(
- string $username,
- string $password,
- string $vmId,
- string $filePath,
- string $program = '/bin/bash'
- ) {
- $body = [
- '_this' => [
- 'type' => 'GuestProcessManager',
- '_' => 'guestOperationsProcessManager',
- ],
- 'vm' => [
- 'type' => 'VirtualMachine',
- '_' => $vmId,
- ],
- 'auth' => [
- '@type' => 'NamePasswordAuthentication',
- 'interactiveSession' => false,
- 'username' => $username,
- 'password' => $password,
- ],
- 'spec' => [
- 'programPath' => $program,
- 'arguments' => "{$filePath}",
- ],
- ];
-
- return $this->soapClient->StartProgramInGuest($this->arrayToSoapVar($body));
- }
-}
diff --git a/src/Traits/Soap/SoapGuestApis.php b/src/Traits/Soap/SoapGuestApis.php
new file mode 100644
index 0000000..7443bf1
--- /dev/null
+++ b/src/Traits/Soap/SoapGuestApis.php
@@ -0,0 +1,347 @@
+ 0) {
+ foreach ($params as $key => $value) {
+ $data = str_replace('{'.$key.'}', $value, $data);
+ }
+ }
+
+ $body = [
+ '_this' => [
+ 'type' => 'GuestFileManager',
+ '_' => 'guestOperationsFileManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ 'guestFilePath' => $guestFilePath,
+ 'fileAttributes' => new \stdClass(),
+ 'fileSize' => strlen($data),
+ 'overwrite' => true,
+ ];
+
+ $response = $this->request('InitiateFileTransferToGuest', $body);
+
+ $client = new GuzzleClient(['verify' => false]);
+
+ try {
+ if (! isset($response->returnval) || ! is_string($response->returnval) || substr($response->returnval, 0, 4) !== 'http') {
+ throw new Exception('File transfer invalid response url');
+ }
+ $client->request('PUT', $response->returnval, ['body' => $data]);
+ } catch (Exception $e) {
+ throw new Exception("{$e->getMessage()}. Response: ".json_encode($response));
+ }
+ }
+
+ public function createTemporaryDirectoryInGuest(
+ string $username,
+ string $password,
+ string $vmId,
+ string $directoryPath,
+ string $prefix = '',
+ string $sufix = ''
+ ) {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestFileManager',
+ '_' => 'guestOperationsFileManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ 'prefix' => $prefix,
+ 'suffix' => $sufix,
+ 'directoryPath' => $directoryPath,
+ ];
+
+ return $this->request('CreateTemporaryDirectoryInGuest', $body);
+ }
+
+ public function makeDirectoryInGuest(
+ string $username,
+ string $password,
+ string $vmId,
+ string $directoryPath,
+ bool $createParentDirectories = false
+ ) {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestFileManager',
+ '_' => 'guestOperationsFileManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ 'directoryPath' => $directoryPath,
+ 'createParentDirectories' => $createParentDirectories,
+ ];
+
+ return $this->request('MakeDirectoryInGuest', $body);
+ }
+
+ public function listFilesInGuest(
+ string $username,
+ string $password,
+ string $vmId,
+ string $filePath,
+ int $index = 0,
+ int $maxResults = 50,
+ ?string $matchPattern = null
+ ) {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestFileManager',
+ '_' => 'guestOperationsFileManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ 'filePath' => $filePath,
+ 'index' => $index,
+ 'maxResults' => $maxResults,
+ 'matchPattern' => $matchPattern,
+ ];
+
+ return $this->request('ListFilesInGuest', $body);
+ }
+
+ public function deleteDirectoryInGuest(
+ string $username,
+ string $password,
+ string $vmId,
+ string $directoryPath
+ ) {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestFileManager',
+ '_' => 'guestOperationsFileManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ 'directoryPath' => $directoryPath,
+ 'recursive' => true,
+ ];
+
+ return $this->request('DeleteDirectoryInGuest', $body);
+ }
+
+ public function deleteFileInGuest(
+ string $username,
+ string $password,
+ string $vmId,
+ string $filePath
+ ) {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestFileManager',
+ '_' => 'guestOperationsFileManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ 'filePath' => $filePath,
+ ];
+
+ return $this->request('DeleteFileInGuest', $body);
+ }
+
+ public function startProgramInGuest(
+ string $username,
+ string $password,
+ string $vmId,
+ string $filePath,
+ string $program = '/bin/bash'
+ ) {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestProcessManager',
+ '_' => 'guestOperationsProcessManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ 'spec' => [
+ 'programPath' => $program,
+ 'arguments' => $filePath,
+ ],
+ ];
+
+ return $this->request('StartProgramInGuest', $body);
+ }
+
+ public function createTaskCollectorForVm(string $vmId)
+ {
+ $body = [
+ '_this' => [
+ '_' => 'TaskManager',
+ 'type' => 'TaskManager',
+ ],
+ 'filter' => [
+ 'entity' => [
+ 'entity' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'recursion' => 'self',
+ ],
+ ],
+ ];
+
+ return $this->request('CreateCollectorForTasks', $body);
+ }
+
+ public function destroyTaskCollector(string $taskCollectorId)
+ {
+ $body = [
+ '_this' => [
+ 'type' => 'HistoryCollector',
+ '_' => $taskCollectorId,
+ ],
+ ];
+
+ return $this->request('DestroyCollector', $body);
+ }
+
+ public function getListFilesInGuest(
+ string $username,
+ string $password,
+ string $vmId,
+ string $filePath
+ ) {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestFileManager',
+ '_' => 'guestOperationsFileManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ 'filePath' => $filePath,
+ ];
+
+ return $this->request('ListFilesInGuest', $body);
+ }
+
+ public function getListProcessInGuest(
+ string $username,
+ string $password,
+ string $vmId
+ ) {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestFileManager',
+ '_' => 'guestOperationsFileManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ '@type' => 'NamePasswordAuthentication',
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ ];
+
+ return $this->request('ListProcessesInGuest', $body);
+ }
+
+ public function validateCredentialsInGuest(string $username, string $password, string $vmId)
+ {
+ $body = [
+ '_this' => [
+ 'type' => 'GuestAuthManager',
+ '_' => 'guestOperationsAuthManager',
+ ],
+ 'vm' => [
+ 'type' => 'VirtualMachine',
+ '_' => $vmId,
+ ],
+ 'auth' => new NamePasswordAuthentication([
+ 'interactiveSession' => false,
+ 'username' => $username,
+ 'password' => $password,
+ ]),
+ ];
+
+ return $this->request('ValidateCredentialsInGuest', $body);
+ }
+}
diff --git a/src/Traits/Soap/SoapStorageApis.php b/src/Traits/Soap/SoapStorageApis.php
new file mode 100644
index 0000000..0e91a57
--- /dev/null
+++ b/src/Traits/Soap/SoapStorageApis.php
@@ -0,0 +1,94 @@
+ [
+ 'id' => $vstorageId,
+ ],
+ '_this' => [
+ 'type' => 'VcenterVStorageObjectManager',
+ '_' => 'VStorageObjectManager',
+ ],
+ 'datastore' => [
+ 'type' => 'Datastore',
+ '_' => $datastore,
+ ],
+ ];
+
+ return $this->transformToArrayValues($this->request('RetrieveVStorageObject', $body));
+ }
+
+ public function deleteVcenterVStorageInfo(string $vstorageId, string $datastore)
+ {
+ $body = [
+ 'id' => [
+ 'id' => $vstorageId,
+ ],
+ '_this' => [
+ 'type' => 'VcenterVStorageObjectManager',
+ '_' => 'VStorageObjectManager',
+ ],
+ 'datastore' => [
+ 'type' => 'Datastore',
+ '_' => $datastore,
+ ],
+ ];
+
+ return $this->request('DeleteVStorageObject_Task', $body);
+ }
+
+ public function createVStorage(string $name, int $capacityInMB, string $datastore, bool $keepAfterDeleteVm = true)
+ {
+ $body = [
+ '_this' => [
+ 'type' => 'VcenterVStorageObjectManager',
+ '_' => 'VStorageObjectManager',
+ ],
+ 'spec' => [
+ 'name' => $name,
+ 'keepAfterDeleteVm' => $keepAfterDeleteVm,
+ 'backingSpec' => new VslmCreateSpecDiskFileBackingSpec([
+ 'datastore' => [
+ 'type' => 'Datastore',
+ '_' => $datastore,
+ ],
+ ]),
+ 'capacityInMB' => $capacityInMB,
+ ],
+ ];
+
+ return $this->request('CreateDisk_Task', $body);
+ }
+
+ public function extendVStorage(string $vstorageId, string $datastore, int $newCapacityInMB)
+ {
+ $body = [
+ '_this' => [
+ 'type' => 'VcenterVStorageObjectManager',
+ '_' => 'VStorageObjectManager',
+ ],
+ 'id' => [
+ 'id' => $vstorageId,
+ ],
+ 'datastore' => [
+ 'type' => 'Datastore',
+ '_' => $datastore,
+ ],
+ 'newCapacityInMB' => $newCapacityInMB,
+ ];
+
+ return $this->request('ExtendDisk_Task', $body);
+ }
+}
diff --git a/src/Traits/Soap/SoapVmApis.php b/src/Traits/Soap/SoapVmApis.php
index 4d098c0..f8bdffa 100644
--- a/src/Traits/Soap/SoapVmApis.php
+++ b/src/Traits/Soap/SoapVmApis.php
@@ -2,70 +2,99 @@
namespace Xelon\VmWareClient\Traits\Soap;
+use Illuminate\Support\Facades\Log;
use Xelon\VmWareClient\Requests\SoapRequest;
use Xelon\VmWareClient\Transform\SoapTransform;
+use Xelon\VmWareClient\Types\ClusterAntiAffinityRuleSpec;
+use Xelon\VmWareClient\Types\ClusterConfigSpecEx;
+use Xelon\VmWareClient\Types\ClusterDpmConfigInfo;
+use Xelon\VmWareClient\Types\ClusterDrsConfigInfo;
+use Xelon\VmWareClient\Types\ClusterRuleSpec;
+use Xelon\VmWareClient\Types\DVPortgroupConfigSpec;
+use Xelon\VmWareClient\Types\DVPortSetting;
+use Xelon\VmWareClient\Types\DVSTrafficShapingPolicy;
+use Xelon\VmWareClient\Types\VirtualDeviceConfigSpec;
+use Xelon\VmWareClient\Types\VirtualMachineBootOptionsBootableCdromDevice;
+use Xelon\VmWareClient\Types\VirtualMachineConfigSpec;
trait SoapVmApis
{
use SoapRequest;
use SoapTransform;
- public function getVmInfo(string $vmId, string $pathSet = '')
+ public function getObjectInfo(string $objectId, string $objectType, string $pathSet = '')
{
- $body = [
- '_this' => [
- '_' => 'propertyCollector',
- 'type' => 'PropertyCollector',
- ],
- 'specSet' => [
- 'propSet' => [
- 'type' => 'VirtualMachine',
- 'all' => ! $pathSet,
- 'pathSet' => $pathSet,
- ],
- 'objectSet' => [
- 'obj' => [
- '_' => $vmId,
- 'type' => 'VirtualMachine',
- ],
- ],
- ],
- ];
+ $body = $this->data->objectInfoBody($objectId, $objectType, $pathSet);
- $result = $this->soapClient->RetrieveProperties($body);
+ try {
+ $result = $this->soapClient->RetrieveProperties($body);
+ } catch (\Exception $exception) {
+ Log::error(
+ "SOAP REQUEST FAILED:\nMessage: ".$exception->getMessage().
+ "\nSOAP request: ".$this->soapClient->__last_request.
+ "\nSOAP response: ".$this->soapClient->__last_response
+ );
+
+ if (array_keys(json_decode(json_encode($exception->detail), true))[0] === 'ManagedObjectNotFoundFault') {
+ Log::error("404 error, type: $objectType, object id: $objectId");
+
+ return new \stdClass();
+ }
+ }
return $pathSet
? ($result->returnval->propSet->val ?? null)
: $this->transformPropSet($result->returnval->propSet);
}
+ public function getVmInfo(string $vmId, string $pathSet = '')
+ {
+ if (substr($vmId, 0, 2) !== 'vm') {
+ Log::error("Wrong vm id format: $vmId");
+
+ return new \stdClass();
+ }
+
+ return $this->getObjectInfo($vmId, 'VirtualMachine', $pathSet);
+ }
+
public function getTaskInfo(string $taskId, string $pathSet = '')
{
- $body = [
- '_this' => [
- '_' => 'propertyCollector',
- 'type' => 'PropertyCollector',
- ],
- 'specSet' => [
- 'propSet' => [
- 'type' => 'Task',
- 'all' => ! $pathSet,
- 'pathSet' => $pathSet,
- ],
- 'objectSet' => [
- 'obj' => [
- '_' => $taskId,
- 'type' => 'Task',
- ],
- ],
- ],
- ];
+ return $this->getObjectInfo($taskId, 'Task', $pathSet);
+ }
+
+ public function getClusterComputeResourceInfo(string $clusterComputeResourceId, string $pathSet = '')
+ {
+ return $this->getObjectInfo($clusterComputeResourceId, 'ClusterComputeResource', $pathSet);
+ }
- $result = $this->soapClient->RetrieveProperties($body);
+ public function getDatastoreInfo(string $datastore, string $pathSet = '')
+ {
+ return $this->getObjectInfo($datastore, 'Datastore', $pathSet);
+ }
- return $pathSet
- ? ($result->returnval->propSet->val ?? null)
- : $this->transformPropSet($result->returnval->propSet);
+ public function getSnapshotInfo(string $taskId, string $pathSet = '')
+ {
+ return $this->getObjectInfo($taskId, 'VirtualMachineSnapshot', $pathSet);
+ }
+
+ public function getTaskHistoryCollectorInfo(string $taskHistoryCollectorId)
+ {
+ return $this->getObjectInfo($taskHistoryCollectorId, 'TaskHistoryCollector');
+ }
+
+ public function getResourcePoolInfo(?string $resourcePoolId, string $pathSet = '')
+ {
+ if (! $resourcePoolId) {
+ return [];
+ }
+
+ return $this->getObjectInfo($resourcePoolId, 'ResourcePool', $pathSet);
+ }
+
+ public function getDistributedVirtualPortgroupInfo(string $distributedVirtualPortgroupId, string $pathSet = '')
+ {
+ return $this->getObjectInfo($distributedVirtualPortgroupId, 'DistributedVirtualPortgroup', $pathSet);
}
public function reconfigVmTask(string $vmId, array $requestBody)
@@ -93,25 +122,27 @@ public function cloneVmTask(string $vmId, array $params)
],
],
'template' => $params['spec']['template'] ?? false,
- 'config' => [
- 'numCPUs' => $params['spec']['config']['numCPUs'],
- 'numCoresPerSocket' => $params['spec']['config']['numCoresPerSocket'],
- 'memoryMB' => $params['spec']['config']['memoryMB'],
- 'deviceChange' => $params['spec']['config']['deviceChange'] ?? null,
- ],
+ 'config' => isset($params['spec']['config'])
+ ? [
+ 'numCPUs' => $params['spec']['config']['numCPUs'],
+ 'numCoresPerSocket' => $params['spec']['config']['numCoresPerSocket'],
+ 'memoryMB' => $params['spec']['config']['memoryMB'],
+ 'deviceChange' => $params['spec']['config']['deviceChange'] ?? null,
+ ]
+ : null,
'customization' => $params['spec']['customization'] ?? null,
'powerOn' => $params['spec']['powerOn'] ?? true,
/*'bootOptions' => [
'bootDelay' => $params['spec']['bootOptions']['bootDelay'] ?? 0,
'bootRetryEnabled' => $params['spec']['bootOptions']['bootRetryEnabled'] ?? true,
'bootOrder' => [
- '@type' => 'VirtualMachineBootOptionsBootableCdromDevice'
+ '@type' => new VirtualMachineBootOptionsBootableCdromDevice()
]
],*/
],
];
- return $this->vmRequest('CloneVM_Task', $vmId, $this->arrayToSoapVar($body));
+ return $this->vmRequest('CloneVM_Task', $vmId, $body);
}
public function addDisk(
@@ -122,15 +153,13 @@ public function addDisk(
string $name = 'New Hard disk'
) {
$body = [
- 'spec' => [
- '@type' => 'VirtualMachineConfigSpec',
- 'deviceChange' => [
- '@type' => 'VirtualDeviceConfigSpec',
+ 'spec' => new VirtualMachineConfigSpec([
+ 'deviceChange' => new VirtualDeviceConfigSpec([
'operation' => 'add',
'fileOperation' => 'create',
'device' => $this->data->addVirtualDiskSpec($capacityInKB, $unitNumber, $isHdd, $name),
- ],
- ],
+ ]),
+ ]),
];
return $this->reconfigVmTask($vmId, $body);
@@ -139,30 +168,40 @@ public function addDisk(
public function editDisk(string $vmId, array $params)
{
$body = [
- 'spec' => [
- '@type' => 'VirtualMachineConfigSpec',
- 'deviceChange' => [
- '@type' => 'VirtualDeviceConfigSpec',
+ 'spec' => new VirtualMachineConfigSpec([
+ 'deviceChange' => new VirtualDeviceConfigSpec([
'operation' => 'edit',
'device' => $this->data->editVirtualDiskSpec($params),
- ],
- ],
+ ]),
+ ]),
];
return $this->reconfigVmTask($vmId, $body);
}
+ public function addPersistantDisk(string $vmId, string $blockStoragePath, int $capacityInKB, int $controllerKey = 1000)
+ {
+ $body = [
+ 'spec' => new VirtualMachineConfigSpec([
+ 'deviceChange' => new VirtualDeviceConfigSpec([
+ 'operation' => 'add',
+ 'device' => $this->data->addBlockStorageSpec($blockStoragePath, $capacityInKB, $controllerKey),
+ ]),
+ ]),
+ ];
+
+ return $this->reconfigVmTask($vmId, $this->arrayToSoapVar($body));
+ }
+
public function addNetwork(string $vmId, int $unitNumber, string $portgroupKey, string $switchUuid)
{
$body = [
- 'spec' => [
- '@type' => 'VirtualMachineConfigSpec',
- 'deviceChange' => [
- '@type' => 'VirtualDeviceConfigSpec',
+ 'spec' => new VirtualMachineConfigSpec([
+ 'deviceChange' => new VirtualDeviceConfigSpec([
'operation' => 'add',
'device' => $this->data->addNetworkSpec($switchUuid, $portgroupKey, $unitNumber),
- ],
- ],
+ ]),
+ ]),
];
return $this->reconfigVmTask($vmId, $body);
@@ -176,14 +215,12 @@ public function editNetwork(
int $key
) {
$body = [
- 'spec' => [
- '@type' => 'VirtualMachineConfigSpec',
- 'deviceChange' => [
- '@type' => 'VirtualDeviceConfigSpec',
+ 'spec' => new VirtualMachineConfigSpec([
+ 'deviceChange' => new VirtualDeviceConfigSpec([
'operation' => 'edit',
'device' => $this->data->editNetworkSpec($switchUuid, $portgroupKey, $key, $macAddress),
- ],
- ],
+ ]),
+ ]),
];
return $this->reconfigVmTask($vmId, $body);
@@ -192,19 +229,113 @@ public function editNetwork(
public function addSasController(string $vmId)
{
$body = [
- 'spec' => [
- '@type' => 'VirtualMachineConfigSpec',
- 'deviceChange' => [
- '@type' => 'VirtualLsiLogicSASController',
+ 'spec' => new VirtualMachineConfigSpec([
+ 'deviceChange' => new VirtualDeviceConfigSpec([
'operation' => 'add',
'device' => $this->data->addSasControllerSpec(),
- ],
- ],
+ ]),
+ ]),
];
return $this->reconfigVmTask($vmId, $body);
}
+ public function changeDVPortgroupSpeed(
+ string $distributedVirtualPortgroupId,
+ string $configVersion,
+ int $speed
+ ) {
+ $body = [
+ '_this' => [
+ '_' => $distributedVirtualPortgroupId,
+ 'type' => 'DistributedVirtualPortgroup',
+ ],
+ 'spec' => new DVPortgroupConfigSpec([
+ 'configVersion' => $configVersion,
+ 'defaultPortConfig' => new DVPortSetting([
+ 'inShapingPolicy' => new DVSTrafficShapingPolicy([
+ 'inherited' => false,
+ 'enabled' => [
+ 'inherited' => false,
+ 'value' => true,
+ ],
+ 'averageBandwidth' => [
+ 'inherited' => false,
+ 'value' => $speed,
+ ],
+ 'peakBandwidth' => [
+ 'inherited' => false,
+ 'value' => $speed,
+ ],
+ 'burstSize' => [
+ 'inherited' => false,
+ 'value' => $speed,
+ ],
+ ]),
+ 'outShapingPolicy' => new DVSTrafficShapingPolicy([
+ 'inherited' => false,
+ 'enabled' => [
+ 'inherited' => false,
+ 'value' => true,
+ ],
+ 'averageBandwidth' => [
+ 'inherited' => false,
+ 'value' => $speed,
+ ],
+ 'peakBandwidth' => [
+ 'inherited' => false,
+ 'value' => $speed,
+ ],
+ 'burstSize' => [
+ 'inherited' => false,
+ 'value' => $speed,
+ ],
+ ]),
+ ]),
+ ]),
+ ];
+
+ return $this->request('ReconfigureDVPortgroup_Task', $body);
+ }
+
+ public function reconfigureComputeResource(
+ string $clusterComputerResourceId,
+ string $name,
+ array $vmIds
+ ) {
+ $vm = [];
+
+ foreach ($vmIds as $vmId) {
+ $vm[] = [
+ '_' => $vmId,
+ 'type' => 'VirtualMachine',
+ ];
+ }
+
+ $body = [
+ '_this' => [
+ '_' => $clusterComputerResourceId,
+ 'type' => 'ComputeResource',
+ ],
+ 'spec' => new ClusterConfigSpecEx([
+ 'drsConfig' => new ClusterDrsConfigInfo(),
+ 'rulesSpec' => new ClusterRuleSpec([
+ 'operation' => 'add',
+ 'info' => new ClusterAntiAffinityRuleSpec([
+ 'enabled' => true,
+ 'name' => $name,
+ 'userCreated' => true,
+ 'vm' => $vm,
+ ]),
+ ]),
+ 'dpmConfig' => new ClusterDpmConfigInfo(),
+ ]),
+ 'modify' => false,
+ ];
+
+ return $this->request('ReconfigureComputeResource_Task', $body);
+ }
+
public function mountIso(string $vmId, string $fileName, int $key, int $controllerKey, string $datastore)
{
$body = [
@@ -215,9 +346,7 @@ public function mountIso(string $vmId, string $fileName, int $key, int $controll
],
'bootOptions' => [
'bootDelay' => 5000,
- 'bootOrder' => [
- '@type' => 'VirtualMachineBootOptionsBootableCdromDevice',
- ],
+ 'bootOrder' => new VirtualMachineBootOptionsBootableCdromDevice(),
],
],
];
@@ -255,7 +384,7 @@ public function findRulesForVm(string $vmId, string $clusterComputerResource)
],
];
- return $this->soapClient->FindRulesForVm($body);
+ return $this->request('FindRulesForVm', $body);
}
public function createFolder(string $parentFolder, string $name)
@@ -268,13 +397,25 @@ public function createFolder(string $parentFolder, string $name)
'name' => $name,
];
- return $this->soapClient->CreateFolder($body);
+ return $this->request('CreateFolder', $body);
+ }
+
+ public function deleteFolder(string $folderId)
+ {
+ $body = [
+ '_this' => [
+ '_' => $folderId,
+ 'type' => 'Folder',
+ ],
+ ];
+
+ return $this->request('Destroy_Task', $body);
}
public function createSnapshot(
string $vmId,
string $name,
- string $description,
+ ?string $description,
bool $memory = false,
bool $quiesce = true
) {
@@ -287,4 +428,76 @@ public function createSnapshot(
return $this->vmRequest('CreateSnapshot_Task', $vmId, $body);
}
+
+ public function revertSnapshot(string $snapshopId)
+ {
+ $body = [
+ '_this' => [
+ '_' => $snapshopId,
+ 'type' => 'VirtualMachineSnapshot',
+ ],
+ ];
+
+ return $this->request('RevertToSnapshot_Task', $body);
+ }
+
+ public function removeSnapshot(string $snapshopId, bool $removeChildren = true, bool $consolidate = true)
+ {
+ $body = [
+ '_this' => [
+ '_' => $snapshopId,
+ 'type' => 'VirtualMachineSnapshot',
+ ],
+ 'removeChildren' => $removeChildren,
+ 'consolidate' => $consolidate,
+ ];
+
+ return $this->request('RemoveSnapshot_Task', $body);
+ }
+
+ public function queryPerf(
+ string $objectId,
+ ?string $startTime = null,
+ ?string $endTime = null,
+ int $intervalId = 20,
+ ?int $maxSample = null,
+ array $metricIds = [],
+ string $entity = 'VirtualMachine'
+ ) {
+ $body = [
+ '_this' => [
+ '_' => 'PerfMgr',
+ 'type' => 'PerformanceManager',
+ ],
+ 'querySpec' => [
+ 'entity' => [
+ '_' => $objectId,
+ 'type' => $entity,
+ ],
+ 'startTime' => $startTime,
+ 'endTime' => $endTime,
+ 'maxSample' => $maxSample,
+ 'metricId' => array_map(fn (int $id): array => ['counterId' => $id, 'instance' => ''], $metricIds),
+ 'intervalId' => $intervalId,
+ 'format' => 'normal',
+ ],
+ ];
+
+ return $this->transformToArrayValues($this->request('QueryPerf', $body, false));
+ }
+
+ public function acquireTicket(string $vmId, string $ticketType = 'webmks')
+ {
+ return $this->vmRequest('AcquireTicket', $vmId, ['ticketType' => $ticketType]);
+ }
+
+ public function mountToolsInstaller(string $vmId)
+ {
+ return $this->vmRequest('MountToolsInstaller', $vmId);
+ }
+
+ public function unmountToolsInstaller(string $vmId)
+ {
+ return $this->vmRequest('UnmountToolsInstaller', $vmId);
+ }
}
diff --git a/src/Transform/SoapTransform.php b/src/Transform/SoapTransform.php
index 4d7d9d1..28eb1d6 100644
--- a/src/Transform/SoapTransform.php
+++ b/src/Transform/SoapTransform.php
@@ -4,55 +4,80 @@
use SoapVar;
use stdClass;
+use Xelon\VmWareClient\Types\Core\DynamicData;
trait SoapTransform
{
+ private $soapTypes = [
+ 'string' => XSD_STRING,
+ 'integer' => XSD_INT,
+ 'boolean' => XSD_BOOLEAN,
+ 'double' => XSD_FLOAT,
+ 'array' => SOAP_ENC_OBJECT,
+ 'object' => SOAP_ENC_OBJECT,
+ ];
+
public function arrayToSoapVar(array $array): array
{
$typeName = null;
$data = [];
foreach ($array as $key => $value) {
- if (is_array($value)) {
+ if (is_array($value) || $value instanceof DynamicData) {
+ if ($value instanceof DynamicData) {
+ $typeName = (new \ReflectionClass($value))->getShortName();
+ $value = $value->toArray();
+ }
+
if (array_key_exists('@type', $value)) {
$typeName = $value['@type'];
unset($value['@type']);
}
if (array_key_exists('type', $value)) {
- $data[$key] = new SoapVar($value['_'], null, $value['type'], '', '', '');
+ $data[$key] = new SoapVar($value['_'], null, $value['type'], '', $key, '');
continue;
}
- // TODO: Get rid of BOGUS and ENV:Struct tags
- /*if (array_key_exists(0, $value)) {
- $arrayData = [];
+ if (is_array($value) && array_key_exists(0, $value)) {
+ foreach ($value as $childItem) {
+ if ($childItem instanceof DynamicData) {
+ $typeName = (new \ReflectionClass($childItem))->getShortName();
+ $childItem = $childItem->toArray();
+ }
- foreach ($value as $item) {
- $arrayData[] = new SoapVar($this->arrayToSoapVar($item), SOAP_ENC_OBJECT, $typeName, 'VirtualDeviceConfigSpec', 'deviceChange', '');
- }
+ if (is_array($childItem)) {
+ if (array_key_exists('@type', $childItem)) {
+ $typeName = $childItem['@type'];
+ unset($childItem['@type']);
+ }
- $data[$key] = new SoapVar($arrayData, SOAP_ENC_OBJECT, '', '', 'deviceChanges', '');
+ if (array_key_exists('type', $childItem)) {
+ $data[$key] = new SoapVar($childItem['_'], null, $childItem['type'], '', $key, '');
- continue;
- }*/
+ continue;
+ }
+ } else {
+ $data[$key] = new SoapVar($childItem, null, null, null, $key);
- if (array_key_exists(0, $value)) {
- $arrayData = [];
+ continue;
+ }
- foreach ($value as $item) {
- $arrayData[] = new SoapVar($this->arrayToSoapVar($item), SOAP_ENC_OBJECT, $typeName, null, 'deviceChange', null);
+ $data[] = new SoapVar($this->arrayToSoapVar($childItem), SOAP_ENC_OBJECT, $typeName, null, $key);
}
- $data[$key] = new SoapVar($arrayData, SOAP_ENC_OBJECT, null, 'deviceChange', null, null);
+ // unset($array[$key]);
- continue;
+ $deepArraySet = true;
+ }
+
+ if (! isset($deepArraySet)) {
+ $data[$key] = new SoapVar($this->arrayToSoapVar($value), SOAP_ENC_OBJECT, $typeName, null, $key);
}
- $data[$key] = new SoapVar($this->arrayToSoapVar($value), SOAP_ENC_OBJECT, $typeName, null, 'empty');
$typeName = null;
} elseif (! is_null($value)) {
- $data[$key] = $value;
+ $data[$key] = new SoapVar($value, null, null, null, $key);
}
}
@@ -67,6 +92,98 @@ public function transformPropSet(array $data): stdClass
$newData->{$item->name} = $item->val;
}
- return $newData;
+ return $this->transformToArrayValues($newData);
+ }
+
+ /**
+ * @param stdClass $object
+ * @return stdClass
+ * This function transform to array objects that should be array type
+ */
+ public function transformToArrayValues(stdClass $object, int $startIndex = 0, ?int $onlyIndexPath = null)
+ {
+ $pathes = [
+ ['latestPage', 'TaskInfo'],
+ ['returnval', 'sampleInfo'],
+ ['returnval', 'value', 'value'],
+ ['returnval', 'config', 'consumerId'],
+ ['layoutEx', 'file'],
+ ['layoutEx', 'snapshot'],
+ ['layoutEx', 'snapshot', 'disk'],
+ ['layoutEx', 'snapshot', 'disk', 'chain'],
+ ['snapshot', 'rootSnapshotList'],
+ ['snapshot', 'rootSnapshotList', 'childSnapshotList'],
+ ];
+
+ $recursiveOblectNames = ['childSnapshotList'];
+
+ foreach ($pathes as $indexPath => $path) {
+ if ($onlyIndexPath && $onlyIndexPath !== $indexPath) {
+ continue;
+ }
+
+ $lastIndex = count($path) - 1;
+ $newObj = $object;
+
+ foreach ($path as $index => $property) {
+ if ($index < $startIndex || ! is_object($newObj) || empty((array) $newObj) || ! property_exists($newObj, $property)) {
+ continue;
+ }
+
+ $newObj = $newObj->{$property};
+
+ $varName = "el_$indexPath";
+
+ isset($$varName) ? $$varName = &$$varName->{$property} : $$varName = &$object->{$property};
+
+ if ($index === $lastIndex && ! is_array($newObj)) {
+ $$varName = [$$varName];
+ }
+
+ if ($index !== $lastIndex && is_array($$varName)) {
+ foreach ($$varName as &$oblectItem) {
+ $oblectItem = $this->transformToArrayValues($oblectItem, $index + 1, $indexPath);
+ }
+ }
+
+ foreach ($recursiveOblectNames as $recursiveOblectName) {
+ if ($recursiveOblectName === $property) {
+ $this->transformToArrayValuesRecursive($$varName, $property);
+ }
+ }
+ }
+ }
+
+ return $object;
+ }
+
+ public function getListFilterQuery(array $filter): string
+ {
+ if ($this->version < 7) {
+ foreach ($filter as $key => $value) {
+ $filter["filter.$key"] = $value;
+ unset($filter[$key]);
+ }
+ }
+
+ return preg_replace('/%5B(?:[0-9]|[1-9][0-9]+)%5D=/', '=', http_build_query($filter, null, '&'));
+ }
+
+ private function transformToArrayValuesRecursive(&$object, string $propertyName)
+ {
+ if (is_array($object)) {
+ foreach ($object as &$nestedObject) {
+ $nestedObject = $this->transformToArrayValuesRecursive($nestedObject, $propertyName);
+ }
+ } else {
+ if (isset($object->{$propertyName})) {
+ $object->{$propertyName} = [$object->{$propertyName}];
+ foreach ($object->{$propertyName} as &$nestedObject1) {
+ $nestedObject1 = $this->transformToArrayValuesRecursive($nestedObject1, $propertyName);
+ }
+ }
+ }
+
+ return $object;
}
}
diff --git a/src/Types/ArrayUpdateSpec.php b/src/Types/ArrayUpdateSpec.php
new file mode 100644
index 0000000..933a4e4
--- /dev/null
+++ b/src/Types/ArrayUpdateSpec.php
@@ -0,0 +1,12 @@
+ $value) {
+ if (property_exists(static::class, $property)) {
+ $this->{$property} = $value;
+ }
+ }
+ }
+
+ /**
+ * @return array
+ * Generate array of class properties in order from parent to child
+ */
+ public function toArray(): array
+ {
+ $data = [];
+ $classes = [];
+ $properties = [];
+
+ $currentClass = static::class;
+ while ($currentClass && $currentClass !== self::class) {
+ $classes[] = $currentClass;
+ $currentClass = get_parent_class($currentClass);
+ }
+
+ $classes = array_reverse($classes);
+
+ foreach ($classes as $class) {
+ $classInfo = new \ReflectionClass($class);
+
+ foreach ($classInfo->getProperties() as $prop) {
+ if ($prop->class === $class) {
+ $properties[] = $prop->getName();
+ }
+ }
+ }
+
+ foreach ($properties as $property) {
+ if ($this->$property !== null) {
+ $data[$property] = $this->$property;
+ }
+ }
+
+ return $data;
+ }
+
+ public function count(): int
+ {
+ $count = 0;
+
+ foreach ($this as $property) {
+ if ($property !== null) {
+ $count++;
+ }
+ }
+
+ return $count;
+ }
+
+ public function jsonSerialize(): array
+ {
+ return $this->toArray();
+ }
+}
diff --git a/src/Types/CustomizationAdapterMapping.php b/src/Types/CustomizationAdapterMapping.php
new file mode 100644
index 0000000..4ff1452
--- /dev/null
+++ b/src/Types/CustomizationAdapterMapping.php
@@ -0,0 +1,12 @@
+soap = new VcenterSoapClient($this->soapClient);
}
+
+ $this->apiUrlPrefix = $this->version >= 7 ? '/api' : '/rest';
}
}
diff --git a/src/VcenterSoapClient.php b/src/VcenterSoapClient.php
index 066d9ec..a62e261 100755
--- a/src/VcenterSoapClient.php
+++ b/src/VcenterSoapClient.php
@@ -4,13 +4,17 @@
use SoapClient;
use Xelon\VmWareClient\Data\SoapData;
-use Xelon\VmWareClient\Traits\Soap\SoapFileApis;
+use Xelon\VmWareClient\Requests\SoapRequest;
+use Xelon\VmWareClient\Traits\Soap\SoapGuestApis;
+use Xelon\VmWareClient\Traits\Soap\SoapStorageApis;
use Xelon\VmWareClient\Traits\Soap\SoapVmApis;
class VcenterSoapClient
{
+ use SoapRequest;
use SoapVmApis;
- use SoapFileApis;
+ use SoapGuestApis;
+ use SoapStorageApis;
public SoapClient $soapClient;
diff --git a/src/VmWareClientInit.php b/src/VmWareClientInit.php
index 9ebf13f..8cd6cbd 100755
--- a/src/VmWareClientInit.php
+++ b/src/VmWareClientInit.php
@@ -24,15 +24,23 @@ class VmWareClientInit
private string $password;
+ protected float $version;
+
protected ?GuzzleClient $guzzleClient;
protected ?\SoapClient $soapClient;
- public function __construct(string $ip, string $login, string $password, string $mode = self::MODE_REST)
- {
+ public function __construct(
+ string $ip,
+ string $login,
+ string $password,
+ string $mode = self::MODE_REST,
+ float $version = 7
+ ) {
$this->ip = $ip;
$this->login = $login;
$this->password = $password;
+ $this->version = $version;
switch ($mode) {
case self::MODE_REST:
@@ -68,9 +76,16 @@ private function initRestSession(): void
private function createRestSession(): void
{
try {
- $authReponse = $this->guzzleClient->post('/api/session', ['auth' => [$this->login, $this->password]]);
+ $authReponse = $this->guzzleClient->post(
+ $this->version >= 7 ? '/api/session' : '/rest/com/vmware/cis/session',
+ ['auth' => [$this->login, $this->password]]
+ );
$apiSessionId = json_decode($authReponse->getBody());
+ if ($this->version < 7) {
+ $apiSessionId = $apiSessionId->value;
+ }
+
Cache::add("vcenter-rest-session-$this->ip", [
'api_session_id' => $apiSessionId,
'expired_at' => Carbon::now()->addSeconds(config('vmware-php-client.session_ttl') * 60 - 30),
@@ -91,11 +106,10 @@ private function createRestSession(): void
private function deleteRestSession(string $apiSessionId): void
{
try {
- $this->guzzleClient->delete('api/session', [
- 'headers' => [
- 'vmware-api-session-id' => $apiSessionId,
- ],
- ]);
+ $this->guzzleClient->delete(
+ $this->version >= 7 ? 'api/session' : '/rest/com/vmware/cis/session',
+ ['headers' => ['vmware-api-session-id' => $apiSessionId],
+ ]);
} catch (\Exception $exception) {
}
@@ -158,12 +172,25 @@ private function createSoapSession(): void
];
$this->soapClient->Login($loginMessage);
+ if (isset($this->soapClient->_cookies)) {
+ $soapSessionToken = $this->soapClient->_cookies['vmware_soap_session'][0];
+ } else {
+ $responseHeaders = $this->soapClient->__last_response_headers;
+
+ $string = strstr($responseHeaders, 'vmware_soap_session');
+ $string = strstr($string, '"');
+ $string = ltrim($string, '"');
+ $soapSessionToken = substr($string, 0, strpos($string, '"'));
+ $this->soapClient->__setCookie('vmware_soap_session', $soapSessionToken);
+ }
+
Cache::add("vcenter-soap-session-$this->ip", [
- 'vmware_soap_session' => $this->soapClient->_cookies['vmware_soap_session'][0],
+ 'vmware_soap_session' => $soapSessionToken,
'expired_at' => Carbon::now()->addSeconds(config('vmware-php-client.session_ttl') * 60 - 30),
]);
} catch (\Exception $e) {
Log::error('Soap api exception : '.$e->getMessage());
+ throw new \Exception($e->getMessage());
}
}
@@ -186,12 +213,16 @@ private function createSoapClientWithExistingSession(string $soapSessionToken)
private function deleteSoapSession()
{
- $sessionManager = new \stdClass();
- $sessionManager->_ = $sessionManager->type = 'SessionManager';
+ try {
+ Cache::forget("vcenter-soap-session-$this->ip");
- $soaplogout['_this'] = $sessionManager;
- $this->soapClient->Logout($soaplogout);
+ $sessionManager = new \stdClass();
+ $sessionManager->_ = $sessionManager->type = 'SessionManager';
- Cache::forget("vcenter-soap-session-$this->ip");
+ $soaplogout['_this'] = $sessionManager;
+ $this->soapClient->Logout($soaplogout);
+ } catch (\Exception $exception) {
+ Log::error('Can\'t delete soap session');
+ }
}
}