From 5ebf11caebe5332e13196974e9fb182d617fcf47 Mon Sep 17 00:00:00 2001 From: dani <29378233+kheina@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:55:34 -0400 Subject: [PATCH] create a deferral to automatically close sessions after creating them during boundary connect (#6054) --- api/proxy/proxy.go | 12 +++++- internal/cmd/commands/connect/connect.go | 49 +++++++++++++++++------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/api/proxy/proxy.go b/api/proxy/proxy.go index 68e9f7347e..8aa89bac9a 100644 --- a/api/proxy/proxy.go +++ b/api/proxy/proxy.go @@ -350,12 +350,20 @@ func (p *ClientProxy) Start(opt ...Option) (retErr error) { return nil } - ctx, cancel := context.WithTimeout(context.Background(), opts.withSessionTeardownTimeout) + return p.CloseSession(opts.withSessionTeardownTimeout) +} + +// CloseSession attempts to close the currently proxied session by sending a +// request to do so to the worker proxying the connection +func (p *ClientProxy) CloseSession(sessionTeardownTimeout time.Duration) error { + if sessionTeardownTimeout == 0 { + sessionTeardownTimeout = sessionCancelTimeout + } + ctx, cancel := context.WithTimeout(context.Background(), sessionTeardownTimeout) defer cancel() if err := p.sendSessionTeardown(ctx); err != nil { return fmt.Errorf("error sending session teardown request to worker: %w", err) } - return nil } diff --git a/internal/cmd/commands/connect/connect.go b/internal/cmd/commands/connect/connect.go index 214d06f0da..5525cee958 100644 --- a/internal/cmd/commands/connect/connect.go +++ b/internal/cmd/commands/connect/connect.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/boundary/api" apiproxy "github.com/hashicorp/boundary/api/proxy" + "github.com/hashicorp/boundary/api/sessions" "github.com/hashicorp/boundary/api/targets" "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/util" @@ -336,6 +337,19 @@ func (c *Command) Run(args []string) (retCode int) { } } + var addr netip.Addr + if c.flagListenAddr == "" { + c.flagListenAddr = "127.0.0.1" + } + addr, err := netip.ParseAddr(c.flagListenAddr) + if err != nil { + c.PrintCliError(fmt.Errorf("Error parsing listen address: %w", err)) + return base.CommandCliError + } + listenAddr := netip.AddrPortFrom(addr, uint16(c.flagListenPort)) + + var clientProxy *apiproxy.ClientProxy + authzString := c.flagAuthzToken switch { case authzString != "": @@ -431,28 +445,35 @@ func (c *Command) Run(args []string) (retCode int) { HostId: sa.HostId, Credentials: sa.Credentials, } - authzString = sa.AuthorizationToken - } - var listenAddr netip.AddrPort - var addr netip.Addr - if c.flagListenAddr == "" { - c.flagListenAddr = "127.0.0.1" - } - addr, err := netip.ParseAddr(c.flagListenAddr) - if err != nil { - c.PrintCliError(fmt.Errorf("Error parsing listen address: %w", err)) - return base.CommandCliError - } + // the session was created specifically for this `boundary connect` + // command, and should be closed as soon as the command has exited + defer func() { + var err error + switch { + case clientProxy != nil: + err = clientProxy.CloseSession(0) + default: + // this is a weird special case. normally we let the client proxy end + // the session, but it failed to be inited, so we need to create the + // session client to ensure we don't leave hanging sessions + sClient := sessions.NewClient(client) + _, err = sClient.Cancel(c.Context, sa.SessionId, 0, sessions.WithAutomaticVersioning(true)) + } + if err != nil { + c.PrintCliError(fmt.Errorf("Error closing session after command end: %w", err)) + } + }() - listenAddr = netip.AddrPortFrom(addr, uint16(c.flagListenPort)) + authzString = sa.AuthorizationToken + } connsLeftCh := make(chan int32) apiProxyOpts := []apiproxy.Option{apiproxy.WithConnectionsLeftCh(connsLeftCh)} if listenAddr.IsValid() { apiProxyOpts = append(apiProxyOpts, apiproxy.WithListenAddrPort(listenAddr)) } - clientProxy, err := apiproxy.New( + clientProxy, err = apiproxy.New( c.proxyCtx, authzString, apiProxyOpts...,