Add WAL file for database and log instance deployment failures
Some checks failed
Build and Publish Docker Image / build-and-push (push) Has been cancelled
Some checks failed
Build and Publish Docker Image / build-and-push (push) Has been cancelled
This commit is contained in:
@@ -93,6 +93,31 @@ public class SshConnectionService : IDisposable
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run a command on the remote host with a timeout.
|
||||
/// Returns exit code -1 and an error message if the command times out.
|
||||
/// </summary>
|
||||
public async Task<(int ExitCode, string Stdout, string Stderr)> RunCommandAsync(SshHost host, string command, TimeSpan timeout)
|
||||
{
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
var client = GetClient(host);
|
||||
using var cmd = client.CreateCommand(command);
|
||||
cmd.CommandTimeout = timeout;
|
||||
try
|
||||
{
|
||||
cmd.Execute();
|
||||
return (cmd.ExitStatus ?? -1, cmd.Result, cmd.Error);
|
||||
}
|
||||
catch (Renci.SshNet.Common.SshOperationTimeoutException)
|
||||
{
|
||||
_logger.LogWarning("SSH command timed out after {Timeout}s: {Command}",
|
||||
timeout.TotalSeconds, command.Length > 120 ? command[..120] + "…" : command);
|
||||
return (-1, string.Empty, $"Command timed out after {timeout.TotalSeconds}s");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run a command that requires stdin input (e.g., docker stack deploy --compose-file -).
|
||||
/// </summary>
|
||||
@@ -171,6 +196,23 @@ public class SshConnectionService : IDisposable
|
||||
return new SshClient(connInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens an SSH local port-forward from 127.0.0.1:<auto> → <paramref name="remoteHost"/>:<paramref name="remotePort"/>
|
||||
/// through the existing SSH connection for <paramref name="host"/>.
|
||||
/// The caller must dispose the returned <see cref="ForwardedPortLocal"/> to close the tunnel.
|
||||
/// </summary>
|
||||
public ForwardedPortLocal OpenForwardedPort(SshHost host, string remoteHost, uint remotePort)
|
||||
{
|
||||
var client = GetClient(host);
|
||||
// Port 0 lets the OS assign a free local port; SSH.NET updates BoundPort after Start().
|
||||
var tunnel = new ForwardedPortLocal("127.0.0.1", 0, remoteHost, remotePort);
|
||||
client.AddForwardedPort(tunnel);
|
||||
tunnel.Start();
|
||||
_logger.LogDebug("SSH tunnel opened: 127.0.0.1:{LocalPort} → {RemoteHost}:{RemotePort}",
|
||||
tunnel.BoundPort, remoteHost, remotePort);
|
||||
return tunnel;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_lock)
|
||||
|
||||
Reference in New Issue
Block a user