瀏覽代碼

Partial support for service configs

Signed-off-by: Joffrey F <[email protected]>
Joffrey F 8 年之前
父節點
當前提交
39c1cb5988
共有 3 個文件被更改,包括 43 次插入45 次删除
  1. 24 27
      compose/config/config.py
  2. 10 16
      compose/config/serialize.py
  3. 9 2
      compose/config/types.py

+ 24 - 27
compose/config/config.py

@@ -211,8 +211,11 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
     def get_secrets(self):
         return {} if self.version < const.COMPOSEFILE_V3_1 else self.config.get('secrets', {})
 
+    def get_configs(self):
+        return {} if self.version < const.COMPOSEFILE_V3_3 else self.config.get('configs', {})
 
-class Config(namedtuple('_Config', 'version services volumes networks secrets')):
+
+class Config(namedtuple('_Config', 'version services volumes networks secrets configs')):
     """
     :param version: configuration version
     :type  version: int
@@ -224,6 +227,8 @@ class Config(namedtuple('_Config', 'version services volumes networks secrets'))
     :type  networks: :class:`dict`
     :param secrets: Dictionary mapping secret names to description dictionaries
     :type secrets: :class:`dict`
+    :param configs: Dictionary mapping config names to description dictionaries
+    :type configs: :class:`dict`
     """
 
 
@@ -340,6 +345,7 @@ def check_swarm_only_config(service_dicts):
 
     check_swarm_only_key(service_dicts, 'deploy')
     check_swarm_only_key(service_dicts, 'credential_spec')
+    check_swarm_only_key(service_dicts, 'configs')
 
 
 def load(config_details):
@@ -364,7 +370,12 @@ def load(config_details):
     networks = load_mapping(
         config_details.config_files, 'get_networks', 'Network'
     )
-    secrets = load_secrets(config_details.config_files, config_details.working_dir)
+    secrets = load_mapping(
+        config_details.config_files, 'get_secrets', 'Secret', config_details.working_dir
+    )
+    configs = load_mapping(
+        config_details.config_files, 'get_configs', 'Config', config_details.working_dir
+    )
     service_dicts = load_services(config_details, main_file)
 
     if main_file.version != V1:
@@ -373,10 +384,10 @@ def load(config_details):
 
     check_swarm_only_config(service_dicts)
 
-    return Config(main_file.version, service_dicts, volumes, networks, secrets)
+    return Config(main_file.version, service_dicts, volumes, networks, secrets, configs)
 
 
-def load_mapping(config_files, get_func, entity_type):
+def load_mapping(config_files, get_func, entity_type, working_dir=None):
     mapping = {}
 
     for config_file in config_files:
@@ -401,6 +412,9 @@ def load_mapping(config_files, get_func, entity_type):
             if 'labels' in config:
                 config['labels'] = parse_labels(config['labels'])
 
+            if 'file' in config:
+                config['file'] = expand_path(working_dir, config['file'])
+
     return mapping
 
 
@@ -414,29 +428,6 @@ def validate_external(entity_type, name, config):
             entity_type, name, ', '.join(k for k in config if k != 'external')))
 
 
-def load_secrets(config_files, working_dir):
-    mapping = {}
-
-    for config_file in config_files:
-        for name, config in config_file.get_secrets().items():
-            mapping[name] = config or {}
-            if not config:
-                continue
-
-            external = config.get('external')
-            if external:
-                validate_external('Secret', name, config)
-                if isinstance(external, dict):
-                    config['external_name'] = external.get('name')
-                else:
-                    config['external_name'] = name
-
-            if 'file' in config:
-                config['file'] = expand_path(working_dir, config['file'])
-
-    return mapping
-
-
 def load_services(config_details, config_file):
     def build_service(service_name, service_dict, service_names):
         service_config = ServiceConfig.with_abs_paths(
@@ -815,6 +806,11 @@ def finalize_service(service_config, service_names, version, environment):
             types.ServiceSecret.parse(s) for s in service_dict['secrets']
         ]
 
+    if 'configs' in service_dict:
+        service_dict['configs'] = [
+            types.ServiceConfig.parse(c) for c in service_dict['configs']
+        ]
+
     normalize_build(service_dict, service_config.working_dir, environment)
 
     service_dict['name'] = service_config.name
@@ -906,6 +902,7 @@ def merge_service_dicts(base, override, version):
     md.merge_mapping('depends_on', parse_depends_on)
     md.merge_sequence('links', ServiceLink.parse)
     md.merge_sequence('secrets', types.ServiceSecret.parse)
+    md.merge_sequence('configs', types.ServiceConfig.parse)
     md.merge_mapping('deploy', parse_deploy)
 
     for field in ['volumes', 'devices']:

+ 10 - 16
compose/config/serialize.py

@@ -8,7 +8,6 @@ from compose.config import types
 from compose.const import COMPOSEFILE_V1 as V1
 from compose.const import COMPOSEFILE_V2_1 as V2_1
 from compose.const import COMPOSEFILE_V2_2 as V2_2
-from compose.const import COMPOSEFILE_V3_1 as V3_1
 from compose.const import COMPOSEFILE_V3_2 as V3_2
 from compose.const import COMPOSEFILE_V3_3 as V3_3
 
@@ -25,6 +24,7 @@ def serialize_dict_type(dumper, data):
 yaml.SafeDumper.add_representer(types.VolumeFromSpec, serialize_config_type)
 yaml.SafeDumper.add_representer(types.VolumeSpec, serialize_config_type)
 yaml.SafeDumper.add_representer(types.ServiceSecret, serialize_dict_type)
+yaml.SafeDumper.add_representer(types.ServiceConfig, serialize_dict_type)
 yaml.SafeDumper.add_representer(types.ServicePort, serialize_dict_type)
 
 
@@ -41,21 +41,15 @@ def denormalize_config(config, image_digests=None):
         service_dict.pop('name'): service_dict
         for service_dict in denormalized_services
     }
-    result['networks'] = config.networks.copy()
-    for net_name, net_conf in result['networks'].items():
-        if 'external_name' in net_conf:
-            del net_conf['external_name']
-
-    result['volumes'] = config.volumes.copy()
-    for vol_name, vol_conf in result['volumes'].items():
-        if 'external_name' in vol_conf:
-            del vol_conf['external_name']
-
-    if config.version in (V3_1, V3_2, V3_3):
-        result['secrets'] = config.secrets.copy()
-        for secret_name, secret_conf in result['secrets'].items():
-            if 'external_name' in secret_conf:
-                del secret_conf['external_name']
+    for key in ('networks', 'volumes', 'secrets', 'configs'):
+        config_dict = getattr(config, key)
+        if not config_dict:
+            continue
+        result[key] = config_dict.copy()
+        for name, conf in result[key].items():
+            if 'external_name' in conf:
+                del conf['external_name']
+
     return result
 
 

+ 9 - 2
compose/config/types.py

@@ -238,8 +238,7 @@ class ServiceLink(namedtuple('_ServiceLink', 'target alias')):
         return self.alias
 
 
-class ServiceSecret(namedtuple('_ServiceSecret', 'source target uid gid mode')):
-
+class ServiceConfigBase(namedtuple('_ServiceConfigBase', 'source target uid gid mode')):
     @classmethod
     def parse(cls, spec):
         if isinstance(spec, six.string_types):
@@ -262,6 +261,14 @@ class ServiceSecret(namedtuple('_ServiceSecret', 'source target uid gid mode')):
         )
 
 
+class ServiceSecret(ServiceConfigBase):
+    pass
+
+
+class ServiceConfig(ServiceConfigBase):
+    pass
+
+
 class ServicePort(namedtuple('_ServicePort', 'target published protocol mode external_ip')):
     def __new__(cls, target, published, *args, **kwargs):
         try: