Browse Source

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 <[email protected]>
Joffrey F 9 năm trước cách đây
mục cha
commit
fcf78fe3de

+ 11 - 2
compose/config/config.py

@@ -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
 

+ 1 - 1
compose/config/fields_schema_v2.0.json

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

+ 14 - 1
compose/config/service_schema_v2.0.json

@@ -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
             }

+ 4 - 0
compose/utils.py

@@ -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()])

+ 14 - 1
tests/unit/config/config_test.py

@@ -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()