Config command generates invalid volumes (fixes #5176)

Signed-off-by: Guillermo Arribas <garribas@gmail.com>
This commit is contained in:
Guillermo Arribas 2017-10-11 13:56:15 -03:00 committed by Joffrey F
parent f6d7eeb129
commit b9bae89f1d
7 changed files with 114 additions and 15 deletions

View File

@ -15,6 +15,9 @@ from cached_property import cached_property
from . import types from . import types
from .. import const from .. import const
from ..const import COMPOSEFILE_V1 as V1 from ..const import COMPOSEFILE_V1 as V1
from ..const import COMPOSEFILE_V2_1 as V2_1
from ..const import COMPOSEFILE_V3_0 as V3_0
from ..const import COMPOSEFILE_V3_4 as V3_4
from ..utils import build_string_dict from ..utils import build_string_dict
from ..utils import parse_bytes from ..utils import parse_bytes
from ..utils import parse_nanoseconds_int from ..utils import parse_nanoseconds_int
@ -405,7 +408,7 @@ def load_mapping(config_files, get_func, entity_type, working_dir=None):
external = config.get('external') external = config.get('external')
if external: if external:
name_field = 'name' if entity_type == 'Volume' else 'external_name' name_field = 'name' if entity_type == 'Volume' else 'external_name'
validate_external(entity_type, name, config) validate_external(entity_type, name, config, config_file.version)
if isinstance(external, dict): if isinstance(external, dict):
config[name_field] = external.get('name') config[name_field] = external.get('name')
elif not config.get('name'): elif not config.get('name'):
@ -425,14 +428,12 @@ def load_mapping(config_files, get_func, entity_type, working_dir=None):
return mapping return mapping
def validate_external(entity_type, name, config): def validate_external(entity_type, name, config, version):
if len(config.keys()) <= 1: if (version < V2_1 or (version >= V3_0 and version < V3_4)) and len(config.keys()) > 1:
return raise ConfigurationError(
"{} {} declared as external but specifies additional attributes "
raise ConfigurationError( "({}).".format(
"{} {} declared as external but specifies additional attributes " entity_type, name, ', '.join(k for k in config if k != 'external')))
"({}).".format(
entity_type, name, ', '.join(k for k in config if k != 'external')))
def load_services(config_details, config_file): def load_services(config_details, config_file):

View File

@ -9,7 +9,7 @@ from compose.const import COMPOSEFILE_V1 as V1
from compose.const import COMPOSEFILE_V2_1 as V2_1 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_0 as V3_0
from compose.const import COMPOSEFILE_V3_2 as V3_2 from compose.const import COMPOSEFILE_V3_2 as V3_2
from compose.const import COMPOSEFILE_V3_2 as V3_4 from compose.const import COMPOSEFILE_V3_4 as V3_4
def serialize_config_type(dumper, data): def serialize_config_type(dumper, data):
@ -67,7 +67,7 @@ def denormalize_config(config, image_digests=None):
del conf['external_name'] del conf['external_name']
if 'name' in conf: if 'name' in conf:
if config.version < V2_1 or (config.version > V3_0 and config.version < V3_4): if config.version < V2_1 or (config.version >= V3_0 and config.version < V3_4):
del conf['name'] del conf['name']
elif 'external' in conf: elif 'external' in conf:
conf['external'] = True conf['external'] = True

View File

@ -285,15 +285,63 @@ class CLITestCase(DockerClientTestCase):
} }
} }
def test_config_external_volume(self): def test_config_external_volume_v2(self):
self.base_dir = 'tests/fixtures/volumes' self.base_dir = 'tests/fixtures/volumes'
result = self.dispatch(['-f', 'external-volumes.yml', 'config']) result = self.dispatch(['-f', 'external-volumes-v2.yml', 'config'])
json_result = yaml.load(result.stdout) json_result = yaml.load(result.stdout)
assert 'volumes' in json_result assert 'volumes' in json_result
assert json_result['volumes'] == { assert json_result['volumes'] == {
'foo': { 'foo': {
'external': True, 'external': True,
'name': 'foo', },
'bar': {
'external': {
'name': 'some_bar',
},
}
}
def test_config_external_volume_v2_x(self):
self.base_dir = 'tests/fixtures/volumes'
result = self.dispatch(['-f', 'external-volumes-v2-x.yml', 'config'])
json_result = yaml.load(result.stdout)
assert 'volumes' in json_result
assert json_result['volumes'] == {
'foo': {
'external': True,
'name': 'some_foo',
},
'bar': {
'external': True,
'name': 'some_bar',
}
}
def test_config_external_volume_v3_x(self):
self.base_dir = 'tests/fixtures/volumes'
result = self.dispatch(['-f', 'external-volumes-v3-x.yml', 'config'])
json_result = yaml.load(result.stdout)
assert 'volumes' in json_result
assert json_result['volumes'] == {
'foo': {
'external': True,
},
'bar': {
'external': {
'name': 'some_bar',
},
}
}
def test_config_external_volume_v3_4(self):
self.base_dir = 'tests/fixtures/volumes'
result = self.dispatch(['-f', 'external-volumes-v3-4.yml', 'config'])
json_result = yaml.load(result.stdout)
assert 'volumes' in json_result
assert json_result['volumes'] == {
'foo': {
'external': True,
'name': 'some_foo',
}, },
'bar': { 'bar': {
'external': True, 'external': True,

View File

@ -0,0 +1,17 @@
version: "2.1"
services:
web:
image: busybox
command: top
volumes:
- foo:/var/lib/
- bar:/etc/
volumes:
foo:
external: true
name: some_foo
bar:
external:
name: some_bar

View File

@ -1,4 +1,4 @@
version: "2.1" version: "2"
services: services:
web: web:

View File

@ -0,0 +1,17 @@
version: "3.4"
services:
web:
image: busybox
command: top
volumes:
- foo:/var/lib/
- bar:/etc/
volumes:
foo:
external: true
name: some_foo
bar:
external:
name: some_bar

View File

@ -0,0 +1,16 @@
version: "3.0"
services:
web:
image: busybox
command: top
volumes:
- foo:/var/lib/
- bar:/etc/
volumes:
foo:
external: true
bar:
external:
name: some_bar