Skip to content

Commit bd658f7

Browse files
committed
Merge pull request #895 from aanand/alias
Implement support for network-scoped aliases
2 parents e2878cb + d00a5bb commit bd658f7

File tree

8 files changed

+136
-10
lines changed

8 files changed

+136
-10
lines changed

docker/api/container.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from .. import errors
66
from .. import utils
7+
from ..utils.utils import create_networking_config, create_endpoint_config
78

89

910
class ContainerApiMixin(object):
@@ -98,7 +99,7 @@ def create_container(self, image, command=None, hostname=None, user=None,
9899
cpu_shares=None, working_dir=None, domainname=None,
99100
memswap_limit=None, cpuset=None, host_config=None,
100101
mac_address=None, labels=None, volume_driver=None,
101-
stop_signal=None):
102+
stop_signal=None, networking_config=None):
102103

103104
if isinstance(volumes, six.string_types):
104105
volumes = [volumes, ]
@@ -113,7 +114,7 @@ def create_container(self, image, command=None, hostname=None, user=None,
113114
tty, mem_limit, ports, environment, dns, volumes, volumes_from,
114115
network_disabled, entrypoint, cpu_shares, working_dir, domainname,
115116
memswap_limit, cpuset, host_config, mac_address, labels,
116-
volume_driver, stop_signal
117+
volume_driver, stop_signal, networking_config,
117118
)
118119
return self.create_container_from_config(config, name)
119120

@@ -139,6 +140,12 @@ def create_host_config(self, *args, **kwargs):
139140
kwargs['version'] = self._version
140141
return utils.create_host_config(*args, **kwargs)
141142

143+
def create_networking_config(self, *args, **kwargs):
144+
return create_networking_config(*args, **kwargs)
145+
146+
def create_endpoint_config(self, *args, **kwargs):
147+
return create_endpoint_config(self._version, *args, **kwargs)
148+
142149
@utils.check_resource
143150
def diff(self, container):
144151
return self._result(

docker/api/network.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,13 @@ def inspect_network(self, net_id):
4747

4848
@check_resource
4949
@minimum_version('1.21')
50-
def connect_container_to_network(self, container, net_id):
51-
data = {"container": container}
50+
def connect_container_to_network(self, container, net_id, aliases=None):
51+
data = {
52+
"Container": container,
53+
"EndpointConfig": {
54+
"Aliases": aliases,
55+
},
56+
}
5257
url = self._url("/networks/{0}/connect", net_id)
5358
self._post_json(url, data=data)
5459

docker/utils/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
kwargs_from_env, convert_filters, datetime_to_timestamp, create_host_config,
55
create_container_config, parse_bytes, ping_registry, parse_env_file,
66
version_lt, version_gte, decode_json_header, split_command,
7-
create_ipam_config, create_ipam_pool
7+
create_ipam_config, create_ipam_pool,
88
) # flake8: noqa
99

1010
from .types import Ulimit, LogConfig # flake8: noqa

docker/utils/utils.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,26 @@ def create_host_config(binds=None, port_bindings=None, lxc_conf=None,
715715
return host_config
716716

717717

718+
def create_networking_config(endpoints_config=None):
719+
networking_config = {}
720+
721+
if endpoints_config:
722+
networking_config["EndpointsConfig"] = endpoints_config
723+
724+
return networking_config
725+
726+
727+
def create_endpoint_config(version, aliases=None):
728+
endpoint_config = {}
729+
730+
if aliases:
731+
if version_lt(version, '1.22'):
732+
raise host_config_version_error('endpoint_config.aliases', '1.22')
733+
endpoint_config["Aliases"] = aliases
734+
735+
return endpoint_config
736+
737+
718738
def parse_env_file(env_file):
719739
"""
720740
Reads a line-separated environment file.
@@ -752,7 +772,7 @@ def create_container_config(
752772
dns=None, volumes=None, volumes_from=None, network_disabled=False,
753773
entrypoint=None, cpu_shares=None, working_dir=None, domainname=None,
754774
memswap_limit=None, cpuset=None, host_config=None, mac_address=None,
755-
labels=None, volume_driver=None, stop_signal=None
775+
labels=None, volume_driver=None, stop_signal=None, networking_config=None,
756776
):
757777
if isinstance(command, six.string_types):
758778
command = split_command(command)
@@ -878,6 +898,7 @@ def create_container_config(
878898
'WorkingDir': working_dir,
879899
'MemorySwap': memswap_limit,
880900
'HostConfig': host_config,
901+
'NetworkingConfig': networking_config,
881902
'MacAddress': mac_address,
882903
'Labels': labels,
883904
'VolumeDriver': volume_driver,

tests/integration/network_test.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
from ..base import requires_api_version
88

99

10-
@requires_api_version('1.21')
1110
class TestNetworks(helpers.BaseTestCase):
1211
def create_network(self, *args, **kwargs):
1312
net_name = u'dockerpy{}'.format(random.getrandbits(24))[:14]
1413
net_id = self.client.create_network(net_name, *args, **kwargs)['Id']
1514
self.tmp_networks.append(net_id)
1615
return (net_name, net_id)
1716

17+
@requires_api_version('1.21')
1818
def test_list_networks(self):
1919
networks = self.client.networks()
2020
initial_size = len(networks)
@@ -31,6 +31,7 @@ def test_list_networks(self):
3131
networks_by_partial_id = self.client.networks(ids=[net_id[:8]])
3232
self.assertEqual([n['Id'] for n in networks_by_partial_id], [net_id])
3333

34+
@requires_api_version('1.21')
3435
def test_inspect_network(self):
3536
net_name, net_id = self.create_network()
3637

@@ -41,12 +42,14 @@ def test_inspect_network(self):
4142
self.assertEqual(net['Scope'], 'local')
4243
self.assertEqual(net['IPAM']['Driver'], 'default')
4344

45+
@requires_api_version('1.21')
4446
def test_create_network_with_host_driver_fails(self):
4547
net_name = 'dockerpy{}'.format(random.getrandbits(24))[:14]
4648

4749
with pytest.raises(docker.errors.APIError):
4850
self.client.create_network(net_name, driver='host')
4951

52+
@requires_api_version('1.21')
5053
def test_remove_network(self):
5154
initial_size = len(self.client.networks())
5255

@@ -56,6 +59,7 @@ def test_remove_network(self):
5659
self.client.remove_network(net_id)
5760
self.assertEqual(len(self.client.networks()), initial_size)
5861

62+
@requires_api_version('1.21')
5963
def test_connect_and_disconnect_container(self):
6064
net_name, net_id = self.create_network()
6165

@@ -76,6 +80,22 @@ def test_connect_and_disconnect_container(self):
7680
network_data = self.client.inspect_network(net_id)
7781
self.assertFalse(network_data.get('Containers'))
7882

83+
@requires_api_version('1.22')
84+
def test_connect_with_aliases(self):
85+
net_name, net_id = self.create_network()
86+
87+
container = self.client.create_container('busybox', 'top')
88+
self.tmp_containers.append(container)
89+
self.client.start(container)
90+
91+
self.client.connect_container_to_network(
92+
container, net_id, aliases=['foo', 'bar'])
93+
container_data = self.client.inspect_container(container)
94+
self.assertEqual(
95+
container_data['NetworkSettings']['Networks'][net_name]['Aliases'],
96+
['foo', 'bar'])
97+
98+
@requires_api_version('1.21')
7999
def test_connect_on_container_create(self):
80100
net_name, net_id = self.create_network()
81101

@@ -95,3 +115,27 @@ def test_connect_on_container_create(self):
95115
self.client.disconnect_container_from_network(container, net_id)
96116
network_data = self.client.inspect_network(net_id)
97117
self.assertFalse(network_data.get('Containers'))
118+
119+
@requires_api_version('1.22')
120+
def test_create_with_aliases(self):
121+
net_name, net_id = self.create_network()
122+
123+
container = self.client.create_container(
124+
image='busybox',
125+
command='top',
126+
host_config=self.client.create_host_config(
127+
network_mode=net_name,
128+
),
129+
networking_config=self.client.create_networking_config({
130+
net_name: self.client.create_endpoint_config(
131+
aliases=['foo', 'bar'],
132+
),
133+
}),
134+
)
135+
self.tmp_containers.append(container)
136+
self.client.start(container)
137+
138+
container_data = self.client.inspect_container(container)
139+
self.assertEqual(
140+
container_data['NetworkSettings']['Networks'][net_name]['Aliases'],
141+
['foo', 'bar'])

tests/unit/container_test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import six
88

99
from . import fake_api
10+
from ..base import requires_api_version
1011
from .api_test import (
1112
DockerClientTest, url_prefix, fake_request, DEFAULT_TIMEOUT_SECONDS,
1213
fake_inspect_container
@@ -983,6 +984,38 @@ def test_create_container_with_stop_signal(self):
983984
self.assertEqual(args[1]['headers'],
984985
{'Content-Type': 'application/json'})
985986

987+
@requires_api_version('1.22')
988+
def test_create_container_with_aliases(self):
989+
self.client.create_container(
990+
'busybox', 'ls',
991+
host_config=self.client.create_host_config(
992+
network_mode='some-network',
993+
),
994+
networking_config=self.client.create_networking_config({
995+
'some-network': self.client.create_endpoint_config(
996+
aliases=['foo', 'bar'],
997+
),
998+
}),
999+
)
1000+
1001+
args = fake_request.call_args
1002+
self.assertEqual(json.loads(args[1]['data']),
1003+
json.loads('''
1004+
{"Tty": false, "Image": "busybox",
1005+
"Cmd": ["ls"], "AttachStdin": false,
1006+
"AttachStderr": true,
1007+
"AttachStdout": true, "OpenStdin": false,
1008+
"StdinOnce": false,
1009+
"NetworkDisabled": false,
1010+
"HostConfig": {
1011+
"NetworkMode": "some-network"
1012+
},
1013+
"NetworkingConfig": {
1014+
"EndpointsConfig": {
1015+
"some-network": {"Aliases": ["foo", "bar"]}
1016+
}
1017+
}}'''))
1018+
9861019

9871020
class ContainerTest(DockerClientTest):
9881021
def test_list_containers(self):

tests/unit/network_test.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,23 @@ def test_connect_container_to_network(self):
147147

148148
with mock.patch('docker.Client.post', post):
149149
self.client.connect_container_to_network(
150-
{'Id': container_id}, network_id)
150+
{'Id': container_id},
151+
network_id,
152+
aliases=['foo', 'bar'],
153+
)
151154

152155
self.assertEqual(
153156
post.call_args[0][0],
154157
url_prefix + 'networks/{0}/connect'.format(network_id))
155158

156159
self.assertEqual(
157160
json.loads(post.call_args[1]['data']),
158-
{'container': container_id})
161+
{
162+
'Container': container_id,
163+
'EndpointConfig': {
164+
'Aliases': ['foo', 'bar'],
165+
},
166+
})
159167

160168
@base.requires_api_version('1.21')
161169
def test_disconnect_container_from_network(self):

tests/unit/utils_test.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
parse_repository_tag, parse_host, convert_filters, kwargs_from_env,
1919
create_host_config, Ulimit, LogConfig, parse_bytes, parse_env_file,
2020
exclude_paths, convert_volume_binds, decode_json_header, tar,
21-
split_command, create_ipam_config, create_ipam_pool
21+
split_command, create_ipam_config, create_ipam_pool,
2222
)
23+
from docker.utils.utils import create_endpoint_config
2324
from docker.utils.ports import build_port_bindings, split_port
2425

2526
from .. import base
@@ -69,6 +70,13 @@ def test_create_host_config_with_oom_kill_disable(self):
6970
InvalidVersion, lambda: create_host_config(version='1.18.3',
7071
oom_kill_disable=True))
7172

73+
def test_create_endpoint_config_with_aliases(self):
74+
config = create_endpoint_config(version='1.22', aliases=['foo', 'bar'])
75+
assert config == {'Aliases': ['foo', 'bar']}
76+
77+
with pytest.raises(InvalidVersion):
78+
create_endpoint_config(version='1.21', aliases=['foo', 'bar'])
79+
7280

7381
class UlimitTest(base.BaseTestCase):
7482
def test_create_host_config_dict_ulimit(self):

0 commit comments

Comments
 (0)