Merge pull request #1833 from aanand/deprecate-relative-volumes-without-dot

Show a warning when a relative path is specified without "./"
This commit is contained in:
Mazz Mosley 2015-08-11 11:21:17 +01:00
commit 52733f6996
3 changed files with 73 additions and 6 deletions

View File

@ -90,6 +90,13 @@ SUPPORTED_FILENAMES = [
]
PATH_START_CHARS = [
'/',
'.',
'~',
]
log = logging.getLogger(__name__)
@ -260,7 +267,7 @@ def process_container_options(service_dict, working_dir=None):
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 and service_dict.get('volume_driver') is None:
service_dict['volumes'] = resolve_volume_paths(service_dict['volumes'], working_dir=working_dir)
service_dict['volumes'] = resolve_volume_paths(service_dict, working_dir=working_dir)
if 'build' in service_dict:
service_dict['build'] = resolve_build_path(service_dict['build'], working_dir=working_dir)
@ -421,17 +428,31 @@ def env_vars_from_file(filename):
return env
def resolve_volume_paths(volumes, working_dir=None):
def resolve_volume_paths(service_dict, working_dir=None):
if working_dir is None:
raise Exception("No working_dir passed to resolve_volume_paths()")
return [resolve_volume_path(v, working_dir) for v in volumes]
return [
resolve_volume_path(v, working_dir, service_dict['name'])
for v in service_dict['volumes']
]
def resolve_volume_path(volume, working_dir):
def resolve_volume_path(volume, working_dir, service_name):
container_path, host_path = split_path_mapping(volume)
container_path = os.path.expanduser(container_path)
if host_path is not None:
if not any(host_path.startswith(c) for c in PATH_START_CHARS):
log.warn(
'Warning: the mapping "{0}" in the volumes config for '
'service "{1}" is ambiguous. In a future version of Docker, '
'it will designate a "named" volume '
'(see https://github.com/docker/docker/pull/14242). '
'To prevent unexpected behaviour, change it to "./{0}"'
.format(volume, service_name)
)
host_path = os.path.expanduser(host_path)
return "%s:%s" % (expand_path(working_dir, host_path), container_path)
else:

View File

@ -135,11 +135,12 @@ Mount paths as volumes, optionally specifying a path on the host machine
volumes:
- /var/lib/mysql
- cache/:/tmp/cache
- ./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.
the directory of the Compose configuration file being used. Relative paths
should always begin with `.` or `..`.
> Note: No path expansion will be done if you have also specified a
> `volume_driver`.

View File

@ -117,6 +117,51 @@ class InterpolationTest(unittest.TestCase):
d = make_service_dict('foo', {'volumes': ['~:/container/path']}, working_dir='.')
self.assertEqual(d['volumes'], ['/home/user:/container/path'])
@mock.patch.dict(os.environ)
def test_volume_binding_with_local_dir_name_raises_warning(self):
def make_dict(**config):
make_service_dict('foo', config, working_dir='.')
with mock.patch('compose.config.config.log.warn') as warn:
make_dict(volumes=['/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['/data:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['.:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['..:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['./data:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['../data:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['.profile:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['~:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['~/data:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['~tmp:/container/path'])
self.assertEqual(0, warn.call_count)
make_dict(volumes=['data:/container/path'], volume_driver='mydriver')
self.assertEqual(0, warn.call_count)
make_dict(volumes=['data:/container/path'])
self.assertEqual(1, warn.call_count)
warning = warn.call_args[0][0]
self.assertIn('"data:/container/path"', warning)
self.assertIn('"./data:/container/path"', warning)
def test_named_volume_with_driver_does_not_expand(self):
d = make_service_dict('foo', {
'volumes': ['namedvolume:/data'],