Skip to content

Commit

Permalink
machine: linux: Proper exception when retcode parsing fails
Browse files Browse the repository at this point in the history
A long standing ugly error that tbot throws from time to time is one of
the following nature:

	ValueError: invalid literal for int() with base 10: 'some random fragments of console output'

Of course, this doesn't give any clue into what went wrong.  This error
is a result of unexpected output on the console while tbot is trying to
read the return code integer for the last command that it executed.

We can do better and raise a more descriptive exception for
this case.  This will at least give users some pointer into the
direction of the problem.  The exception now looks like this instead:

	tbot.error.InvalidRetcodeError: received string 'some random fragments of console output' instead of a return code integer

Signed-off-by: Rahix <[email protected]>
  • Loading branch information
Rahix committed Feb 16, 2024
1 parent 910eeb7 commit b10aceb
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 10 deletions.
23 changes: 23 additions & 0 deletions tbot/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,29 @@ class ChannelClosedError(MachineError):
"""


class InvalidRetcodeError(MachineError):
"""
While trying to fetch the return code of a command, unexpected output was received.
This error usually indicates some deeper issue with the machine connection.
For example, there could be kernel log messages being printed in between
command output.
.. versionadded:: UNRELEASED
"""

def __init__(
self,
host: "machine.Machine",
retcode_str: str,
) -> None:
self.host = host
self.retcode_str = retcode_str
super().__init__(
f"received string {retcode_str!r} instead of a return code integer"
)


class ChannelBorrowedError(ApiViolationError):
"""
Error type for exceptions when accessing a channel which is currently borrowed.
Expand Down
8 changes: 3 additions & 5 deletions tbot/machine/linux/ash.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,9 @@ def exec(
out = self.ch.read_until_prompt()
ev.data["stdout"] = out

self.ch.sendline("echo $?", read_back=True)
retcode = self.ch.read_until_prompt()
retcode = util.posix_fetch_return_code(self.ch, self)

return (int(retcode), out)
return (retcode, out)

def exec0(
self: Self, *args: typing.Union[str, special.Special[Self], path.Path[Self]]
Expand Down Expand Up @@ -192,8 +191,7 @@ def __str__(self) -> str:
output = proxy_ch.read_until_prompt()
ev.data["stdout"] = ev.getvalue()

proxy_ch.sendline("echo $?", read_back=True)
retcode = int(proxy_ch.read_until_prompt())
retcode = util.posix_fetch_return_code(proxy_ch, self)

return (retcode, output)

Expand Down
8 changes: 3 additions & 5 deletions tbot/machine/linux/bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,9 @@ def exec(
out = self.ch.read_until_prompt()
ev.data["stdout"] = out

self.ch.sendline("echo $?", read_back=True)
retcode = self.ch.read_until_prompt()
retcode = util.posix_fetch_return_code(self.ch, self)

return (int(retcode), out)
return (retcode, out)

def exec0(
self: Self, *args: typing.Union[str, special.Special[Self], path.Path[Self]]
Expand Down Expand Up @@ -199,8 +198,7 @@ def __str__(self) -> str:
output = proxy_ch.read_until_prompt()
ev.data["stdout"] = ev.getvalue()

proxy_ch.sendline("echo $?", read_back=True)
retcode = int(proxy_ch.read_until_prompt())
retcode = util.posix_fetch_return_code(proxy_ch, self)

return (retcode, output)

Expand Down
9 changes: 9 additions & 0 deletions tbot/machine/linux/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ def wait_for_shell(ch: channel.Channel) -> None:
timeout = 3.0


def posix_fetch_return_code(ch: channel.Channel, mach: M) -> int:
ch.sendline("echo $?", read_back=True)
retcode_str = ch.read_until_prompt()
try:
return int(retcode_str)
except ValueError:
raise tbot.error.InvalidRetcodeError(mach, retcode_str) from None


def posix_environment(
mach: M, var: str, value: "typing.Union[str, linux.Path[M], None]" = None
) -> str:
Expand Down

0 comments on commit b10aceb

Please sign in to comment.