mirror of https://github.com/docker/compose.git
Ensure that the config output by config command never contains python objects.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
3021ee12fe
commit
1bfbba36b2
|
@ -9,7 +9,6 @@ import sys
|
|||
from inspect import getdoc
|
||||
from operator import attrgetter
|
||||
|
||||
import yaml
|
||||
from docker.errors import APIError
|
||||
from requests.exceptions import ReadTimeout
|
||||
|
||||
|
@ -18,6 +17,7 @@ from .. import __version__
|
|||
from ..config import config
|
||||
from ..config import ConfigurationError
|
||||
from ..config import parse_environment
|
||||
from ..config.serialize import serialize_config
|
||||
from ..const import DEFAULT_TIMEOUT
|
||||
from ..const import HTTP_TIMEOUT
|
||||
from ..const import IS_WINDOWS_PLATFORM
|
||||
|
@ -215,13 +215,7 @@ class TopLevelCommand(DocoptCommand):
|
|||
print('\n'.join(service['name'] for service in compose_config.services))
|
||||
return
|
||||
|
||||
compose_config = dict(
|
||||
(service.pop('name'), service) for service in compose_config.services)
|
||||
print(yaml.safe_dump(
|
||||
compose_config,
|
||||
default_flow_style=False,
|
||||
indent=2,
|
||||
width=80))
|
||||
print(serialize_config(compose_config))
|
||||
|
||||
def create(self, project, options):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import six
|
||||
import yaml
|
||||
|
||||
from compose.config import types
|
||||
|
||||
|
||||
def serialize_config_type(dumper, data):
|
||||
representer = dumper.represent_str if six.PY3 else dumper.represent_unicode
|
||||
return representer(data.repr())
|
||||
|
||||
|
||||
yaml.SafeDumper.add_representer(types.VolumeFromSpec, serialize_config_type)
|
||||
yaml.SafeDumper.add_representer(types.VolumeSpec, serialize_config_type)
|
||||
|
||||
|
||||
def serialize_config(config):
|
||||
output = {
|
||||
'version': config.version,
|
||||
'services': {service.pop('name'): service for service in config.services},
|
||||
'networks': config.networks,
|
||||
'volumes': config.volumes,
|
||||
}
|
||||
return yaml.safe_dump(
|
||||
output,
|
||||
default_flow_style=False,
|
||||
indent=2,
|
||||
width=80)
|
|
@ -67,6 +67,9 @@ class VolumeFromSpec(namedtuple('_VolumeFromSpec', 'source mode type')):
|
|||
|
||||
return cls(source, mode, type)
|
||||
|
||||
def repr(self):
|
||||
return '{v.type}:{v.source}:{v.mode}'.format(v=self)
|
||||
|
||||
|
||||
def parse_restart_spec(restart_config):
|
||||
if not restart_config:
|
||||
|
@ -156,3 +159,7 @@ class VolumeSpec(namedtuple('_VolumeSpec', 'external internal mode')):
|
|||
mode = parts[2]
|
||||
|
||||
return cls(external, internal, mode)
|
||||
|
||||
def repr(self):
|
||||
external = self.external + ':' if self.external else ''
|
||||
return '{ext}{v.internal}:{v.mode}'.format(ext=external, v=self)
|
||||
|
|
|
@ -460,7 +460,8 @@ class Service(object):
|
|||
'links': self.get_link_names(),
|
||||
'net': self.net.id,
|
||||
'volumes_from': [
|
||||
(v.source.name, v.mode) for v in self.volumes_from if isinstance(v.source, Service)
|
||||
(v.source.name, v.mode)
|
||||
for v in self.volumes_from if isinstance(v.source, Service)
|
||||
],
|
||||
}
|
||||
|
||||
|
@ -519,12 +520,7 @@ class Service(object):
|
|||
return links
|
||||
|
||||
def _get_volumes_from(self):
|
||||
volumes_from = []
|
||||
for volume_from_spec in self.volumes_from:
|
||||
volumes = build_volume_from(volume_from_spec)
|
||||
volumes_from.extend(volumes)
|
||||
|
||||
return volumes_from
|
||||
return [build_volume_from(spec) for spec in self.volumes_from]
|
||||
|
||||
def _get_container_create_options(
|
||||
self,
|
||||
|
@ -927,7 +923,7 @@ def warn_on_masked_volume(volumes_option, container_volumes, service):
|
|||
|
||||
|
||||
def build_volume_binding(volume_spec):
|
||||
return volume_spec.internal, "{}:{}:{}".format(*volume_spec)
|
||||
return volume_spec.internal, volume_spec.repr()
|
||||
|
||||
|
||||
def build_volume_from(volume_from_spec):
|
||||
|
@ -938,12 +934,14 @@ def build_volume_from(volume_from_spec):
|
|||
if isinstance(volume_from_spec.source, Service):
|
||||
containers = volume_from_spec.source.containers(stopped=True)
|
||||
if not containers:
|
||||
return ["{}:{}".format(volume_from_spec.source.create_container().id, volume_from_spec.mode)]
|
||||
return "{}:{}".format(
|
||||
volume_from_spec.source.create_container().id,
|
||||
volume_from_spec.mode)
|
||||
|
||||
container = containers[0]
|
||||
return ["{}:{}".format(container.id, volume_from_spec.mode)]
|
||||
return "{}:{}".format(container.id, volume_from_spec.mode)
|
||||
elif isinstance(volume_from_spec.source, Container):
|
||||
return ["{}:{}".format(volume_from_spec.source.id, volume_from_spec.mode)]
|
||||
return "{}:{}".format(volume_from_spec.source.id, volume_from_spec.mode)
|
||||
|
||||
|
||||
# Labels
|
||||
|
|
|
@ -177,12 +177,16 @@ class CLITestCase(DockerClientTestCase):
|
|||
'networks': {'front': {}},
|
||||
'services': {
|
||||
'web': {
|
||||
'build': os.path.abspath(self.base_dir),
|
||||
'build': {
|
||||
'context': os.path.abspath(self.base_dir),
|
||||
},
|
||||
'networks': ['front', 'default'],
|
||||
'volumes_from': ['service:other:rw'],
|
||||
},
|
||||
'other': {
|
||||
'image': 'busybox:latest',
|
||||
'command': 'top',
|
||||
'volumes': ['/data:rw'],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue