fix: keep systemd's OSC 3008 shell context out of command output (#41)
driver / standard (pull_request) Failing after 17s
driver / lint (pull_request) Successful in 28s
driver / types (pull_request) Successful in 51s
driver / test (3.10) (pull_request) Successful in 1m3s
driver / test (3.11) (pull_request) Successful in 1m4s
driver / test (3.12) (pull_request) Successful in 1m58s
driver / test (3.13) (pull_request) Successful in 2m1s
driver / lowest (pull_request) Successful in 1m19s
driver / build (pull_request) Successful in 23s
driver / security (pull_request) Successful in 4m12s
CI / driver (pull_request) Failing after 8m24s
driver / publish (pull_request) Skipped
driver / standard (pull_request) Failing after 17s
driver / lint (pull_request) Successful in 28s
driver / types (pull_request) Successful in 51s
driver / test (3.10) (pull_request) Successful in 1m3s
driver / test (3.11) (pull_request) Successful in 1m4s
driver / test (3.12) (pull_request) Successful in 1m58s
driver / test (3.13) (pull_request) Successful in 2m1s
driver / lowest (pull_request) Successful in 1m19s
driver / build (pull_request) Successful in 23s
driver / security (pull_request) Successful in 4m12s
CI / driver (pull_request) Failing after 8m24s
driver / publish (pull_request) Skipped
systemd 258 (Ubuntu 26.04) ships /etc/profile.d/80-systemd-osc-context.sh: an interactive bash wraps every command in OSC 3008 sequences from PS0 and PROMPT_COMMAND, each with a fresh UUID. They ended up in every value read through netmiko's shell, and because the prompt never looked the same twice, the prompt line stayed in the output too. os_version grew past 255 characters and netOrk could not store the poll. The session now unsets PS0 and PROMPT_COMMAND right after switching the history off and reads its prompt anew; _send() strips terminal codes from what it returns. Version 0.15.1.
This commit is contained in:
1 parent
3aa1955382
commit
4159612a33
5 files changed
+112
-5
No files matched your search
+21
-3
@@ -165,6 +165,12 @@ _PRIVILEGED_STDIN = (
|
||||
#: a shell without ``set -o history`` (dash) only complains, to /dev/null.
|
||||
_HISTORY_OFF = " unset HISTFILE; set +o history 2>/dev/null; true"
|
||||
|
||||
#: Sent right after ``_HISTORY_OFF`` (#41): systemd 258's
|
||||
#: ``/etc/profile.d/80-systemd-osc-context.sh`` wraps every command in OSC 3008
|
||||
#: sequences from ``PS0`` and ``PROMPT_COMMAND``, each with a fresh UUID. It appends
|
||||
#: to ``PROMPT_COMMAND`` as an array, so only ``unset`` removes its hook.
|
||||
_PROMPT_HOOKS_OFF = " unset PS0 PROMPT_COMMAND; true"
|
||||
|
||||
#: First in every script ``_sudo`` runs: a sudo that does not prompt (NOPASSWD,
|
||||
#: a cached timestamp) leaves the password on stdin, and nothing may read it.
|
||||
_NO_STDIN = "exec </dev/null; "
|
||||
@@ -421,6 +427,17 @@ class LinuxDriver(
|
||||
"Could not switch the shell history off on %s", self.hostname, exc_info=True
|
||||
)
|
||||
|
||||
# No systemd OSC 3008 context around every command (#41). netmiko learned
|
||||
# the prompt with those sequences in front, and a prompt carrying a fresh
|
||||
# UUID never matches again, so it reads the prompt anew once they are gone.
|
||||
try:
|
||||
self._device.send_command(_PROMPT_HOOKS_OFF, expect_string=_PROMPT_RE)
|
||||
self._device.set_base_prompt()
|
||||
except Exception:
|
||||
logger.debug(
|
||||
"Could not switch the prompt hooks off on %s", self.hostname, exc_info=True
|
||||
)
|
||||
|
||||
# Prevent PTY from wrapping long output lines (e.g. docker JSON).
|
||||
try:
|
||||
self._device.send_command(
|
||||
@@ -455,15 +472,16 @@ class LinuxDriver(
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _send(self, command: str, read_timeout: float = 100) -> str:
|
||||
"""Send a command and return stripped output."""
|
||||
"""Send a command and return its output without terminal codes, stripped."""
|
||||
if not self._device:
|
||||
raise ConnectionClosedException("Not connected")
|
||||
return self._device.send_command(
|
||||
output = self._device.send_command(
|
||||
command,
|
||||
read_timeout=read_timeout,
|
||||
cmd_verify=False,
|
||||
expect_string=_expect_for(command),
|
||||
).strip()
|
||||
)
|
||||
return strip_terminal_codes(output).strip()
|
||||
|
||||
def _sudo(self, command: str, read_timeout: float = 100) -> str:
|
||||
"""Run *command* as root and return its output, stdout and stderr together.
|
||||
|
||||
Reference in new issue
Block a user