mirror of https://github.com/docker/compose.git
Add support for expanded mount/volume notation
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
73aff2b50f
commit
69d0c0e3a0
|
@ -1030,7 +1030,13 @@ def resolve_volume_paths(working_dir, service_dict):
|
|||
|
||||
|
||||
def resolve_volume_path(working_dir, volume):
|
||||
container_path, host_path = split_path_mapping(volume)
|
||||
if isinstance(volume, dict):
|
||||
host_path = volume.get('source')
|
||||
container_path = volume.get('target')
|
||||
if host_path and volume.get('read_only'):
|
||||
container_path += ':ro'
|
||||
else:
|
||||
container_path, host_path = split_path_mapping(volume)
|
||||
|
||||
if host_path is not None:
|
||||
if host_path.startswith('.'):
|
||||
|
@ -1112,6 +1118,8 @@ def split_path_mapping(volume_path):
|
|||
path. Using splitdrive so windows absolute paths won't cause issues with
|
||||
splitting on ':'.
|
||||
"""
|
||||
if isinstance(volume_path, dict):
|
||||
return (volume_path.get('target'), volume_path)
|
||||
drive, volume_config = splitdrive(volume_path)
|
||||
|
||||
if ':' in volume_config:
|
||||
|
@ -1123,7 +1131,9 @@ def split_path_mapping(volume_path):
|
|||
|
||||
def join_path_mapping(pair):
|
||||
(container, host) = pair
|
||||
if host is None:
|
||||
if isinstance(host, dict):
|
||||
return host
|
||||
elif host is None:
|
||||
return container
|
||||
else:
|
||||
return ":".join((host, container))
|
||||
|
|
|
@ -321,7 +321,7 @@ class CLITestCase(DockerClientTestCase):
|
|||
result = self.dispatch(['config'])
|
||||
|
||||
assert yaml.load(result.stdout) == {
|
||||
'version': '3.0',
|
||||
'version': '3.2',
|
||||
'networks': {},
|
||||
'volumes': {
|
||||
'foobar': {
|
||||
|
@ -371,6 +371,11 @@ class CLITestCase(DockerClientTestCase):
|
|||
'timeout': '1s',
|
||||
'retries': 5,
|
||||
},
|
||||
'volumes': [
|
||||
'/host/path:/container/path:ro',
|
||||
'foobar:/container/volumepath:rw',
|
||||
'/anonymous'
|
||||
],
|
||||
|
||||
'stop_grace_period': '20s',
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version: "3"
|
||||
version: "3.2"
|
||||
services:
|
||||
web:
|
||||
image: busybox
|
||||
|
@ -34,6 +34,17 @@ services:
|
|||
timeout: 1s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
- source: /host/path
|
||||
target: /container/path
|
||||
type: bind
|
||||
read_only: true
|
||||
- source: foobar
|
||||
type: volume
|
||||
target: /container/volumepath
|
||||
- type: volume
|
||||
target: /anonymous
|
||||
|
||||
stop_grace_period: 20s
|
||||
volumes:
|
||||
foobar:
|
||||
|
|
|
@ -29,6 +29,7 @@ from compose.const import COMPOSEFILE_V2_0 as V2_0
|
|||
from compose.const import COMPOSEFILE_V2_1 as V2_1
|
||||
from compose.const import COMPOSEFILE_V3_0 as V3_0
|
||||
from compose.const import COMPOSEFILE_V3_1 as V3_1
|
||||
from compose.const import COMPOSEFILE_V3_2 as V3_2
|
||||
from compose.const import IS_WINDOWS_PLATFORM
|
||||
from compose.utils import nanoseconds_from_time_seconds
|
||||
from tests import mock
|
||||
|
@ -964,6 +965,44 @@ class ConfigTest(unittest.TestCase):
|
|||
]
|
||||
assert service_sort(service_dicts) == service_sort(expected)
|
||||
|
||||
@mock.patch.dict(os.environ)
|
||||
def test_load_with_multiple_files_v3_2(self):
|
||||
os.environ['COMPOSE_CONVERT_WINDOWS_PATHS'] = 'true'
|
||||
base_file = config.ConfigFile(
|
||||
'base.yaml',
|
||||
{
|
||||
'version': '3.2',
|
||||
'services': {
|
||||
'web': {
|
||||
'image': 'example/web',
|
||||
'volumes': [
|
||||
{'source': '/a', 'target': '/b', 'type': 'bind'},
|
||||
{'source': 'vol', 'target': '/x', 'type': 'volume', 'read_only': True}
|
||||
]
|
||||
}
|
||||
},
|
||||
'volumes': {'vol': {}}
|
||||
}
|
||||
)
|
||||
|
||||
override_file = config.ConfigFile(
|
||||
'override.yaml',
|
||||
{
|
||||
'version': '3.2',
|
||||
'services': {
|
||||
'web': {
|
||||
'volumes': ['/c:/b', '/anonymous']
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
details = config.ConfigDetails('.', [base_file, override_file])
|
||||
service_dicts = config.load(details).services
|
||||
svc_volumes = map(lambda v: v.repr(), service_dicts[0]['volumes'])
|
||||
assert sorted(svc_volumes) == sorted(
|
||||
['/anonymous', '/c:/b:rw', 'vol:/x:ro']
|
||||
)
|
||||
|
||||
def test_undeclared_volume_v2(self):
|
||||
base_file = config.ConfigFile(
|
||||
'base.yaml',
|
||||
|
@ -1544,6 +1583,29 @@ class ConfigTest(unittest.TestCase):
|
|||
'ports': types.ServicePort.parse('5432')
|
||||
}
|
||||
|
||||
def test_merge_service_dicts_heterogeneous_volumes(self):
|
||||
base = {
|
||||
'volumes': ['/a:/b', '/x:/z'],
|
||||
}
|
||||
|
||||
override = {
|
||||
'image': 'alpine:edge',
|
||||
'volumes': [
|
||||
{'source': '/e', 'target': '/b', 'type': 'bind'},
|
||||
{'source': '/c', 'target': '/d', 'type': 'bind'}
|
||||
]
|
||||
}
|
||||
|
||||
actual = config.merge_service_dicts_from_files(
|
||||
base, override, V3_2
|
||||
)
|
||||
|
||||
assert actual['volumes'] == [
|
||||
{'source': '/e', 'target': '/b', 'type': 'bind'},
|
||||
{'source': '/c', 'target': '/d', 'type': 'bind'},
|
||||
'/x:/z'
|
||||
]
|
||||
|
||||
def test_merge_logging_v1(self):
|
||||
base = {
|
||||
'image': 'alpine:edge',
|
||||
|
|
Loading…
Reference in New Issue