feat: Add IP address and DNS fields to module_vmware table
- Introduced `ip` and `dns` columns to the `module_vmware` table to store assigned IP addresses and DNS configurations. - Implemented `ChangePasswordViaSshJob` for secure password changes via SSH. - Created `ChangePasswordJob` for handling password changes during VM provisioning. - Developed `ChangePasswordViaVsphereJob` to reset VM guest OS passwords using PowerShell scripts executed on the vSphere host. - Added `SendVmCredentialsEmailJob` to send final VM credentials to customers. - Implemented `WaitVmReadyJob` to poll vSphere API until VMware Tools are running and guest IP is available. - Created `VmProvisionService` for managing VM provisioning tasks, including password generation and updates. - Developed `VsphereHostSshService` for executing PowerShell scripts on the vSphere host via SSH. - Added `IpPoolSeeder` to populate IP pools for VM service initialization.
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Jobs\VirtualMachine\Provision;
|
||||
|
||||
use App\Services\VmProvisionService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* ChangePasswordJob
|
||||
*
|
||||
* Connects to the VM via SSH (Linux) or WinRM (Windows) using the
|
||||
* template default password (TGS@123), then:
|
||||
* [7] Generates a new secure 16-char password
|
||||
* [8] Changes the password on the OS
|
||||
* [9] Verifies the new password works (re-login)
|
||||
* [10] Saves encrypted password + plain_password to module_vmware
|
||||
* [11] Dispatches SendVmCredentialsEmailJob
|
||||
*
|
||||
* Uses the REAL IP reported by VMware Tools (from WaitVmReadyJob),
|
||||
* NOT the IP pool address.
|
||||
*
|
||||
* Up to 3 job-level retries if an unexpected error occurs.
|
||||
*/
|
||||
class ChangePasswordJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public int $tries = 3;
|
||||
|
||||
/** SSH + WinRM operations should complete within 2 min */
|
||||
public int $timeout = 120;
|
||||
|
||||
public function __construct(
|
||||
public readonly int $moduleVmwareId,
|
||||
public readonly string $vmId,
|
||||
public readonly string $guestIp, // real IP from VMware Tools
|
||||
public readonly string $osFamily, // VmProvisionService::OS_LINUX | OS_WINDOWS
|
||||
public readonly string $username, // root | Administrator
|
||||
) {}
|
||||
|
||||
public function handle(VmProvisionService $provision): void
|
||||
{
|
||||
Log::info('ChangePasswordJob: starting', [
|
||||
'vm_id' => $this->vmId,
|
||||
'ip' => $this->guestIp,
|
||||
'os_family' => $this->osFamily,
|
||||
'username' => $this->username,
|
||||
]);
|
||||
|
||||
// [7] Generate secure password
|
||||
$newPassword = $provision->generatePassword(16);
|
||||
|
||||
// [8] Change password on OS
|
||||
$this->changePassword($provision, $newPassword);
|
||||
|
||||
// [9] Verify new credentials work (critical — throws on failure)
|
||||
$this->verifyPassword($provision, $newPassword);
|
||||
|
||||
// [10] Persist encrypted password + guest IP to DB
|
||||
$provision->savePassword($this->moduleVmwareId, $this->guestIp, $newPassword);
|
||||
|
||||
// [11] Send credentials email
|
||||
SendVmCredentialsEmailJob::dispatch($this->moduleVmwareId);
|
||||
|
||||
Log::info('ChangePasswordJob: completed', [
|
||||
'vm_id' => $this->vmId,
|
||||
'module_vmware_id' => $this->moduleVmwareId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function failed(\Throwable $e): void
|
||||
{
|
||||
Log::error('ChangePasswordJob: failed after max retries', [
|
||||
'vm_id' => $this->vmId,
|
||||
'module_vmware_id' => $this->moduleVmwareId,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
\App\Models\ModuleVmware::where('id', $this->moduleVmwareId)
|
||||
->update(['status' => 0]);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private function changePassword(VmProvisionService $provision, string $newPassword): void
|
||||
{
|
||||
if ($this->osFamily === VmProvisionService::OS_WINDOWS) {
|
||||
Log::info('ChangePasswordJob: changing password via WinRM', [
|
||||
'vm_id' => $this->vmId,
|
||||
'ip' => $this->guestIp,
|
||||
]);
|
||||
|
||||
$provision->winrmChangePassword(
|
||||
$this->guestIp,
|
||||
$this->username,
|
||||
$newPassword,
|
||||
$this->vmId,
|
||||
);
|
||||
} else {
|
||||
Log::info('ChangePasswordJob: changing password via SSH', [
|
||||
'vm_id' => $this->vmId,
|
||||
'ip' => $this->guestIp,
|
||||
]);
|
||||
|
||||
$provision->sshChangePassword(
|
||||
$this->guestIp,
|
||||
$this->username,
|
||||
$newPassword,
|
||||
$this->vmId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function verifyPassword(VmProvisionService $provision, string $newPassword): void
|
||||
{
|
||||
Log::info('ChangePasswordJob: verifying new credentials', [
|
||||
'vm_id' => $this->vmId,
|
||||
'ip' => $this->guestIp,
|
||||
]);
|
||||
|
||||
if ($this->osFamily === VmProvisionService::OS_WINDOWS) {
|
||||
$provision->verifyWinrmLogin($this->guestIp, $this->username, $newPassword, $this->vmId);
|
||||
} else {
|
||||
$provision->verifySshLogin($this->guestIp, $this->username, $newPassword, $this->vmId);
|
||||
}
|
||||
|
||||
Log::info('ChangePasswordJob: credential verification passed', [
|
||||
'vm_id' => $this->vmId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user