refactor: implement centralized cache key management and add utility traits for vCenter SSH operations.

This commit is contained in:
pbao9
2026-05-16 16:52:21 +07:00
parent 06dbd54ecd
commit 8a115c5175
36 changed files with 1694 additions and 517 deletions
+76 -5
View File
@@ -34,6 +34,10 @@ final class VsphereHostSshService
private const SCRIPT_VERIFY_LINUX = 'verifyIPLinux.ps1';
private const SCRIPT_VERIFY_WINDOWS = 'verifyIPWindows.ps1';
private const CHANGE_PWD_DIR = 'C:\\CLISave\\changePassword';
private const SCRIPT_CHANGE_PWD_LINUX = 'changePwdLinux.ps1';
private const SCRIPT_CHANGE_PWD_WINDOWS = 'changePwdWindows.ps1';
private const CONNECT_TIMEOUT = 20;
private const MAX_RETRIES = 5;
private const RETRY_DELAY = 5;
@@ -91,8 +95,8 @@ final class VsphereHostSshService
* Assign a static IP to the VM guest OS via PS1 script.
* Calls assignIPLinux.ps1 or assignIPWindows.ps1 in C:\CLISave\AssignIP\.
*
* Windows script params (7): VMName IP MaskBits Gateway DNS GuestUser GuestPassword
* Linux script params (9): VCenter VCUser VCPass VMName IP Gateway DNS GuestUser GuestPassword
* Windows script params (7): VMName IP MaskBits Gateway DNS GuestUser GuestPassword
* Linux script params (10): VCenter VCUser VCPass VMName IP MaskBits Gateway DNS GuestUser GuestPassword
*
* Script output: JSON {"status":"ok"} or {"status":"error","message":"..."}
*/
@@ -127,9 +131,9 @@ final class VsphereHostSshService
$this->warg($guestPassword),
);
} else {
// assignIPLinux.ps1: VCenter VCUser VCPass VMName IP Gateway DNS GuestUser GuestPassword
// 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',
'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),
@@ -137,6 +141,7 @@ final class VsphereHostSshService
$this->warg($vcenterPassword),
$this->warg($vmId),
$this->warg($ip),
$this->warg($cidr),
$this->warg($gateway),
$this->warg($dns),
$this->warg($guestUser),
@@ -272,12 +277,78 @@ final class VsphereHostSshService
);
}
/**
* Customer-initiated VM password change.
*
* Calls changePwdLinux.ps1 / changePwdWindows.ps1 in C:\CLISave\changePassword\.
*
* Param order (matches PS1 declaration):
* $vm vm_id / vmware display name double-quoted
* $password new password single-quoted
* $vcenter_host vCenter host double-quoted
* $vcenter_user vCenter user double-quoted
* $vcenter_password vCenter password single-quoted
* $guest_password current guest password single-quoted
*
* PS1 outputs "SUCCESS" or "ERROR".
*/
public function changePasswordCustomer(
string $vmId,
string $newPassword,
string $currentGuestPassword,
string $osFamily,
string $vcenterHost,
string $vcenterUser,
string $vcenterPassword,
): string {
$script = strtoupper($osFamily) === VmProvisionService::OS_WINDOWS
? self::SCRIPT_CHANGE_PWD_WINDOWS
: self::SCRIPT_CHANGE_PWD_LINUX;
$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($newPassword),
$this->warg($vcenterHost),
$this->warg($vcenterUser),
$this->warg($vcenterPassword),
$this->warg($currentGuestPassword),
);
Log::info('VsphereHostSshService: changePasswordCustomer', [
'vm_id' => $vmId,
'script' => $script,
'os' => $osFamily,
]);
$output = $this->sshExec($remoteCmd);
Log::info('VsphereHostSshService: changePasswordCustomer output', [
'vm_id' => $vmId,
'output' => trim($output),
]);
return $output;
}
// ─────────────────────────────────────────────────────────────────────────
/**
* Windows cmd.exe safe argument: wrap in double quotes, escape inner double quotes.
* Password charset excludes " and % so wrapping is always safe.
*/
private function warg(string $value): string
{
return '"' . str_replace('"', '\\"', $value) . '"';
}
/**
* Single-quote wrap for passwords — prevents PowerShell variable expansion on $, %, ^ etc.
* Inside a single-quoted PS string, a literal single quote is escaped as ''.
*/
private function sarg(string $value): string
{
return "'" . str_replace("'", "''", $value) . "'";
}
}