Constraint build argument types. Numbers are cast into strings

Numerical driver_opts are also valid and typecast into strings.
Additional config tests.

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2016-02-16 16:48:04 -08:00 committed by Daniel Nephin
parent 8d7b1e9047
commit fcf78fe3de
5 changed files with 44 additions and 5 deletions

View File

@ -16,6 +16,7 @@ from cached_property import cached_property
from ..const import COMPOSEFILE_V1 as V1
from ..const import COMPOSEFILE_V2_0 as V2_0
from ..utils import build_string_dict
from .errors import CircularReference
from .errors import ComposeFileNotFound
from .errors import ConfigurationError
@ -291,7 +292,7 @@ def load(config_details):
config_details = config_details._replace(config_files=processed_files)
main_file = config_details.config_files[0]
volumes = load_mapping(config_details.config_files, 'get_volumes', 'Volume')
volumes = load_volumes(config_details.config_files)
networks = load_mapping(config_details.config_files, 'get_networks', 'Network')
service_dicts = load_services(
config_details.working_dir,
@ -335,6 +336,14 @@ def load_mapping(config_files, get_func, entity_type):
return mapping
def load_volumes(config_files):
volumes = load_mapping(config_files, 'get_volumes', 'Volume')
for volume_name, volume in volumes.items():
if 'driver_opts' in volume:
volume['driver_opts'] = build_string_dict(volume['driver_opts'])
return volumes
def load_services(working_dir, config_file, service_configs):
def build_service(service_name, service_dict, service_names):
service_config = ServiceConfig.with_abs_paths(
@ -854,7 +863,7 @@ def normalize_build(service_dict, working_dir):
else:
build.update(service_dict['build'])
if 'args' in build:
build['args'] = resolve_build_args(build)
build['args'] = build_string_dict(resolve_build_args(build))
service_dict['build'] = build

View File

@ -78,7 +78,7 @@
"driver_opts": {
"type": "object",
"patternProperties": {
"^.+$": {"type": "string"}
"^.+$": {"type": ["string", "number"]}
}
},
"external": {

View File

@ -23,7 +23,20 @@
"properties": {
"context": {"type": "string"},
"dockerfile": {"type": "string"},
"args": {"$ref": "#/definitions/list_or_dict"}
"args": {
"oneOf": [
{"$ref": "#/definitions/list_of_strings"},
{
"type": "object",
"patternProperties": {
"^.+$": {
"type": ["string", "number"]
}
},
"additionalProperties": false
}
]
}
},
"additionalProperties": false
}

View File

@ -92,3 +92,7 @@ def json_hash(obj):
def microseconds_from_time_nano(time_nano):
return int(time_nano % 1000000000 / 1000)
def build_string_dict(source_dict):
return dict([(k, str(v)) for k, v in source_dict.items()])

View File

@ -231,7 +231,7 @@ class ConfigTest(unittest.TestCase):
assert volumes['simple'] == {}
assert volumes['other'] == {}
def test_volume_invalid_driver_opt(self):
def test_volume_numeric_driver_opt(self):
config_details = build_config_details({
'version': '2',
'services': {
@ -241,6 +241,19 @@ class ConfigTest(unittest.TestCase):
'simple': {'driver_opts': {'size': 42}},
}
})
cfg = config.load(config_details)
assert cfg.volumes['simple']['driver_opts']['size'] == '42'
def test_volume_invalid_driver_opt(self):
config_details = build_config_details({
'version': '2',
'services': {
'simple': {'image': 'busybox'}
},
'volumes': {
'simple': {'driver_opts': {'size': True}},
}
})
with pytest.raises(ConfigurationError) as exc:
config.load(config_details)
assert 'driver_opts.size contains an invalid type' in exc.exconly()