Refactor vCenter snapshot handling and VM operations

- Introduced a new method `resolveVCenterFromProduct` in `SnapshotService` to streamline vCenter resolution from product data.
- Updated `CreateSnapshot`, `RemoveSnapshot`, and `RevertSnapshot` jobs to utilize the new vCenter resolution method.
- Enhanced the `VmController` to support UUID-based service identification for VM operations.
- Added new actions for changing VM IP and RDP port, encapsulating the logic for these operations.
- Improved error handling and logging for VM operations, including detailed responses for API consumers.
- Removed unnecessary relationships in model queries to optimize performance.
This commit is contained in:
pbao9
2026-04-15 23:38:38 +07:00
parent 64a9d603e2
commit bb73d6c5a2
14 changed files with 987 additions and 120 deletions
+65
View File
@@ -0,0 +1,65 @@
<?php
namespace App\Actions\VM;
use App\Http\Services\vCenter;
use App\Models\ModuleVmware;
class ChangeIpVMAction
{
public function __construct(private vCenter $vcenter) {}
/**
* Change IP address of a VM.
*
* Linux → changeIPLinux.ps1 (-VMName, -IP, -Gateway, -DNS, -GuestUser, -GuestPassword)
* Windows → changeWindows1line.ps1 (legacy inline variable pattern)
*
* @param ModuleVmware $vm
* @param string $ipAddress
* @param string $gateway Empty string if not provided
* @param string $osType 'windows' | 'linux'
* @param string $dns DNS server, default 8.8.8.8
* @return string
*/
public function execute(
ModuleVmware $vm,
string $ipAddress,
string $gateway,
string $osType,
string $dns = '8.8.8.8',
string $guestUser = '',
string $guestPassword = ''
): string {
try {
$vcenter = $vm->vCenter
?? $vm->ipAddress?->host?->datacenter?->vCenter;
if (!$vcenter) {
return 'vCenter_Not_Found';
}
if (!$this->vcenter->loginServer($vcenter)) {
return 'Login_Again';
}
// Use provided guest credentials, fallback to VM stored credentials
$user = $guestUser ?: (string) $vm->user;
$pass = $guestPassword ?: (string) $vm->getRawOriginal('password');
return $this->vcenter->changeIpVM(
(string) $vm->name, // -VMName (Get-VM -Name)
(string) $vm->vmware_id, // VMware ID (Windows -Id pattern)
$ipAddress,
$gateway,
$osType,
$user, // -GuestUser
$pass, // -GuestPassword (plaintext)
$dns,
(string) $vm->hostname
);
} catch (\Throwable $e) {
return 'Error: ' . $e->getMessage();
}
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace App\Actions\VM;
use App\Http\Services\vCenter;
use App\Models\ModuleVmware;
class ChangePortVMAction
{
public function __construct(private vCenter $vcenter) {}
/**
* Change the RDP port for a Windows VM.
*
* Delegates EXACTLY to the existing changeRDPPortWindows() — no logic is
* duplicated here. loginServer() must be called first because
* CommandChangePort() uses $this->apiUri / username / password to build
* the VMware.PowerCLI connection string.
*
* @param ModuleVmware $vm
* @param string $newPort
* @return array|string
*/
public function execute(ModuleVmware $vm, string $newPort): array|string
{
try {
$vcenter = $vm->vCenter
?? $vm->ipAddress?->host?->datacenter?->vCenter;
if (!$vcenter) {
return ['error' => true, 'data' => 'Không tìm thấy thông tin vCenter cho VM này.'];
}
if (!$this->vcenter->loginServer($vcenter)) {
return 'Login_Again';
}
return $this->vcenter->changeRDPPortWindows(
(string) $vm->name,
(string) $vm->user,
(string) $vm->getRawOriginal('password'),
$newPort
);
} catch (\Throwable $e) {
return ['error' => true, 'data' => $e->getMessage()];
}
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace App\Actions\VM;
use App\Http\Services\vCenter;
use App\Models\ModuleVmware;
class PowerOffVMAction
{
public function __construct(private vCenter $vcenter) {}
/**
* Hard power-off a VM (equivalent of pulling the plug).
*
* PowerOffVirtualMachine() calls checkApiExits() which requires a valid
* session token, so loginServer() MUST be called first to set the token.
*/
public function execute(ModuleVmware $vm): array|string
{
try {
$vcenter = $vm->vCenter
?? $vm->ipAddress?->host?->datacenter?->vCenter;
if (!$vcenter) {
return ['error' => true, 'data' => 'Không tìm thấy thông tin vCenter cho VM này.'];
}
if (!$this->vcenter->loginServer($vcenter)) {
return 'Login_Again';
}
return $this->vcenter->PowerOffVirtualMachine($vm->vmware_id);
} catch (\Throwable $e) {
return ['error' => true, 'data' => $e->getMessage()];
}
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace App\Actions\VM;
use App\Http\Services\vCenter;
use App\Models\ModuleVmware;
class PowerOnVMAction
{
public function __construct(private vCenter $vcenter) {}
/**
* Power on a VM.
*
* Resolves the vCenter, logs in (sets apiUri / token), then delegates
* to the existing StartVirtualMachine() method.
*/
public function execute(ModuleVmware $vm): array|string
{
try {
$vcenter = $vm->vCenter
?? $vm->ipAddress?->host?->datacenter?->vCenter;
if (!$vcenter) {
return ['error' => true, 'data' => 'Không tìm thấy thông tin vCenter cho VM này.'];
}
if (!$this->vcenter->loginServer($vcenter)) {
return 'Login_Again';
}
return $this->vcenter->StartVirtualMachine($vm, $vm->vmware_id);
} catch (\Throwable $e) {
return ['error' => true, 'data' => $e->getMessage()];
}
}
}