Refactor VM provisioning pipeline into focused services and add IP pool
management
This commit is contained in:
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Http\Facade\SignRSA;
|
||||
use App\Models\InfraManagement;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
@@ -19,11 +21,6 @@ use Illuminate\Support\Facades\Log;
|
||||
*/
|
||||
final class VsphereHostSshService
|
||||
{
|
||||
private const HOST = '10.10.10.173';
|
||||
private const PORT = 22;
|
||||
private const USER = 'administrator';
|
||||
private const PASS = 'Thegioiso@123**$$8899TgTk2';
|
||||
|
||||
private const SCRIPT_DIR = 'C:\\CLISave'; // backslash required for Windows cmd.exe
|
||||
private const SCRIPT_LINUX = 'changePasswordLinux.ps1';
|
||||
private const SCRIPT_WINDOWS = 'changePasswordWindows.ps1';
|
||||
@@ -60,13 +57,14 @@ final class VsphereHostSshService
|
||||
$script = strtoupper($osFamily) === VmProvisionService::OS_WINDOWS
|
||||
? self::SCRIPT_WINDOWS
|
||||
: self::SCRIPT_LINUX;
|
||||
$powerCliVmId = $this->powerCliVmId($vmId);
|
||||
|
||||
// Remote Windows cmd.exe command — all args double-quoted
|
||||
$remoteCmd = sprintf(
|
||||
'cd %s && powershell -ExecutionPolicy Bypass -NonInteractive -File %s %s %s %s %s %s',
|
||||
self::SCRIPT_DIR,
|
||||
$script,
|
||||
$this->warg($vmId),
|
||||
$this->warg($powerCliVmId),
|
||||
$this->warg($newPassword),
|
||||
$this->warg($vcenterHost),
|
||||
$this->warg($vcenterUser),
|
||||
@@ -115,42 +113,27 @@ final class VsphereHostSshService
|
||||
): string {
|
||||
$isWindows = strtoupper($osFamily) === VmProvisionService::OS_WINDOWS;
|
||||
$script = $isWindows ? self::SCRIPT_ASSIGN_WINDOWS : self::SCRIPT_ASSIGN_LINUX;
|
||||
$powerCliVmId = $this->powerCliVmId($vmId);
|
||||
|
||||
if ($isWindows) {
|
||||
// assignIPWindows.ps1: VMName IP MaskBits Gateway DNS GuestUser GuestPassword
|
||||
$remoteCmd = sprintf(
|
||||
'cd %s && powershell -ExecutionPolicy Bypass -NonInteractive -File %s %s %s %s %s %s %s %s',
|
||||
self::ASSIGN_DIR,
|
||||
$script,
|
||||
$this->warg($vmId),
|
||||
$this->warg($ip),
|
||||
$this->warg($cidr),
|
||||
$this->warg($gateway),
|
||||
$this->warg($dns),
|
||||
$this->warg($guestUser),
|
||||
$this->warg($guestPassword),
|
||||
);
|
||||
} else {
|
||||
// assignIPLinux.ps1: VCenter VCUser VCPass VMName IP MaskBits Gateway DNS GuestUser GuestPassword
|
||||
$remoteCmd = sprintf(
|
||||
'cd %s && powershell -ExecutionPolicy Bypass -NonInteractive -File %s %s %s %s %s %s %s %s %s %s %s',
|
||||
self::ASSIGN_DIR,
|
||||
$script,
|
||||
$this->warg($vcenterHost),
|
||||
$this->warg($vcenterUser),
|
||||
$this->warg($vcenterPassword),
|
||||
$this->warg($vmId),
|
||||
$this->warg($ip),
|
||||
$this->warg($cidr),
|
||||
$this->warg($gateway),
|
||||
$this->warg($dns),
|
||||
$this->warg($guestUser),
|
||||
$this->warg($guestPassword),
|
||||
);
|
||||
}
|
||||
// assignIP{Linux|Windows}.ps1:
|
||||
// VmId IP Gateway Cidr VCenterHost VCenterUser VCenterPassword GuestPassword
|
||||
$remoteCmd = sprintf(
|
||||
'cd %s && powershell -ExecutionPolicy Bypass -NonInteractive -File %s %s %s %s %s %s %s %s %s',
|
||||
self::ASSIGN_DIR,
|
||||
$script,
|
||||
$this->warg($powerCliVmId),
|
||||
$this->warg($ip),
|
||||
$this->warg($gateway),
|
||||
$this->warg($cidr),
|
||||
$this->warg($vcenterHost),
|
||||
$this->warg($vcenterUser),
|
||||
$this->warg($vcenterPassword),
|
||||
$this->warg($guestPassword),
|
||||
);
|
||||
|
||||
Log::info('VsphereHostSshService: executing assignIp', [
|
||||
'vm_id' => $vmId,
|
||||
'powercli_vm_id' => $powerCliVmId,
|
||||
'ip' => $ip,
|
||||
'script' => $script,
|
||||
'os' => $osFamily,
|
||||
@@ -188,36 +171,25 @@ final class VsphereHostSshService
|
||||
): string {
|
||||
$isWindows = strtoupper($osFamily) === VmProvisionService::OS_WINDOWS;
|
||||
$script = $isWindows ? self::SCRIPT_VERIFY_WINDOWS : self::SCRIPT_VERIFY_LINUX;
|
||||
$powerCliVmId = $this->powerCliVmId($vmId);
|
||||
|
||||
if ($isWindows) {
|
||||
// verifyIPWindows.ps1: VMName IP GuestUser GuestPassword
|
||||
$remoteCmd = sprintf(
|
||||
'cd %s && powershell -ExecutionPolicy Bypass -NonInteractive -File %s %s %s %s %s',
|
||||
self::ASSIGN_DIR,
|
||||
$script,
|
||||
$this->warg($vmId),
|
||||
$this->warg($ip),
|
||||
$this->warg($guestUser),
|
||||
$this->warg($guestPassword),
|
||||
);
|
||||
} else {
|
||||
// verifyIPLinux.ps1: VCenter VCUser VCPass VMName IP GuestUser GuestPassword
|
||||
$remoteCmd = sprintf(
|
||||
'cd %s && powershell -ExecutionPolicy Bypass -NonInteractive -File %s %s %s %s %s %s %s %s',
|
||||
self::ASSIGN_DIR,
|
||||
$script,
|
||||
$this->warg($vcenterHost),
|
||||
$this->warg($vcenterUser),
|
||||
$this->warg($vcenterPassword),
|
||||
$this->warg($vmId),
|
||||
$this->warg($ip),
|
||||
$this->warg($guestUser),
|
||||
$this->warg($guestPassword),
|
||||
);
|
||||
}
|
||||
// verifyIP{Linux|Windows}.ps1:
|
||||
// VmId IP VCenterHost VCenterUser VCenterPassword GuestPassword
|
||||
$remoteCmd = sprintf(
|
||||
'cd %s && powershell -ExecutionPolicy Bypass -NonInteractive -File %s %s %s %s %s %s %s',
|
||||
self::ASSIGN_DIR,
|
||||
$script,
|
||||
$this->warg($powerCliVmId),
|
||||
$this->warg($ip),
|
||||
$this->warg($vcenterHost),
|
||||
$this->warg($vcenterUser),
|
||||
$this->warg($vcenterPassword),
|
||||
$this->warg($guestPassword),
|
||||
);
|
||||
|
||||
Log::info('VsphereHostSshService: executing verifyIpInGuest', [
|
||||
'vm_id' => $vmId,
|
||||
'powercli_vm_id' => $powerCliVmId,
|
||||
'ip' => $ip,
|
||||
'script' => $script,
|
||||
'os' => $osFamily,
|
||||
@@ -244,14 +216,16 @@ final class VsphereHostSshService
|
||||
*/
|
||||
private function sshExec(string $remoteCmd): string
|
||||
{
|
||||
$ssh = $this->sshConfig();
|
||||
|
||||
// Full native SSH command executed on local shell
|
||||
$sshCmd = sprintf(
|
||||
'sshpass -p %s ssh -o StrictHostKeyChecking=no -o ConnectTimeout=%d -p %d %s@%s %s 2>&1',
|
||||
escapeshellarg(self::PASS),
|
||||
escapeshellarg($ssh['password']),
|
||||
self::CONNECT_TIMEOUT,
|
||||
self::PORT,
|
||||
escapeshellarg(self::USER),
|
||||
escapeshellarg(self::HOST),
|
||||
$ssh['port'],
|
||||
escapeshellarg($ssh['username']),
|
||||
escapeshellarg($ssh['host']),
|
||||
escapeshellarg($remoteCmd),
|
||||
);
|
||||
|
||||
@@ -273,10 +247,31 @@ final class VsphereHostSshService
|
||||
}
|
||||
|
||||
throw new \RuntimeException(
|
||||
'SSH exec to ' . self::HOST . ' failed after ' . self::MAX_RETRIES . ' attempts',
|
||||
'SSH exec to ' . $ssh['host'] . ' failed after ' . self::MAX_RETRIES . ' attempts',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{host:string, port:int, username:string, password:string}
|
||||
*/
|
||||
private function sshConfig(): array
|
||||
{
|
||||
$infra = InfraManagement::where('type', 'jumphost')
|
||||
->where('status', true)
|
||||
->first();
|
||||
|
||||
if (!$infra) {
|
||||
throw new \RuntimeException('No active jumphost configuration found in InfraManagement.');
|
||||
}
|
||||
|
||||
return [
|
||||
'host' => $infra->host,
|
||||
'port' => (int) ($infra->meta_data['port'] ?? 22),
|
||||
'username' => $infra->username,
|
||||
'password' => SignRSA::DecryptFunc($infra->password),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer-initiated VM password change.
|
||||
*
|
||||
@@ -304,12 +299,13 @@ final class VsphereHostSshService
|
||||
$script = strtoupper($osFamily) === VmProvisionService::OS_WINDOWS
|
||||
? self::SCRIPT_CHANGE_PWD_WINDOWS
|
||||
: self::SCRIPT_CHANGE_PWD_LINUX;
|
||||
$powerCliVmId = $this->powerCliVmId($vmId);
|
||||
|
||||
$remoteCmd = sprintf(
|
||||
'cd %s && powershell -ExecutionPolicy Bypass -NonInteractive -File %s %s %s %s %s %s %s',
|
||||
self::CHANGE_PWD_DIR,
|
||||
$script,
|
||||
$this->warg($vmId),
|
||||
$this->warg($powerCliVmId),
|
||||
$this->warg($newPassword),
|
||||
$this->warg($vcenterHost),
|
||||
$this->warg($vcenterUser),
|
||||
@@ -343,6 +339,15 @@ final class VsphereHostSshService
|
||||
return '"' . str_replace('"', '\\"', $value) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* vCenter REST returns MoRef strings like "vm-3340"; PowerCLI scripts build
|
||||
* IDs as "VirtualMachine-$vmId", so keep the MoRef intact.
|
||||
*/
|
||||
private function powerCliVmId(string $vmId): string
|
||||
{
|
||||
return $vmId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Single-quote wrap for passwords — prevents PowerShell variable expansion on $, %, ^ etc.
|
||||
* Inside a single-quoted PS string, a literal single quote is escaped as ''.
|
||||
|
||||
Reference in New Issue
Block a user