diff options
author | Joffrey F <joffrey@docker.com> | 2015-10-08 08:02:48 -0700 |
---|---|---|
committer | Joffrey F <joffrey@docker.com> | 2015-10-08 08:02:48 -0700 |
commit | 77df9c485d1b7f1efbb91f655d3cf19a18a6e3da (patch) | |
tree | e1d6125270a8c02022562e38f9331a3eee87e213 | |
parent | 73e45ef3598dafd2ffbcc2e14b779f2ae0aa761d (diff) | |
parent | 75e55f1805cbe7d40e340629bf32ac889131d260 (diff) | |
download | docker-py-77df9c485d1b7f1efbb91f655d3cf19a18a6e3da.tar.gz |
Merge branch 'aanand-networking'
-rw-r--r-- | docker/api/__init__.py | 1 | ||||
-rw-r--r-- | docker/api/network.py | 55 | ||||
-rw-r--r-- | docker/client.py | 3 | ||||
-rw-r--r-- | tests/integration_test.py | 104 | ||||
-rw-r--r-- | tests/test.py | 134 |
5 files changed, 296 insertions, 1 deletions
diff --git a/docker/api/__init__.py b/docker/api/__init__.py index 7979634..9e74428 100644 --- a/docker/api/__init__.py +++ b/docker/api/__init__.py @@ -5,3 +5,4 @@ from .daemon import DaemonApiMixin from .exec_api import ExecApiMixin from .image import ImageApiMixin from .volume import VolumeApiMixin +from .network import NetworkApiMixin diff --git a/docker/api/network.py b/docker/api/network.py new file mode 100644 index 0000000..2dea679 --- /dev/null +++ b/docker/api/network.py @@ -0,0 +1,55 @@ +import json + +from ..utils import check_resource, minimum_version + + +class NetworkApiMixin(object): + @minimum_version('1.21') + def networks(self, names=None, ids=None): + filters = {} + if names: + filters['name'] = names + if ids: + filters['id'] = ids + + params = {'filters': json.dumps(filters)} + + url = self._url("/networks") + res = self._get(url, params=params) + return self._result(res, json=True) + + @minimum_version('1.21') + def create_network(self, name, driver=None): + data = { + 'name': name, + 'driver': driver, + } + url = self._url("/networks/create") + res = self._post_json(url, data=data) + return self._result(res, json=True) + + @minimum_version('1.21') + def remove_network(self, net_id): + url = self._url("/networks/{0}", net_id) + res = self._delete(url) + self._raise_for_status(res) + + @minimum_version('1.21') + def inspect_network(self, net_id): + url = self._url("/networks/{0}", net_id) + res = self._get(url) + return self._result(res, json=True) + + @check_resource + @minimum_version('1.21') + def connect_container_to_network(self, container, net_id): + data = {"container": container} + url = self._url("/networks/{0}/connect", net_id) + self._post_json(url, data=data) + + @check_resource + @minimum_version('1.21') + def disconnect_container_from_network(self, container, net_id): + data = {"container": container} + url = self._url("/networks/{0}/disconnect", net_id) + self._post_json(url, data=data) diff --git a/docker/client.py b/docker/client.py index 9decd61..79efc9f 100644 --- a/docker/client.py +++ b/docker/client.py @@ -39,7 +39,8 @@ class Client( api.DaemonApiMixin, api.ExecApiMixin, api.ImageApiMixin, - api.VolumeApiMixin): + api.VolumeApiMixin, + api.NetworkApiMixin): def __init__(self, base_url=None, version=None, timeout=constants.DEFAULT_TIMEOUT_SECONDS, tls=False): super(Client, self).__init__() diff --git a/tests/integration_test.py b/tests/integration_test.py index a715ef6..f4e2089 100644 --- a/tests/integration_test.py +++ b/tests/integration_test.py @@ -21,6 +21,7 @@ import random import shutil import signal import socket +import sys import tarfile import tempfile import threading @@ -95,6 +96,7 @@ class BaseTestCase(unittest.TestCase): self.tmp_containers = [] self.tmp_folders = [] self.tmp_volumes = [] + self.tmp_networks = [] def tearDown(self): for img in self.tmp_imgs: @@ -108,6 +110,11 @@ class BaseTestCase(unittest.TestCase): self.client.remove_container(container) except docker.errors.APIError: pass + for network in self.tmp_networks: + try: + self.client.remove_network(network) + except docker.errors.APIError: + pass for folder in self.tmp_folders: shutil.rmtree(folder) @@ -1590,6 +1597,103 @@ class TestBuildWithDockerignore(Cleanup, BaseTestCase): ['not-ignored'], ) + +####################### +# NETWORK TESTS # +####################### + + +@requires_api_version('1.21') +class TestNetworks(BaseTestCase): + def create_network(self, *args, **kwargs): + net_name = 'dockerpy{}'.format(random.randrange(sys.maxint))[:14] + net_id = self.client.create_network(net_name, *args, **kwargs)['id'] + self.tmp_networks.append(net_id) + return (net_name, net_id) + + def test_list_networks(self): + networks = self.client.networks() + initial_size = len(networks) + + net_name, net_id = self.create_network() + + networks = self.client.networks() + self.assertEqual(len(networks), initial_size + 1) + self.assertTrue(net_id in [n['id'] for n in networks]) + + networks_by_name = self.client.networks(names=[net_name]) + self.assertEqual([n['id'] for n in networks_by_name], [net_id]) + + networks_by_partial_id = self.client.networks(ids=[net_id[:8]]) + self.assertEqual([n['id'] for n in networks_by_partial_id], [net_id]) + + def test_inspect_network(self): + net_name, net_id = self.create_network() + + net = self.client.inspect_network(net_id) + self.assertEqual(net, { + u'name': net_name, + u'id': net_id, + u'driver': 'bridge', + u'containers': {}, + }) + + def test_create_network_with_host_driver_fails(self): + net_name = 'dockerpy{}'.format(random.randrange(sys.maxint))[:14] + + with pytest.raises(APIError): + self.client.create_network(net_name, driver='host') + + def test_remove_network(self): + initial_size = len(self.client.networks()) + + net_name, net_id = self.create_network() + self.assertEqual(len(self.client.networks()), initial_size + 1) + + self.client.remove_network(net_id) + self.assertEqual(len(self.client.networks()), initial_size) + + def test_connect_and_disconnect_container(self): + net_name, net_id = self.create_network() + + container = self.client.create_container('busybox', 'top') + self.tmp_containers.append(container) + self.client.start(container) + + network_data = self.client.inspect_network(net_id) + self.assertFalse(network_data.get('containers')) + + self.client.connect_container_to_network(container, net_id) + network_data = self.client.inspect_network(net_id) + self.assertEqual( + list(network_data['containers'].keys()), + [container['Id']]) + + self.client.disconnect_container_from_network(container, net_id) + network_data = self.client.inspect_network(net_id) + self.assertFalse(network_data.get('containers')) + + def test_connect_on_container_create(self): + net_name, net_id = self.create_network() + + container = self.client.create_container( + image='busybox', + command='top', + host_config=self.client.create_host_config(network_mode=net_name), + ) + self.tmp_containers.append(container) + self.client.start(container) + + network_data = self.client.inspect_network(net_id) + self.assertEqual( + list(network_data['containers'].keys()), + [container['Id']]) + + self.client.disconnect_container_from_network(container, net_id) + network_data = self.client.inspect_network(net_id) + self.assertFalse(network_data.get('containers')) + + ####################### # PY SPECIFIC TESTS # ####################### diff --git a/tests/test.py b/tests/test.py index 719ac9e..42c925f 100644 --- a/tests/test.py +++ b/tests/test.py @@ -369,6 +369,41 @@ class DockerClientTest(Cleanup, base.BaseTestCase): timeout=DEFAULT_TIMEOUT_SECONDS ) + def test_list_networks(self): + networks = [ + { + "name": "none", + "id": "8e4e55c6863ef424", + "type": "null", + "endpoints": [] + }, + { + "name": "host", + "id": "062b6d9ea7913fde", + "type": "host", + "endpoints": [] + }, + ] + + get = mock.Mock(return_value=response( + status_code=200, content=json.dumps(networks).encode('utf-8'))) + + with mock.patch('docker.Client.get', get): + self.assertEqual(self.client.networks(), networks) + + self.assertEqual(get.call_args[0][0], url_prefix + 'networks') + + filters = json.loads(get.call_args[1]['params']['filters']) + self.assertFalse(filters) + + self.client.networks(names=['foo']) + filters = json.loads(get.call_args[1]['params']['filters']) + self.assertEqual(filters, {'name': ['foo']}) + + self.client.networks(ids=['123']) + filters = json.loads(get.call_args[1]['params']['filters']) + self.assertEqual(filters, {'id': ['123']}) + ##################### # CONTAINER TESTS # ##################### @@ -2229,6 +2264,105 @@ class DockerClientTest(Cleanup, base.BaseTestCase): self.assertEqual(args[0][0], 'DELETE') self.assertEqual(args[0][1], '{0}volumes/{1}'.format(url_prefix, name)) + ##################### + # NETWORK TESTS # + ##################### + + def test_create_network(self): + network_data = { + "id": 'abc12345', + "warning": "", + } + + network_response = response(status_code=200, content=network_data) + post = mock.Mock(return_value=network_response) + + with mock.patch('docker.Client.post', post): + result = self.client.create_network('foo') + self.assertEqual(result, network_data) + + self.assertEqual( + post.call_args[0][0], + url_prefix + 'networks/create') + + self.assertEqual( + json.loads(post.call_args[1]['data']), + {"name": "foo"}) + + self.client.create_network('foo', 'bridge') + + self.assertEqual( + json.loads(post.call_args[1]['data']), + {"name": "foo", "driver": "bridge"}) + + def test_remove_network(self): + network_id = 'abc12345' + delete = mock.Mock(return_value=response(status_code=200)) + + with mock.patch('docker.Client.delete', delete): + self.client.remove_network(network_id) + + args = delete.call_args + self.assertEqual(args[0][0], + url_prefix + 'networks/{0}'.format(network_id)) + + def test_inspect_network(self): + network_id = 'abc12345' + network_name = 'foo' + network_data = { + six.u('name'): network_name, + six.u('id'): network_id, + six.u('driver'): 'bridge', + six.u('containers'): {}, + } + + network_response = response(status_code=200, content=network_data) + get = mock.Mock(return_value=network_response) + + with mock.patch('docker.Client.get', get): + result = self.client.inspect_network(network_id) + self.assertEqual(result, network_data) + + args = get.call_args + self.assertEqual(args[0][0], + url_prefix + 'networks/{0}'.format(network_id)) + + def test_connect_container_to_network(self): + network_id = 'abc12345' + container_id = 'def45678' + + post = mock.Mock(return_value=response(status_code=201)) + + with mock.patch('docker.Client.post', post): + self.client.connect_container_to_network( + {'Id': container_id}, network_id) + + self.assertEqual( + post.call_args[0][0], + url_prefix + 'networks/{0}/connect'.format(network_id)) + + self.assertEqual( + json.loads(post.call_args[1]['data']), + {'container': container_id}) + + def test_disconnect_container_from_network(self): + network_id = 'abc12345' + container_id = 'def45678' + + post = mock.Mock(return_value=response(status_code=201)) + + with mock.patch('docker.Client.post', post): + self.client.disconnect_container_from_network( + {'Id': container_id}, network_id) + + self.assertEqual( + post.call_args[0][0], + url_prefix + 'networks/{0}/disconnect'.format(network_id)) + + self.assertEqual( + json.loads(post.call_args[1]['data']), + {'container': container_id}) + ####################### # PY SPECIFIC TESTS # ####################### |