Implement VM deletion functionality and update related services; add confirmation check and logging
This commit is contained in:
@@ -240,7 +240,7 @@ class vCenter
|
||||
|
||||
public function CreateSnapShot($product, ?string $snapshotName = null): string|array
|
||||
{
|
||||
return $this->snapshot->CreateSnapShot($product);
|
||||
return $this->snapshot->CreateSnapShot($product, $snapshotName);
|
||||
}
|
||||
public function getSnapShot($product): string|array
|
||||
{
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Services\vCenter;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DeleteVMService
|
||||
{
|
||||
protected Client $client;
|
||||
protected PowerShellService $powerShellService;
|
||||
|
||||
public function __construct(Client $client, PowerShellService $powerShellService)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->powerShellService = $powerShellService;
|
||||
}
|
||||
|
||||
protected function resolveVCenterFromProduct($product): ?\App\Models\vCenter
|
||||
{
|
||||
if ($product->vCenter) {
|
||||
return $product->vCenter;
|
||||
}
|
||||
|
||||
if ($product->ipaddress?->host?->datacenter?->vCenter) {
|
||||
return $product->ipaddress->host->datacenter->vCenter;
|
||||
}
|
||||
|
||||
$service = $product->services()->first();
|
||||
if ($service) {
|
||||
$service->load('vmware.vCenter');
|
||||
if ($service->vmware?->vCenter) {
|
||||
return $service->vmware->vCenter;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function deleteVM($product, string $confirmName): array
|
||||
{
|
||||
$vmName = (string) $product->name;
|
||||
|
||||
// ponytail: confirm guard — caller must pass exact vm name to proceed
|
||||
if ($confirmName !== $vmName) {
|
||||
return ['error' => true, 'message' => "Tên server xác nhận không khớp. Vui lòng nhập đúng: $vmName"];
|
||||
}
|
||||
|
||||
$vcenter = $this->resolveVCenterFromProduct($product);
|
||||
if (!$vcenter) {
|
||||
return ['error' => true, 'message' => 'Không tìm thấy thông tin vCenter cho VM'];
|
||||
}
|
||||
|
||||
$loginResult = $this->client->loginServer($vcenter);
|
||||
if (!$loginResult) {
|
||||
return ['error' => true, 'message' => 'Login_Again'];
|
||||
}
|
||||
|
||||
$check = $this->client->checkApiExits();
|
||||
if (!$check) {
|
||||
return ['error' => true, 'message' => 'Login_Again'];
|
||||
}
|
||||
|
||||
$host = $this->client->apiUri;
|
||||
$user = $this->client->getUsername();
|
||||
$password = $this->client->getPassword();
|
||||
|
||||
try {
|
||||
Log::channel('Custom')->info("===================================================================");
|
||||
Log::channel('Custom')->info("Delete VM - $vmName");
|
||||
|
||||
$command = "& 'C:\CLISave\DeleteVM\deleteVM.ps1' -VmName '$vmName' -VCenterHost '$host' -VCenterUser '$user' -VCenterPassword '$password'";
|
||||
Log::channel('Custom')->info("Executing deleteVM command for: $vmName");
|
||||
|
||||
$cmdResult = $this->powerShellService->executePowerCLI($command);
|
||||
Log::channel('Custom')->info("Command Result: " . $cmdResult);
|
||||
|
||||
if (strpos($cmdResult, 'Login_Fail') !== false) {
|
||||
return ['error' => true, 'message' => 'SSH Login to PowerShell server failed'];
|
||||
}
|
||||
|
||||
if (strpos($cmdResult, 'SUCCESS') === false) {
|
||||
return ['error' => true, 'message' => 'PowerShell command failed: ' . $cmdResult];
|
||||
}
|
||||
|
||||
Log::channel('Custom')->info("After run Command |" . now());
|
||||
Log::channel('Custom')->info("===================================================================");
|
||||
|
||||
return ['error' => false];
|
||||
} catch (\Exception $error) {
|
||||
Log::channel('Custom')->error("Delete VM error: " . $error->getMessage());
|
||||
return ['error' => true, 'message' => $error->getMessage()];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,8 @@ class PowerShellService
|
||||
try {
|
||||
$out = $auth->exec($action);
|
||||
$errOut = $auth->getStdError();
|
||||
return $out . ($errOut ? "\n[STDERR]\n" . $errOut : '');
|
||||
$realErr = $errOut && !str_starts_with(trim($errOut), '#< CLIXML');
|
||||
return $out . ($realErr ? "\n[STDERR]\n" . $errOut : '');
|
||||
} catch (\Throwable $e) {
|
||||
return "Error: " . $e->getMessage();
|
||||
}
|
||||
@@ -132,7 +133,9 @@ PS;
|
||||
try {
|
||||
$out = $auth->exec($action);
|
||||
$errOut = $auth->getStdError();
|
||||
return $out . ($errOut ? "\n[STDERR]\n" . $errOut : '');
|
||||
// PowerCLI banner is CLIXML informational records — not an error
|
||||
$realErr = $errOut && !str_starts_with(trim($errOut), '#< CLIXML');
|
||||
return $out . ($realErr ? "\n[STDERR]\n" . $errOut : '');
|
||||
} catch (\Throwable $e) {
|
||||
return "Error: " . $e->getMessage();
|
||||
}
|
||||
|
||||
@@ -47,57 +47,54 @@ class SnapshotService
|
||||
return null;
|
||||
}
|
||||
|
||||
public function CreateSnapShot($product): string|array
|
||||
public function CreateSnapShot($product, ?string $snapshotName = null): string|array
|
||||
{
|
||||
$vcenter = $this->resolveVCenterFromProduct($product);
|
||||
if (!$vcenter) {
|
||||
return ['error' => true, 'message' => 'Không tìm thấy thông tin vCenter cho VM'];
|
||||
}
|
||||
|
||||
$loginResult = $this->client->loginServer($vcenter);
|
||||
if (!$loginResult) {
|
||||
return "Login_Again";
|
||||
}
|
||||
|
||||
$vmName = (string) $product->name;
|
||||
$name = $snapshotName ?? ($vmName . '_' . date('d_m_Y_H_i_s'));
|
||||
|
||||
$check = $this->client->checkApiExits();
|
||||
if (!$check) {
|
||||
return "Login_Again";
|
||||
}
|
||||
|
||||
try {
|
||||
// Note: credentials setup logic from original vCenter.php seemed redundant with Client logic,
|
||||
// but CreateSnapShot was overwriting $this->username/password.
|
||||
// Here we assume Client is used, or we need to update Client.
|
||||
// Client stores token. If we need username/password for something else, Client has them now via getters.
|
||||
// But CreateSnapshot used $product->ipaddress...->vCenter->user/password.
|
||||
Log::channel('Custom')->info("===================================================================");
|
||||
Log::channel('Custom')->info("Create Snapshot with VirtualMachine Name - $vmName - Snap #$name");
|
||||
|
||||
// Re-login to ensure we have the right credentials for the vCenter associated with the product
|
||||
$vcenterModel = $this->resolveVCenterFromProduct($product);
|
||||
$command = "& 'C:\CLISave\createsnapshot.ps1' -vm_name '$vmName' -name '$name'";
|
||||
Log::channel('Custom')->info($command);
|
||||
|
||||
if (!$vcenterModel) {
|
||||
return ['error' => true, 'message' => 'Không tìm thấy thông tin vCenter cho VM'];
|
||||
$cmdResult = $this->powerShellService->executePowerCLI($command);
|
||||
Log::channel('Custom')->info("Command Result: " . $cmdResult);
|
||||
|
||||
if (strpos($cmdResult, 'Login_Fail') !== false) {
|
||||
return ['error' => true, 'message' => 'SSH Login to PowerShell server failed'];
|
||||
}
|
||||
|
||||
$this->client->loginServer($vcenterModel);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return ['error' => true, 'message' => 'Lỗi setup credentials: ' . $e->getMessage()];
|
||||
}
|
||||
|
||||
$vmware_name = (string) $product->name;
|
||||
// In original code, it checks checkApiExits(), if true proceed.
|
||||
|
||||
if ($this->client->checkApiExits()) {
|
||||
try {
|
||||
$Snapshot = $vmware_name . "_" . date('d_m_Y_H_i_s');
|
||||
|
||||
Log::channel('Custom')->info("===================================================================");
|
||||
Log::channel('Custom')->info("Create Snapshot with VirtualMachine Name - $vmware_name - Snap #$Snapshot");
|
||||
|
||||
$Command = "\$vm_name = '$vmware_name';\$name = '$Snapshot'; cd /; C:\CLISave\createsnapshot.ps1;";
|
||||
Log::channel('Custom')->info("$Command");
|
||||
|
||||
$this->powerShellService->executePowerCLI($Command);
|
||||
|
||||
$this->clearSnapshotCache($product);
|
||||
|
||||
return [
|
||||
'error' => false,
|
||||
'data' => $Snapshot
|
||||
];
|
||||
} catch (\Exception $error) {
|
||||
return [
|
||||
'error' => true,
|
||||
'message' => $error->getMessage()
|
||||
];
|
||||
if (strpos($cmdResult, '[STDERR]') !== false || stripos($cmdResult, 'error') !== false) {
|
||||
return ['error' => true, 'message' => 'PowerShell command failed: ' . $cmdResult];
|
||||
}
|
||||
|
||||
Log::channel('Custom')->info("After run Command |" . now());
|
||||
Log::channel('Custom')->info("===================================================================");
|
||||
|
||||
$this->clearSnapshotCache($product);
|
||||
|
||||
return ['error' => false, 'data' => $name];
|
||||
} catch (\Exception $error) {
|
||||
Log::channel('Custom')->error("Create Snapshot error: " . $error->getMessage());
|
||||
return ['error' => true, 'message' => $error->getMessage()];
|
||||
}
|
||||
return "Login_Again";
|
||||
}
|
||||
|
||||
private function clearSnapshotCache($product): void
|
||||
|
||||
Reference in New Issue
Block a user