Mirco Blitz Mirco Blitz - 1 year ago 78
Python Question

docker-py: how can I check if the build was successful?

I'm trying to build myself a neat pipeline in Python 3. My problem, everything seems to be working nice, Jenkins always gives me a green bubble, but sometimes docker build fails to executed.

So

client.build
doesn't raise an error if the build breaks for some reason:

try:
self.client.build(path=self.arguments.projectPath, pull=True, rm=False, tag=self.arguments.dockerImageTag)
except:
print("Error: Docker did not build)
raise


does not raise an error if the build failed.

Can someone please help me finding the right method, how I can be sure my build was done, and if not getting a valid message? I am totally lost.

Best regards
Mirco

Jim Jim
Answer Source

client.build returns the messages outputted by docker when issuing the docker build command. Your initial mistake is in not capturing the response:

response = cl.build(fileobj=f, rm = True, tag='myv/v')

and if successful the contents look as they do if executed through the command line:

list(response)
b'{"stream":" ---\\u003e bb44cb7f2d89\\n"}\r\n',
# snipped for brevity
b'{"stream":"Successfully built 6bc18019ddb6\\n"}\r\n']

On error cases, for example, using a silly dockerfile:

# a dockerfile with a type in 'MAINTAINER'
f = BytesIO('''
# Shared Volume
FROM busybox:buildroot-2014.02
MAINTAIER first last, first.last@yourdomain.com
VOLUME /data
CMD ["/bin/sh"]
'''.encode('utf-8'))

The output contained in response looks like:

[b'{"stream":"Step 1 : FROM busybox:buildroot-2014.02\\n"}\r\n',
 b'{"stream":" ---\\u003e 9875fb006e07\\n"}\r\n',
 b'{"stream":"Step 2 : MAINTAIER \\n"}\r\n',
 b'{"errorDetail":{"message":"Unknown instruction: MAINTAIER"},"error":"Unknown instruction: MAINTAIER"}\r\n']

As you see, a key of errorDetail is contained containing the error message.

So, you can check for that, either with byte string search:

class DockerBuildException(BaseException): pass 


try:
    responce = self.client.build(path=self.arguments.projectPath, pull=True, rm=False, tag=self.arguments.dockerImageTag)
    for i in respone:
        if b'errorDetail' in i:
             raise DockerBuildException("Build Failed")
except DockerBuildException as e:
     print("Error: " + e.args[0])
     raise

Or, even better, by transforming each entry to a dict with ast.literal_eval and also using the message supplied to inform the user:

from ast import literal_eval

try:
    responce = self.client.build(path=self.arguments.projectPath, pull=True, rm=False, tag=self.arguments.dockerImageTag)
    for i in respone:
        if b'errorDetail' in i:
            d = literal_eval(i.decode('ascii')
            raise DockerBuildException(d['errorDetail']['message'])
except DockerBuildException as e:
     print("Error: " + e.args[0])
     raise