From ce896972a0b263e1d83b61f071e5ccbb945c8696 Mon Sep 17 00:00:00 2001
From: xudan <xudan16@huawei.com>
Date: Mon, 27 Mar 2017 03:32:50 +0000
Subject: dovetail tool: change function pull_image

JIRA: DOVETAIL-378

1. test_runner checks the result of cmd "pull image". If fail to pull,
   then break the running.
2. pull_image will return None when there are errors, otherwise return image name.
3. if there is an old image named the same as the new one, the old one's tag
   will be changed into <none>. In this case, the old image needs to be removed.
4. if there are some containers using this old image, the remove will be skipped
   rather than logging error.

Change-Id: I940cb18911112d5e13f3c14f87ddbdbaced3538a
Signed-off-by: xudan <xudan16@huawei.com>
---
 dovetail/container.py   | 45 +++++++++++++++++++++++++++------------------
 dovetail/test_runner.py |  7 ++++---
 2 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/dovetail/container.py b/dovetail/container.py
index 878b21cb..71fa346f 100644
--- a/dovetail/container.py
+++ b/dovetail/container.py
@@ -35,10 +35,14 @@ class Container(object):
     def get(cls, type):
         return cls.container_list[type]
 
-    @staticmethod
-    def get_docker_image(type):
-        return '%s:%s' % (dt_cfg.dovetail_config[type]['image_name'],
-                          dt_cfg.dovetail_config[type]['docker_tag'])
+    @classmethod
+    def get_docker_image(cls, type):
+        try:
+            return '%s:%s' % (dt_cfg.dovetail_config[type]['image_name'],
+                              dt_cfg.dovetail_config[type]['docker_tag'])
+        except KeyError as e:
+            cls.logger.error('There is no %s in %s config file.', e, type)
+            return None
 
     # get the openrc_volume for creating the container
     @classmethod
@@ -136,16 +140,24 @@ class Container(object):
         if ret == 0:
             return image_id
         else:
-            return False
+            return None
 
+    # remove the image according to the image_id
+    # if there exists containers using this image, then skip
     @classmethod
     def remove_image(cls, image_id):
+        cmd = "sudo docker ps -aq -f 'ancestor=%s'" % (image_id)
+        ret, msg = dt_utils.exec_cmd(cmd, cls.logger)
+        if msg and ret == 0:
+            cls.logger.debug('image %s has containers, skip.', image_id)
+            return True
         cmd = 'sudo docker rmi %s' % (image_id)
+        cls.logger.debug('remove image %s', image_id)
         ret, msg = dt_utils.exec_cmd(cmd, cls.logger)
         if ret == 0:
             cls.logger.debug('remove image %s successfully', image_id)
             return True
-        cls.logger.error('image %s has containers, fail to remove.', image_id)
+        cls.logger.error('fail to remove image %s.', image_id)
         return False
 
     @classmethod
@@ -158,33 +170,30 @@ class Container(object):
         cls.logger.debug('success to pull docker image %s!', image_name)
         return True
 
-    # returncode 0: succeed to pull new image and remove the old one
-    # returncode 1: fail to pull the image
-    # returncode 2: succeed to pull but fail to get the new image id
-    # returncode 3: fail to remove the old image
     @classmethod
     def pull_image(cls, validate_type):
         docker_image = cls.get_docker_image(validate_type)
+        if not docker_image:
+            return None
         if cls.has_pull_latest_image[validate_type] is True:
             cls.logger.debug('%s is already the newest version.', docker_image)
-            return 0
+            return docker_image
         old_image_id = cls.get_image_id(docker_image)
         if not cls.pull_image_only(docker_image):
-            return 1
+            return None
         cls.has_pull_latest_image[validate_type] = True
         new_image_id = cls.get_image_id(docker_image)
         if not new_image_id:
             cls.logger.error("fail to get the new image's id %s", docker_image)
-            return 2
+            return None
+        if not old_image_id:
+            return docker_image
         if new_image_id == old_image_id:
             cls.logger.debug('image %s has no changes, no need to remove.',
                              docker_image)
         else:
-            if old_image_id:
-                cls.logger.debug('remove the old image %s', old_image_id)
-                if not cls.remove_image(old_image_id):
-                    return 3
-        return 0
+            cls.remove_image(old_image_id)
+        return docker_image
 
     @classmethod
     def check_image_exist(cls, validate_type):
diff --git a/dovetail/test_runner.py b/dovetail/test_runner.py
index ea58768c..1ac9f196 100644
--- a/dovetail/test_runner.py
+++ b/dovetail/test_runner.py
@@ -35,10 +35,11 @@ class DockerRunner(object):
                 self.logger.error('%s image not exist offline running',
                                   self.testcase.validate_type())
                 return
-            container_id = Container.create(self.testcase.validate_type())
         else:
-            Container.pull_image(self.testcase.validate_type())
-            container_id = Container.create(self.testcase.validate_type())
+            if not Container.pull_image(self.testcase.validate_type()):
+                self.logger.error("Failed to pull the image.")
+                return
+        container_id = Container.create(self.testcase.validate_type())
         if not container_id:
             self.logger.error('failed to create container')
             return
-- 
cgit