@@ -62,27 +62,50 @@ 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 ): # pylint: disable=line-too-long
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/pkg/util/term/resizeevents_windows.go
90+
91+ Args:
92+ exec_stream: The WebSocket stream object
93+ stop_event: Threading event to stop monitoring
94+ """
95+ last_size = _get_terminal_size ()
96+
97+ while not stop_event .is_set () and exec_stream .is_open ():
98+ try :
99+ current_size = _get_terminal_size ()
100+ if current_size != last_size :
101+ _send_terminal_size (exec_stream , current_size [0 ], current_size [1 ])
102+ last_size = current_size
103+ except Exception as e : # pylint: disable=broad-exception-caught
104+ logger .debug ("Error monitoring terminal size: %s" , e )
105+ break
106+
107+ # Sleep to avoid hot looping (same interval as kubectl)
108+ stop_event .wait (0.25 )
86109
87110
88111def _set_terminal_raw_mode ():
@@ -294,6 +317,8 @@ def exec_command_in_pod(pod_name: str, command: List[str], # pylint: disable=to
294317 fl = None
295318 cleanup_done = False
296319 windows_console_state = None
320+ resize_stop_event = None
321+ resize_thread = None
297322
298323 def cleanup ():
299324 """Cleanup function to ensure proper resource cleanup."""
@@ -304,7 +329,7 @@ def cleanup():
304329 return
305330 cleanup_done = True
306331
307- # Restore signal handler
332+ # Restore signal handler (Unix/Linux). Windows does not use signal handlers for resize.
308333 if original_sigwinch and not IS_WINDOWS :
309334 try :
310335 signal .signal (signal .SIGWINCH , original_sigwinch )
@@ -403,13 +428,27 @@ def signal_handler(signum, _frame):
403428 if tty :
404429 terminal_state = _set_terminal_raw_mode ()
405430
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 )
431+ # Set up terminal resize monitoring
432+ # Reference: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/kubectl/pkg/util/term/
433+ if IS_WINDOWS :
434+ # Windows: Poll for size changes in background thread
435+ resize_stop_event = threading .Event ()
436+ resize_thread = threading .Thread (
437+ target = _monitor_resize_events_windows ,
438+ args = (resp , resize_stop_event ),
439+ daemon = True
440+ )
441+ resize_thread .start ()
442+ elif hasattr (signal , 'SIGWINCH' ):
443+ # Unix/Linux: Use SIGWINCH signal handler (must be in main thread)
444+ def sigwinch_handler (_signum , _frame ):
445+ try :
446+ rows , cols = _get_terminal_size ()
447+ _send_terminal_size (resp , rows , cols )
448+ except Exception as e : # pylint: disable=broad-exception-caught
449+ logger .debug ("Error handling terminal resize: %s" , e )
450+
451+ original_sigwinch = signal .signal (signal .SIGWINCH , sigwinch_handler )
413452
414453 # Set up heartbeat mechanism
415454 heartbeat_stop_event = threading .Event ()
@@ -524,6 +563,12 @@ def resize_handler(signum, frame):
524563 logger .info ("Pod exec session interrupted by user" )
525564 return True
526565 finally :
566+ # Stop resize monitoring
567+ if resize_stop_event :
568+ resize_stop_event .set ()
569+ if resize_thread and resize_thread .is_alive ():
570+ resize_thread .join (timeout = 2.0 )
571+
527572 # Stop heartbeat
528573 if heartbeat_stop_event :
529574 heartbeat_stop_event .set ()
0 commit comments