Skip to content

Commit df61ee1

Browse files
committed
dockerpty output
1 parent 2ee0abe commit df61ee1

File tree

4 files changed

+533
-90
lines changed

4 files changed

+533
-90
lines changed

images/utils/launcher/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ def start(self):
211211
break
212212
try:
213213
self.handle_command(cmd)
214+
except KeyboardInterrupt:
215+
pass
214216
except ServiceNotFound as e:
215217
print("Service not found: %s" % e)
216218
except ContainerNotFound as e:

images/utils/launcher/node/base.py

Lines changed: 24 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@
33
import itertools
44
import logging
55
import os
6-
import sys
76
from typing import List, Dict, Any, Optional
87
import docker
98
from docker import DockerClient
109
from docker.errors import NotFound
1110
from docker.models.containers import Container
1211
from typing import TYPE_CHECKING
13-
import dockerpty
1412

1513
from launcher.config import PortPublish
1614
from .image import Image
15+
from .pty import exec_command
1716

1817
if TYPE_CHECKING:
1918
from launcher.config import Config
@@ -45,28 +44,16 @@ def __init__(self, name: str, image: Image, hostname: str, environment: List[str
4544
self.volumes = volumes
4645
self.ports = ports
4746

48-
def __repr__(self):
49-
return f"<ContainerSpec {self.name=} {self.image=} {self.hostname=} {self.environment=} {self.command=} {self.volumes=} {self.ports=}>"
5047

48+
class OutputStream:
49+
def __init__(self, fd):
50+
self.fd = fd
5151

52-
class CompareEntity:
53-
def __init__(self, obj: Any, diff: Any = None):
54-
self.obj = obj
55-
self.diff = diff
56-
57-
def __repr__(self):
58-
return f"<CompareEntity obj={self.obj} diff={self.diff}>"
59-
60-
61-
class CompareResult:
62-
def __init__(self, same: bool, message: str, old: CompareEntity, new: CompareEntity):
63-
self.same = same
64-
self.message = message
65-
self.old = old
66-
self.new = new
52+
def isatty(self) -> bool:
53+
return True
6754

68-
def __repr__(self):
69-
return f"<CompareDetails same={self.same} message={self.message} old={self.old} new={self.new}>"
55+
def fileno(self) -> int:
56+
return self.fd
7057

7158

7259
def diff_details(s1, s2):
@@ -267,65 +254,28 @@ def status(self) -> str:
267254
def exec(self, command: str) -> Any:
268255
return self.container.exec_run(command)
269256

270-
def exec2(self, command: str) -> None:
271-
try:
272-
dockerpty.exec_command(self.client.api, self.container_name, command)
273-
except docker.errors.NotFound:
274-
raise ContainerNotFound(self.name)
275-
276-
def cli(self, command: str) -> None:
277-
cli_cmd = self._cli + " " + command
278-
logger.info("[CLI] %s", cli_cmd)
279-
self.exec2(cli_cmd)
280-
281-
def cli2(self, cmd, shell):
257+
def cli(self, command: str, exception=False) -> None:
282258
if self.mode != "native":
283259
return
284-
full_cmd = "%s %s" % (self._cli, cmd)
285-
self._logger.debug("[Execute] %s", full_cmd)
286-
_, socket = self._container.exec_run(full_cmd, stdin=True, tty=True, socket=True)
287260

288-
shell.redirect_stdin(socket._sock)
289261
try:
290-
output = ""
291-
pre_data = None
292-
while True:
293-
data = socket.read(1024)
294-
295-
if pre_data is not None:
296-
data = pre_data + data
297-
298-
if len(data) == 0:
299-
break
300-
301-
try:
302-
text = data.decode()
303-
pre_data = None
304-
except:
305-
pre_data = data
306-
continue
307-
308-
text = self.cli_filter(cmd, text)
309-
output += text
310-
311-
# Write text in chunks in case trigger BlockingIOError: could not complete without blocking
312-
# because text is too large to fit the output buffer
313-
# https://stackoverflow.com/questions/54185874/logging-chokes-on-blockingioerror-write-could-not-complete-without-blocking
314-
i = 0
315-
while i < len(text):
316-
os.write(sys.stdout.fileno(), text[i: i + 1024].encode())
317-
i = i + 1024
318-
sys.stdout.flush()
319-
finally:
320-
shell.stop_redirect_stdin()
321-
322-
# TODO get exit code here
323-
exception = self.extract_exception(cmd, output)
324-
if exception:
325-
raise exception
262+
full_cmd = "%s %s" % (self._cli, command)
263+
# FIXME use blocking docker client here
264+
output = exec_command(self.client.api, self.container_name, full_cmd)
265+
logger.debug("[Execute] %s (interactive)\n%s", full_cmd, output)
266+
try:
267+
self.extract_exception(command, output)
268+
except KeyboardInterrupt:
269+
raise
270+
except:
271+
if exception:
272+
raise
273+
except docker.errors.NotFound:
274+
# FIXME use self.container
275+
raise ContainerNotFound(self.name)
326276

327277
def extract_exception(self, cmd, text):
328-
return None
278+
pass
329279

330280
def cli_filter(self, cmd, text):
331281
return text

0 commit comments

Comments
 (0)