How can I detect when docker-py client.build() fails

docker python sdk
python docker exec_run example
python docker inspect
python docker api example
python check if docker container is running
docker python sdk tutorial
docker-py vs docker
docker-py examples

I'm using docker-py to build and run Docker images.

From reading the documentation it isn't clear to me how I'm supposed to detect if there was an error building the image. build() doesn't raise an exception when there's an error. That makes me think I have to investigate the responses coming back.

What's the best way to determine if docker-py's client.build() fails?

It looks like the 'best' way is to decode the response and look for a key named 'error'.

For example:

for response in client.build(path, tag, decode=True):
    if response.has_key('error'):
        raise Exception("Error building docker image: {}".format(response['error']))

Creating a client; Client reference The easiest way to do that is by calling the function from_env() . Set to auto to automatically detect the server's version. docker-py api client.images.load fails but the cli client works fine #2049

Create a StreamLineBuilder generator:

import json
class StreamLineBuildGenerator(object):
    def __init__(self, json_data):
        self.__dict__ = json.loads(json_data)

And then use this generator in order to parse your stream:

import docker
docker_client = docker.Client(version="1.18", base_url="unix:///var/run/docker.sock")

generator = docker_client.build(nocache=False, rm=True, stream=True, tag="my_image_tag", path="my_path")

for line in generator:
    try:
        stream_line = StreamLineBuildGenerator(line)
        if hasattr(stream_line, "error"):
            print(stream_line.error)
            if hasattr(stream_line, "errorDetail"):
                if not stream_line.error == stream_line.errorDetail["message"]:
                    if hasattr(stream_line.errorDetail, "code"):
                        print("[" + stream_line.errorDetail["code"] + "] ", False)
                    print(stream_line.errorDetail["message"])
    except ValueError:
        # If we are not able to deserialize the received line as JSON object, just print it out
        print(line)
        continue

container = client.containers.run('bfirsh/reticulate-splines', detach=True) You can connect to additional networks using Network.connect() . bridge Create a new network stack for the container on on the bridge network. none No networking for this MaximumRetryCount Number of times to restart the container on failure. Hi! This actually works as intended - we're doing exactly the same thing the CLI does. The untagged image you're seeing is an intermediary image that hasn't been cleaned up because you didn't set rm=True when calling Client.build, which is False by default for backwards compatibility reasons.

In the spirit of sharing, I want to show an implementation that is a progression of Fabien's answer (which was extremely useful). This does printing, cleanup, et cetera, and throws an informed exception when things are bad:

import json
import logging
import re

import docker

log = logging.getLogger(__name__)


class StreamLineBuildGenerator(object):
    def __init__(self, json_data):
        self.__dict__ = json.loads(json_data)


class Docker(object):
    REGISTRY = "some_docker_registry"

    def __init__(self):
        self.client = docker.from_env()
        self.api_client = docker.APIClient()

    def build(self, path, repository):
        tag = "{}/{}".format(Docker.REGISTRY, repository)
        output = self.api_client.build(path=path, tag=tag)
        self._process_output(output)
        log.info("done building {}".format(repository))

    def push(self, repository):
        tag = "{}/{}".format(Docker.REGISTRY, repository)
        output = self.client.images.push(tag)
        self._process_output(output)
        log.info("done pushing {}".format(tag))

    def _process_output(self, output):
        if type(output) == str:
            output = output.split("\n")

        for line in output:
            if line:
                errors = set()
                try:
                    stream_line = StreamLineBuildGenerator(line)

                    if hasattr(stream_line, "status"):
                        log.info(stream_line.status)

                    elif hasattr(stream_line, "stream"):
                        stream = re.sub("^\n", "", stream_line.stream)
                        stream = re.sub("\n$", "", stream)
                        # found after newline to close (red) "error" blocks: 27 91 48 109
                        stream = re.sub("\n(\x1B\[0m)$", "\\1", stream)
                        if stream:
                            log.info(stream)

                    elif hasattr(stream_line, "aux"):
                        if hasattr(stream_line.aux, "Digest"):
                            log.info("digest: {}".format(stream_line.aux["Digest"]))

                        if hasattr(stream_line.aux, "ID"):
                            log.info("ID: {}".format(stream_line.aux["ID"]))

                    else:
                        log.info("not recognized (1): {}".format(line))

                    if hasattr(stream_line, "error"):
                        errors.add(stream_line.error)

                    if hasattr(stream_line, "errorDetail"):
                        errors.add(stream_line.errorDetail["message"])

                        if hasattr(stream_line.errorDetail, "code"):
                            error_code = stream_line.errorDetail["code"]
                            errors.add("Error code: {}".format(error_code))

                except ValueError as e:
                    log.error("not recognized (2): {}".format(line))

                if errors:
                    message = "problem executing Docker: {}".format(". ".join(errors))
                    raise SystemError(message)

I've realized that it's not easy to detect when build fails. Should I really I'll keep this open and see if anyone else using docker-py to build regularly has a better answer. in docker.Client.build when something goes wrong. Building via docker-compose fails #3805. Open tobiashinz opened this issue Aug 6, 2019 · 13 comments Open build 4667896b docker-py version: 3.7.3 CPython version

Hi, I create an ubuntu container and then running exec_run later. import docker >>> client = docker.from_env() >>> container = client.containers.run('ubuntu', error: exec failed: exec: "not_exist": executable file not found in $PATH\r\n' >>> There's no way for the client to detect reliably when the exec  Description of the issue When running docker-compose pull on a docker-docker compose file that has both a build directive and an image specified, docker-compose pull will fail if the directory specified in the build directive does not ex

To talk to a Docker daemon, you first need to instantiate a client. You can use from_env() to connect using the Set to auto to automatically detect the bridge Create a new network stack for the container on on the bridge network. ignore_removed (bool) – Ignore failures due to missing containers when  docker-py open issues Ask a question (View All Issues) over 3 years pull call doesn't raise an exception when image is not found. over 3 years _stream_helper within Client.py occasionally fails to parse chunked data

Build, load or pull an image, making the image available for creating containers. Otherwise, it is recommended to install the docker Python module. specified in the docker client configuration (by default $HOME/.docker/config.json ), the From Ansible 2.12 on, auto-detection will be disabled and this option will be made  A Python library for the Docker Engine API. Contribute to docker/docker-py development by creating an account on GitHub.