summaryrefslogtreecommitdiff
path: root/contrib/python/podman/libs/_containers_attach.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/python/podman/libs/_containers_attach.py')
-rw-r--r--contrib/python/podman/libs/_containers_attach.py111
1 files changed, 111 insertions, 0 deletions
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)