Blob Blame History Raw
commit 2014a746753e7f4133e1d13516c4cbadbdd424e8
Author: Tim Waugh <twaugh@redhat.com>
Date:   Fri Jul 14 10:17:43 2017 +0100

    Add minimal support for docker-py-2.x module
    
    Signed-off-by: Tim Waugh <twaugh@redhat.com>

diff --git a/atomic_reactor/core.py b/atomic_reactor/core.py
index ffea392..c3d413d 100644
--- a/atomic_reactor/core.py
+++ b/atomic_reactor/core.py
@@ -31,7 +31,6 @@ import requests
 
 import docker
 from docker.errors import APIError
-from docker.utils import create_host_config
 
 from atomic_reactor.constants import CONTAINER_SHARE_PATH, CONTAINER_SHARE_SOURCE_SUBDIR,\
         BUILD_JSON, DOCKER_SOCKET_PATH
@@ -163,11 +162,9 @@ class BuildContainerFactory(object):
 
         container_id = self.tasker.run(
             ImageName.parse(build_image),
-            create_kwargs={'volumes': [DOCKER_SOCKET_PATH, json_args_path],
-                           'host_config': create_host_config(
-                               binds=volume_bindings,
-                               privileged=True)
-                           }
+            create_kwargs={'volumes': [DOCKER_SOCKET_PATH, json_args_path]},
+            volume_bindings=volume_bindings,
+            privileged=True,
         )
 
         return container_id
@@ -206,11 +203,9 @@ class BuildContainerFactory(object):
 
         container_id = self.tasker.run(
             ImageName.parse(build_image),
-            create_kwargs={'volumes': [json_args_path],
-                           'host_config': create_host_config(
-                               binds=volume_bindings,
-                               privileged=True)
-                           }
+            create_kwargs={'volumes': [json_args_path]},
+            volume_bindings=volume_bindings,
+            privileged=True,
         )
 
         return container_id
@@ -226,7 +221,7 @@ class DockerTasker(LastLogger):
         """
         super(DockerTasker, self).__init__(**kwargs)
 
-        client_kwargs = {}
+        client_kwargs = {'timeout': timeout}
         if base_url:
             client_kwargs['base_url'] = base_url
         elif os.environ.get('DOCKER_CONNECTION'):
@@ -235,7 +230,12 @@ class DockerTasker(LastLogger):
         if hasattr(docker, 'AutoVersionClient'):
             client_kwargs['version'] = 'auto'
 
-        self.d = docker.Client(timeout=timeout, **client_kwargs)
+        try:
+            # docker-py 2.x
+            self.d = docker.APIClient(**client_kwargs)
+        except AttributeError:
+            # docker-py 1.x
+            self.d = docker.Client(**client_kwargs)
 
     def build_image_from_path(self, path, image, stream=False, use_cache=False, remove_im=True):
         """
@@ -301,7 +301,8 @@ class DockerTasker(LastLogger):
         logger.info("build finished")
         return response
 
-    def run(self, image, command=None, create_kwargs=None, start_kwargs=None):
+    def run(self, image, command=None, create_kwargs=None, start_kwargs=None,
+            volume_bindings=None, privileged=None):
         """
         create container from provided image and start it
 
@@ -317,6 +318,17 @@ class DockerTasker(LastLogger):
         """
         logger.info("creating container from image '%s' and running it", image)
         create_kwargs = create_kwargs or {}
+
+        if 'host_config' not in create_kwargs:
+            conf = {}
+            if volume_bindings is not None:
+                conf['binds'] = volume_bindings
+
+            if privileged is not None:
+                conf['privileged'] = privileged
+
+            create_kwargs['host_config'] = self.d.create_host_config(**conf)
+
         start_kwargs = start_kwargs or {}
         logger.debug("image = '%s', command = '%s', create_kwargs = '%s', start_kwargs = '%s'",
                      image, command, create_kwargs, start_kwargs)
diff --git a/tests/README b/tests/README
index f59150b..f9d4a29 100644
--- a/tests/README
+++ b/tests/README
@@ -3,7 +3,7 @@ Requirements: see requirements.txt
 How to run:
 $ py.test -v
 
-By default all docker.Client methods are mocked, so you don't need docker to run these tests.
+By default all docker.APIClient methods are mocked, so you don't need docker to run these tests.
 If you want to run 'integration' tests, i.e. test with running docker instance, you need:
 $ yum install docker docker-registry
 $ systemctl start docker docker-registry
diff --git a/tests/docker_mock.py b/tests/docker_mock.py
index 367924d..0987bda 100644
--- a/tests/docker_mock.py
+++ b/tests/docker_mock.py
@@ -270,7 +270,7 @@ def mock_docker(build_should_fail=False,
                 push_should_fail=False,
                 build_should_fail_generator=False):
     """
-    mock all used docker.Client methods
+    mock all used docker.APIClient methods
 
     :param build_should_fail: True == build() log will contain error
     :param inspect_should_fail: True == inspect_image() will raise docker.errors.NotFound
@@ -291,11 +291,14 @@ def mock_docker(build_should_fail=False,
     else:
         build_result = iter(mock_build_logs)
 
-    flexmock(docker.Client, build=lambda **kwargs: build_result)
-    flexmock(docker.Client, commit=lambda cid, **kwargs: mock_containers[0])
-    flexmock(docker.Client, containers=lambda **kwargs: mock_containers)
-    flexmock(docker.Client, create_container=lambda img, **kwargs: mock_containers[0])
-    flexmock(docker.Client, images=lambda **kwargs: [mock_image])
+    if not hasattr(docker, 'APIClient'):
+        setattr(docker, 'APIClient', docker.Client)
+
+    flexmock(docker.APIClient, build=lambda **kwargs: build_result)
+    flexmock(docker.APIClient, commit=lambda cid, **kwargs: mock_containers[0])
+    flexmock(docker.APIClient, containers=lambda **kwargs: mock_containers)
+    flexmock(docker.APIClient, create_container=lambda img, **kwargs: mock_containers[0])
+    flexmock(docker.APIClient, images=lambda **kwargs: [mock_image])
 
     def mock_inspect_image(image_id):
         if inspect_should_fail:
@@ -303,21 +306,21 @@ def mock_docker(build_should_fail=False,
         else:
             return mock_image
 
-    flexmock(docker.Client, inspect_image=mock_inspect_image)
-    flexmock(docker.Client, inspect_container=lambda im_id: mock_inspect_container)
-    flexmock(docker.Client, logs=lambda cid, **kwargs: iter([mock_logs]) if kwargs.get('stream')
+    flexmock(docker.APIClient, inspect_image=mock_inspect_image)
+    flexmock(docker.APIClient, inspect_container=lambda im_id: mock_inspect_container)
+    flexmock(docker.APIClient, logs=lambda cid, **kwargs: iter([mock_logs]) if kwargs.get('stream')
              else mock_logs)
-    flexmock(docker.Client, pull=lambda img, **kwargs: iter(mock_pull_logs))
-    flexmock(docker.Client, push=lambda iid, **kwargs: iter(push_result))
-    flexmock(docker.Client, remove_container=lambda cid, **kwargs: None)
-    flexmock(docker.Client, remove_image=lambda iid, **kwargs: None)
-    flexmock(docker.Client, start=lambda cid, **kwargs: None)
-    flexmock(docker.Client, tag=lambda img, rep, **kwargs: True)
-    flexmock(docker.Client, wait=lambda cid: 1 if wait_should_fail else 0)
-    flexmock(docker.Client, version=lambda **kwargs: mock_version)
-    flexmock(docker.Client, info=lambda **kwargs: mock_info)
-    flexmock(docker.Client, import_image_from_data=lambda url: mock_import_image)
-    flexmock(docker.Client, import_image_from_stream=lambda url: mock_import_image)
+    flexmock(docker.APIClient, pull=lambda img, **kwargs: iter(mock_pull_logs))
+    flexmock(docker.APIClient, push=lambda iid, **kwargs: iter(push_result))
+    flexmock(docker.APIClient, remove_container=lambda cid, **kwargs: None)
+    flexmock(docker.APIClient, remove_image=lambda iid, **kwargs: None)
+    flexmock(docker.APIClient, start=lambda cid, **kwargs: None)
+    flexmock(docker.APIClient, tag=lambda img, rep, **kwargs: True)
+    flexmock(docker.APIClient, wait=lambda cid: 1 if wait_should_fail else 0)
+    flexmock(docker.APIClient, version=lambda **kwargs: mock_version)
+    flexmock(docker.APIClient, info=lambda **kwargs: mock_info)
+    flexmock(docker.APIClient, import_image_from_data=lambda url: mock_import_image)
+    flexmock(docker.APIClient, import_image_from_stream=lambda url: mock_import_image)
 
     class GetImageResult(object):
         data = b''
@@ -334,7 +337,7 @@ def mock_docker(build_should_fail=False,
         def __exit__(self, tp, val, tb):
             self.fp.close()
 
-    flexmock(docker.Client, get_image=lambda img, **kwargs: GetImageResult())
+    flexmock(docker.APIClient, get_image=lambda img, **kwargs: GetImageResult())
     flexmock(os.path, exists=lambda p: True if p == DOCKER_SOCKET_PATH else old_ope(p))
 
     def remove_volume(volume_name):
@@ -346,24 +349,27 @@ def mock_docker(build_should_fail=False,
             raise docker.errors.APIError("failed to remove volume %s" % volume_name, response)
         return None
 
-    flexmock(docker.Client, remove_volume=lambda iid, **kwargs: remove_volume(iid))
+    flexmock(docker.APIClient, remove_volume=lambda iid, **kwargs: remove_volume(iid))
 
     for method, args in should_raise_error.items():
         response = flexmock(content="abc", status_code=123)
         if args:
-            flexmock(docker.Client).should_receive(method).with_args(*args).and_raise(
-                docker.errors.APIError, "xyz", response)
+            (flexmock(docker.APIClient)
+             .should_receive(method)
+             .with_args(*args).and_raise(docker.errors.APIError, "xyz",
+                                         response))
         else:
-            flexmock(docker.Client).should_receive(method).and_raise(docker.errors.APIError, "xyz",
-                                                                     response)
+            (flexmock(docker.APIClient)
+             .should_receive(method)
+             .and_raise(docker.errors.APIError, "xyz", response))
 
     if remember_images:
         global mock_images
         mock_images = [mock_image]
 
-        flexmock(docker.Client, inspect_image=_mock_inspect)
-        flexmock(docker.Client, pull=_mock_pull)
-        flexmock(docker.Client, remove_image=_mock_remove_image)
-        flexmock(docker.Client, tag=_mock_tag)
+        flexmock(docker.APIClient, inspect_image=_mock_inspect)
+        flexmock(docker.APIClient, pull=_mock_pull)
+        flexmock(docker.APIClient, remove_image=_mock_remove_image)
+        flexmock(docker.APIClient, tag=_mock_tag)
 
-    flexmock(docker.Client, _retrieve_server_version=lambda: '1.20')
+    flexmock(docker.APIClient, _retrieve_server_version=lambda: '1.20')
diff --git a/tests/plugins/test_rpmqa.py b/tests/plugins/test_rpmqa.py
index ba5cbc5..fe7afe8 100644
--- a/tests/plugins/test_rpmqa.py
+++ b/tests/plugins/test_rpmqa.py
@@ -69,7 +69,7 @@ def test_rpmqa_plugin(remove_container_error, ignore_autogenerated):
     setattr(workflow.builder.source, 'dockerfile_path', "/non/existent")
     setattr(workflow.builder.source, 'path', "/non/existent")
 
-    flexmock(docker.Client, logs=mock_logs)
+    flexmock(docker.APIClient, logs=mock_logs)
     runner = PostBuildPluginsRunner(
         tasker,
         workflow,
@@ -95,7 +95,8 @@ def test_rpmqa_plugin_exception(docker_tasker):  # noqa
     setattr(workflow.builder.source, 'dockerfile_path', "/non/existent")
     setattr(workflow.builder.source, 'path', "/non/existent")
 
-    flexmock(docker.Client, logs=mock_logs_raise)
+    mock_docker()
+    flexmock(docker.APIClient, logs=mock_logs_raise)
     runner = PostBuildPluginsRunner(docker_tasker, workflow,
                                     [{"name": PostBuildRPMqaPlugin.key,
                                       "args": {'image_id': TEST_IMAGE}}])
diff --git a/tests/plugins/test_tag_and_push.py b/tests/plugins/test_tag_and_push.py
index 2e5b773..9fce57c 100644
--- a/tests/plugins/test_tag_and_push.py
+++ b/tests/plugins/test_tag_and_push.py
@@ -103,7 +103,7 @@ def test_tag_and_push_plugin(
 
     if MOCK:
         mock_docker()
-        flexmock(docker.Client, push=lambda iid, **kwargs: iter(logs),
+        flexmock(docker.APIClient, push=lambda iid, **kwargs: iter(logs),
                  login=lambda username, registry, dockercfg_path: {'Status': 'Login Succeeded'})
 
     tasker = DockerTasker()
diff --git a/tests/test_tasker.py b/tests/test_tasker.py
index 8978d0c..db0423d 100644
--- a/tests/test_tasker.py
+++ b/tests/test_tasker.py
@@ -327,12 +327,45 @@ def test_get_version():
     (60, 60),
 ])
 def test_timeout(timeout, expected_timeout):
-    (flexmock(docker.Client)
+    if not hasattr(docker, 'APIClient'):
+        setattr(docker, 'APIClient', docker.Client)
+
+    expected_kwargs = {
+        'timeout': expected_timeout,
+    }
+    if hasattr(docker, 'AutoVersionClient'):
+        expected_kwargs['version'] = 'auto'
+
+    (flexmock(docker.APIClient)
         .should_receive('__init__')
-        .with_args(version=str, timeout=expected_timeout))
+        .with_args(**expected_kwargs))
 
     kwargs = {}
     if timeout is not None:
         kwargs['timeout'] = timeout
 
     DockerTasker(**kwargs)
+
+
+def test_docker2():
+    class MockClient(object):
+        def __init__(self, **kwargs):
+            pass
+
+        def version(self):
+            return {}
+
+    for client in ['APIClient', 'Client']:
+        if not hasattr(docker, client):
+            setattr(docker, client, MockClient)
+
+    (flexmock(docker)
+        .should_receive('APIClient')
+        .once()
+        .and_raise(AttributeError))
+
+    (flexmock(docker)
+        .should_receive('Client')
+        .once())
+
+    DockerTasker()
diff --git a/tests/test_util.py b/tests/test_util.py
index c2ec701..3b4c6c8 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -85,7 +85,7 @@ def test_wait_for_command():
     if MOCK:
         mock_docker()
 
-    d = docker.Client()
+    d = docker.APIClient()
     logs_gen = d.pull(INPUT_IMAGE, stream=True)
     assert wait_for_command(logs_gen) is not None