Replace subprocess commands with Docker SDK 70/67170/10
authorStamatis Katsaounis <mokats@intracom-telecom.com>
Mon, 4 Mar 2019 14:12:10 +0000 (16:12 +0200)
committerDan Xu <xudan16@huawei.com>
Mon, 18 Mar 2019 02:29:02 +0000 (02:29 +0000)
JIRA: DOVETAIL-752

This patch replaces all python subprocess commands with the
Docker SDK relevant commands.

Change-Id: Iac7caffd80a863a8a022247d735b2a7f2792e49d
Signed-off-by: Stamatis Katsaounis <mokats@intracom-telecom.com>
dovetail/container.py
dovetail/tests/unit/test_container.py
dovetail/tests/unit/utils/test_dovetail_utils.py
dovetail/utils/dovetail_utils.py
etc/conf/bottlenecks_config.yml
etc/conf/functest-k8s_config.yml
etc/conf/functest_config.yml
etc/conf/onap-vtp_config.yml
etc/conf/onap-vvp_config.yml
etc/conf/yardstick_config.yml
requirements.txt

index 5714503..250bb54 100644 (file)
@@ -9,6 +9,9 @@
 # http://www.apache.org/licenses/LICENSE-2.0
 #
 
+import docker
+import sys
+
 import utils.dovetail_logger as dt_logger
 import utils.dovetail_utils as dt_utils
 from utils.dovetail_config import DovetailConfig as dt_cfg
@@ -19,9 +22,10 @@ class Container(object):
     logger = None
 
     def __init__(self, testcase):
-        self.container_id = None
+        self.container = None
         self.testcase = testcase
         self.valid_type = self.testcase.validate_type()
+        self.client = docker.from_env(timeout=None)
 
     def __str__(self):
         pass
@@ -45,70 +49,69 @@ class Container(object):
 
         name = self._get_config('image_name', project_cfg, testcase_cfg)
         tag = self._get_config('docker_tag', project_cfg, testcase_cfg)
-        return "{}:{}".format(name, tag) if name and tag else None
+        return '{}:{}'.format(name, tag) if name and tag else None
 
     def create(self, docker_image):
         dovetail_config = dt_cfg.dovetail_config
         project_cfg = dovetail_config[self.valid_type]
 
-        opts = dt_utils.get_value_from_dict('opts', project_cfg)
+        kwargs = dt_utils.get_value_from_dict('opts', project_cfg)
         shell = dt_utils.get_value_from_dict('shell', project_cfg)
         if not shell:
             return None
-        envs = dt_utils.get_value_from_dict('envs', project_cfg)
-        volumes_list = dt_utils.get_value_from_dict('volumes', project_cfg)
-        opts = ' ' if not opts else opts
-        envs = ' ' if not envs else envs
-        volumes = ' '.join(volume for volume in volumes_list if volume) \
-            if volumes_list else ' '
-
-        hosts_config = dt_utils.get_hosts_info(self.logger)
-
-        cmd = 'sudo docker run {opts} {envs} {volumes} ' \
-              '{hosts_config} {docker_image} {shell}'.format(**locals())
-        ret, container_id = dt_utils.exec_cmd(cmd, self.logger)
-        if ret != 0:
+        env_list = dt_utils.get_value_from_dict('envs', project_cfg)
+        kwargs['environment'] = [env for env in env_list if env is not None]
+        volume_list = dt_utils.get_value_from_dict('volumes', project_cfg)
+        kwargs['volumes'] = [vol for vol in volume_list if vol is not None]
+        kwargs['extra_hosts'] = dt_utils.get_hosts_info(self.logger)
+
+        try:
+            self.container = self.client.containers.run(
+                docker_image, shell, **kwargs)
+        except (docker.errors.ContainerError, docker.errors.ImageNotFound,
+                docker.errors.APIError):
             return None
 
-        self.container_id = container_id
-        return container_id
+        return self.container.id
 
     def get_image_id(self, image_name):
-        cmd = 'sudo docker images -q %s' % (image_name)
-        ret, image_id = dt_utils.exec_cmd(cmd, self.logger)
-        if ret == 0:
-            return image_id
-        else:
-            return None
+        try:
+            image_id = self.client.images.get(image_name).id
+        except (docker.errors.ImageNotFound, docker.errors.APIError):
+            image_id = None
+        return image_id
 
     # remove the image according to the image_id
     # if there exists containers using this image, then skip
     def remove_image(self, image_id):
-        cmd = "sudo docker ps -aq -f 'ancestor=%s'" % (image_id)
-        ret, msg = dt_utils.exec_cmd(cmd, self.logger)
-        if msg and ret == 0:
+        try:
+            containers = self.client.containers.list(
+                filters={'ancestor': image_id})
+        except docker.errors.APIError:
+            containers = []
+        if containers:
             self.logger.debug('Image {} has containers, skip.'
                               .format(image_id))
             return True
-        cmd = 'sudo docker rmi %s' % (image_id)
         self.logger.debug('Remove image {}.'.format(image_id))
-        ret, msg = dt_utils.exec_cmd(cmd, self.logger)
-        if ret == 0:
+        try:
+            self.client.images.remove(image_id)
             self.logger.debug('Remove image {} successfully.'.format(image_id))
             return True
-        self.logger.error('Failed to remove image {}.'.format(image_id))
-        return False
+        except (docker.errors.ImageNotFound, docker.errors.APIError):
+            self.logger.error('Failed to remove image {}.'.format(image_id))
+            return False
 
     def pull_image_only(self, image_name):
-        cmd = 'sudo docker pull %s' % (image_name)
-        ret, _ = dt_utils.exec_cmd(cmd, self.logger)
-        if ret != 0:
+        try:
+            self.client.images.pull(image_name)
+            self.logger.debug(
+                'Success to pull docker image {}!'.format(image_name))
+            return True
+        except docker.errors.APIError:
             self.logger.error(
                 'Failed to pull docker image {}!'.format(image_name))
             return False
-        self.logger.debug('Success to pull docker image {}!'
-                          .format(image_name))
-        return True
 
     def pull_image(self, docker_image):
         if not docker_image:
@@ -119,7 +122,7 @@ class Container(object):
         new_image_id = self.get_image_id(docker_image)
         if not new_image_id:
             self.logger.error(
-                "Failed to get the id of image {}.".format(docker_image))
+                'Failed to get the id of image {}.'.format(docker_image))
             return None
         if not old_image_id:
             return docker_image
@@ -130,35 +133,50 @@ class Container(object):
             self.remove_image(old_image_id)
         return docker_image
 
-    def check_container_exist(self, container_name):
-        cmd = ('sudo docker ps -aq -f name={}'.format(container_name))
-        ret, msg = dt_utils.exec_cmd(cmd, self.logger)
-        if ret == 0 and msg:
-            return True
-        return False
+    def get_container(self, container_name):
+        try:
+            container = self.client.containers.get(container_name)
+        except (docker.errors.NotFound, docker.errors.APIError):
+            container = None
+        return container
 
     def clean(self):
-        cmd = ('sudo docker rm -f {}'.format(self.container_id))
-        dt_utils.exec_cmd(cmd, self.logger)
+        try:
+            self.container.remove(force=True)
+            self.logger.debug(
+                'container: {} was removed'.format(self.container.name))
+        except docker.errors.APIError as e:
+            self.logger.error(e)
         extra_containers = dt_utils.get_value_from_dict(
             'extra_container', dt_cfg.dovetail_config[self.valid_type])
         if extra_containers:
-            for container in extra_containers:
-                if self.check_container_exist(container):
-                    cmd = ('sudo docker rm -f {}'.format(container))
-                    dt_utils.exec_cmd(cmd, self.logger)
+            for container_name in extra_containers:
+                container = self.get_container(container_name)
+                if container:
+                    try:
+                        container.remove(force=True)
+                        self.logger.debug(
+                            'container: {} was removed'.format(container_name))
+                    except docker.errors.APIError as e:
+                        self.logger.error(e)
 
     def exec_cmd(self, sub_cmd, exit_on_error=False):
-        if sub_cmd == "":
+        if not sub_cmd:
             return (1, 'sub_cmd is empty')
-        dovetail_config = dt_cfg.dovetail_config
-        project_cfg = dovetail_config[self.valid_type]
-        shell = dt_utils.get_value_from_dict('shell', project_cfg)
+        shell = dt_utils.get_value_from_dict(
+            'shell', dt_cfg.dovetail_config[self.valid_type])
         if not shell:
             return (1, 'shell is empty')
-        cmd = 'sudo docker exec {} {} -c "{}"'.format(self.container_id, shell,
-                                                      sub_cmd)
-        return dt_utils.exec_cmd(cmd, self.logger, exit_on_error)
+        cmd = '{} -c "{}"'.format(shell, sub_cmd)
+        try:
+            result = self.container.exec_run(cmd)
+        except docker.errors.APIError as e:
+            result = (e.response.status_code, str(e))
+            self.logger.error(e)
+            if exit_on_error:
+                sys.exit(1)
+
+        return result
 
     def copy_file(self, src_path, dest_path, exit_on_error=False):
         if not src_path or not dest_path:
@@ -166,14 +184,6 @@ class Container(object):
         cmd = 'cp %s %s' % (src_path, dest_path)
         return self.exec_cmd(cmd, exit_on_error)
 
-    def docker_copy(self, src_path, dest_path):
-        if not src_path or not dest_path:
-            return (1, 'src_path or dest_path is empty')
-        cmd = 'docker cp {} {}:{}'.format(src_path,
-                                          self.container_id,
-                                          dest_path)
-        return dt_utils.exec_cmd(cmd, self.logger)
-
     def copy_files_in_container(self):
         project_config = dt_cfg.dovetail_config[self.valid_type]
         if 'copy_file_in_container' not in project_config.keys():
index 6a8b99f..7c758a7 100644 (file)
@@ -10,6 +10,7 @@
 
 import unittest
 from mock import patch, call, Mock
+import docker
 
 from dovetail.container import Container
 
@@ -19,6 +20,7 @@ __author__ = 'Stamatis Katsaounis <mokats@intracom-telecom.com>'
 class ContainerTesting(unittest.TestCase):
 
     def setUp(self):
+        self.patcher1 = patch.object(docker, 'from_env')
         testcase = patch.object(Container, 'testcase')
         testcase.testcase = {'validate': {
             'type': 'bottlenecks'}}
@@ -28,12 +30,13 @@ class ContainerTesting(unittest.TestCase):
         val_type_obj = Mock()
         val_type_obj.return_value = 'bottlenecks'
         testcase.validate_type = val_type_obj
+        self.client = self.patcher1.start().return_value
         self.container = Container(testcase)
         self.logger = Mock()
         self.container.logger = self.logger
 
     def tearDown(self):
-        pass
+        self.patcher1.stop()
 
     @patch('dovetail.container.dt_cfg')
     @patch.object(Container, 'copy_file')
@@ -72,22 +75,6 @@ class ContainerTesting(unittest.TestCase):
 
         mock_copy.assert_not_called()
 
-    def test_docker_copy_error(self):
-        expected = (1, 'src_path or dest_path is empty')
-        result = self.container.docker_copy(None, None)
-
-        self.assertEqual(expected, result)
-
-    @patch('dovetail.container.dt_utils')
-    def test_docker_copy(self, mock_utils):
-        expected = (0, 'success')
-        mock_utils.exec_cmd.return_value = expected
-        result = self.container.docker_copy('source', 'dest')
-
-        mock_utils.exec_cmd.assert_called_once_with(
-            'docker cp source None:dest', self.logger)
-        self.assertEqual(expected, result)
-
     def test_copy_file_error(self):
         expected = (1, 'src_path or dest_path is empty')
         result = self.container.copy_file(None, None)
@@ -114,15 +101,35 @@ class ContainerTesting(unittest.TestCase):
     @patch('dovetail.container.dt_utils')
     def test_exec_cmd(self, mock_utils, mock_config):
         expected = (0, 'success')
-        mock_utils.exec_cmd.return_value = expected
         mock_utils.get_value_from_dict.return_value = 'shell'
         mock_config.dovetail_config = {'bottlenecks': 'value'}
+        container_obj = Mock()
+        container_obj.exec_run.return_value = expected
+        self.container.container = container_obj
+
         result = self.container.exec_cmd('command')
 
-        mock_utils.exec_cmd.assert_called_once_with(
-            'sudo docker exec None shell -c "command"', self.logger, False)
         self.assertEqual(expected, result)
 
+    @patch('dovetail.container.dt_cfg')
+    @patch('dovetail.container.dt_utils')
+    @patch('sys.exit')
+    def test_exec_cmd_exception(self, mock_exit, mock_utils, mock_config):
+        mock_utils.get_value_from_dict.return_value = 'shell'
+        mock_config.dovetail_config = {'bottlenecks': 'value'}
+        container_obj = Mock()
+        response_obj = Mock()
+        response_obj.status_code = 1
+        container_obj.exec_run.side_effect = \
+            docker.errors.APIError('error', response=response_obj)
+        self.container.container = container_obj
+
+        expected = (1, 'error')
+        result = self.container.exec_cmd('command', exit_on_error=True)
+
+        self.assertEqual(expected, result)
+        mock_exit.assert_called_once_with(1)
+
     @patch('dovetail.container.dt_cfg')
     @patch('dovetail.container.dt_utils')
     def test_exec_cmd_no_shell(self, mock_utils, mock_config):
@@ -136,50 +143,65 @@ class ContainerTesting(unittest.TestCase):
 
     @patch('dovetail.container.dt_cfg')
     @patch('dovetail.container.dt_utils')
-    @patch.object(Container, 'check_container_exist')
+    @patch.object(Container, 'get_container')
     def test_clean(self, mock_check, mock_utils, mock_config):
         container_name = 'container'
         mock_config.dovetail_config = {'bottlenecks': 'value'}
         mock_utils.get_value_from_dict.return_value = [container_name]
-        mock_check.return_value = True
+        self.container.container = Mock()
+        mock_check.return_value = Mock()
+
+        self.container.clean()
+
+        mock_utils.get_value_from_dict.assert_called_once_with(
+            'extra_container', 'value')
+        mock_check.assert_called_once_with(container_name)
+
+    @patch('dovetail.container.dt_cfg')
+    @patch('dovetail.container.dt_utils')
+    @patch.object(Container, 'get_container')
+    def test_clean_extra_error(self, mock_check, mock_utils, mock_config):
+        container_name = 'container'
+        mock_config.dovetail_config = {'bottlenecks': 'value'}
+        mock_utils.get_value_from_dict.return_value = [container_name]
+        container_obj = Mock()
+        container_obj.remove.side_effect = docker.errors.APIError('error')
+        self.container.container = Mock()
+        mock_check.return_value = container_obj
 
         self.container.clean()
 
         mock_utils.get_value_from_dict.assert_called_once_with(
             'extra_container', 'value')
         mock_check.assert_called_once_with(container_name)
-        mock_utils.exec_cmd.assert_has_calls([
-            call('sudo docker rm -f None', self.logger),
-            call('sudo docker rm -f container', self.logger)])
 
     @patch('dovetail.container.dt_cfg')
     @patch('dovetail.container.dt_utils')
     def test_clean_no_extra_container(self, mock_utils, mock_config):
         mock_utils.get_value_from_dict.return_value = None
+        container_obj = Mock()
+        container_obj.remove.side_effect = docker.errors.APIError('error')
+        self.container.container = container_obj
         self.container.clean()
         mock_utils.get_value_from_dict.assert_called_once()
 
-    @patch('dovetail.container.dt_utils')
-    def test_check_container_exist_true(self, mock_utils):
+    def test_get_container_exist_true(self):
         container_name = 'container'
-        cmd = ('sudo docker ps -aq -f name={}'.format(container_name))
-        mock_utils.exec_cmd.return_value = (0, 'msg')
+        expected = Mock()
+        self.client.containers.get.return_value = expected
 
-        result = self.container.check_container_exist(container_name)
+        result = self.container.get_container(container_name)
 
-        mock_utils.exec_cmd.assert_called_once_with(cmd, self.logger)
-        self.assertEquals(True, result)
+        self.assertEquals(expected, result)
 
-    @patch('dovetail.container.dt_utils')
-    def test_check_container_exist_false(self, mock_utils):
+    def test_get_container_none(self):
         container_name = 'container'
-        cmd = ('sudo docker ps -aq -f name={}'.format(container_name))
-        mock_utils.exec_cmd.return_value = (1, 'msg')
+        self.client.containers.get.side_effect = \
+            docker.errors.APIError('error')
 
-        result = self.container.check_container_exist(container_name)
+        result = self.container.get_container(container_name)
 
-        mock_utils.exec_cmd.assert_called_once_with(cmd, self.logger)
-        self.assertEquals(False, result)
+        self.assertEquals(None, result)
 
     def test_pull_image_none(self):
         result = self.container.pull_image(None)
@@ -260,98 +282,78 @@ class ContainerTesting(unittest.TestCase):
         mock_remove.assert_called_once_with(old_obj)
         self.assertEquals(docker_image, result)
 
-    @patch('dovetail.container.dt_utils')
-    def test_pull_image_only(self, mock_utils):
+    def test_pull_image_only(self):
         docker_image = 'image'
-        mock_utils.exec_cmd.return_value = (0, 'msg')
 
         result = self.container.pull_image_only(docker_image)
 
-        cmd = 'sudo docker pull %s' % (docker_image)
-        mock_utils.exec_cmd.assert_called_once_with(cmd, self.logger)
         self.logger.debug.assert_called_once_with(
             'Success to pull docker image {}!'.format(docker_image))
         self.assertEquals(True, result)
 
-    @patch('dovetail.container.dt_utils')
-    def test_pull_image_only_error(self, mock_utils):
+    def test_pull_image_only_error(self):
         docker_image = 'image'
-        mock_utils.exec_cmd.return_value = (1, 'error')
+        self.client.images.pull.side_effect = docker.errors.APIError('error')
 
         result = self.container.pull_image_only(docker_image)
 
-        cmd = 'sudo docker pull %s' % (docker_image)
-        mock_utils.exec_cmd.assert_called_once_with(cmd, self.logger)
         self.logger.error.assert_called_once_with(
             'Failed to pull docker image {}!'.format(docker_image))
         self.assertEquals(False, result)
 
-    @patch('dovetail.container.dt_utils')
-    def test_remove_image(self, mock_utils):
+    def test_remove_image(self):
         image_id = 'image_id'
-        mock_utils.exec_cmd.side_effect = [(1, 'error'), (0, 'msg')]
+        self.client.containers.list.side_effect = \
+            docker.errors.APIError('error')
 
         result = self.container.remove_image(image_id)
 
-        mock_utils.exec_cmd.assert_has_calls([
-            call("sudo docker ps -aq -f 'ancestor=%s'" % (image_id),
-                 self.logger),
-            call('sudo docker rmi %s' % (image_id), self.logger)])
         self.logger.debug.assert_has_calls([
             call('Remove image {}.'.format(image_id)),
             call('Remove image {} successfully.'.format(image_id))])
         self.assertEquals(True, result)
 
-    @patch('dovetail.container.dt_utils')
-    def test_remove_image_ancestors(self, mock_utils):
+    def test_remove_image_ancestors(self):
         image_id = 'image_id'
-        mock_utils.exec_cmd.return_value = (0, 'msg')
+        self.client.containers.list.return_value = ['cont_a']
 
         result = self.container.remove_image(image_id)
 
-        cmd = "sudo docker ps -aq -f 'ancestor=%s'" % (image_id)
-        mock_utils.exec_cmd.assert_called_once_with(cmd, self.logger)
         self.logger.debug.assert_called_once_with(
             'Image {} has containers, skip.'.format(image_id))
         self.assertEquals(True, result)
 
-    @patch('dovetail.container.dt_utils')
-    def test_remove_image_error(self, mock_utils):
+    def test_remove_image_error(self):
         image_id = 'image_id'
-        mock_utils.exec_cmd.return_value = (1, 'error')
+        self.client.containers.list.return_value = []
+        self.client.images.remove.side_effect = \
+            docker.errors.ImageNotFound('error')
 
         result = self.container.remove_image(image_id)
 
-        mock_utils.exec_cmd.assert_has_calls([
-            call("sudo docker ps -aq -f 'ancestor=%s'" % (image_id),
-                 self.logger),
-            call('sudo docker rmi %s' % (image_id), self.logger)])
         self.logger.debug.assert_called_once_with(
             'Remove image {}.'.format(image_id))
         self.logger.error.assert_called_once_with(
             'Failed to remove image {}.'.format(image_id))
         self.assertEquals(False, result)
 
-    @patch('dovetail.container.dt_utils')
-    def test_get_image_id(self, mock_utils):
+    def test_get_image_id(self):
         image_name = 'image_id'
-        mock_utils.exec_cmd.return_value = (0, image_name)
+        mock_img = Mock()
+        mock_img.id = image_name
+        self.client.images.get.return_value = mock_img
 
         result = self.container.get_image_id(image_name)
 
-        cmd = 'sudo docker images -q %s' % (image_name)
-        mock_utils.exec_cmd.assert_called_once_with(cmd, self.logger)
         self.assertEquals(image_name, result)
 
-    @patch('dovetail.container.dt_utils')
-    def test_get_image_id_error(self, mock_utils):
+    def test_get_image_id_error(self):
         image_name = 'image_id'
-        mock_utils.exec_cmd.return_value = (1, 'error')
+        self.client.images.get.side_effect = \
+            docker.errors.ImageNotFound('error')
 
         result = self.container.get_image_id(image_name)
 
-        cmd = 'sudo docker images -q %s' % (image_name)
-        mock_utils.exec_cmd.assert_called_once_with(cmd, self.logger)
         self.assertEquals(None, result)
 
     @patch('dovetail.container.dt_utils')
@@ -406,9 +408,11 @@ class ContainerTesting(unittest.TestCase):
         docker_image = 'docker_image'
         container_id = 'container_id'
         mock_utils.get_value_from_dict.side_effect = [
-            'opts', 'shell', 'envs', ['volume_one', 'volume_two']]
+            {'key': 'value'}, 'shell', 'envs', ['volume_one', 'volume_two']]
         mock_utils.get_hosts_info.return_value = 'host_info'
-        mock_utils.exec_cmd.return_value = (0, container_id)
+        container_obj = Mock()
+        container_obj.id = container_id
+        self.client.containers.run.return_value = container_obj
         project_config = {}
         mock_config.dovetail_config = {'bottlenecks': project_config}
 
@@ -421,9 +425,6 @@ class ContainerTesting(unittest.TestCase):
             call('envs', project_config),
             call('volumes', project_config)])
         mock_utils.get_hosts_info.assert_called_once_with(self.logger)
-        mock_utils.exec_cmd.assert_called_once_with(
-            'sudo docker run opts envs volume_one volume_two host_info '
-            'docker_image shell', self.logger)
         self.assertEquals(expected, result)
 
     @patch('dovetail.container.dt_utils')
@@ -446,10 +447,11 @@ class ContainerTesting(unittest.TestCase):
     def test_create_error(self, mock_config, mock_utils):
         docker_image = 'docker_image'
         mock_utils.get_value_from_dict.side_effect = [
-            'opts', 'shell', 'envs', ['volume_one']]
+            {'key': 'value'}, 'shell', ['envs'], ['volume_one']]
         mock_utils.get_hosts_info.return_value = 'host_info'
         mock_utils.check_https_enabled.return_value = True
-        mock_utils.exec_cmd.return_value = (1, 'error')
+        self.client.containers.run.side_effect = \
+            docker.errors.ImageNotFound('error')
         project_config = {}
         mock_config.dovetail_config = {'bottlenecks': project_config}
         result = self.container.create(docker_image)
@@ -460,7 +462,4 @@ class ContainerTesting(unittest.TestCase):
             call('envs', project_config),
             call('volumes', project_config)])
         mock_utils.get_hosts_info.assert_called_once_with(self.logger)
-        mock_utils.exec_cmd.assert_called_once_with(
-            'sudo docker run opts envs volume_one host_info '
-            'docker_image shell', self.logger)
         self.assertEquals(None, result)
index 0f0e14f..33fc1ea 100644 (file)
@@ -227,7 +227,7 @@ class DovetailUtilsTesting(unittest.TestCase):
         mock_path.isfile.return_value = False
         logger = Mock()
 
-        expected = ''
+        expected = {}
         result = dovetail_utils.get_hosts_info(logger)
 
         mock_path.join.assert_called_once_with(file_path, 'hosts.yaml')
@@ -248,7 +248,7 @@ class DovetailUtilsTesting(unittest.TestCase):
         mock_load.return_value = None
         logger = Mock()
 
-        expected = ''
+        expected = {}
         result = dovetail_utils.get_hosts_info(logger)
 
         mock_path.join.assert_called_once_with(file_path, 'hosts.yaml')
@@ -274,7 +274,7 @@ class DovetailUtilsTesting(unittest.TestCase):
         mock_load.return_value = {'a': 'b'}
         logger = Mock()
 
-        expected = ''
+        expected = {}
         result = dovetail_utils.get_hosts_info(logger)
 
         mock_path.join.assert_called_once_with(file_path, 'hosts.yaml')
@@ -299,7 +299,7 @@ class DovetailUtilsTesting(unittest.TestCase):
         mock_open.return_value.__enter__.return_value = file_obj
         mock_load.return_value = {'hosts_info': {'127.0.0.1': []}}
 
-        expected = ''
+        expected = {}
         result = dovetail_utils.get_hosts_info()
 
         mock_path.join.assert_called_once_with(file_path, 'hosts.yaml')
@@ -324,7 +324,7 @@ class DovetailUtilsTesting(unittest.TestCase):
         hosts_info = {'127.0.0.1': [None]}
         mock_load.return_value = {'hosts_info': hosts_info}
 
-        expected = ''
+        expected = {}
         result = dovetail_utils.get_hosts_info()
 
         mock_path.join.assert_called_once_with(file_path, 'hosts.yaml')
@@ -353,7 +353,7 @@ class DovetailUtilsTesting(unittest.TestCase):
         logger = Mock()
 
         names_str = ' '.join(hostnames)
-        expected = ' --add-host=\'{}\':{} '.format(names_str, hosts_ip)
+        expected = {names_str: hosts_ip}
         result = dovetail_utils.get_hosts_info(logger)
 
         mock_path.join.assert_called_once_with(file_path, 'hosts.yaml')
@@ -547,66 +547,45 @@ class DovetailUtilsTesting(unittest.TestCase):
         mock_open.assert_called_once_with(file_path, 'r')
         mock_env.update.assert_called_once_with({env_name: env_value})
 
-    @patch('dovetail.utils.dovetail_utils.exec_cmd')
-    def test_check_docker_version(self, mock_exec):
-        server_version = client_version = '1.12.3'
-        server_ret = client_ret = 0
-        mock_exec.side_effect = [(server_ret, server_version),
-                                 (client_ret, client_version)]
+    @patch('dovetail.utils.dovetail_utils.docker')
+    def test_check_docker_version(self, mock_docker):
+        server_version = '1.12.3'
+        client_obj = Mock()
+        mock_docker.from_env.return_value = client_obj
+        client_obj.version.return_value = {'Version': server_version}
         logger = Mock()
 
         dovetail_utils.check_docker_version(logger)
 
-        mock_exec.assert_has_calls(
-            [call("sudo docker version -f'{{.Server.Version}}'",
-                  logger=logger),
-             call("sudo docker version -f'{{.Client.Version}}'",
-                  logger=logger)])
         logger.debug.assert_has_calls(
-            [call('docker server version: {}'.format(server_version)),
-             call('docker client version: {}'.format(client_version))])
+            [call('Docker server version: {}'.format(server_version))])
 
-    @patch('dovetail.utils.dovetail_utils.exec_cmd')
-    def test_check_docker_version_error(self, mock_exec):
-        server_version = client_version = '1.12.3'
-        server_ret = client_ret = 1
-        mock_exec.side_effect = [(server_ret, server_version),
-                                 (client_ret, client_version)]
+    @patch('dovetail.utils.dovetail_utils.docker')
+    def test_check_docker_version_error(self, mock_docker):
+        client_obj = Mock()
+        mock_docker.from_env.return_value = client_obj
+        client_obj.version.return_value = {}
         logger = Mock()
 
         dovetail_utils.check_docker_version(logger)
 
-        mock_exec.assert_has_calls(
-            [call("sudo docker version -f'{{.Server.Version}}'",
-                  logger=logger),
-             call("sudo docker version -f'{{.Client.Version}}'",
-                  logger=logger)])
         logger.error.assert_has_calls(
             [call("Don't support this Docker server version. "
-                  "Docker server should be updated to at least 1.12.3."),
-             call("Don't support this Docker client version. "
-                  "Docker client should be updated to at least 1.12.3.")])
-
-    @patch('dovetail.utils.dovetail_utils.exec_cmd')
-    def test_check_docker_version_less_than(self, mock_exec):
-        server_version = client_version = '1.12.1'
-        server_ret = client_ret = 0
-        mock_exec.side_effect = [(server_ret, server_version),
-                                 (client_ret, client_version)]
+                  "Docker server should be updated to at least 1.12.3.")])
+
+    @patch('dovetail.utils.dovetail_utils.docker')
+    def test_check_docker_version_less_than(self, mock_docker):
+        server_version = '1.12.1'
+        client_obj = Mock()
+        mock_docker.from_env.return_value = client_obj
+        client_obj.version.return_value = {'Version': server_version}
         logger = Mock()
 
         dovetail_utils.check_docker_version(logger)
 
-        mock_exec.assert_has_calls(
-            [call("sudo docker version -f'{{.Server.Version}}'",
-                  logger=logger),
-             call("sudo docker version -f'{{.Client.Version}}'",
-                  logger=logger)])
         logger.error.assert_has_calls(
             [call("Don't support this Docker server version. "
-                  "Docker server should be updated to at least 1.12.3."),
-             call("Don't support this Docker client version. "
-                  "Docker client should be updated to at least 1.12.3.")])
+                  "Docker server should be updated to at least 1.12.3.")])
 
     @patch('__builtin__.open')
     @patch('os.path')
index 0f26eb2..a3d0782 100644 (file)
@@ -19,6 +19,7 @@ from datetime import datetime
 from distutils.version import LooseVersion
 import yaml
 import python_hosts
+import docker
 
 from dovetail import constants
 from dovetail_config import DovetailConfig as dt_cfg
@@ -157,20 +158,17 @@ def show_progress_bar(length):
 
 
 def check_docker_version(logger=None):
-    server_ret, server_ver = \
-        exec_cmd("sudo docker version -f'{{.Server.Version}}'", logger=logger)
-    client_ret, client_ver = \
-        exec_cmd("sudo docker version -f'{{.Client.Version}}'", logger=logger)
-    if server_ret == 0:
-        logger.debug('docker server version: {}'.format(server_ver))
-    if server_ret != 0 or (LooseVersion(server_ver) < LooseVersion('1.12.3')):
+    client = docker.from_env()
+    server_ver = None
+    try:
+        server_ver = client.version()['Version']
+    except Exception:
+        logger.error('Failed to get Docker server version')
+    if server_ver and (LooseVersion(server_ver) >= LooseVersion('1.12.3')):
+        logger.debug('Docker server version: {}'.format(server_ver))
+    else:
         logger.error("Don't support this Docker server version. "
                      "Docker server should be updated to at least 1.12.3.")
-    if client_ret == 0:
-        logger.debug('docker client version: {}'.format(client_ver))
-    if client_ret != 0 or (LooseVersion(client_ver) < LooseVersion('1.12.3')):
-        logger.error("Don't support this Docker client version. "
-                     "Docker client should be updated to at least 1.12.3.")
 
 
 def add_hosts_info(ip, hostnames):
@@ -316,7 +314,7 @@ def check_cacert_file(cacert, logger=None):
 
 
 def get_hosts_info(logger=None):
-    hosts_config = ''
+    hosts_config = {}
     hosts_config_file = os.path.join(dt_cfg.dovetail_config['config_dir'],
                                      'hosts.yaml')
     if not os.path.isfile(hosts_config_file):
@@ -341,7 +339,7 @@ def get_hosts_info(logger=None):
                                  if hostname)
             if not names_str:
                 continue
-            hosts_config += ' --add-host=\'{}\':{} '.format(names_str, ip)
+            hosts_config[names_str] = ip
             logger.debug('Get hosts info {}:{}.'.format(ip, names_str))
     return hosts_config
 
index 8a0a39b..eb067c4 100644 (file)
@@ -8,7 +8,7 @@
 {% set build_tag = build_tag or '' %}
 {% set cacert_volume = '' %}
 {% if cacert %}
-    {% set cacert_volume = ' -v ' + cacert + ':' + cacert %}
+    {% set cacert_volume = cacert + ':' + cacert %}
 {% endif %}
 {% set openrc_file = '/tmp/admin_rc.sh' %}
 {% set result_dir = '/home/opnfv/bottlenecks/results' %}
 bottlenecks:
   image_name: opnfv/bottlenecks
   docker_tag: latest
-  opts: '-id --privileged=true'
+  opts:
+    detach: true
+    stdin_open: true
+    privileged: true
   shell: '/bin/bash'
-  envs: '-e DEPLOY_SCENARIO={{deploy_scenario}} -e Yardstick_TAG=stable
-         -e OUTPUT_FILE={{testcase}}.out -e CI_DEBUG={{debug}}
-         -e BUILD_TAG={{build_tag}}-{{testcase}}'
+  envs:
+    - 'DEPLOY_SCENARIO={{deploy_scenario}}'
+    - 'Yardstick_TAG=stable'
+    - 'OUTPUT_FILE={{testcase}}.out'
+    - 'CI_DEBUG={{debug}}'
+    - 'BUILD_TAG={{build_tag}}-{{testcase}}'
   volumes:
-    - '-v /var/run/docker.sock:/var/run/docker.sock'
-    - '-v {{dovetail_home}}/results/bottlenecks:/tmp'
-    - '-v {{dovetail_home}}/pre_config/env_config.sh:{{openrc_file}}'
+    - '/var/run/docker.sock:/var/run/docker.sock'
+    - '{{dovetail_home}}/results/bottlenecks:/tmp'
+    - '{{dovetail_home}}/pre_config/env_config.sh:{{openrc_file}}'
     - {{cacert_volume}}
-    - '-v {{dovetail_home}}/images:{{images_dir}}'
-    - '-v {{dovetail_home}}/results:{{result_dir}}'
+    - '{{dovetail_home}}/images:{{images_dir}}'
+    - '{{dovetail_home}}/results:{{result_dir}}'
   pre_condition:
     - 'cp {{images_dir}}/ubuntu-16.04-server-cloudimg-amd64-disk1.img {{image_file}}'
   cmds:
index b5ad12b..e478171 100644 (file)
 functest-k8s:
   image_name: opnfv/functest-kubernetes-healthcheck
   docker_tag: gambia
-  opts: '-id'
+  opts:
+    detach: true
+    stdin_open: true
   shell: '/bin/bash'
-  envs: '-e INSTALLER_TYPE=unknown -e DEPLOY_SCENARIO=k8-deploy -e NODE_NAME=unknown
-         -e TEST_DB_URL=file:///home/opnfv/functest/results/functest_results.txt
-         -e CI_DEBUG={{debug}} -e BUILD_TAG={{build_tag}}-{{testcase}}'
+  envs:
+    - 'INSTALLER_TYPE=unknown'
+    - 'DEPLOY_SCENARIO=k8-deploy'
+    - 'NODE_NAME=unknown'
+    - 'TEST_DB_URL=file:///home/opnfv/functest/results/functest_results.txt'
+    - 'CI_DEBUG={{debug}}'
+    - 'BUILD_TAG={{build_tag}}-{{testcase}}'
   volumes:
-    - '-v {{dovetail_home}}/pre_config/k8.creds:{{openrc_file}}'
-    - '-v {{dovetail_home}}/pre_config/admin.conf:{{kube_file}}'
-    - '-v {{dovetail_home}}/results/:{{result_dir}}'
+    - '{{dovetail_home}}/pre_config/k8.creds:{{openrc_file}}'
+    - '{{dovetail_home}}/pre_config/admin.conf:{{kube_file}}'
+    - '{{dovetail_home}}/results/:{{result_dir}}'
   pre_condition:
     - 'echo test for precondition in functest'
   cmds:
index bf63754..3bf9021 100644 (file)
@@ -6,14 +6,14 @@
 {% set os_insecure = os_insecure or 'False' %}
 {% set os_verify = '' %}
 {% if os_insecure == 'True' %}
-    {% set os_verify = ' -e OS_VERIFY= ' %}
+    {% set os_verify = 'OS_VERIFY=' %}
 {% endif %}
 {% set dovetail_home = dovetail_home or '' %}
 {% set debug = debug or 'false' %}
 {% set build_tag = build_tag or '' %}
 {% set cacert_volume = '' %}
 {% if cacert %}
-    {% set cacert_volume = ' -v ' + cacert + ':' + cacert %}
+    {% set cacert_volume = cacert + ':' + cacert %}
 {% endif %}
 {% set openrc_file = '/home/opnfv/functest/conf/env_file' %}
 {% set result_dir = '/home/opnfv/functest/results' %}
 functest:
   image_name: opnfv/functest-smoke
   docker_tag: gambia
-  opts: '-id --privileged=true'
+  opts:
+    detach: true
+    stdin_open: true
+    privileged: true
   shell: '/bin/bash'
-  envs: '{{os_verify}} -e INSTALLER_TYPE=unknown -e DEPLOY_SCENARIO={{deploy_scenario}} -e NODE_NAME=unknown
-         -e TEST_DB_URL=file://{{result_dir}}/functest_results.txt
-         -e CI_DEBUG={{debug}} -e BUILD_TAG={{build_tag}}-{{testcase}}'
+  envs:
+    - {{os_verify}}
+    - 'INSTALLER_TYPE=unknown'
+    - 'DEPLOY_SCENARIO={{deploy_scenario}}'
+    - 'NODE_NAME=unknown'
+    - 'TEST_DB_URL=file://{{result_dir}}/functest_results.txt'
+    - 'CI_DEBUG={{debug}}'
+    - 'BUILD_TAG={{build_tag}}-{{testcase}}'
   volumes:
-    - '-v {{dovetail_home}}/pre_config/env_config.sh:{{openrc_file}}'
+    - '{{dovetail_home}}/pre_config/env_config.sh:{{openrc_file}}'
     - {{cacert_volume}}
-    - '-v {{dovetail_home}}/pre_config:/home/opnfv/pre_config'
-    - '-v {{dovetail_home}}/userconfig:{{userconfig_dir}}'
-    - '-v {{dovetail_home}}/patches:{{patches_dir}}'
-    - '-v {{dovetail_home}}/results:{{result_dir}}'
-    - '-v {{dovetail_home}}/images:{{images_dir}}'
+    - '{{dovetail_home}}/pre_config:/home/opnfv/pre_config'
+    - '{{dovetail_home}}/userconfig:{{userconfig_dir}}'
+    - '{{dovetail_home}}/patches:{{patches_dir}}'
+    - '{{dovetail_home}}/results:{{result_dir}}'
+    - '{{dovetail_home}}/images:{{images_dir}}'
   patches_dir: {{patches_dir}}
   pre_condition:
     - 'echo test for precondition in functest'
index 72ebeab..eb9b024 100644 (file)
 onap-vtp:
   image_name: nexus3.onap.org:10001/onap/cli
   docker_tag: 2.0.5
-  opts: '-td '
+  opts:
+    detach: true
+    tty: true
   shell: '/bin/bash'
-  envs: '-e OPEN_CLI_MODE=daemon -e BUILD_TAG={{build_tag}}-{{testcase}}
-         -e OPEN_CLI_PRODUCT_IN_USE=onap-vtp'
+  envs:
+    - 'OPEN_CLI_MODE=daemon'
+    - 'BUILD_TAG={{build_tag}}-{{testcase}}'
+    - 'OPEN_CLI_PRODUCT_IN_USE=onap-vtp'
   volumes:
-    - '-v {{dovetail_home}}/pre_config/{{csar_file}}:/{{csar_file}}'
-    - '-v {{dovetail_home}}/results:{{result_dir}}'
+    - '{{dovetail_home}}/pre_config/{{csar_file}}:/{{csar_file}}'
+    - '{{dovetail_home}}/results:{{result_dir}}'
   pre_condition:
     - 'echo this is pre_condition'
   cmds:
index 67d21fa..d812e1f 100644 (file)
@@ -7,11 +7,14 @@
 onap-vvp:
   image_name: nexus3.onap.org:10001/onap/vvp/validation-scripts
   docker_tag: latest
-  opts: '-td --entrypoint=""'
+  opts:
+    detach: true
+    tty: true
+    entrypoint: ''
   shell: '/bin/ash'
   volumes:
-    - '-v {{dovetail_home}}/pre_config/{{heat_templates_archive}}.tar.gz:/tmp/{{heat_templates_archive}}.tar.gz'
-    - '-v {{dovetail_home}}/results:{{result_dir}}'
+    - '{{dovetail_home}}/pre_config/{{heat_templates_archive}}.tar.gz:/tmp/{{heat_templates_archive}}.tar.gz'
+    - '{{dovetail_home}}/results:{{result_dir}}'
   pre_condition:
     - 'tar xf /tmp/{{heat_templates_archive}}.tar.gz -C /vvp'
   cmds:
index e43989e..610cbfd 100644 (file)
@@ -7,14 +7,14 @@
 {% set os_insecure = os_insecure or 'False' %}
 {% set os_verify = '' %}
 {% if os_insecure == 'True' %}
-    {% set os_verify = ' -e OS_VERIFY= ' %}
+    {% set os_verify = 'OS_VERIFY=' %}
 {% endif %}
 {% set dovetail_home = dovetail_home or '' %}
 {% set debug = debug or 'false' %}
 {% set build_tag = build_tag or '' %}
 {% set cacert_volume = '' %}
 {% if cacert %}
-    {% set cacert_volume = ' -v ' + cacert + ':' + cacert %}
+    {% set cacert_volume = cacert + ':' + cacert %}
 {% endif %}
 {% set openrc_file = '/etc/yardstick/openstack.creds' %}
 {% set pod_file = '/etc/yardstick/pod.yaml' %}
 yardstick:
   image_name: opnfv/yardstick
   docker_tag: latest
-  opts: '-id --privileged=true'
+  opts:
+    detach: true
+    stdin_open: true
+    privileged: true
   shell: '/bin/bash'
-  envs: "{{os_verify}} -e YARDSTICK_BRANCH=fraser -e CI_DEBUG={{debug}}
-         -e BUILD_TAG={{build_tag}}-{{testcase}}"
+  envs:
+    - {{os_verify}}
+    - 'YARDSTICK_BRANCH=fraser'
+    - 'CI_DEBUG={{debug}}'
+    - 'BUILD_TAG={{build_tag}}-{{testcase}}"'
   volumes:
-    - '-v {{dovetail_home}}/pre_config/env_config.sh:{{openrc_file}}'
+    - '{{dovetail_home}}/pre_config/env_config.sh:{{openrc_file}}'
     - {{cacert_volume}}
-    - '-v {{dovetail_home}}/pre_config/pod.yaml:{{pod_file}}'
-    - '-v {{dovetail_home}}/images:/home/opnfv/images'
-    - '-v {{dovetail_home}}/results:{{result_dir}}'
+    - '{{dovetail_home}}/pre_config/pod.yaml:{{pod_file}}'
+    - '{{dovetail_home}}/images:/home/opnfv/images'
+    - '{{dovetail_home}}/results:{{result_dir}}'
   pre_condition:
     - 'echo this is pre_condition'
   cmds:
index b79c1b6..7f95c60 100644 (file)
@@ -6,3 +6,4 @@ pbr==3.1.1
 python-hosts==0.4.1
 PyYAML==3.12
 shade==1.27.2
+docker==3.4.1