Keep reconnectable exec SSH tunnels alive

This commit is contained in:
Fedor Korotkov 2026-05-01 13:35:50 -04:00
parent 3fe6cf8d53
commit 82f5db8cfc
2 changed files with 38 additions and 3 deletions

View File

@ -175,7 +175,7 @@ func (controller *Controller) execVMReconnectable(
} }
func (controller *Controller) newSSHExecSession( func (controller *Controller) newSSHExecSession(
ctx *gin.Context, _ *gin.Context,
waitContext context.Context, waitContext context.Context,
vm *v1.VM, vm *v1.VM,
key execSessionKey, key execSessionKey,
@ -184,6 +184,8 @@ func (controller *Controller) newSSHExecSession(
registry *execSessionRegistry, registry *execSessionRegistry,
policy execSessionPolicy, policy execSessionPolicy,
) (*execSession, error) { ) (*execSession, error) {
sessionContext, sessionContextCancel := context.WithCancel(context.Background())
portForwardConn, err := retry.NewWithData[net.Conn]( portForwardConn, err := retry.NewWithData[net.Conn](
retry.Context(waitContext), retry.Context(waitContext),
retry.DelayType(retry.FixedDelay), retry.DelayType(retry.FixedDelay),
@ -191,20 +193,25 @@ func (controller *Controller) newSSHExecSession(
retry.Attempts(0), retry.Attempts(0),
retry.LastErrorOnly(true), retry.LastErrorOnly(true),
).Do(func() (net.Conn, error) { ).Do(func() (net.Conn, error) {
return controller.portForwardConnection(ctx, waitContext, vm.Worker, vm.UID, 22) return controller.portForwardConnection(sessionContext, waitContext, vm.Worker, vm.UID, 22)
}) })
if err != nil { if err != nil {
sessionContextCancel()
return nil, err return nil, err
} }
exec, err := sshexec.New(portForwardConn, vm.SSHUsername(), vm.SSHPassword(), stdin) exec, err := sshexec.New(portForwardConn, vm.SSHUsername(), vm.SSHPassword(), stdin)
if err != nil { if err != nil {
sessionContextCancel()
_ = portForwardConn.Close() _ = portForwardConn.Close()
return nil, fmt.Errorf("failed to establish SSH connection to a VM: %w", err) return nil, fmt.Errorf("failed to establish SSH connection to a VM: %w", err)
} }
return newExecSession( return newExecSessionWithContext(
sessionContext,
sessionContextCancel,
key, key,
command, command,
exec, exec,

View File

@ -334,6 +334,34 @@ func newExecSession(
) *execSession { ) *execSession {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
return newExecSessionWithContext(
ctx,
cancel,
key,
command,
exec,
transport,
registry,
exitTTL,
policy,
)
}
func newExecSessionWithContext(
ctx context.Context,
cancel context.CancelFunc,
key execSessionKey,
command string,
exec sshExecRunner,
transport net.Conn,
registry *execSessionRegistry,
exitTTL time.Duration,
policy execSessionPolicy,
) *execSession {
if ctx == nil || cancel == nil {
ctx, cancel = context.WithCancel(context.Background())
}
session := &execSession{ session := &execSession{
key: key, key: key,
command: command, command: command,