diff --git a/app/Jobs/VirtualMachine/Create/CreateVirtualMachineJob.php b/app/Jobs/VirtualMachine/Create/CreateVirtualMachineJob.php index 8a503e7..fcf735d 100644 --- a/app/Jobs/VirtualMachine/Create/CreateVirtualMachineJob.php +++ b/app/Jobs/VirtualMachine/Create/CreateVirtualMachineJob.php @@ -58,6 +58,8 @@ class CreateVirtualMachineJob implements ShouldQueue $ipPoolId = null; $lock = null; + $vmLogger->for('CreateVirtualMachineJob'); + try { $customerId = $this->item->order->customer_id; $lock = VmProvisionLock::updateOrCreate( diff --git a/app/Jobs/VirtualMachine/Provision/AssignIpToGuestJob.php b/app/Jobs/VirtualMachine/Provision/AssignIpToGuestJob.php index ca9bb50..6131c7a 100644 --- a/app/Jobs/VirtualMachine/Provision/AssignIpToGuestJob.php +++ b/app/Jobs/VirtualMachine/Provision/AssignIpToGuestJob.php @@ -13,6 +13,7 @@ use App\Models\Service; use App\Models\VirtualMachines; use App\Http\Services\vCenter as vCenterService; use App\Models\vCenter; +use App\Services\VirtualMachine\VmProvisionLogger; use App\Services\VmProvisionService; use App\Services\VsphereHostSshService; use Illuminate\Bus\Queueable; @@ -64,9 +65,11 @@ class AssignIpToGuestJob implements ShouldQueue // ───────────────────────────────────────────────────────────────────────── - public function handle(VsphereHostSshService $ssh, vCenterService $vCenterService): void + public function handle(VsphereHostSshService $ssh, vCenterService $vCenterService, VmProvisionLogger $logger): void { - Log::info('AssignIpToGuestJob: start', [ + $logger->for('AssignIpToGuestJob'); + + $logger->step('start', [ 'module_vmware_id' => $this->moduleVmwareId, 'vm_id' => $this->vmId, 'os_family' => $this->osFamily, @@ -79,7 +82,7 @@ class AssignIpToGuestJob implements ShouldQueue ])->find($this->moduleVmwareId); if (!$moduleVmware) { - Log::error('AssignIpToGuestJob: ModuleVmware not found', [ + $logger->error('ModuleVmware not found', [ 'module_vmware_id' => $this->moduleVmwareId, ]); return; @@ -110,7 +113,7 @@ class AssignIpToGuestJob implements ShouldQueue $maxAttempts = $this->reservationId ? 1 : self::MAX_ATTEMPTS; for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) { - Log::info('AssignIpToGuestJob: attempt', [ + $logger->step('attempt', [ 'attempt' => $attempt, 'module_vmware_id' => $this->moduleVmwareId, 'network_id' => $networkId, @@ -119,15 +122,15 @@ class AssignIpToGuestJob implements ShouldQueue // [3] Use upstream reservation if provided, else reserve a fresh IP. $picked = $this->reservationId - ? $this->loadReservation($this->reservationId, $this->reservedIpPoolId) + ? $this->loadReservation($this->reservationId, $this->reservedIpPoolId, $logger) : $this->reserveIp($networkId, $hostId, $dns); if (!$picked) { - Log::error('AssignIpToGuestJob: no free IPs in pool', [ + $logger->error('no free IPs in pool', [ 'network_id' => $networkId, 'attempt' => $attempt, ]); - break; // No point retrying — no IPs available + break; } $reservation = $picked['reservation']; @@ -153,19 +156,19 @@ class AssignIpToGuestJob implements ShouldQueue // [5] If assign failed → release and try next IP if (!$this->isSuccess($assignOutput)) { - Log::warning('AssignIpToGuestJob: assignIp FAIL', [ + $logger->warning('assignIp FAIL', [ 'ip' => $ip, 'attempt' => $attempt, 'output' => trim($assignOutput), ]); - $this->releaseIp($reservation, $ipPoolId); + $this->releaseIp($reservation, $ipPoolId, $logger); continue; } if (strtoupper($this->osFamily) === VmProvisionService::OS_WINDOWS) { $this->persistIp($reservation, $moduleVmware, $ipPoolId, $serviceId); - Log::info('AssignIpToGuestJob: Windows IP assigned', [ + $logger->success('Windows IP assigned', [ 'module_vmware_id' => $this->moduleVmwareId, 'vm_id' => $this->vmId, 'ip' => $ip, @@ -195,19 +198,19 @@ class AssignIpToGuestJob implements ShouldQueue // [7] If verification failed → release and try next IP if (!$this->isSuccess($verifyOutput)) { - Log::warning('AssignIpToGuestJob: verifyIpInGuest FAIL', [ + $logger->warning('verifyIpInGuest FAIL', [ 'ip' => $ip, 'attempt' => $attempt, 'output' => trim($verifyOutput), ]); - $this->releaseIp($reservation, $ipPoolId); + $this->releaseIp($reservation, $ipPoolId, $logger); continue; } // [8] SUCCESS — persist confirmed IP to module_vmware + virtual_machines + ip_pools $this->persistIp($reservation, $moduleVmware, $ipPoolId, $serviceId); - Log::info('AssignIpToGuestJob: IP assigned and verified', [ + $logger->success('IP assigned and verified', [ 'module_vmware_id' => $this->moduleVmwareId, 'vm_id' => $this->vmId, 'ip' => $ip, @@ -225,7 +228,7 @@ class AssignIpToGuestJob implements ShouldQueue } // [9] All attempts exhausted - Log::error('AssignIpToGuestJob: all attempts failed — marking VM inactive', [ + $logger->error('all attempts failed — marking VM inactive', [ 'module_vmware_id' => $this->moduleVmwareId, 'vm_id' => $this->vmId, 'attempts' => $maxAttempts, @@ -246,7 +249,7 @@ class AssignIpToGuestJob implements ShouldQueue $guestIp = $guestInfo['data']['ip_address'] ?? null; if ($guestIp) { $moduleVmware->update(['ip' => $guestIp, 'status' => 1]); - Log::info('AssignIpToGuestJob: recovered IP from guest identity', [ + $logger->step('recovered IP from guest identity', [ 'module_vmware_id' => $this->moduleVmwareId, 'ip' => $guestIp, ]); @@ -255,7 +258,7 @@ class AssignIpToGuestJob implements ShouldQueue } } } catch (\Throwable $e) { - Log::error('AssignIpToGuestJob: failed to recover IP after exhausted attempts', [ + $logger->error('failed to recover IP after exhausted attempts', [ 'module_vmware_id' => $this->moduleVmwareId, 'error' => $e->getMessage(), ]); @@ -348,11 +351,11 @@ class AssignIpToGuestJob implements ShouldQueue * * @return array{reservation:ModuleIpAddress,ip_pool_id:int,gateway:string,cidr:int}|null */ - private function loadReservation(int $reservationId, ?int $ipPoolId): ?array + private function loadReservation(int $reservationId, ?int $ipPoolId, VmProvisionLogger $logger): ?array { $reservation = ModuleIpAddress::find($reservationId); if (!$reservation) { - Log::error('AssignIpToGuestJob: upstream reservation missing', [ + $logger->error('upstream reservation missing', [ 'reservation_id' => $reservationId, ]); return null; @@ -374,16 +377,16 @@ class AssignIpToGuestJob implements ShouldQueue * Release a failed reservation by deleting the pending ModuleIpAddress row. * This returns the IP to the available pool. */ - private function releaseIp(ModuleIpAddress $reservation, ?int $ipPoolId): void + private function releaseIp(ModuleIpAddress $reservation, ?int $ipPoolId, VmProvisionLogger $logger): void { try { $reservation->delete(); if ($ipPoolId) { IpPool::where('id', $ipPoolId)->update(['status' => 'free']); } - Log::info('AssignIpToGuestJob: IP reservation released', ['ip' => $reservation->ip]); + $logger->step('IP reservation released', ['ip' => $reservation->ip]); } catch (\Throwable $e) { - Log::warning('AssignIpToGuestJob: could not release IP reservation', [ + $logger->warning('could not release IP reservation', [ 'ip' => $reservation->ip, 'error' => $e->getMessage(), ]); @@ -462,13 +465,4 @@ class AssignIpToGuestJob implements ShouldQueue return is_array($data) && ($data['status'] ?? '') === 'ok'; } - /** Convert dotted-decimal netmask to CIDR prefix length (e.g. 255.255.255.0 → 24). */ - private function netmaskToCidr(string $netmask): int - { - $bits = 0; - foreach (explode('.', $netmask) as $octet) { - $bits += substr_count(decbin((int) $octet), '1'); - } - return $bits; - } } diff --git a/app/Services/VirtualMachine/VmProvisionLogger.php b/app/Services/VirtualMachine/VmProvisionLogger.php index a2f455d..9015f40 100644 --- a/app/Services/VirtualMachine/VmProvisionLogger.php +++ b/app/Services/VirtualMachine/VmProvisionLogger.php @@ -10,7 +10,7 @@ use Throwable; class VmProvisionLogger { - private const JOB_NAME = 'CreateVirtualMachineJob'; + private string $jobName = 'System'; private const REDACTED_KEYS = [ 'password', @@ -29,6 +29,12 @@ class VmProvisionLogger { } + public function for(string $jobName): static + { + $this->jobName = $jobName; + return $this; + } + public function step(string $title, array $context = []): void { $safe = $this->redact($context); @@ -90,7 +96,7 @@ class VmProvisionLogger private function jobLabel(): string { - return self::JOB_NAME; + return $this->jobName; } private function redact(array $context): array diff --git a/composer.json b/composer.json index 3e552f8..16733b5 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "nwidart/laravel-modules": "^10.0", "opcodesio/log-viewer": "^3.18", "phpseclib/phpseclib": "*", + "plesk/ext-laravel-integration": "^7.0", "predis/predis": "^2.2", "pusher/pusher-php-server": "^7.2", "spatie/laravel-permission": "^6.3", diff --git a/composer.lock b/composer.lock index 2e21c96..1f0a54e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cfc535c27971a90c45e31a2ddd47afe3", + "content-hash": "4996106ea97079078f843b42993edb6f", "packages": [ { "name": "barryvdh/laravel-dompdf", @@ -4181,6 +4181,53 @@ ], "time": "2026-06-14T23:24:10+00:00" }, + { + "name": "plesk/ext-laravel-integration", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/plesk/ext-laravel-integration.git", + "reference": "73dc4ea3f99e033396497f147aa033eb0602f943" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/plesk/ext-laravel-integration/zipball/73dc4ea3f99e033396497f147aa033eb0602f943", + "reference": "73dc4ea3f99e033396497f147aa033eb0602f943", + "shasum": "" + }, + "require": { + "laravel/framework": ">=7.0.0", + "php": ">=7.4" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "PleskExtLaravel\\Providers\\ConsoleServiceProvider" + ] + }, + "component": "package" + }, + "autoload": { + "psr-4": { + "PleskExtLaravel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Plesk Laravel Toolkit integration with Laravel applications.", + "keywords": [ + "laravel", + "plesk" + ], + "support": { + "issues": "https://github.com/plesk/ext-laravel-integration/issues", + "source": "https://github.com/plesk/ext-laravel-integration/tree/7.0.0" + }, + "time": "2023-01-20T09:40:57+00:00" + }, { "name": "predis/predis", "version": "v2.4.1",