fix: fixes a possible deadlock in kube moderator joining (#54500)

* fix: fixes a possible deadlock in kube moderator joining

This PR addresses a bug in the Kubernetes session join logic where a joined session could hang under specific conditions. The issue occurred when one or more peers triggered multiple terminal resize events in rapid succession.

The client handling the resize was only performing a single resize operation and failing to respond to subsequent events, resulting in the terminal becoming unresponsive. This led to a state where session data was no longer displayed to moderators or observers, effectively freezing the shared session view. The fix ensures proper handling of repeated resize events to maintain session responsiveness and continuity.

Signed-off-by: Tiago Silva <tiago.silva@goteleport.com>

* Update lib/client/kubesession.go

Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>

---------

Signed-off-by: Tiago Silva <tiago.silva@goteleport.com>
Co-authored-by: Zac Bergquist <zac.bergquist@goteleport.com>
This commit is contained in:
Tiago Silva
2025-05-05 19:46:30 +00:00
committed by GitHub
co-authored by Zac Bergquist
parent c0eb83474b
commit c16b6c1244
+19 -25
View File
@@ -136,8 +136,7 @@ func NewKubeSession(ctx context.Context, cfg KubeSessionConfig) (*KubeSession, e
stdout := utils.NewSyncWriter(term.Stdout())
go handleOutgoingResizeEvents(ctx, stream, term)
go handleIncomingResizeEvents(ctx, stream, term)
go handleResizeEvents(ctx, stream, term)
s := &KubeSession{stream, term, ctx, cancel, cfg.Tracker, sync.WaitGroup{}}
if err := s.handleMFA(ctx, cfg.AuthClient, cfg.Ceremony, cfg.Mode, stdout); err != nil {
@@ -170,29 +169,28 @@ func kubeSessionNetDialer(ctx context.Context, cfg KubeSessionConfig) client.Con
)
}
func handleOutgoingResizeEvents(ctx context.Context, stream *streamproto.SessionStream, term *terminal.Terminal) {
queue := stream.ResizeQueue()
select {
case <-ctx.Done():
return
case size := <-queue:
if size == nil {
return
}
term.Resize(int16(size.Width), int16(size.Height))
}
}
func handleIncomingResizeEvents(ctx context.Context, stream *streamproto.SessionStream, term *terminal.Terminal) {
events := term.Subscribe()
func handleResizeEvents(ctx context.Context, stream *streamproto.SessionStream, term *terminal.Terminal) {
streamResizes := stream.ResizeQueue()
terminalResizes := term.Subscribe()
defer stream.Close()
for {
select {
case <-ctx.Done():
return
case event, more := <-events:
case size, more := <-streamResizes:
if !more {
return
}
if size == nil {
continue
}
if err := term.Resize(int16(size.Width), int16(size.Height)); err != nil {
fmt.Printf("Error attempting to resize terminal: %v\n\r", err)
}
case event, more := <-terminalResizes:
if !more {
return
}
_, ok := event.(terminal.ResizeEvent)
if ok {
w, h, err := term.Size()
@@ -205,10 +203,6 @@ func handleIncomingResizeEvents(ctx context.Context, stream *streamproto.Session
fmt.Printf("Error attempting to resize terminal: %v\n\r", err)
}
}
if !more {
return
}
}
}
}