From 1192a4e817feda3031b228f801e58f02b88ee6db Mon Sep 17 00:00:00 2001 From: aiordache Date: Thu, 17 Sep 2020 09:47:07 +0200 Subject: [PATCH 1/4] Update changelog for 1.27.3 release Signed-off-by: aiordache --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b98799b5..5df82a02e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ Change log ========== +1.27.3 (2020-09-16) +------------------- + +### Bugs + +- Merge `max_replicas_per_node` on `docker-compose config` + +- Fix `depends_on` serialization on `docker-compose config` + +- Fix scaling when some containers are not running on `docker-compose up` + +- Enable relative paths for `driver_opts.device` for `local` driver + +- Allow strings for `cpus` fields + 1.27.2 (2020-09-10) ------------------- From 1ff05ac060b2aaba2b0396d5bccebf80d4543699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20H=C3=B6ltje?= Date: Wed, 11 Mar 2020 14:39:18 -0400 Subject: [PATCH 2/4] run.sh: handle unix:// prefix in DOCKER_HOST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docker currently requires the `unix://` prefix when pointing `DOCKER_HOST` at a socket. fixes #7281 Signed-off-by: Christian Höltje --- script/run/run.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/script/run/run.sh b/script/run/run.sh index 8bc6798f3..bacf39d88 100755 --- a/script/run/run.sh +++ b/script/run/run.sh @@ -21,10 +21,10 @@ IMAGE="docker/compose:$VERSION" # Setup options for connecting to docker host if [ -z "$DOCKER_HOST" ]; then - DOCKER_HOST="/var/run/docker.sock" + DOCKER_HOST='unix:///var/run/docker.sock' fi -if [ -S "$DOCKER_HOST" ]; then - DOCKER_ADDR="-v $DOCKER_HOST:$DOCKER_HOST -e DOCKER_HOST" +if [ -S "${DOCKER_HOST#unix://}" ]; then + DOCKER_ADDR="-v ${DOCKER_HOST#unix://}:${DOCKER_HOST#unix://} -e DOCKER_HOST" else DOCKER_ADDR="-e DOCKER_HOST -e DOCKER_TLS_VERIFY -e DOCKER_CERT_PATH" fi From ce59a4c22397624d21a318745d534f2463ba4fd1 Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Tue, 22 Sep 2020 17:47:24 +0200 Subject: [PATCH 3/4] Fix port rendering Signed-off-by: Ulysses Souza --- compose/config/config.py | 25 ++++++++++++++++--------- compose/config/serialize.py | 2 +- tests/acceptance/cli_test.py | 6 +++--- tests/integration/project_test.py | 1 + tests/unit/config/config_test.py | 20 +++++++++++++++++--- tests/unit/project_test.py | 1 + 6 files changed, 39 insertions(+), 16 deletions(-) diff --git a/compose/config/config.py b/compose/config/config.py index 55e8c2757..aa8dd068b 100644 --- a/compose/config/config.py +++ b/compose/config/config.py @@ -20,6 +20,7 @@ from ..utils import json_hash from ..utils import parse_bytes from ..utils import parse_nanoseconds_int from ..utils import splitdrive +from ..version import ComposeVersion from .environment import env_vars_from_file from .environment import Environment from .environment import split_env @@ -184,6 +185,13 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')): def from_filename(cls, 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 def version(self): version = self.config.get('version', None) @@ -222,15 +230,13 @@ class ConfigFile(namedtuple('_ConfigFile', 'filename config')): 'Version "{}" in "{}" is invalid.' .format(version, self.filename)) - if version.startswith("1"): - version = V1 - - if version == V1: + if version.startswith("1"): raise ConfigurationError( 'Version in "{}" is invalid. {}' .format(self.filename, VERSION_EXPLANATION) ) - return version + + return VERSION def get_service(self, 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', {}) -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 :type version: int :param services: List of service description dictionaries @@ -401,9 +409,8 @@ def load(config_details, interpolate=True): for service_dict in service_dicts: match_named_volumes(service_dict, volumes) - version = main_file.version - - return Config(version, service_dicts, volumes, networks, secrets, configs) + return Config(main_file.config_version, main_file.version, + service_dicts, volumes, networks, secrets, configs) def load_mapping(config_files, get_func, entity_type, working_dir=None): diff --git a/compose/config/serialize.py b/compose/config/serialize.py index 2d9493a03..e3295df78 100644 --- a/compose/config/serialize.py +++ b/compose/config/serialize.py @@ -44,7 +44,7 @@ yaml.SafeDumper.add_representer(types.ServicePort, serialize_dict_type) def denormalize_config(config, image_digests=None): - result = {'version': str(config.version)} + result = {'version': str(config.config_version)} denormalized_services = [ denormalize_service_dict( service_dict, diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index 3d9a31c2d..d678130c1 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -359,7 +359,7 @@ services: 'web': { 'command': 'true', 'image': 'alpine:latest', - 'ports': ['5643/tcp', '9999/tcp'] + 'ports': [{'target': 5643}, {'target': 9999}] } } } @@ -374,7 +374,7 @@ services: 'web': { 'command': 'false', 'image': 'alpine:latest', - 'ports': ['5644/tcp', '9998/tcp'] + 'ports': [{'target': 5644}, {'target': 9998}] } } } @@ -389,7 +389,7 @@ services: 'web': { 'command': 'echo uwu', 'image': 'alpine:3.10.1', - 'ports': ['3341/tcp', '4449/tcp'] + 'ports': [{'target': 3341}, {'target': 4449}] } } } diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index 96929f209..c4210291f 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -37,6 +37,7 @@ from tests.integration.testcases import no_cluster def build_config(**kwargs): return config.Config( + config_version=kwargs.get('version', VERSION), version=kwargs.get('version', VERSION), services=kwargs.get('services'), volumes=kwargs.get('volumes'), diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index b1586ae1f..b67ecdaf4 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -168,12 +168,14 @@ class ConfigTest(unittest.TestCase): } }) ) + assert cfg.config_version == VERSION assert cfg.version == VERSION 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']: 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): 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'} 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)], 'image': 'alpine', @@ -5380,8 +5382,20 @@ class SerializeTest(unittest.TestCase): serialized_config = yaml.safe_load(serialize_config(config_dict)) 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): - 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')], 'image': 'alpine', diff --git a/tests/unit/project_test.py b/tests/unit/project_test.py index 01f0b11ef..a3ffdb67d 100644 --- a/tests/unit/project_test.py +++ b/tests/unit/project_test.py @@ -28,6 +28,7 @@ from compose.service import Service def build_config(**kwargs): return Config( + config_version=kwargs.get('config_version', VERSION), version=kwargs.get('version', VERSION), services=kwargs.get('services'), volumes=kwargs.get('volumes'), From df05472bcc6f1596e519a1e02f01cebd4e160011 Mon Sep 17 00:00:00 2001 From: aiordache Date: Tue, 22 Sep 2020 10:27:14 +0200 Subject: [PATCH 4/4] Remove path check for bind mounts Signed-off-by: aiordache --- compose/config/config.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/compose/config/config.py b/compose/config/config.py index aa8dd068b..1b067e788 100644 --- a/compose/config/config.py +++ b/compose/config/config.py @@ -457,9 +457,6 @@ def format_device_option(entity_type, config): device = config['driver_opts'].get('device') if o and o == 'bind' and 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