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:
@@ -12,6 +12,7 @@ use App\Models\Service;
|
||||
use App\Models\ServiceAddon;
|
||||
use App\Models\vCenter;
|
||||
use App\Services\VirtualMachine\VmProvisionLogger;
|
||||
use App\Services\VmProvisionService;
|
||||
use App\Services\VsphereHostSshService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
@@ -26,22 +27,27 @@ use Illuminate\Support\Facades\Log;
|
||||
* UpdateVmConfigJob
|
||||
*
|
||||
* Applies customer-selected CPU/RAM addons (from addons_meta on the OrderItem)
|
||||
* to the live vSphere VM via updateVMConfig.ps1.
|
||||
* to the vSphere VM via updateVMConfig.ps1. Runs right after clone, while the
|
||||
* VM is still powered off — this is also what CreateVirtualMachineJob relies
|
||||
* on to power the VM on before the next step.
|
||||
*
|
||||
* Skipped if the order has no cpu/ram addon → goes straight to ChangePasswordViaVsphereJob.
|
||||
* Skipped if the order has no cpu/ram addon → just power on, dispatch AssignIpToGuestJob.
|
||||
*
|
||||
* PS1 on vSphere host must accept:
|
||||
* $server_name, $cpu, $memoryGB, $vcenter_host, $vcenter_user, $vcenter_password
|
||||
* and call Connect-VIServer before Get-VM.
|
||||
*
|
||||
* Flow:
|
||||
* Flow (order-creation path, reservationId set):
|
||||
* [1] Load ModuleVmware → order → orderItems.first() → product
|
||||
* [2] Resolve addon cpu/ram from addons_meta (code field saved by OrderService)
|
||||
* [3] If no cpu/ram addon → skip, dispatch ChangePasswordViaVsphereJob
|
||||
* [3] If no cpu/ram addon → power on, dispatch AssignIpToGuestJob
|
||||
* [4] Load vCenter credentials (same pattern as ChangePasswordViaVsphereJob)
|
||||
* [5] Compute total: base (product.cpu/ram) + addon qty
|
||||
* [6] SSH → vSphere → updateVMConfig.ps1 with vCenter creds
|
||||
* [7] Assert SUCCESS → dispatch ChangePasswordViaVsphereJob
|
||||
* [6] Power off → SSH → vSphere → updateVMConfig.ps1 → power on
|
||||
* [7] Assert SUCCESS → dispatch AssignIpToGuestJob
|
||||
*
|
||||
* Manual-override path (admin panel, reservationId null): same power-off →
|
||||
* resize → power-on, but only updates DB — no further job is dispatched.
|
||||
*/
|
||||
class UpdateVmConfigJob implements ShouldQueue
|
||||
{
|
||||
@@ -57,6 +63,8 @@ class UpdateVmConfigJob implements ShouldQueue
|
||||
public readonly string $osFamily,
|
||||
public readonly ?int $cpuOverride = null,
|
||||
public readonly ?int $ramOverride = null,
|
||||
public readonly ?int $reservationId = null,
|
||||
public readonly ?int $reservedIpPoolId = null,
|
||||
) {}
|
||||
|
||||
public function handle(VsphereHostSshService $ssh, VmProvisionLogger $logger, Telegram $telegram): void
|
||||
@@ -91,10 +99,16 @@ class UpdateVmConfigJob implements ShouldQueue
|
||||
[$addonCpu, $addonRamGb] = $this->resolveAddonCpuRam($addonsMeta);
|
||||
|
||||
if ($addonCpu === 0 && $addonRamGb === 0) {
|
||||
$logger->step('no cpu/ram addon — skipping UpdateVmConfigJob', [
|
||||
$logger->step('no cpu/ram addon — powering on and skipping resize', [
|
||||
'module_vmware_id' => $this->moduleVmwareId,
|
||||
'vm_id' => $this->vmId,
|
||||
]);
|
||||
|
||||
$vcenterForPowerOn = $moduleVmware->vcenter ?? vCenter::first();
|
||||
if ($vcenterForPowerOn) {
|
||||
$this->powerCycle($vcenterForPowerOn, (string) $moduleVmware->vmware_id, $logger, powerOff: false);
|
||||
}
|
||||
|
||||
$this->nextStep();
|
||||
return;
|
||||
}
|
||||
@@ -133,9 +147,10 @@ class UpdateVmConfigJob implements ShouldQueue
|
||||
'total_ram_gb' => $totalRam,
|
||||
]);
|
||||
|
||||
if ($isManualOverride) {
|
||||
$this->powerCycle($vcenter, (string) $moduleVmware->vmware_id, $logger, powerOff: true);
|
||||
}
|
||||
// Power off before resizing (both the create-flow addon path and admin
|
||||
// manual overrides) — hot CPU/RAM resize isn't reliable across guest
|
||||
// OSes and is what caused Set-VM to reject the config as invalid.
|
||||
$this->powerCycle($vcenter, (string) $moduleVmware->vmware_id, $logger, powerOff: true);
|
||||
|
||||
try {
|
||||
$output = $ssh->updateVmConfig(
|
||||
@@ -147,9 +162,7 @@ class UpdateVmConfigJob implements ShouldQueue
|
||||
$vcenterPass,
|
||||
);
|
||||
} finally {
|
||||
if ($isManualOverride) {
|
||||
$this->powerCycle($vcenter, (string) $moduleVmware->vmware_id, $logger, powerOff: false);
|
||||
}
|
||||
$this->powerCycle($vcenter, (string) $moduleVmware->vmware_id, $logger, powerOff: false);
|
||||
}
|
||||
|
||||
Log::info('UpdateVmConfigJob: PS1 output', [
|
||||
@@ -273,8 +286,9 @@ class UpdateVmConfigJob implements ShouldQueue
|
||||
|
||||
/**
|
||||
* Power off/on the VM via vCenter REST and wait (up to 30s) for the state to land.
|
||||
* Used only for manual admin overrides — hot-add isn't reliable for RAM on every guest OS,
|
||||
* so we power-cycle around the resize to guarantee it applies.
|
||||
* Hot-add isn't reliable for CPU/RAM resize on every guest OS, so we
|
||||
* power-cycle around the resize (and around the power-on-only skip path)
|
||||
* to guarantee the config applies and the VM ends up running either way.
|
||||
*/
|
||||
private function powerCycle(vCenter $vcenter, string $vmwareId, VmProvisionLogger $logger, bool $powerOff): void
|
||||
{
|
||||
@@ -347,10 +361,13 @@ class UpdateVmConfigJob implements ShouldQueue
|
||||
|
||||
private function nextStep(): void
|
||||
{
|
||||
ChangePasswordViaVsphereJob::dispatch(
|
||||
AssignIpToGuestJob::dispatch(
|
||||
$this->moduleVmwareId,
|
||||
$this->vmId,
|
||||
$this->osFamily,
|
||||
VmProvisionService::TEMPLATE_PASSWORD,
|
||||
$this->reservationId,
|
||||
$this->reservedIpPoolId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user