Refactor VM creation and configuration process

- Updated VpsServiceResource to return product UUID instead of ID.
- Modified VirtualMachineService to utilize product data for CPU, RAM, and disk settings.
- Replaced AssignIpToGuestJob with UpdateVmConfigJob in CreateVirtualMachineJob to streamline VM configuration after cloning.
- Adjusted AssignIpToGuestJob to remove unnecessary UpdateVmConfigJob dispatch and focus on IP assignment.
- Enhanced UpdateVmConfigJob to handle CPU/RAM configuration and power cycling more effectively.
- Introduced ChangeIpVMJob for handling customer-initiated IP changes asynchronously.
- Updated InvoiceRepository to set invoice due date based on maximum months instead of a fixed 7 days.
- Improved web design quote PDF layout for better readability.
- Added Times-Roman font metrics for PDF generation.
This commit is contained in:
baodev0
2026-07-24 09:29:43 +07:00
parent ccf95114f6
commit 3ed33ea7e4
10 changed files with 767 additions and 127 deletions
+120
View File
@@ -0,0 +1,120 @@
<?php
declare(strict_types=1);
namespace App\Jobs\VirtualMachine;
use App\Actions\VM\ChangeIpVMAction;
use App\Http\Services\Telegram;
use App\Models\ModuleVmware;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
/**
* ChangeIpVMJob
*
* Customer-initiated VM IP change. Runs the same ChangeIpVMAction that used
* to execute synchronously inside VmController::changeIp — moved to a queued
* job so the SSH → PowerCLI round trip can no longer blow past nginx/php-fpm's
* timeout and surface as a 502.
*/
class ChangeIpVMJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** No auto-retry — mirrors the previous synchronous behaviour (single attempt). */
public int $tries = 1;
public int $timeout = 180;
public function __construct(
public readonly int $moduleVmwareId,
public readonly string $ipAddress,
public readonly string $gateway,
public readonly string $osType,
public readonly string $dns,
public readonly string $guestUser,
public readonly string $guestPassword,
) {}
public function handle(ChangeIpVMAction $action): void
{
$vm = ModuleVmware::with([
'vCenter',
'ipAddress.host.datacenter.vCenter',
])->find($this->moduleVmwareId);
if (!$vm) {
Log::error('[ChangeIpVMJob] ModuleVmware not found', ['module_vmware_id' => $this->moduleVmwareId]);
return;
}
$raw = $action->execute(
$vm,
$this->ipAddress,
$this->gateway,
$this->osType,
$this->dns,
$this->guestUser,
$this->guestPassword,
);
Log::channel('Custom')->info('[ChangeIpVMJob] raw output', [
'module_vmware_id' => $this->moduleVmwareId,
'ip_address' => $this->ipAddress,
'gateway' => $this->gateway,
'os_type' => $this->osType,
'vm_name' => $vm->name,
'vmware_id' => $vm->vmware_id,
'raw' => $raw,
]);
$telegram = new Telegram();
if ($raw === 'Login_Again' || $raw === 'vCenter_Not_Found') {
$errMsg = $raw === 'vCenter_Not_Found'
? 'Không tìm thấy vCenter cho VM này.'
: 'Không thể đăng nhập vào vCenter.';
$telegram->SendErrorMessage("❌ Đổi IP thất bại [{$this->osType}]\n"
. "🖥 VM: {$vm->name} ({$vm->vmware_id})\n"
. "📍 IP mới: {$this->ipAddress}\n"
. "🔗 GW: {$this->gateway}\n"
. "🚫 Lỗi: {$errMsg}");
return;
}
if (str_starts_with((string) $raw, 'Error:') || str_contains((string) $raw, '[STDERR]')) {
$telegram->SendErrorMessage("❌ Đổi IP thất bại [{$this->osType}]\n"
. "🖥 VM: {$vm->name} ({$vm->vmware_id})\n"
. "📍 IP mới: {$this->ipAddress}\n"
. "🔗 GW: {$this->gateway}\n"
. "📋 Output:\n" . mb_substr((string) $raw, 0, 800));
return;
}
// Empty raw = script chạy không có output → coi là thành công (PowerShell script không echo)
// Nhưng vẫn gửi cảnh báo để theo dõi
if (trim((string) $raw) === '') {
$telegram->SendMessage("⚠️ Đổi IP [{$this->osType}] - Script chạy nhưng không có output\n"
. "🖥 VM: {$vm->name} ({$vm->vmware_id})\n"
. "📍 IP mới: {$this->ipAddress}\n"
. "🔗 GW: {$this->gateway}\n"
. "ℹ️ Kiểm tra lại VM để xác nhận IP đã thay đổi chưa.");
}
}
public function failed(\Throwable $e): void
{
Log::error('[ChangeIpVMJob] job failed with exception', [
'module_vmware_id' => $this->moduleVmwareId,
'ip_address' => $this->ipAddress,
'error' => $e->getMessage(),
]);
}
}