From 40089a781c3e12e628fe1cb8c6d60efa86402cf9 Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Mon, 9 Jan 2017 15:13:09 -0800 Subject: [PATCH] Detect mount type in parse_mount_string Signed-off-by: Joffrey F --- docker/types/services.py | 12 ++++++++- tests/unit/dockertypes_test.py | 49 +++++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/docker/types/services.py b/docker/types/services.py index b52afd27..93503dc0 100644 --- a/docker/types/services.py +++ b/docker/types/services.py @@ -1,6 +1,7 @@ import six from .. import errors +from ..constants import IS_WINDOWS_PLATFORM from ..utils import format_environment, split_command @@ -175,8 +176,17 @@ class Mount(dict): else: target = parts[1] source = parts[0] + mount_type = 'volume' + if source.startswith('/') or ( + IS_WINDOWS_PLATFORM and source[0].isalpha() and + source[1] == ':' + ): + # FIXME: That windows condition will fail earlier since we + # split on ':'. We should look into doing a smarter split + # if we detect we are on Windows. + mount_type = 'bind' read_only = not (len(parts) == 2 or parts[2] == 'rw') - return cls(target, source, read_only=read_only) + return cls(target, source, read_only=read_only, type=mount_type) class Resources(dict): diff --git a/tests/unit/dockertypes_test.py b/tests/unit/dockertypes_test.py index 5cf5f4e7..d11e4f03 100644 --- a/tests/unit/dockertypes_test.py +++ b/tests/unit/dockertypes_test.py @@ -10,6 +10,11 @@ from docker.types import ( EndpointConfig, HostConfig, IPAMConfig, IPAMPool, LogConfig, Mount, Ulimit, ) +try: + from unittest import mock +except: + import mock + def create_host_config(*args, **kwargs): return HostConfig(*args, **kwargs) @@ -258,28 +263,48 @@ class IPAMConfigTest(unittest.TestCase): class TestMounts(unittest.TestCase): def test_parse_mount_string_ro(self): mount = Mount.parse_mount_string("/foo/bar:/baz:ro") - self.assertEqual(mount['Source'], "/foo/bar") - self.assertEqual(mount['Target'], "/baz") - self.assertEqual(mount['ReadOnly'], True) + assert mount['Source'] == "/foo/bar" + assert mount['Target'] == "/baz" + assert mount['ReadOnly'] is True def test_parse_mount_string_rw(self): mount = Mount.parse_mount_string("/foo/bar:/baz:rw") - self.assertEqual(mount['Source'], "/foo/bar") - self.assertEqual(mount['Target'], "/baz") - self.assertEqual(mount['ReadOnly'], False) + assert mount['Source'] == "/foo/bar" + assert mount['Target'] == "/baz" + assert not mount['ReadOnly'] def test_parse_mount_string_short_form(self): mount = Mount.parse_mount_string("/foo/bar:/baz") - self.assertEqual(mount['Source'], "/foo/bar") - self.assertEqual(mount['Target'], "/baz") - self.assertEqual(mount['ReadOnly'], False) + assert mount['Source'] == "/foo/bar" + assert mount['Target'] == "/baz" + assert not mount['ReadOnly'] def test_parse_mount_string_no_source(self): mount = Mount.parse_mount_string("foo/bar") - self.assertEqual(mount['Source'], None) - self.assertEqual(mount['Target'], "foo/bar") - self.assertEqual(mount['ReadOnly'], False) + assert mount['Source'] is None + assert mount['Target'] == "foo/bar" + assert not mount['ReadOnly'] def test_parse_mount_string_invalid(self): with pytest.raises(InvalidArgument): Mount.parse_mount_string("foo:bar:baz:rw") + + def test_parse_mount_named_volume(self): + mount = Mount.parse_mount_string("foobar:/baz") + assert mount['Source'] == 'foobar' + assert mount['Target'] == '/baz' + assert mount['Type'] == 'volume' + + def test_parse_mount_bind(self): + mount = Mount.parse_mount_string('/foo/bar:/baz') + assert mount['Source'] == "/foo/bar" + assert mount['Target'] == "/baz" + assert mount['Type'] == 'bind' + + @pytest.mark.xfail + def test_parse_mount_bind_windows(self): + with mock.patch('docker.types.services.IS_WINDOWS_PLATFORM', True): + mount = Mount.parse_mount_string('C:/foo/bar:/baz') + assert mount['Source'] == "C:/foo/bar" + assert mount['Target'] == "/baz" + assert mount['Type'] == 'bind'