简体   繁体   中英

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

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']))

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

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM