Files
portal-api/app/Jobs/VirtualMachine/Provision/ChangePasswordViaVsphereJob.php
T

139 lines
4.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Jobs\VirtualMachine\Provision;
use App\Http\Facade\SignRSA;
use App\Models\ModuleVmware;
use App\Models\vCenter;
use App\Services\VmProvisionService;
use App\Services\VsphereHostSshService;
use App\Jobs\VirtualMachine\Provision\AssignIpToGuestJob;
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;
/**
* ChangePasswordViaVsphereJob
*
* Resets the VM guest OS password via:
* Laravel → SSH (10.10.10.173) → PowerShell PS1 → Invoke-VMScript (guest OS)
*
* Flow:
* [1] VM already exists, vm_id known
* [2] Generate random 16-char password (plain text)
* [3] Load vCenter credentials from module_vcenter
* [4] SSH into vSphere host
* [5] Execute changePassword{Linux|Windows}.ps1 with 5 params
* [6] Parse "SUCCESS" / "FAIL" from script output
* [7] On SUCCESS → save encrypted password to DB
* [8] Dispatch AssignIpToGuestJob with the new guest password
* [9] On FAIL → throw exception → job retries
*/
class ChangePasswordViaVsphereJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 5;
public int $timeout = 180;
public int $backoff = 60;
public function __construct(
public readonly int $moduleVmwareId,
public readonly string $vmId,
public readonly string $osFamily, // VmProvisionService::OS_LINUX | OS_WINDOWS
) {}
// ─────────────────────────────────────────────────────────────────────────
public function handle(VmProvisionService $provision, VsphereHostSshService $ssh): void
{
Log::info('ChangePasswordViaVsphereJob: starting', [
'module_vmware_id' => $this->moduleVmwareId,
'vm_id' => $this->vmId,
'os_family' => $this->osFamily,
]);
// [2] Generate plain-text password (not hashed)
$newPassword = $provision->generatePassword(16);
// [3] Load vCenter credentials from database
$vcenter = vCenter::first();
if (!$vcenter) {
throw new \RuntimeException('No vCenter record found in module_vcenter');
}
$vcenterHost = $vcenter->host;
$vcenterUser = $vcenter->user;
$vcenterPass = SignRSA::DecryptFunc($vcenter->password);
// [4–5] SSH → vSphere host → run PS1 with 5 params
$output = $ssh->changePassword(
$this->vmId,
$newPassword,
$this->osFamily,
$vcenterHost,
$vcenterUser,
$vcenterPass,
);
// [6] Parse output — throw on FAIL so job retries
$this->assertSuccess($output);
// [7] Save encrypted + plain password (IP will be set later by AssignIpToGuestJob)
$provision->updatePassword($this->moduleVmwareId, $newPassword);
// [8] Assign real IP into guest OS using the new password
AssignIpToGuestJob::dispatch(
$this->moduleVmwareId,
$this->vmId,
$this->osFamily,
$newPassword, // guest_password — MUST use new password, not template
);
Log::info('ChangePasswordViaVsphereJob: completed', [
'module_vmware_id' => $this->moduleVmwareId,
'vm_id' => $this->vmId,
]);
}
// ─────────────────────────────────────────────────────────────────────────
public function failed(\Throwable $e): void
{
Log::error('ChangePasswordViaVsphereJob: all retries exhausted', [
'module_vmware_id' => $this->moduleVmwareId,
'vm_id' => $this->vmId,
'error' => $e->getMessage(),
]);
ModuleVmware::where('id', $this->moduleVmwareId)->update(['status' => 0]);
}
// ─────────────────────────────────────────────────────────────────────────
/**
* PS1 scripts output exactly "SUCCESS" or "FAIL".
* Throw RuntimeException on FAIL → triggers job retry.
*
* @throws \RuntimeException
*/
private function assertSuccess(string $output): void
{
$trimmed = trim($output);
if (str_contains(strtoupper($trimmed), 'SUCCESS')) {
return;
}
throw new \RuntimeException(
"PS1 script returned failure for VM {$this->vmId}. Output: {$trimmed}",
);
}
}