Merge branch 'master' into 1.27.x

This commit is contained in:
aiordache 2020-09-24 17:06:31 +02:00
commit 959dd849cf
7 changed files with 42 additions and 22 deletions

View File

@ -20,6 +20,7 @@ from ..utils import json_hash
from ..utils import parse_bytes from ..utils import parse_bytes
from ..utils import parse_nanoseconds_int from ..utils import parse_nanoseconds_int
from ..utils import splitdrive from ..utils import splitdrive
from ..version import ComposeVersion
from .environment import env_vars_from_file from .environment import env_vars_from_file
from .environment import Environment from .environment import Environment
from .environment import split_env from .environment import split_env
@ -184,6 +185,13 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
def from_filename(cls, filename): def from_filename(cls, filename):
return cls(filename, load_yaml(filename)) return cls(filename, load_yaml(filename))
@cached_property
def config_version(self):
version = self.config.get('version', None)
if isinstance(version, dict):
return V1
return ComposeVersion(version) if version else self.version
@cached_property @cached_property
def version(self): def version(self):
version = self.config.get('version', None) version = self.config.get('version', None)
@ -222,15 +230,13 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
'Version "{}" in "{}" is invalid.' 'Version "{}" in "{}" is invalid.'
.format(version, self.filename)) .format(version, self.filename))
if version.startswith("1"): if version.startswith("1"):
version = V1
if version == V1:
raise ConfigurationError( raise ConfigurationError(
'Version in "{}" is invalid. {}' 'Version in "{}" is invalid. {}'
.format(self.filename, VERSION_EXPLANATION) .format(self.filename, VERSION_EXPLANATION)
) )
return version
return VERSION
def get_service(self, name): def get_service(self, name):
return self.get_service_dicts()[name] return self.get_service_dicts()[name]
@ -253,8 +259,10 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')):
return {} if self.version == V1 else self.config.get('configs', {}) return {} if self.version == V1 else self.config.get('configs', {})
class Config(namedtuple('_Config', 'version services volumes networks secrets configs')): class Config(namedtuple('_Config', 'config_version version services volumes networks secrets configs')):
""" """
:param config_version: configuration file version
:type config_version: int
:param version: configuration version :param version: configuration version
:type version: int :type version: int
:param services: List of service description dictionaries :param services: List of service description dictionaries
@ -401,9 +409,8 @@ def load(config_details, interpolate=True):
for service_dict in service_dicts: for service_dict in service_dicts:
match_named_volumes(service_dict, volumes) match_named_volumes(service_dict, volumes)
version = main_file.version return Config(main_file.config_version, main_file.version,
service_dicts, volumes, networks, secrets, configs)
return Config(version, service_dicts, volumes, networks, secrets, configs)
def load_mapping(config_files, get_func, entity_type, working_dir=None): def load_mapping(config_files, get_func, entity_type, working_dir=None):
@ -450,9 +457,6 @@ def format_device_option(entity_type, config):
device = config['driver_opts'].get('device') device = config['driver_opts'].get('device')
if o and o == 'bind' and device: if o and o == 'bind' and device:
fullpath = os.path.abspath(os.path.expanduser(device)) fullpath = os.path.abspath(os.path.expanduser(device))
if not os.path.exists(fullpath):
raise ConfigurationError(
"Device path {} does not exist.".format(fullpath))
return fullpath return fullpath

View File

@ -44,7 +44,7 @@ yaml.SafeDumper.add_representer(types.ServicePort, serialize_dict_type)
def denormalize_config(config, image_digests=None): def denormalize_config(config, image_digests=None):
result = {'version': str(config.version)} result = {'version': str(config.config_version)}
denormalized_services = [ denormalized_services = [
denormalize_service_dict( denormalize_service_dict(
service_dict, service_dict,

View File

@ -21,10 +21,10 @@ IMAGE="docker/compose:$VERSION"
# Setup options for connecting to docker host # Setup options for connecting to docker host
if [ -z "$DOCKER_HOST" ]; then if [ -z "$DOCKER_HOST" ]; then
DOCKER_HOST="/var/run/docker.sock" DOCKER_HOST='unix:///var/run/docker.sock'
fi fi
if [ -S "$DOCKER_HOST" ]; then if [ -S "${DOCKER_HOST#unix://}" ]; then
DOCKER_ADDR="-v $DOCKER_HOST:$DOCKER_HOST -e DOCKER_HOST" DOCKER_ADDR="-v ${DOCKER_HOST#unix://}:${DOCKER_HOST#unix://} -e DOCKER_HOST"
else else
DOCKER_ADDR="-e DOCKER_HOST -e DOCKER_TLS_VERIFY -e DOCKER_CERT_PATH" DOCKER_ADDR="-e DOCKER_HOST -e DOCKER_TLS_VERIFY -e DOCKER_CERT_PATH"
fi fi

View File

@ -359,7 +359,7 @@ services:
'web': { 'web': {
'command': 'true', 'command': 'true',
'image': 'alpine:latest', 'image': 'alpine:latest',
'ports': ['5643/tcp', '9999/tcp'] 'ports': [{'target': 5643}, {'target': 9999}]
} }
} }
} }
@ -374,7 +374,7 @@ services:
'web': { 'web': {
'command': 'false', 'command': 'false',
'image': 'alpine:latest', 'image': 'alpine:latest',
'ports': ['5644/tcp', '9998/tcp'] 'ports': [{'target': 5644}, {'target': 9998}]
} }
} }
} }
@ -389,7 +389,7 @@ services:
'web': { 'web': {
'command': 'echo uwu', 'command': 'echo uwu',
'image': 'alpine:3.10.1', 'image': 'alpine:3.10.1',
'ports': ['3341/tcp', '4449/tcp'] 'ports': [{'target': 3341}, {'target': 4449}]
} }
} }
} }

View File

@ -37,6 +37,7 @@ from tests.integration.testcases import no_cluster
def build_config(**kwargs): def build_config(**kwargs):
return config.Config( return config.Config(
config_version=kwargs.get('version', VERSION),
version=kwargs.get('version', VERSION), version=kwargs.get('version', VERSION),
services=kwargs.get('services'), services=kwargs.get('services'),
volumes=kwargs.get('volumes'), volumes=kwargs.get('volumes'),

View File

@ -168,12 +168,14 @@ class ConfigTest(unittest.TestCase):
} }
}) })
) )
assert cfg.config_version == VERSION
assert cfg.version == VERSION assert cfg.version == VERSION
for version in ['2', '2.0', '2.1', '2.2', '2.3', for version in ['2', '2.0', '2.1', '2.2', '2.3',
'3', '3.0', '3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8']: '3', '3.0', '3.1', '3.2', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8']:
cfg = config.load(build_config_details({'version': version})) cfg = config.load(build_config_details({'version': version}))
assert cfg.version == version assert cfg.config_version == version
assert cfg.version == VERSION
def test_v1_file_version(self): def test_v1_file_version(self):
cfg = config.load(build_config_details({'web': {'image': 'busybox'}})) cfg = config.load(build_config_details({'web': {'image': 'busybox'}}))
@ -5369,7 +5371,7 @@ class SerializeTest(unittest.TestCase):
assert serialized_config['secrets']['two'] == {'external': True, 'name': 'two'} assert serialized_config['secrets']['two'] == {'external': True, 'name': 'two'}
def test_serialize_ports(self): def test_serialize_ports(self):
config_dict = config.Config(version=VERSION, services=[ config_dict = config.Config(config_version=VERSION, version=VERSION, services=[
{ {
'ports': [types.ServicePort('80', '8080', None, None, None)], 'ports': [types.ServicePort('80', '8080', None, None, None)],
'image': 'alpine', 'image': 'alpine',
@ -5380,8 +5382,20 @@ class SerializeTest(unittest.TestCase):
serialized_config = yaml.safe_load(serialize_config(config_dict)) serialized_config = yaml.safe_load(serialize_config(config_dict))
assert [{'published': 8080, 'target': 80}] == serialized_config['services']['web']['ports'] assert [{'published': 8080, 'target': 80}] == serialized_config['services']['web']['ports']
def test_serialize_ports_v1(self):
config_dict = config.Config(config_version=V1, version=V1, services=[
{
'ports': [types.ServicePort('80', '8080', None, None, None)],
'image': 'alpine',
'name': 'web'
}
], volumes={}, networks={}, secrets={}, configs={})
serialized_config = yaml.safe_load(serialize_config(config_dict))
assert ['8080:80/tcp'] == serialized_config['services']['web']['ports']
def test_serialize_ports_with_ext_ip(self): def test_serialize_ports_with_ext_ip(self):
config_dict = config.Config(version=VERSION, services=[ config_dict = config.Config(config_version=VERSION, version=VERSION, services=[
{ {
'ports': [types.ServicePort('80', '8080', None, None, '127.0.0.1')], 'ports': [types.ServicePort('80', '8080', None, None, '127.0.0.1')],
'image': 'alpine', 'image': 'alpine',

View File

@ -28,6 +28,7 @@ from compose.service import Service
def build_config(**kwargs): def build_config(**kwargs):
return Config( return Config(
config_version=kwargs.get('config_version', VERSION),
version=kwargs.get('version', VERSION), version=kwargs.get('version', VERSION),
services=kwargs.get('services'), services=kwargs.get('services'),
volumes=kwargs.get('volumes'), volumes=kwargs.get('volumes'),