@@ -62,27 +62,51 @@ def _get_terminal_size() -> Tuple[int, int]:
6262 return int (os .environ .get ('LINES' , 24 )), int (os .environ .get ('COLUMNS' , 80 ))
6363
6464
65- def _resize_terminal_handler ( _signum , _frame , exec_stream ):
65+ def _send_terminal_size ( exec_stream , rows , cols ):
6666 """
67- Handle terminal resize signal and send new size to pod via WebSocket channel.
67+ Send terminal size to pod via WebSocket channel.
6868
6969 Args:
70- signum: Signal number
71- frame: Current stack frame
7270 exec_stream: The WebSocket stream object
71+ rows: Terminal height
72+ cols: Terminal width
7373 """
7474 try :
75- rows , cols = _get_terminal_size ()
76- # Create resize message as JSON
7775 resize_message = json .dumps ({
7876 "Width" : cols ,
7977 "Height" : rows
8078 })
81- # Send resize message through WebSocket channel 4 (RESIZE_CHANNEL)
8279 exec_stream .write_channel (RESIZE_CHANNEL , resize_message )
8380 logger .debug ("Terminal resized to %dx%d" , cols , rows )
8481 except Exception as e : # pylint: disable=broad-exception-caught
85- logger .debug ("Failed to resize terminal: %s" , e )
82+ logger .debug ("Failed to send terminal size: %s" , e )
83+
84+
85+ def _monitor_resize_events_windows (exec_stream , stop_event ):
86+ """
87+ Monitor terminal resize events on Windows by polling.
88+ Implementation based on Kubernetes kubectl.
89+ Reference: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/kubectl/
90+ pkg/util/term/resizeevents_windows.go
91+
92+ Args:
93+ exec_stream: The WebSocket stream object
94+ stop_event: Threading event to stop monitoring
95+ """
96+ last_size = _get_terminal_size ()
97+
98+ while not stop_event .is_set () and exec_stream .is_open ():
99+ try :
100+ current_size = _get_terminal_size ()
101+ if current_size != last_size :
102+ _send_terminal_size (exec_stream , current_size [0 ], current_size [1 ])
103+ last_size = current_size
104+ except Exception as e : # pylint: disable=broad-exception-caught
105+ logger .debug ("Error monitoring terminal size: %s" , e )
106+ break
107+
108+ # Sleep to avoid hot looping (same interval as kubectl)
109+ stop_event .wait (0.25 )
86110
87111
88112def _set_terminal_raw_mode ():
@@ -294,6 +318,8 @@ def exec_command_in_pod(pod_name: str, command: List[str], # pylint: disable=to
294318 fl = None
295319 cleanup_done = False
296320 windows_console_state = None
321+ resize_stop_event = None
322+ resize_thread = None
297323
298324 def cleanup ():
299325 """Cleanup function to ensure proper resource cleanup."""
@@ -304,7 +330,7 @@ def cleanup():
304330 return
305331 cleanup_done = True
306332
307- # Restore signal handler
333+ # Restore signal handler (Unix/Linux). Windows does not use signal handlers for resize.
308334 if original_sigwinch and not IS_WINDOWS :
309335 try :
310336 signal .signal (signal .SIGWINCH , original_sigwinch )
@@ -403,13 +429,27 @@ def signal_handler(signum, _frame):
403429 if tty :
404430 terminal_state = _set_terminal_raw_mode ()
405431
406- # Set up terminal resize handler (Unix/Linux only)
407- if not IS_WINDOWS and hasattr (signal , 'SIGWINCH' ):
408- def resize_handler (signum , frame ):
409- _resize_terminal_handler (signum , frame , resp )
410-
411- # Register signal handler for terminal resize
412- original_sigwinch = signal .signal (signal .SIGWINCH , resize_handler )
432+ # Set up terminal resize monitoring
433+ # Reference: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/kubectl/pkg/util/term/
434+ if IS_WINDOWS :
435+ # Windows: Poll for size changes in background thread
436+ resize_stop_event = threading .Event ()
437+ resize_thread = threading .Thread (
438+ target = _monitor_resize_events_windows ,
439+ args = (resp , resize_stop_event ),
440+ daemon = True
441+ )
442+ resize_thread .start ()
443+ elif hasattr (signal , 'SIGWINCH' ):
444+ # Unix/Linux: Use SIGWINCH signal handler (must be in main thread)
445+ def sigwinch_handler (_signum , _frame ):
446+ try :
447+ rows , cols = _get_terminal_size ()
448+ _send_terminal_size (resp , rows , cols )
449+ except Exception as e : # pylint: disable=broad-exception-caught
450+ logger .debug ("Error handling terminal resize: %s" , e )
451+
452+ original_sigwinch = signal .signal (signal .SIGWINCH , sigwinch_handler )
413453
414454 # Set up heartbeat mechanism
415455 heartbeat_stop_event = threading .Event ()
@@ -524,6 +564,12 @@ def resize_handler(signum, frame):
524564 logger .info ("Pod exec session interrupted by user" )
525565 return True
526566 finally :
567+ # Stop resize monitoring
568+ if resize_stop_event :
569+ resize_stop_event .set ()
570+ if resize_thread and resize_thread .is_alive ():
571+ resize_thread .join (timeout = 2.0 )
572+
527573 # Stop heartbeat
528574 if heartbeat_stop_event :
529575 heartbeat_stop_event .set ()
0 commit comments