Refactor VsphereHostSshService to use phpseclib for SSH execution, removing sshpass dependency; enhance error handling and logging
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user