From a68ee0d9c2d3969e161ca973cfbe3e62bcb3dd2e Mon Sep 17 00:00:00 2001 From: Luke Marsden Date: Wed, 3 Jun 2015 12:21:29 +0100 Subject: [PATCH] Support volume_driver in compose * Add support for volume_driver parameter in compose yml * Don't expand volume host paths if a volume_driver is specified (i.e., disable compose feature "relative to absolute path transformation" when volume drivers are in use, since volume drivers can use name where host path is normally specified; this is a heuristic) Signed-off-by: Luke Marsden --- compose/config.py | 3 ++- docs/yml.md | 10 +++++++++- tests/integration/service_test.py | 6 ++++++ tests/unit/config_test.py | 16 ++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/compose/config.py b/compose/config.py index 064dadaec..af8983961 100644 --- a/compose/config.py +++ b/compose/config.py @@ -43,6 +43,7 @@ DOCKER_CONFIG_KEYS = [ 'stdin_open', 'tty', 'user', + 'volume_driver', 'volumes', 'volumes_from', 'working_dir', @@ -251,7 +252,7 @@ def process_container_options(service_dict, working_dir=None): if 'memswap_limit' in service_dict and 'mem_limit' not in service_dict: raise ConfigurationError("Invalid 'memswap_limit' configuration for %s service: when defining 'memswap_limit' you must set 'mem_limit' as well" % service_dict['name']) - if 'volumes' in service_dict: + if 'volumes' in service_dict and service_dict.get('volume_driver') is None: service_dict['volumes'] = resolve_volume_paths(service_dict['volumes'], working_dir=working_dir) if 'build' in service_dict: diff --git a/docs/yml.md b/docs/yml.md index f92b56825..f89d107bd 100644 --- a/docs/yml.md +++ b/docs/yml.md @@ -134,6 +134,12 @@ Mount paths as volumes, optionally specifying a path on the host machine - cache/:/tmp/cache - ~/configs:/etc/configs/:ro +You can mount a relative path on the host, which will expand relative to +the directory of the Compose configuration file being used. + +> Note: No path expansion will be done if you have also specified a +> `volume_driver`. + ### volumes_from Mount all of the volumes from another service or container. @@ -333,7 +339,7 @@ Override the default labeling scheme for each container. - label:user:USER - label:role:ROLE -### working\_dir, entrypoint, user, hostname, domainname, mac\_address, mem\_limit, memswap\_limit, privileged, restart, stdin\_open, tty, cpu\_shares, cpuset, read\_only +### working\_dir, entrypoint, user, hostname, domainname, mac\_address, mem\_limit, memswap\_limit, privileged, restart, stdin\_open, tty, cpu\_shares, cpuset, read\_only, volume\_driver Each of these is a single value, analogous to its [docker run](https://docs.docker.com/reference/run/) counterpart. @@ -360,6 +366,8 @@ Each of these is a single value, analogous to its tty: true read_only: true + volume_driver: mydriver +``` ## Compose documentation diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py index abab7c579..8856d0245 100644 --- a/tests/integration/service_test.py +++ b/tests/integration/service_test.py @@ -117,6 +117,12 @@ class ServiceTest(DockerClientTestCase): service.start_container(container) self.assertIn('/var/db', container.get('Volumes')) + def test_create_container_with_volume_driver(self): + service = self.create_service('db', volume_driver='foodriver') + container = service.create_container() + service.start_container(container) + self.assertEqual('foodriver', container.get('Config.VolumeDriver')) + def test_create_container_with_cpu_shares(self): service = self.create_service('db', cpu_shares=73) container = service.create_container() diff --git a/tests/unit/config_test.py b/tests/unit/config_test.py index 281717db7..a2c17d725 100644 --- a/tests/unit/config_test.py +++ b/tests/unit/config_test.py @@ -72,6 +72,22 @@ class VolumePathTest(unittest.TestCase): d = make_service_dict('foo', {'volumes': ['~:/container/path']}, working_dir='.') self.assertEqual(d['volumes'], ['/home/user:/container/path']) + def test_named_volume_with_driver(self): + d = make_service_dict('foo', { + 'volumes': ['namedvolume:/data'], + 'volume_driver': 'foodriver', + }, working_dir='.') + self.assertEqual(d['volumes'], ['namedvolume:/data']) + + @mock.patch.dict(os.environ) + def test_named_volume_with_special_chars(self): + os.environ['NAME'] = 'surprise!' + d = make_service_dict('foo', { + 'volumes': ['~/${NAME}:/data'], + 'volume_driver': 'foodriver', + }, working_dir='.') + self.assertEqual(d['volumes'], ['~/${NAME}:/data']) + class MergePathMappingTest(object): def config_name(self):