Skip to content

Commit f2a683f

Browse files
committed
remote/client: Move terminal handling into a separate file
There is quite a lot of code here, so move the terminal function into its own file. This will make it easier to extend it later. Signed-off-by: Simon Glass <sjg@chromium.org>
1 parent 884a31c commit f2a683f

2 files changed

Lines changed: 79 additions & 49 deletions

File tree

labgrid/remote/client.py

Lines changed: 8 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import signal
1515
import sys
1616
import shlex
17-
import shutil
1817
import json
1918
import itertools
2019
import ipaddress
@@ -46,7 +45,7 @@
4645
from ..exceptions import NoDriverFoundError, NoResourceFoundError, InvalidConfigError
4746
from .generated import labgrid_coordinator_pb2, labgrid_coordinator_pb2_grpc
4847
from ..resource.remote import RemotePlaceManager, RemotePlace
49-
from ..util import diff_dict, flat_dict, dump, atomic_replace, labgrid_version, Timeout
48+
from ..util import diff_dict, flat_dict, dump, atomic_replace, labgrid_version, Timeout, term
5049
from ..util.proxy import proxymanager
5150
from ..util.helper import processwrapper
5251
from ..driver import Mode, ExecutionError
@@ -1072,56 +1071,16 @@ async def _console(self, place, target, timeout, *, logfile=None, loop=False, li
10721071

10731072
# check for valid resources
10741073
assert port is not None, "Port is not set"
1075-
1076-
microcom_bin = shutil.which("microcom")
1077-
1078-
if microcom_bin is not None:
1079-
call = [microcom_bin, "-s", str(resource.speed), "-t", f"{host}:{port}"]
1080-
1081-
if listen_only:
1082-
call.append("--listenonly")
1083-
1084-
if logfile:
1085-
call.append(f"--logfile={logfile}")
1086-
else:
1087-
call = ["telnet", host, str(port)]
1088-
1089-
logging.info("microcom not available, using telnet instead")
1090-
1091-
if listen_only:
1092-
logging.warning("--listenonly option not supported by telnet, ignoring")
1093-
1094-
if logfile:
1095-
logging.warning("--logfile option not supported by telnet, ignoring")
1096-
1097-
if logfile:
1098-
call.append(f"--logfile={logfile}")
1099-
logging.info("connecting to %s calling %s", resource, " ".join(call))
11001074
try:
1101-
p = await asyncio.create_subprocess_exec(*call)
1075+
returncode = await term.external(
1076+
lambda: self.is_allowed(place), host, port, resource, logfile, listen_only
1077+
)
11021078
except FileNotFoundError as e:
11031079
raise ServerError(f"failed to execute remote console command: {e}")
1104-
while p.returncode is None:
1105-
try:
1106-
await asyncio.wait_for(p.wait(), 1.0)
1107-
except asyncio.TimeoutError:
1108-
# subprocess is still running
1109-
pass
11101080

1111-
try:
1112-
self._check_allowed(place)
1113-
except UserError:
1114-
p.terminate()
1115-
try:
1116-
await asyncio.wait_for(p.wait(), 1.0)
1117-
except asyncio.TimeoutError:
1118-
# try harder
1119-
p.kill()
1120-
await asyncio.wait_for(p.wait(), 1.0)
1121-
raise
1122-
if p.returncode:
1123-
print("connection lost", file=sys.stderr)
1124-
return p.returncode
1081+
# Raise an exception if the place was released
1082+
self._check_allowed(place)
1083+
return returncode
11251084

11261085
async def console(self, place, target):
11271086
while True:
@@ -1133,7 +1092,7 @@ async def console(self, place, target):
11331092
break
11341093
if not self.args.loop:
11351094
if res:
1136-
raise InteractiveCommandError("microcom error", res)
1095+
raise InteractiveCommandError("console error", res)
11371096
break
11381097
await asyncio.sleep(1.0)
11391098

labgrid/util/term.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""Terminal handling, using microcom or telnet"""
2+
3+
import asyncio
4+
import logging
5+
import sys
6+
import shutil
7+
8+
EXIT_CHAR = 0x1d # FS (Ctrl + ])
9+
10+
async def external(check_allowed, host, port, resource, logfile, listen_only):
11+
"""Start an external terminal sessions
12+
13+
This uses microcom if available, otherwise falls back to telnet.
14+
15+
Args:
16+
check_allowed (lambda): Function to call to make sure the terminal is
17+
still accessible. No args. Returns True if allowed, False if not.
18+
host (str): Host name to connect to
19+
port (int): Port number to connect to
20+
resource (str): Serial resource to connect to (used to get speed / name)
21+
logfile (str): Logfile to write output too, or None. This is ignored if
22+
telnet is used
23+
listen_only (bool): True to ignore keyboard input (ignored with telnet)
24+
25+
Returns:
26+
int: Return code from tool
27+
"""
28+
microcom_bin = shutil.which("microcom")
29+
30+
if microcom_bin is not None:
31+
call = [microcom_bin, "-s", str(resource.speed), "-t", f"{host}:{port}"]
32+
33+
if listen_only:
34+
call.append("--listenonly")
35+
36+
if logfile:
37+
call.append(f"--logfile={logfile}")
38+
else:
39+
call = ["telnet", host, str(port)]
40+
41+
logging.info("microcom not available, using telnet instead")
42+
43+
if listen_only:
44+
logging.warning("--listenonly option not supported by telnet, ignoring")
45+
46+
if logfile:
47+
logging.warning("--logfile option not supported by telnet, ignoring")
48+
49+
if logfile:
50+
call.append(f"--logfile={logfile}")
51+
logging.info("connecting to %s calling %s", resource, " ".join(call))
52+
p = await asyncio.create_subprocess_exec(*call)
53+
while p.returncode is None:
54+
try:
55+
await asyncio.wait_for(p.wait(), 1.0)
56+
except asyncio.TimeoutError:
57+
# subprocess is still running
58+
pass
59+
60+
if check_allowed():
61+
p.terminate()
62+
try:
63+
await asyncio.wait_for(p.wait(), 1.0)
64+
except asyncio.TimeoutError:
65+
# try harder
66+
p.kill()
67+
await asyncio.wait_for(p.wait(), 1.0)
68+
break
69+
if p.returncode:
70+
print("connection lost", file=sys.stderr)
71+
return p.returncode

0 commit comments

Comments
 (0)