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

This commit is contained in:
Matt Batchelder
2026-02-19 08:27:54 -05:00
parent 4a903bfd2a
commit adf1a2e4db
41 changed files with 2789 additions and 1297 deletions

View File

@@ -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:&lt;auto&gt; → <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)