|
14 | 14 |
|
15 | 15 | import base64
|
16 | 16 | import contextlib
|
| 17 | +import errno |
17 | 18 | import json
|
18 | 19 | import io
|
19 | 20 | import os
|
20 | 21 | import random
|
21 | 22 | import shutil
|
22 | 23 | import signal
|
23 | 24 | import socket
|
| 25 | +import struct |
24 | 26 | import tarfile
|
25 | 27 | import tempfile
|
26 | 28 | import threading
|
@@ -76,7 +78,17 @@ def setup_module():
|
76 | 78 | try:
|
77 | 79 | c.inspect_image(BUSYBOX)
|
78 | 80 | except NotFound:
|
79 |
| - c.pull(BUSYBOX) |
| 81 | + os.write(2, "\npulling busybox\n".encode('utf-8')) |
| 82 | + for data in c.pull('busybox', stream=True): |
| 83 | + data = json.loads(data.decode('utf-8')) |
| 84 | + os.write(2, ("%c[2K\r" % 27).encode('utf-8')) |
| 85 | + status = data.get("status") |
| 86 | + progress = data.get("progress") |
| 87 | + detail = "{0} - {1}".format(status, progress).encode('utf-8') |
| 88 | + os.write(2, detail) |
| 89 | + os.write(2, "\npulled busybox\n".encode('utf-8')) |
| 90 | + |
| 91 | + # Double make sure we now have busybox |
80 | 92 | c.inspect_image(BUSYBOX)
|
81 | 93 | c.close()
|
82 | 94 |
|
@@ -887,7 +899,6 @@ def runTest(self):
|
887 | 899 |
|
888 | 900 | self.client.start(container)
|
889 | 901 | res = self.client.top(container['Id'])
|
890 |
| - print(res) |
891 | 902 | self.assertEqual(
|
892 | 903 | res['Titles'],
|
893 | 904 | ['UID', 'PID', 'PPID', 'C', 'STIME', 'TTY', 'TIME', 'CMD']
|
@@ -1213,6 +1224,64 @@ def runTest(self):
|
1213 | 1224 | self.assertTrue(sock.fileno() > -1)
|
1214 | 1225 |
|
1215 | 1226 |
|
| 1227 | +class TestRunContainerReadingSocket(BaseTestCase): |
| 1228 | + def runTest(self): |
| 1229 | + line = 'hi there and stuff and things, words!' |
| 1230 | + command = "echo '{0}'".format(line) |
| 1231 | + container = self.client.create_container(BUSYBOX, command, |
| 1232 | + detach=True, tty=False) |
| 1233 | + ident = container['Id'] |
| 1234 | + self.tmp_containers.append(ident) |
| 1235 | + |
| 1236 | + opts = {"stdout": 1, "stream": 1, "logs": 1} |
| 1237 | + pty_stdout = self.client.attach_socket(ident, opts) |
| 1238 | + self.client.start(ident) |
| 1239 | + |
| 1240 | + recoverable_errors = (errno.EINTR, errno.EDEADLK, errno.EWOULDBLOCK) |
| 1241 | + |
| 1242 | + def read(n=4096): |
| 1243 | + """Code stolen from dockerpty to read the socket""" |
| 1244 | + try: |
| 1245 | + if hasattr(pty_stdout, 'recv'): |
| 1246 | + return pty_stdout.recv(n) |
| 1247 | + return os.read(pty_stdout.fileno(), n) |
| 1248 | + except EnvironmentError as e: |
| 1249 | + if e.errno not in recoverable_errors: |
| 1250 | + raise |
| 1251 | + |
| 1252 | + def next_packet_size(): |
| 1253 | + """Code stolen from dockerpty to get the next packet size""" |
| 1254 | + data = six.binary_type() |
| 1255 | + while len(data) < 8: |
| 1256 | + next_data = read(8 - len(data)) |
| 1257 | + if not next_data: |
| 1258 | + return 0 |
| 1259 | + data = data + next_data |
| 1260 | + |
| 1261 | + if data is None: |
| 1262 | + return 0 |
| 1263 | + |
| 1264 | + if len(data) == 8: |
| 1265 | + _, actual = struct.unpack('>BxxxL', data) |
| 1266 | + return actual |
| 1267 | + |
| 1268 | + next_size = next_packet_size() |
| 1269 | + self.assertEqual(next_size, len(line)+1) |
| 1270 | + |
| 1271 | + data = six.binary_type() |
| 1272 | + while len(data) < next_size: |
| 1273 | + next_data = read(next_size - len(data)) |
| 1274 | + if not next_data: |
| 1275 | + assert False, "Failed trying to read in the dataz" |
| 1276 | + data += next_data |
| 1277 | + self.assertEqual(data.decode('utf-8'), "{0}\n".format(line)) |
| 1278 | + pty_stdout.close() |
| 1279 | + |
| 1280 | + # Prevent segfault at the end of the test run |
| 1281 | + if hasattr(pty_stdout, "_response"): |
| 1282 | + del pty_stdout._response |
| 1283 | + |
| 1284 | + |
1216 | 1285 | class TestPauseUnpauseContainer(BaseTestCase):
|
1217 | 1286 | def runTest(self):
|
1218 | 1287 | container = self.client.create_container(BUSYBOX, ['sleep', '9999'])
|
|
0 commit comments