Refactor VsphereHostSshService to use phpseclib for SSH execution, removing sshpass dependency; enhance error handling and logging

This commit is contained in:
baodev0
2026-07-13 15:30:55 +07:00
parent f45c92c3ad
commit c852fb13ff
+17 -34
View File
@@ -7,12 +7,13 @@ namespace App\Services;
use App\Http\Facade\SignRSA;
use App\Models\InfraManagement;
use Illuminate\Support\Facades\Log;
use phpseclib3\Net\SSH2;
/**
* VsphereHostSshService
*
* Executes pre-deployed PowerShell scripts on the vSphere Windows host
* via native SSH (sshpass). No phpseclib dependency.
* via phpseclib SSH (no sshpass required).
*
* Scripts in C:/CLISave/ accept 5 positional params:
* VM_ID NEW_PASSWORD VCENTER_HOST VCENTER_USER VCENTER_PASSWORD
@@ -36,8 +37,6 @@ final class VsphereHostSshService
private const SCRIPT_CHANGE_PWD_WINDOWS = 'changePwdWindows.ps1';
private const CONNECT_TIMEOUT = 20;
private const MAX_RETRIES = 5;
private const RETRY_DELAY = 5;
// ─────────────────────────────────────────────────────────────────────────
@@ -232,46 +231,30 @@ final class VsphereHostSshService
// ─────────────────────────────────────────────────────────────────────────
/**
* Run a command on the vSphere SSH host via sshpass.
* Retries up to MAX_RETRIES times on connection failure.
* Run a command on the vSphere SSH host via phpseclib (no sshpass required).
*
* @throws \RuntimeException
*/
private function sshExec(string $remoteCmd): string
{
$ssh = $this->sshConfig();
$config = $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($ssh['password']),
self::CONNECT_TIMEOUT,
$ssh['port'],
escapeshellarg($ssh['username']),
escapeshellarg($ssh['host']),
escapeshellarg($remoteCmd),
);
$client = new SSH2($config['host'], $config['port'], self::CONNECT_TIMEOUT);
for ($attempt = 1; $attempt <= self::MAX_RETRIES; $attempt++) {
$output = shell_exec($sshCmd);
if ($output === null) {
Log::warning('VsphereHostSshService: shell_exec returned null', [
'attempt' => $attempt,
]);
} else {
Log::info('VsphereHostSshService: SSH executed', ['attempt' => $attempt]);
return $output;
}
if ($attempt < self::MAX_RETRIES) {
sleep(self::RETRY_DELAY);
}
if (!$client->login($config['username'], $config['password'])) {
throw new \RuntimeException(
"SSH login failed: {$config['host']}:{$config['port']}"
);
}
throw new \RuntimeException(
'SSH exec to ' . $ssh['host'] . ' failed after ' . self::MAX_RETRIES . ' attempts',
);
$output = $client->exec($remoteCmd);
Log::info('VsphereHostSshService: SSH executed', [
'host' => $config['host'],
'port' => $config['port'],
]);
return (string) $output;
}
/**