Fix serial login detection when IOM is already logged in
Adds _at_shell_prompt() helper that detects a shell prompt by checking whether any line ends with '#' or '# ', rather than using a bare '#' in response check guarded by 'login' not in output. The old guard caused a false negative when the IOM echoed 'Last login: ...' text alongside the prompt, sending an unnecessary login attempt to an active session. Also broadens _ANSI_RE to catch all CSI escape sequences and two-character ESC sequences, not just the original five terminal codes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,8 +26,24 @@ from ui import (
|
|||||||
prompt, prompt_ip, prompt_yn, prompt_password,
|
prompt, prompt_ip, prompt_yn, prompt_password,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Strip ANSI escape sequences from serial terminal output
|
# Strip ANSI escape sequences from serial terminal output.
|
||||||
_ANSI_RE = re.compile(r'\x1b\[[0-9;]*[mGKHF]')
|
# Catches CSI sequences (ESC[...X) and other two-character ESC sequences.
|
||||||
|
_ANSI_RE = re.compile(r'\x1b(?:\[[0-9;]*[A-Za-z]|[^[])')
|
||||||
|
|
||||||
|
|
||||||
|
def _at_shell_prompt(text: str) -> bool:
|
||||||
|
"""
|
||||||
|
Return True if any line in text looks like a root shell prompt.
|
||||||
|
Checks whether a non-empty line ends with '#' or '# ' — the pattern
|
||||||
|
produced by prompts like 'root@hostname:~#' — without being tripped
|
||||||
|
up by the word 'login' appearing elsewhere in the output (e.g. in
|
||||||
|
'Last login: ...' messages shown after a session is resumed).
|
||||||
|
"""
|
||||||
|
for line in text.splitlines():
|
||||||
|
stripped = line.rstrip()
|
||||||
|
if stripped.endswith("#") or stripped.endswith("# "):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
# ── Serial Redfish transport ───────────────────────────────────────────────────
|
# ── Serial Redfish transport ───────────────────────────────────────────────────
|
||||||
@@ -35,7 +51,8 @@ def _login_serial_console(ser: SerialPort, password: str) -> bool:
|
|||||||
"""
|
"""
|
||||||
Perform the root login sequence on the IOM serial console.
|
Perform the root login sequence on the IOM serial console.
|
||||||
Handles both the case where a login prompt is showing and where
|
Handles both the case where a login prompt is showing and where
|
||||||
a shell session is already active.
|
a shell session is already active (i.e. was never logged out after
|
||||||
|
a prior run — the IOM stays logged in until power-cycled).
|
||||||
Returns True if a shell prompt is reached, False on failure.
|
Returns True if a shell prompt is reached, False on failure.
|
||||||
"""
|
"""
|
||||||
info("Logging in to IOM serial console...")
|
info("Logging in to IOM serial console...")
|
||||||
@@ -43,13 +60,16 @@ def _login_serial_console(ser: SerialPort, password: str) -> bool:
|
|||||||
# Send a newline to get the current state of the console
|
# Send a newline to get the current state of the console
|
||||||
ser.send_line("", delay=0.5)
|
ser.send_line("", delay=0.5)
|
||||||
response = _ANSI_RE.sub("", ser.read_until_quiet(quiet_period=0.5))
|
response = _ANSI_RE.sub("", ser.read_until_quiet(quiet_period=0.5))
|
||||||
low = response.lower()
|
|
||||||
|
|
||||||
# Already at a shell prompt — no login needed
|
# Already at a shell prompt — no login needed.
|
||||||
if ("#" in response or "$" in response) and "login" not in low:
|
# Use _at_shell_prompt() rather than a bare '#' check so that
|
||||||
|
# 'Last login: ...' text in the response does not cause a false negative.
|
||||||
|
if _at_shell_prompt(response):
|
||||||
ok("Already at shell prompt.")
|
ok("Already at shell prompt.")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
low = response.lower()
|
||||||
|
|
||||||
# Send username if we see a login prompt (or an empty/unknown response)
|
# Send username if we see a login prompt (or an empty/unknown response)
|
||||||
if "login" in low or not response.strip():
|
if "login" in low or not response.strip():
|
||||||
ser.send_line("root", delay=0.5)
|
ser.send_line("root", delay=0.5)
|
||||||
@@ -60,7 +80,7 @@ def _login_serial_console(ser: SerialPort, password: str) -> bool:
|
|||||||
ser.send_line(password, delay=0.5)
|
ser.send_line(password, delay=0.5)
|
||||||
response = _ANSI_RE.sub("", ser.read_until_quiet(quiet_period=2.0))
|
response = _ANSI_RE.sub("", ser.read_until_quiet(quiet_period=2.0))
|
||||||
|
|
||||||
if "#" in response or "$" in response:
|
if _at_shell_prompt(response):
|
||||||
ok("Logged in to IOM console.")
|
ok("Logged in to IOM console.")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user