From a4d3dd6197b9e15cf993823d93d321778d2fdcd8 Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Fri, 18 Mar 2016 13:00:55 +0000 Subject: [PATCH 1/4] Remove v2_only decorators on config tests Signed-off-by: Aanand Prasad --- tests/acceptance/cli_test.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index 0b49efa0..4d1990be 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -145,15 +145,11 @@ class CLITestCase(DockerClientTestCase): # Prevent tearDown from trying to create a project self.base_dir = None - # TODO: this shouldn't be v2-dependent - @v2_only() def test_config_list_services(self): self.base_dir = 'tests/fixtures/v2-full' result = self.dispatch(['config', '--services']) assert set(result.stdout.rstrip().split('\n')) == {'web', 'other'} - # TODO: this shouldn't be v2-dependent - @v2_only() def test_config_quiet_with_error(self): self.base_dir = None result = self.dispatch([ @@ -162,14 +158,10 @@ class CLITestCase(DockerClientTestCase): ], returncode=1) assert "'notaservice' must be a mapping" in result.stderr - # TODO: this shouldn't be v2-dependent - @v2_only() def test_config_quiet(self): self.base_dir = 'tests/fixtures/v2-full' assert self.dispatch(['config', '-q']).stdout == '' - # TODO: this shouldn't be v2-dependent - @v2_only() def test_config_default(self): self.base_dir = 'tests/fixtures/v2-full' result = self.dispatch(['config']) From 84a3e2fe79552ca94172bd3958776b01eed0e31e Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Fri, 18 Mar 2016 13:01:35 +0000 Subject: [PATCH 2/4] Check full error message in test_up_with_net_is_invalid Signed-off-by: Aanand Prasad --- tests/acceptance/cli_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index 4d1990be..2a5a8604 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -675,9 +675,7 @@ class CLITestCase(DockerClientTestCase): ['-f', 'v2-invalid.yml', 'up', '-d'], returncode=1) - # TODO: fix validation error messages for v2 files - # assert "Unsupported config option for service 'web': 'net'" in exc.exconly() - assert "Unsupported config option" in result.stderr + assert "Unsupported config option for services.bar: 'net'" in result.stderr def test_up_with_net_v1(self): self.base_dir = 'tests/fixtures/net-container' From 6064d200f946c8d9738e1b73a03b1f78f947e2ef Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Fri, 18 Mar 2016 13:14:33 +0000 Subject: [PATCH 3/4] Fix output of 'config' for v1 files Signed-off-by: Aanand Prasad --- compose/config/serialize.py | 14 ++++++++++-- tests/acceptance/cli_test.py | 25 +++++++++++++++++++++ tests/fixtures/v1-config/docker-compose.yml | 10 +++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/v1-config/docker-compose.yml diff --git a/compose/config/serialize.py b/compose/config/serialize.py index 06e0a027..be6ba720 100644 --- a/compose/config/serialize.py +++ b/compose/config/serialize.py @@ -5,6 +5,8 @@ import six import yaml from compose.config import types +from compose.config.config import V1 +from compose.config.config import V2_0 def serialize_config_type(dumper, data): @@ -17,12 +19,20 @@ yaml.SafeDumper.add_representer(types.VolumeSpec, serialize_config_type) def serialize_config(config): + services = {service.pop('name'): service for service in config.services} + + if config.version == V1: + for service_dict in services.values(): + if 'network_mode' not in service_dict: + service_dict['network_mode'] = 'bridge' + output = { - 'version': config.version, - 'services': {service.pop('name'): service for service in config.services}, + 'version': V2_0, + 'services': services, 'networks': config.networks, 'volumes': config.volumes, } + return yaml.safe_dump( output, default_flow_style=False, diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index 2a5a8604..f7c958dd 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -190,6 +190,31 @@ class CLITestCase(DockerClientTestCase): } assert output == expected + def test_config_v1(self): + self.base_dir = 'tests/fixtures/v1-config' + result = self.dispatch(['config']) + assert yaml.load(result.stdout) == { + 'version': '2.0', + 'services': { + 'net': { + 'image': 'busybox', + 'network_mode': 'bridge', + }, + 'volume': { + 'image': 'busybox', + 'volumes': ['/data:rw'], + 'network_mode': 'bridge', + }, + 'app': { + 'image': 'busybox', + 'volumes_from': ['service:volume:rw'], + 'network_mode': 'service:net', + }, + }, + 'networks': {}, + 'volumes': {}, + } + def test_ps(self): self.project.get_service('simple').create_container() result = self.dispatch(['ps']) diff --git a/tests/fixtures/v1-config/docker-compose.yml b/tests/fixtures/v1-config/docker-compose.yml new file mode 100644 index 00000000..8646c4ed --- /dev/null +++ b/tests/fixtures/v1-config/docker-compose.yml @@ -0,0 +1,10 @@ +net: + image: busybox +volume: + image: busybox + volumes: + - /data +app: + image: busybox + net: "container:net" + volumes_from: ["volume"] From 756ef14edc824ce2c52a2eb636c4884c95652e1e Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Tue, 26 Apr 2016 17:30:04 +0100 Subject: [PATCH 4/4] Fix format of 'restart' option in 'config' output Signed-off-by: Aanand Prasad --- compose/config/serialize.py | 26 +++++++++++++++++----- compose/config/types.py | 9 ++++++++ tests/acceptance/cli_test.py | 27 +++++++++++++++++++++++ tests/fixtures/restart/docker-compose.yml | 14 ++++++++++++ 4 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 tests/fixtures/restart/docker-compose.yml diff --git a/compose/config/serialize.py b/compose/config/serialize.py index be6ba720..1b498c01 100644 --- a/compose/config/serialize.py +++ b/compose/config/serialize.py @@ -19,12 +19,14 @@ yaml.SafeDumper.add_representer(types.VolumeSpec, serialize_config_type) def serialize_config(config): - services = {service.pop('name'): service for service in config.services} - - if config.version == V1: - for service_dict in services.values(): - if 'network_mode' not in service_dict: - service_dict['network_mode'] = 'bridge' + denormalized_services = [ + denormalize_service_dict(service_dict, config.version) + for service_dict in config.services + ] + services = { + service_dict.pop('name'): service_dict + for service_dict in denormalized_services + } output = { 'version': V2_0, @@ -38,3 +40,15 @@ def serialize_config(config): default_flow_style=False, indent=2, width=80) + + +def denormalize_service_dict(service_dict, version): + service_dict = service_dict.copy() + + if 'restart' in service_dict: + service_dict['restart'] = types.serialize_restart_spec(service_dict['restart']) + + if version == V1 and 'network_mode' not in service_dict: + service_dict['network_mode'] = 'bridge' + + return service_dict diff --git a/compose/config/types.py b/compose/config/types.py index fc3347c8..e6a3dea0 100644 --- a/compose/config/types.py +++ b/compose/config/types.py @@ -7,6 +7,8 @@ from __future__ import unicode_literals import os from collections import namedtuple +import six + from compose.config.config import V1 from compose.config.errors import ConfigurationError from compose.const import IS_WINDOWS_PLATFORM @@ -89,6 +91,13 @@ def parse_restart_spec(restart_config): return {'Name': name, 'MaximumRetryCount': int(max_retry_count)} +def serialize_restart_spec(restart_spec): + parts = [restart_spec['Name']] + if restart_spec['MaximumRetryCount']: + parts.append(six.text_type(restart_spec['MaximumRetryCount'])) + return ':'.join(parts) + + def parse_extra_hosts(extra_hosts_config): if not extra_hosts_config: return {} diff --git a/tests/acceptance/cli_test.py b/tests/acceptance/cli_test.py index f7c958dd..515acb04 100644 --- a/tests/acceptance/cli_test.py +++ b/tests/acceptance/cli_test.py @@ -190,6 +190,33 @@ class CLITestCase(DockerClientTestCase): } assert output == expected + def test_config_restart(self): + self.base_dir = 'tests/fixtures/restart' + result = self.dispatch(['config']) + assert yaml.load(result.stdout) == { + 'version': '2.0', + 'services': { + 'never': { + 'image': 'busybox', + 'restart': 'no', + }, + 'always': { + 'image': 'busybox', + 'restart': 'always', + }, + 'on-failure': { + 'image': 'busybox', + 'restart': 'on-failure', + }, + 'on-failure-5': { + 'image': 'busybox', + 'restart': 'on-failure:5', + }, + }, + 'networks': {}, + 'volumes': {}, + } + def test_config_v1(self): self.base_dir = 'tests/fixtures/v1-config' result = self.dispatch(['config']) diff --git a/tests/fixtures/restart/docker-compose.yml b/tests/fixtures/restart/docker-compose.yml new file mode 100644 index 00000000..2d10aa39 --- /dev/null +++ b/tests/fixtures/restart/docker-compose.yml @@ -0,0 +1,14 @@ +version: "2" +services: + never: + image: busybox + restart: "no" + always: + image: busybox + restart: always + on-failure: + image: busybox + restart: on-failure + on-failure-5: + image: busybox + restart: "on-failure:5"