Move parsing of volumes_from to the last step of config parsing.
Includes creating a new compose.config.types module for all the domain objects. Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
c9ca5e86b0
commit
068edfa313
9 changed files with 74 additions and 45 deletions
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import codecs
|
||||
import logging
|
||||
import operator
|
||||
|
|
@ -12,6 +14,7 @@ from .errors import CircularReference
|
|||
from .errors import ComposeFileNotFound
|
||||
from .errors import ConfigurationError
|
||||
from .interpolation import interpolate_environment_variables
|
||||
from .types import VolumeFromSpec
|
||||
from .validation import validate_against_fields_schema
|
||||
from .validation import validate_against_service_schema
|
||||
from .validation import validate_extends_file_path
|
||||
|
|
@ -198,8 +201,12 @@ def load(config_details):
|
|||
service_dict)
|
||||
resolver = ServiceExtendsResolver(service_config)
|
||||
service_dict = process_service(resolver.run())
|
||||
|
||||
# TODO: move to validate_service()
|
||||
validate_against_service_schema(service_dict, service_config.name)
|
||||
validate_paths(service_dict)
|
||||
|
||||
service_dict = finalize_service(service_config._replace(config=service_dict))
|
||||
service_dict['name'] = service_config.name
|
||||
return service_dict
|
||||
|
||||
|
|
@ -353,6 +360,7 @@ def validate_ulimits(ulimit_config):
|
|||
"than 'hard' value".format(ulimit_config))
|
||||
|
||||
|
||||
# TODO: rename to normalize_service
|
||||
def process_service(service_config):
|
||||
working_dir = service_config.working_dir
|
||||
service_dict = dict(service_config.config)
|
||||
|
|
@ -370,12 +378,23 @@ def process_service(service_config):
|
|||
if 'labels' in service_dict:
|
||||
service_dict['labels'] = parse_labels(service_dict['labels'])
|
||||
|
||||
# TODO: move to a validate_service()
|
||||
if 'ulimits' in service_dict:
|
||||
validate_ulimits(service_dict['ulimits'])
|
||||
|
||||
return service_dict
|
||||
|
||||
|
||||
def finalize_service(service_config):
|
||||
service_dict = dict(service_config.config)
|
||||
|
||||
if 'volumes_from' in service_dict:
|
||||
service_dict['volumes_from'] = [
|
||||
VolumeFromSpec.parse(vf) for vf in service_dict['volumes_from']]
|
||||
|
||||
return service_dict
|
||||
|
||||
|
||||
def merge_service_dicts_from_files(base, override):
|
||||
"""When merging services from multiple files we need to merge the `extends`
|
||||
field. This is not handled by `merge_service_dicts()` which is used to
|
||||
|
|
|
|||
28
compose/config/types.py
Normal file
28
compose/config/types.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
"""
|
||||
Types for objects parsed from the configuration.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from compose.config.errors import ConfigurationError
|
||||
|
||||
|
||||
class VolumeFromSpec(namedtuple('_VolumeFromSpec', 'source mode')):
|
||||
|
||||
@classmethod
|
||||
def parse(cls, volume_from_config):
|
||||
parts = volume_from_config.split(':')
|
||||
if len(parts) > 2:
|
||||
raise ConfigurationError(
|
||||
"volume_from {} has incorrect format, should be "
|
||||
"service[:mode]".format(volume_from_config))
|
||||
|
||||
if len(parts) == 1:
|
||||
source = parts[0]
|
||||
mode = 'rw'
|
||||
else:
|
||||
source, mode = parts
|
||||
|
||||
return cls(source, mode)
|
||||
|
|
@ -19,10 +19,8 @@ from .legacy import check_for_legacy_containers
|
|||
from .service import ContainerNet
|
||||
from .service import ConvergenceStrategy
|
||||
from .service import Net
|
||||
from .service import parse_volume_from_spec
|
||||
from .service import Service
|
||||
from .service import ServiceNet
|
||||
from .service import VolumeFromSpec
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -38,10 +36,7 @@ def sort_service_dicts(services):
|
|||
return [link.split(':')[0] for link in links]
|
||||
|
||||
def get_service_names_from_volumes_from(volumes_from):
|
||||
return [
|
||||
parse_volume_from_spec(volume_from).source
|
||||
for volume_from in volumes_from
|
||||
]
|
||||
return [volume_from.source for volume_from in volumes_from]
|
||||
|
||||
def get_service_dependents(service_dict, services):
|
||||
name = service_dict['name']
|
||||
|
|
@ -192,16 +187,15 @@ class Project(object):
|
|||
def get_volumes_from(self, service_dict):
|
||||
volumes_from = []
|
||||
if 'volumes_from' in service_dict:
|
||||
for volume_from_config in service_dict.get('volumes_from', []):
|
||||
volume_from_spec = parse_volume_from_spec(volume_from_config)
|
||||
for volume_from_spec in service_dict.get('volumes_from', []):
|
||||
# Get service
|
||||
try:
|
||||
service_name = self.get_service(volume_from_spec.source)
|
||||
volume_from_spec = VolumeFromSpec(service_name, volume_from_spec.mode)
|
||||
service = self.get_service(volume_from_spec.source)
|
||||
volume_from_spec = volume_from_spec._replace(source=service)
|
||||
except NoSuchService:
|
||||
try:
|
||||
container_name = Container.from_id(self.client, volume_from_spec.source)
|
||||
volume_from_spec = VolumeFromSpec(container_name, volume_from_spec.mode)
|
||||
container = Container.from_id(self.client, volume_from_spec.source)
|
||||
volume_from_spec = volume_from_spec._replace(source=container)
|
||||
except APIError:
|
||||
raise ConfigurationError(
|
||||
'Service "%s" mounts volumes from "%s", which is '
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ class BuildError(Exception):
|
|||
self.reason = reason
|
||||
|
||||
|
||||
# TODO: remove
|
||||
class ConfigError(ValueError):
|
||||
pass
|
||||
|
||||
|
|
@ -86,9 +87,6 @@ class NoSuchImageError(Exception):
|
|||
VolumeSpec = namedtuple('VolumeSpec', 'external internal mode')
|
||||
|
||||
|
||||
VolumeFromSpec = namedtuple('VolumeFromSpec', 'source mode')
|
||||
|
||||
|
||||
ServiceName = namedtuple('ServiceName', 'project service number')
|
||||
|
||||
|
||||
|
|
@ -1029,21 +1027,6 @@ def build_volume_from(volume_from_spec):
|
|||
return ["{}:{}".format(volume_from_spec.source.id, volume_from_spec.mode)]
|
||||
|
||||
|
||||
def parse_volume_from_spec(volume_from_config):
|
||||
parts = volume_from_config.split(':')
|
||||
if len(parts) > 2:
|
||||
raise ConfigError("Volume %s has incorrect format, should be "
|
||||
"external:internal[:mode]" % volume_from_config)
|
||||
|
||||
if len(parts) == 1:
|
||||
source = parts[0]
|
||||
mode = 'rw'
|
||||
else:
|
||||
source, mode = parts
|
||||
|
||||
return VolumeFromSpec(source, mode)
|
||||
|
||||
|
||||
# Labels
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue