Skip to content

Commit 080b471

Browse files
authored
Merge pull request #1083 from docker/1042-ip-networking-config
Support ipv4_address and ipv6_address in create_endpoint_config
2 parents f4de376 + d991db5 commit 080b471

File tree

5 files changed

+237
-31
lines changed

5 files changed

+237
-31
lines changed

docker/api/network.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json
22

33
from ..errors import InvalidVersion
4-
from ..utils import check_resource, minimum_version, normalize_links
4+
from ..utils import check_resource, minimum_version
55
from ..utils import version_lt
66

77

@@ -63,26 +63,12 @@ def connect_container_to_network(self, container, net_id,
6363
aliases=None, links=None):
6464
data = {
6565
"Container": container,
66-
"EndpointConfig": {
67-
"Aliases": aliases,
68-
"Links": normalize_links(links) if links else None,
69-
},
66+
"EndpointConfig": self.create_endpoint_config(
67+
aliases=aliases, links=links, ipv4_address=ipv4_address,
68+
ipv6_address=ipv6_address
69+
),
7070
}
7171

72-
# IPv4 or IPv6 or neither:
73-
if ipv4_address or ipv6_address:
74-
if version_lt(self._version, '1.22'):
75-
raise InvalidVersion('IP address assignment is not '
76-
'supported in API version < 1.22')
77-
78-
data['EndpointConfig']['IPAMConfig'] = dict()
79-
if ipv4_address:
80-
data['EndpointConfig']['IPAMConfig']['IPv4Address'] = \
81-
ipv4_address
82-
if ipv6_address:
83-
data['EndpointConfig']['IPAMConfig']['IPv6Address'] = \
84-
ipv6_address
85-
8672
url = self._url("/networks/{0}/connect", net_id)
8773
res = self._post_json(url, data=data)
8874
self._raise_for_status(res)

docker/utils/utils.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -813,19 +813,30 @@ def create_networking_config(endpoints_config=None):
813813
return networking_config
814814

815815

816-
def create_endpoint_config(version, aliases=None, links=None):
816+
def create_endpoint_config(version, aliases=None, links=None,
817+
ipv4_address=None, ipv6_address=None):
818+
if version_lt(version, '1.22'):
819+
raise errors.InvalidVersion(
820+
'Endpoint config is not supported for API version < 1.22'
821+
)
817822
endpoint_config = {}
818823

819824
if aliases:
820-
if version_lt(version, '1.22'):
821-
raise host_config_version_error('endpoint_config.aliases', '1.22')
822825
endpoint_config["Aliases"] = aliases
823826

824827
if links:
825-
if version_lt(version, '1.22'):
826-
raise host_config_version_error('endpoint_config.links', '1.22')
827828
endpoint_config["Links"] = normalize_links(links)
828829

830+
ipam_config = {}
831+
if ipv4_address:
832+
ipam_config['IPv4Address'] = ipv4_address
833+
834+
if ipv6_address:
835+
ipam_config['IPv6Address'] = ipv6_address
836+
837+
if ipam_config:
838+
endpoint_config['IPAMConfig'] = ipam_config
839+
829840
return endpoint_config
830841

831842

docs/api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ from. Optionally a single string joining container id's with commas
242242
* labels (dict or list): A dictionary of name-value labels (e.g. `{"label1": "value1", "label2": "value2"}`) or a list of names of labels to set with empty values (e.g. `["label1", "label2"]`)
243243
* volume_driver (str): The name of a volume driver/plugin.
244244
* stop_signal (str): The stop signal to use to stop the container (e.g. `SIGINT`).
245+
* networking_config (dict): A [NetworkingConfig](networks.md) dictionary
245246

246247
**Returns** (dict): A dictionary with an image 'Id' key and a 'Warnings' key.
247248

docs/networks.md

Lines changed: 155 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,176 @@
11
# Using Networks
22

3+
## Network creation
4+
35
With the release of Docker 1.9 you can now manage custom networks.
46

57

6-
Here you can see how to create a network named ```network1``` using the ```bridge``` driver
8+
Here you can see how to create a network named `network1` using
9+
the `bridge` driver
710

811
```python
912
docker_client.create_network("network1", driver="bridge")
1013
```
1114

12-
You can also create more advanced networks with custom IPAM configurations. For example,
13-
setting the subnet to ```192.168.52.0/24``` and gateway to ```192.168.52.254```
15+
You can also create more advanced networks with custom IPAM configurations.
16+
For example, setting the subnet to `192.168.52.0/24` and gateway address
17+
to `192.168.52.254`
1418

1519
```python
16-
17-
ipam_config = docker.utils.create_ipam_config(subnet='192.168.52.0/24', gateway='192.168.52.254')
20+
ipam_pool = docker.utils.create_ipam_pool(
21+
subnet='192.168.52.0/24',
22+
gateway='192.168.52.254'
23+
)
24+
ipam_config = docker.utils.create_ipam_config(
25+
pool_configs=[ipam_pool]
26+
)
1827

1928
docker_client.create_network("network1", driver="bridge", ipam=ipam_config)
2029
```
2130

22-
With Docker 1.10 you can now also create internal networks
31+
By default, when you connect a container to an overlay network, Docker also
32+
connects a bridge network to it to provide external connectivity. If you want
33+
to create an externally isolated overlay network, with Docker 1.10 you can
34+
create an internal network.
2335

2436
```python
2537

2638
docker_client.create_network("network1", driver="bridge", internal=True)
2739
```
40+
41+
## Container network configuration
42+
43+
In order to specify which network a container will be connected to, and
44+
additional configuration, use the `networking_config` parameter in
45+
`Client.create_container`. Note that at the time of creation, you can
46+
only connect a container to a single network. Later on, you may create more
47+
connections using `Client.connect_container_to_network`.
48+
49+
50+
```python
51+
networking_config = docker_client.create_networking_config({
52+
'network1': docker_client.create_endpoint_config(
53+
ipv4_address='172.28.0.124',
54+
aliases=['foo', 'bar'],
55+
links=['container2']
56+
)
57+
})
58+
59+
ctnr = docker_client.create_container(
60+
img, command, networking_config=networking_config
61+
)
62+
63+
```
64+
65+
## Network API documentation
66+
67+
### Client.create_networking_config
68+
69+
Create a networking config dictionary to be used as the `networking_config`
70+
parameter in `Client.create_container_config`
71+
72+
**Params**:
73+
74+
* endpoints_config (dict): A dictionary of `network_name -> endpoint_config`
75+
relationships. Values should be endpoint config dictionaries created by
76+
`Client.create_endpoint_config`. Defaults to `None` (default config).
77+
78+
**Returns** A networking config dictionary.
79+
80+
```python
81+
82+
docker_client.create_network('network1')
83+
84+
networking_config = docker_client.create_networking_config({
85+
'network1': docker_client.create_endpoint_config()
86+
})
87+
88+
container = docker_client.create_container(
89+
img, command, networking_config=networking_config
90+
)
91+
```
92+
93+
94+
### Client.create_endpoint_config
95+
96+
Create an endpoint config dictionary to be used with
97+
`Client.create_networking_config`.
98+
99+
**Params**:
100+
101+
* aliases (list): A list of aliases for this endpoint. Names in that list can
102+
be used within the network to reach the container. Defaults to `None`.
103+
* links (list): A list of links for this endpoint. Containers declared in this
104+
list will be [linked](https://docs.docker.com/engine/userguide/networking/work-with-networks/#linking-containers-in-user-defined-networks)
105+
to this container. Defaults to `None`.
106+
* ipv4_address (str): The IP address of this container on the network,
107+
using the IPv4 protocol. Defaults to `None`.
108+
* ipv6_address (str): The IP address of this container on the network,
109+
using the IPv6 protocol. Defaults to `None`.
110+
111+
**Returns** An endpoint config dictionary.
112+
113+
```python
114+
endpoint_config = docker_client.create_endpoint_config(
115+
aliases=['web', 'app'],
116+
links=['app_db'],
117+
ipv4_address='132.65.0.123'
118+
)
119+
120+
docker_client.create_network('network1')
121+
networking_config = docker_client.create_networking_config({
122+
'network1': endpoint_config
123+
})
124+
container = docker_client.create_container(
125+
img, command, networking_config=networking_config
126+
)
127+
```
128+
### docker.utils.create_ipam_config
129+
130+
Create an IPAM (IP Address Management) config dictionary to be used with
131+
`Client.create_network`.
132+
133+
134+
**Params**:
135+
136+
* driver (str): The IPAM driver to use. Defaults to `'default'`.
137+
* pool_configs (list): A list of pool configuration dictionaries as created
138+
by `docker.utils.create_ipam_pool`. Defaults to empty list.
139+
140+
**Returns** An IPAM config dictionary
141+
142+
```python
143+
ipam_config = docker.utils.create_ipam_config(driver='default')
144+
network = docker_client.create_network('network1', ipam=ipam_config)
145+
```
146+
147+
### docker.utils.create_ipam_pool
148+
149+
Create an IPAM pool config dictionary to be added to the `pool_configs` param
150+
in `docker.utils.create_ipam_config`.
151+
152+
**Params**:
153+
154+
* subnet (str): Custom subnet for this IPAM pool using the CIDR notation.
155+
Defaults to `None`.
156+
* iprange (str): Custom IP range for endpoints in this IPAM pool using the
157+
CIDR notation. Defaults to `None`.
158+
* gateway (str): Custom IP address for the pool's gateway.
159+
* aux_addresses (dict): A dictionary of `key -> ip_address` relationships
160+
specifying auxiliary addresses that need to be allocated by the
161+
IPAM driver.
162+
163+
**Returns** An IPAM pool config dictionary
164+
165+
```python
166+
ipam_pool = docker.utils.create_ipam_pool(
167+
subnet='124.42.0.0/16',
168+
iprange='124.42.0.0/24',
169+
gateway='124.42.0.254',
170+
aux_addresses={
171+
'reserved1': '124.42.1.1'
172+
}
173+
)
174+
ipam_config = docker.utils.create_ipam_config(pool_configs=[ipam_pool])
175+
network = docker_client.create_network('network1', ipam=ipam_config)
176+
```

tests/integration/network_test.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,66 @@ def test_create_with_aliases(self):
185185
container_data = self.client.inspect_container(container)
186186
self.assertEqual(
187187
container_data['NetworkSettings']['Networks'][net_name]['Aliases'],
188-
['foo', 'bar'])
188+
['foo', 'bar']
189+
)
190+
191+
@requires_api_version('1.22')
192+
def test_create_with_ipv4_address(self):
193+
net_name, net_id = self.create_network(
194+
ipam=create_ipam_config(
195+
driver='default',
196+
pool_configs=[create_ipam_pool(subnet="132.124.0.0/16")],
197+
),
198+
)
199+
container = self.client.create_container(
200+
image='busybox', command='top',
201+
host_config=self.client.create_host_config(network_mode=net_name),
202+
networking_config=self.client.create_networking_config({
203+
net_name: self.client.create_endpoint_config(
204+
ipv4_address='132.124.0.23'
205+
)
206+
})
207+
)
208+
self.tmp_containers.append(container)
209+
self.client.start(container)
210+
211+
container_data = self.client.inspect_container(container)
212+
self.assertEqual(
213+
container_data[
214+
'NetworkSettings']['Networks'][net_name]['IPAMConfig'][
215+
'IPv4Address'
216+
],
217+
'132.124.0.23'
218+
)
219+
220+
@requires_api_version('1.22')
221+
def test_create_with_ipv6_address(self):
222+
net_name, net_id = self.create_network(
223+
ipam=create_ipam_config(
224+
driver='default',
225+
pool_configs=[create_ipam_pool(subnet="2001:389::1/64")],
226+
),
227+
)
228+
container = self.client.create_container(
229+
image='busybox', command='top',
230+
host_config=self.client.create_host_config(network_mode=net_name),
231+
networking_config=self.client.create_networking_config({
232+
net_name: self.client.create_endpoint_config(
233+
ipv6_address='2001:389::f00d'
234+
)
235+
})
236+
)
237+
self.tmp_containers.append(container)
238+
self.client.start(container)
239+
240+
container_data = self.client.inspect_container(container)
241+
self.assertEqual(
242+
container_data[
243+
'NetworkSettings']['Networks'][net_name]['IPAMConfig'][
244+
'IPv6Address'
245+
],
246+
'2001:389::f00d'
247+
)
189248

190249
@requires_api_version('1.22')
191250
def test_create_with_links(self):

0 commit comments

Comments
 (0)