As the title says, how can I get the exit code of a command when using exec_run() with stream=True?
result = container.exec_run(cmd, stream=True, **kwargs)
for line in result.output:
sys.stdout.buffer.write(b' ')
sys.stdout.buffer.write(line)
print(result) # exit_code is None
Thank you
I found a workaround. Maybe this or similar functionality could be added to the ExitResult returned by Container.exec_run()?
# tools.py
import sys
def container_exec(container, cmd, stdout=True, stderr=True, stdin=False,
tty=False, privileged=False, user='', detach=False,
stream=False, socket=False, environment=None, workdir=None):
"""
An enhanced version of #docker.Container.exec_run() which returns an object
that can be properly inspected for the status of the executed commands.
"""
exec_id = container.client.api.exec_create(
container.id, cmd, stdout=stdout, stderr=stderr, stdin=stdin, tty=tty,
privileged=privileged, user=user, environment=environment,
workdir=workdir)['Id']
output = container.client.api.exec_start(
exec_id, detach=detach, tty=tty, stream=stream, socket=socket)
return ContainerExec(container.client, exec_id, output)
class ContainerExec(object):
def __init__(self, client, id, output):
self.client = client
self.id = id
self.output = output
def inspect(self):
return self.client.api.exec_inspect(self.id)
def poll(self):
return self.inspect()['ExitCode']
def communicate(self, line_prefix=b''):
for data in self.output:
if not data: continue
offset = 0
while offset < len(data):
sys.stdout.buffer.write(line_prefix)
nl = data.find(b'\n', offset)
if nl >= 0:
slice = data[offset:nl+1]
offset = nl+1
else:
slice = data[offset:]
offset += len(slice)
sys.stdout.buffer.write(slice)
sys.stdout.flush()
while self.poll() is None:
raise RuntimeError('Hm could that really happen?')
return self.poll()
__Usage example__
result = tools.container_exec(container, cmd, stream=True, **kwargs)
res = result.communicate(line_prefix=b'--> ')
if res != 0:
error('exit code {!r}'.format(res))
Exit code should be in this metadata:
def inspect(self):
return self.client.api.exec_inspect(self.id)
Looks like you have to use the low level API then. No way to get at the id using exec_run.
Most helpful comment
Exit code should be in this metadata: