Skip to content

Commit 8469721

Browse files
committed
add resize for windows
1 parent b23fda3 commit 8469721

File tree

1 file changed

+61
-16
lines changed

1 file changed

+61
-16
lines changed

src/aks-agent/azext_aks_agent/agent/k8s/pod_exec.py

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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: 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

88111
def _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

Comments
 (0)