diff options
Diffstat (limited to 'contrib/python/podman')
-rw-r--r-- | contrib/python/podman/libs/__init__.py | 6 | ||||
-rw-r--r-- | contrib/python/podman/libs/_containers_attach.py | 111 | ||||
-rw-r--r-- | contrib/python/podman/libs/containers.py | 10 |
3 files changed, 117 insertions, 10 deletions
diff --git a/contrib/python/podman/libs/__init__.py b/contrib/python/podman/libs/__init__.py index 9db5dacf5..3a8a35021 100644 --- a/contrib/python/podman/libs/__init__.py +++ b/contrib/python/podman/libs/__init__.py @@ -1,4 +1,5 @@ """Support files for podman API implementation.""" +import collections import datetime import functools @@ -12,12 +13,11 @@ __all__ = [ def cached_property(fn): - """Cache return to save future expense.""" + """Decorate property to cache return value.""" return property(functools.lru_cache(maxsize=8)(fn)) -# Cannot subclass collections.UserDict, breaks varlink -class Config(dict): +class Config(collections.UserDict): """Silently ignore None values, only take key once.""" def __init__(self, **kwargs): diff --git a/contrib/python/podman/libs/_containers_attach.py b/contrib/python/podman/libs/_containers_attach.py new file mode 100644 index 000000000..54e6a009e --- /dev/null +++ b/contrib/python/podman/libs/_containers_attach.py @@ -0,0 +1,111 @@ +"""Exported method Container.attach().""" + +import fcntl +import os +import select +import signal +import socket +import struct +import sys +import termios +import tty + +CONMON_BUFSZ = 8192 + + +class Mixin: + """Publish attach() for inclusion in Container class.""" + + def attach(self, eot=4, stdin=None, stdout=None): + """Attach to container's PID1 stdin and stdout. + + stderr is ignored. + """ + if stdin is None: + stdin = sys.stdin.fileno() + + if stdout is None: + stdout = sys.stdout.fileno() + + with self._client() as podman: + attach = podman.GetAttachSockets(self._id) + + # This is the UDS where all the IO goes + io_socket = attach['sockets']['io_socket'] + assert len(io_socket) <= 107,\ + 'Path length for sockets too long. {} > 107'.format( + len(io_socket) + ) + + # This is the control socket where resizing events are sent to conmon + ctl_socket = attach['sockets']['control_socket'] + + def resize_handler(signum, frame): + """Send the new window size to conmon. + + The method arguments are not used. + """ + packed = fcntl.ioctl(stdout, termios.TIOCGWINSZ, + struct.pack('HHHH', 0, 0, 0, 0)) + rows, cols, _, _ = struct.unpack('HHHH', packed) + + with open(ctl_socket, 'w') as skt: + # send conmon window resize message + skt.write('1 {} {}\n'.format(rows, cols)) + + def log_handler(signum, frame): + """Send command to reopen log to conmon. + + The method arguments are not used. + """ + with open(ctl_socket, 'w') as skt: + # send conmon reopen log message + skt.write('2\n') + + try: + # save off the old settings for terminal + original_attr = termios.tcgetattr(stdout) + tty.setraw(stdin) + + # initialize containers window size + resize_handler(None, sys._getframe(0)) + + # catch any resizing events and send the resize info + # to the control fifo "socket" + signal.signal(signal.SIGWINCH, resize_handler) + except termios.error: + original_attr = None + + try: + # Prepare socket for communicating with conmon/container + with socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) as skt: + skt.connect(io_socket) + skt.sendall(b'\n') + + sources = [skt, stdin] + while sources: + readable, _, _ = select.select(sources, [], []) + for r in readable: + if r is skt: + data = r.recv(CONMON_BUFSZ) + if not data: + sources.remove(skt) + + # Remove source marker when writing + os.write(stdout, data[1:]) + elif r is stdin: + data = os.read(stdin, CONMON_BUFSZ) + if not data: + sources.remove(stdin) + + skt.sendall(data) + + if eot in data: + sources.clear() + break + else: + raise ValueError('Unknown source in select') + finally: + if original_attr: + termios.tcsetattr(stdout, termios.TCSADRAIN, original_attr) + signal.signal(signal.SIGWINCH, signal.SIG_DFL) diff --git a/contrib/python/podman/libs/containers.py b/contrib/python/podman/libs/containers.py index 96ec6be37..a350a128a 100644 --- a/contrib/python/podman/libs/containers.py +++ b/contrib/python/podman/libs/containers.py @@ -6,8 +6,10 @@ import json import signal import time +from ._containers_attach import Mixin as AttachMixin -class Container(collections.UserDict): + +class Container(collections.UserDict, AttachMixin): """Model for a container.""" def __init__(self, client, id, data): @@ -46,12 +48,6 @@ class Container(collections.UserDict): with self._client() as podman: return self._refresh(podman) - def attach(self, detach_key=None, no_stdin=False, sig_proxy=True): - """Attach to running container.""" - with self._client() as podman: - # TODO: streaming and port magic occur, need arguments - podman.AttachToContainer() - def processes(self): """Show processes running in container.""" with self._client() as podman: |