Docker-py: How to get exit code of command from exec_run(stream=True)?

Created on 7 Apr 2018  路  3Comments  路  Source: docker/docker-py

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

kinquestion

Most helpful comment

Exit code should be in this metadata:

  def inspect(self):
    return self.client.api.exec_inspect(self.id)

All 3 comments

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.

Was this page helpful?
0 / 5 - 0 ratings