From b9c70053f492bb04e98f1daf15e824b19e83ed6f Mon Sep 17 00:00:00 2001 From: Louis-Philippe Huberdeau Date: Fri, 12 Feb 2016 16:25:19 -0500 Subject: [PATCH] Round-robin container attribution on service network_mode instead of always attaching to the first container Signed-off-by: Louis-Philippe Huberdeau --- compose/service.py | 19 +++++++++++++++---- tests/unit/service_test.py | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/compose/service.py b/compose/service.py index 9dd2865b8d..edc6606036 100644 --- a/compose/service.py +++ b/compose/service.py @@ -621,11 +621,12 @@ def _get_container_create_options( container_options['host_config'] = self._get_container_host_config( override_options, - one_off=one_off) + one_off=one_off, + number=number) return container_options - def _get_container_host_config(self, override_options, one_off=False): + def _get_container_host_config(self, override_options, one_off=False, number=1): options = dict(self.options, **override_options) logging_dict = options.get('logging', None) @@ -637,7 +638,7 @@ def _get_container_host_config(self, override_options, one_off=False): binds=options.get('binds'), volumes_from=self._get_volumes_from(), privileged=options.get('privileged', False), - network_mode=self.network_mode.mode, + network_mode=self.network_mode.for_number(number), devices=options.get('devices'), dns=options.get('dns'), dns_search=options.get('dns_search'), @@ -790,6 +791,9 @@ def id(self): mode = id + def for_number(self, number): + return self.mode + class ContainerNetworkMode(object): """A network mode that uses a container's network stack.""" @@ -807,6 +811,9 @@ def id(self): def mode(self): return 'container:' + self.container.id + def for_number(self, number): + return self.mode + class ServiceNetworkMode(object): """A network mode that uses a service's network stack.""" @@ -822,9 +829,13 @@ def id(self): @property def mode(self): + return self.for_number(1) + + def for_number(self, number): containers = self.service.containers() if containers: - return 'container:' + containers[0].id + target_container = (number - 1) % len(containers) + return 'container:' + containers[target_container].id log.warn("Service %s is trying to use reuse the network stack " "of another service that is not running." % (self.id)) diff --git a/tests/unit/service_test.py b/tests/unit/service_test.py index f34de3bf12..f2dec2d2e3 100644 --- a/tests/unit/service_test.py +++ b/tests/unit/service_test.py @@ -631,6 +631,24 @@ def test_network_mode_service_no_containers(self): self.assertEqual(network_mode.mode, None) self.assertEqual(network_mode.service_name, service_name) + def test_network_mode_service_multiple_containers(self): + service_name = 'web' + mock_client = mock.create_autospec(docker.Client) + mock_client.containers.return_value = [ + {'Id': 'a', 'Name': 'a', 'Image': 'abcd'}, + {'Id': 'b', 'Name': 'b', 'Image': 'abcd'}, + {'Id': 'c', 'Name': 'c', 'Image': 'abcd'}, + ] + + service = Service(name=service_name, client=mock_client) + network_mode = ServiceNetworkMode(service) + + self.assertEqual(network_mode.mode, 'container:a') + self.assertEqual(network_mode.for_number(1), 'container:a') + self.assertEqual(network_mode.for_number(2), 'container:b') + self.assertEqual(network_mode.for_number(3), 'container:c') + self.assertEqual(network_mode.for_number(4), 'container:a') + def build_mount(destination, source, mode='rw'): return {'Source': source, 'Destination': destination, 'Mode': mode}