From 3bd1f14c4fad60fa52d96c6bbb43f6f1c26f0bf6 Mon Sep 17 00:00:00 2001
From: Joshua Harlow <jxharlow@godaddy.com>
Date: Wed, 15 Jun 2016 12:43:54 -0700
Subject: [PATCH] Be smarter about what to do when making a docker client

Instead of having the program sys.exit when a docker
client object can not be created (which kills all the threads
and messes up the program and its associated state) have a
exception be raised when this (for whatever reason) fails.

Also refactor so that there is a docker task that the docker
client using tasks can all inherit from.

TrivalFix

Change-Id: Ie81aff10cfe6f2fc5c65d53402200e3928fb460c
---
 kolla/image/build.py | 83 ++++++++++++++++++++++++--------------------
 1 file changed, 46 insertions(+), 37 deletions(-)

diff --git a/kolla/image/build.py b/kolla/image/build.py
index 014de4fc1f..626f5163e0 100755
--- a/kolla/image/build.py
+++ b/kolla/image/build.py
@@ -121,14 +121,21 @@ def join_many(threads):
             t.join()
 
 
-def docker_client():
-    try:
-        docker_kwargs = docker.utils.kwargs_from_env()
-        return docker.Client(version='auto', **docker_kwargs)
-    except docker.errors.DockerException:
-        LOG.exception('Can not communicate with docker service.'
-                      'Please check docker service is running without errors')
-        sys.exit(1)
+class DockerTask(task.Task):
+
+    docker_kwargs = docker.utils.kwargs_from_env()
+
+    def __init__(self):
+        super(DockerTask, self).__init__()
+        self._dc = None
+
+    @property
+    def dc(self):
+        if self._dc is not None:
+            return self._dc
+        docker_kwargs = self.docker_kwargs.copy()
+        self._dc = docker.Client(version='auto', **docker_kwargs)
+        return self._dc
 
 
 class Image(object):
@@ -185,12 +192,11 @@ class PushIntoQueueTask(task.Task):
         self.success = True
 
 
-class PushTask(task.Task):
+class PushTask(DockerTask):
     """Task that pushes a image to a docker repository."""
 
     def __init__(self, conf, image):
         super(PushTask, self).__init__()
-        self.dc = docker_client()
         self.conf = conf
         self.image = image
         self.logger = image.logger
@@ -232,14 +238,13 @@ class PushTask(task.Task):
                 self.logger.error(stream['errorDetail']['message'])
 
 
-class BuildTask(task.Task):
+class BuildTask(DockerTask):
     """Task that builds out an image."""
 
     def __init__(self, conf, image, push_queue):
         super(BuildTask, self).__init__()
         self.conf = conf
         self.image = image
-        self.dc = docker_client()
         self.push_queue = push_queue
         self.nocache = not conf.cache or conf.no_cache
         self.forcerm = not conf.keep
@@ -403,31 +408,35 @@ class BuildTask(task.Task):
         pull = True if image.parent is None else False
 
         buildargs = self.update_buildargs()
-        for response in self.dc.build(path=image.path,
-                                      tag=image.canonical_name,
-                                      nocache=not self.conf.cache,
-                                      rm=True,
-                                      pull=pull,
-                                      forcerm=self.forcerm,
-                                      buildargs=buildargs):
-            stream = json.loads(response.decode('utf-8'))
-
-            if 'stream' in stream:
-                for line in stream['stream'].split('\n'):
-                    if line:
-                        self.logger.info('%s', line)
-
-            if 'errorDetail' in stream:
-                image.status = STATUS_ERROR
-                self.logger.error('Error\'d with the following message')
-                for line in stream['errorDetail']['message'].split('\n'):
-                    if line:
-                        self.logger.error('%s', line)
-                return
-
-        image.status = STATUS_BUILT
-
-        self.logger.info('Built')
+        try:
+            for response in self.dc.build(path=image.path,
+                                          tag=image.canonical_name,
+                                          nocache=not self.conf.cache,
+                                          rm=True,
+                                          pull=pull,
+                                          forcerm=self.forcerm,
+                                          buildargs=buildargs):
+                stream = json.loads(response.decode('utf-8'))
+                if 'stream' in stream:
+                    for line in stream['stream'].split('\n'):
+                        if line:
+                            self.logger.info('%s', line)
+                if 'errorDetail' in stream:
+                    image.status = STATUS_ERROR
+                    self.logger.error('Error\'d with the following message')
+                    for line in stream['errorDetail']['message'].split('\n'):
+                        if line:
+                            self.logger.error('%s', line)
+                    return
+        except docker.errors.DockerException:
+            image.status = STATUS_ERROR
+            self.logger.exception('Unknown docker error when building')
+        except Exception:
+            image.status = STATUS_ERROR
+            self.logger.exception('Unknown error when building')
+        else:
+            image.status = STATUS_BUILT
+            self.logger.info('Built')
 
 
 class WorkerThread(threading.Thread):
-- 
GitLab