Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Round-robin container attribution on service network_mode #2906

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions compose/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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'),
Expand Down Expand Up @@ -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."""
Expand All @@ -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."""
Expand All @@ -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))
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/service_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down