119 lines
3.6 KiB
PHP
119 lines
3.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Jobs\VirtualMachine;
|
|
|
|
use App\Http\Facade\SignRSA;
|
|
use App\Mail\Customer\VmPasswordChanged;
|
|
use App\Models\ModuleVmware;
|
|
use App\Models\vCenter;
|
|
use App\Services\VmProvisionService;
|
|
use App\Services\VsphereHostSshService;
|
|
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;
|
|
use Illuminate\Support\Facades\Mail;
|
|
|
|
/**
|
|
* ChangeVmPasswordJob
|
|
*
|
|
* Customer-initiated VM guest OS password change.
|
|
*
|
|
* Flow:
|
|
* [1] Load vCenter credentials
|
|
* [2] SSH → jumphost → changePwdLinux.ps1 / changePwdWindows.ps1
|
|
* [3] Parse SUCCESS / ERROR from output
|
|
* [4] On SUCCESS → persist encrypted new password to DB
|
|
* [5] On FAIL → retry (up to $tries times)
|
|
*/
|
|
class ChangeVmPasswordJob implements ShouldQueue
|
|
{
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
public int $tries = 3;
|
|
public int $timeout = 180;
|
|
public int $backoff = 30;
|
|
|
|
public function __construct(
|
|
public readonly int $moduleVmwareId,
|
|
public readonly string $vmId,
|
|
public readonly string $osFamily,
|
|
public readonly string $newPassword,
|
|
public readonly string $currentGuestPassword,
|
|
) {}
|
|
|
|
public function handle(VmProvisionService $provision, VsphereHostSshService $ssh): void
|
|
{
|
|
Log::info('ChangeVmPasswordJob: starting', [
|
|
'module_vmware_id' => $this->moduleVmwareId,
|
|
'vm_id' => $this->vmId,
|
|
'os_family' => $this->osFamily,
|
|
]);
|
|
|
|
$vcenter = vCenter::first();
|
|
if (!$vcenter) {
|
|
throw new \RuntimeException('No vCenter record found in module_vcenter');
|
|
}
|
|
|
|
$output = $ssh->changePasswordCustomer(
|
|
vmId: $this->vmId,
|
|
newPassword: $this->newPassword,
|
|
currentGuestPassword: $this->currentGuestPassword,
|
|
osFamily: $this->osFamily,
|
|
vcenterHost: $vcenter->host,
|
|
vcenterUser: $vcenter->user,
|
|
vcenterPassword: SignRSA::DecryptFunc($vcenter->password),
|
|
);
|
|
|
|
$this->assertSuccess($output);
|
|
|
|
// Persist encrypted password to DB
|
|
$provision->updatePassword($this->moduleVmwareId, $this->newPassword);
|
|
|
|
$this->notifyCustomer();
|
|
|
|
Log::info('ChangeVmPasswordJob: password changed successfully', [
|
|
'module_vmware_id' => $this->moduleVmwareId,
|
|
'vm_id' => $this->vmId,
|
|
]);
|
|
}
|
|
|
|
public function failed(\Throwable $e): void
|
|
{
|
|
Log::error('ChangeVmPasswordJob: all retries exhausted', [
|
|
'module_vmware_id' => $this->moduleVmwareId,
|
|
'vm_id' => $this->vmId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
|
|
private function notifyCustomer(): void
|
|
{
|
|
$vm = ModuleVmware::with('customer')->find($this->moduleVmwareId);
|
|
if (!$vm?->customer?->email) {
|
|
return;
|
|
}
|
|
|
|
Mail::to($vm->customer->email)->queue(new VmPasswordChanged([
|
|
'fullname' => $vm->customer->fullname,
|
|
'vm_name' => $vm->name,
|
|
'newPassword' => $this->newPassword,
|
|
]));
|
|
}
|
|
|
|
private function assertSuccess(string $output): void
|
|
{
|
|
if (str_contains(strtoupper(trim($output)), 'SUCCESS')) {
|
|
return;
|
|
}
|
|
|
|
throw new \RuntimeException(
|
|
"Password change script failed for VM {$this->vmId}. Output: " . trim($output)
|
|
);
|
|
}
|
|
}
|