From 7829b728a40b59b6efd1d0a3d8b92f48d351e5aa Mon Sep 17 00:00:00 2001 From: Viktor Adam Date: Thu, 16 Nov 2017 23:15:31 +0000 Subject: [PATCH 1/3] Fetch network details with network lists greedily Signed-off-by: Viktor Adam --- docker/api/network.py | 10 ++++-- docker/models/networks.py | 13 ++++++-- tests/integration/api_network_test.py | 37 +++++++++++++++++++++++ tests/integration/models_networks_test.py | 10 ++++-- tests/unit/models_networks_test.py | 8 +++-- 5 files changed, 70 insertions(+), 8 deletions(-) diff --git a/docker/api/network.py b/docker/api/network.py index 79778085..09f5a8bd 100644 --- a/docker/api/network.py +++ b/docker/api/network.py @@ -6,7 +6,7 @@ from .. import utils class NetworkApiMixin(object): @minimum_version('1.21') - def networks(self, names=None, ids=None, filters=None): + def networks(self, names=None, ids=None, filters=None, greedy=False): """ List networks. Similar to the ``docker networks ls`` command. @@ -18,6 +18,8 @@ class NetworkApiMixin(object): - ``driver=[]`` Matches a network's driver. - ``label=[]`` or ``label=[=]``. - ``type=["custom"|"builtin"]`` Filters networks by type. + greedy (bool): Fetch more details for each network individually. + You might want this to get the containers attached to them. Returns: (dict): List of network objects. @@ -36,7 +38,11 @@ class NetworkApiMixin(object): params = {'filters': utils.convert_filters(filters)} url = self._url("/networks") res = self._get(url, params=params) - return self._result(res, json=True) + result = self._result(res, json=True) + if greedy: + return [self.inspect_network(net['Id']) for net in result] + else: + return result @minimum_version('1.21') def create_network(self, name, driver=None, options=None, ipam=None, diff --git a/docker/models/networks.py b/docker/models/networks.py index 158af99b..06ff22b1 100644 --- a/docker/models/networks.py +++ b/docker/models/networks.py @@ -153,7 +153,7 @@ class NetworkCollection(Collection): resp = self.client.api.create_network(name, *args, **kwargs) return self.get(resp['Id']) - def get(self, network_id): + def get(self, network_id, *args, **kwargs): """ Get a network by its ID. @@ -175,7 +175,9 @@ class NetworkCollection(Collection): If the server returns an error. """ - return self.prepare_model(self.client.api.inspect_network(network_id)) + return self.prepare_model( + self.client.api.inspect_network(network_id, *args, **kwargs) + ) def list(self, *args, **kwargs): """ @@ -184,6 +186,13 @@ class NetworkCollection(Collection): Args: names (:py:class:`list`): List of names to filter by. ids (:py:class:`list`): List of ids to filter by. + filters (dict): Filters to be processed on the network list. + Available filters: + - ``driver=[]`` Matches a network's driver. + - ``label=[]`` or ``label=[=]``. + - ``type=["custom"|"builtin"]`` Filters networks by type. + greedy (bool): Fetch more details for each network individually. + You might want this to get the containers attached to them. Returns: (list of :py:class:`Network`) The networks on the server. diff --git a/tests/integration/api_network_test.py b/tests/integration/api_network_test.py index f4fefde5..57d26304 100644 --- a/tests/integration/api_network_test.py +++ b/tests/integration/api_network_test.py @@ -112,6 +112,16 @@ class TestNetworks(BaseAPIIntegrationTest): [container['Id']] ) + network_list = self.client.networks(ids=[net_id], greedy=True) + self.assertEqual( + list( + key + for net in network_list + for key in net['Containers'].keys() + ), + [container['Id']] + ) + with pytest.raises(docker.errors.APIError): self.client.connect_container_to_network(container, net_id) @@ -140,10 +150,27 @@ class TestNetworks(BaseAPIIntegrationTest): [container['Id']] ) + network_list = self.client.networks(ids=[net_id], greedy=True) + self.assertEqual( + list( + key + for net in network_list + for key in net['Containers'].keys() + ), + [container['Id']] + ) + self.client.disconnect_container_from_network(container, net_id, True) network_data = self.client.inspect_network(net_id) self.assertFalse(network_data.get('Containers')) + network_list = self.client.networks(ids=[net_id], greedy=True) + self.assertFalse(list( + key + for net in network_list + for key in net['Containers'].keys() + )) + with pytest.raises(docker.errors.APIError): self.client.disconnect_container_from_network( container, net_id, force=True @@ -183,6 +210,16 @@ class TestNetworks(BaseAPIIntegrationTest): list(network_data['Containers'].keys()), [container['Id']]) + network_list = self.client.networks(ids=[net_id], greedy=True) + self.assertEqual( + list( + key + for net in network_list + for key in net['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')) diff --git a/tests/integration/models_networks_test.py b/tests/integration/models_networks_test.py index 105dcc59..25fea33e 100644 --- a/tests/integration/models_networks_test.py +++ b/tests/integration/models_networks_test.py @@ -3,7 +3,7 @@ from .. import helpers from .base import BaseIntegrationTest, TEST_API_VERSION -class ImageCollectionTest(BaseIntegrationTest): +class NetworkCollectionTest(BaseIntegrationTest): def test_create(self): client = docker.from_env(version=TEST_API_VERSION) @@ -47,7 +47,7 @@ class ImageCollectionTest(BaseIntegrationTest): assert network.id not in [n.id for n in client.networks.list()] -class ImageTest(BaseIntegrationTest): +class NetworkTest(BaseIntegrationTest): def test_connect_disconnect(self): client = docker.from_env(version=TEST_API_VERSION) @@ -59,6 +59,12 @@ class ImageTest(BaseIntegrationTest): network.connect(container) container.start() assert client.networks.get(network.id).containers == [container] + network_containers = list( + c + for net in client.networks.list(greedy=True) + for c in net.containers + ) + assert network_containers == [container] network.disconnect(container) assert network.containers == [] assert client.networks.get(network.id).containers == [] diff --git a/tests/unit/models_networks_test.py b/tests/unit/models_networks_test.py index 943b9045..df0650a2 100644 --- a/tests/unit/models_networks_test.py +++ b/tests/unit/models_networks_test.py @@ -4,7 +4,7 @@ from .fake_api import FAKE_NETWORK_ID, FAKE_CONTAINER_ID from .fake_api_client import make_fake_client -class ImageCollectionTest(unittest.TestCase): +class NetworkCollectionTest(unittest.TestCase): def test_create(self): client = make_fake_client() @@ -36,8 +36,12 @@ class ImageCollectionTest(unittest.TestCase): client.networks.list(names=["foobar"]) assert client.api.networks.called_once_with(names=["foobar"]) + client = make_fake_client() + client.networks.list(greedy=True) + assert client.api.networks.called_once_with(greedy=True) -class ImageTest(unittest.TestCase): + +class NetworkTest(unittest.TestCase): def test_connect(self): client = make_fake_client() From 2878900a71a026803fd89cc14c47ac31adbf1485 Mon Sep 17 00:00:00 2001 From: Viktor Adam Date: Sun, 19 Nov 2017 21:03:07 +0000 Subject: [PATCH 2/3] Fixing integration tests Signed-off-by: Viktor Adam --- tests/integration/api_network_test.py | 4 ++++ tests/integration/models_networks_test.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/integration/api_network_test.py b/tests/integration/api_network_test.py index 57d26304..bb900d45 100644 --- a/tests/integration/api_network_test.py +++ b/tests/integration/api_network_test.py @@ -118,6 +118,7 @@ class TestNetworks(BaseAPIIntegrationTest): key for net in network_list for key in net['Containers'].keys() + if net['Id'] == net_id ), [container['Id']] ) @@ -156,6 +157,7 @@ class TestNetworks(BaseAPIIntegrationTest): key for net in network_list for key in net['Containers'].keys() + if net['Id'] == net_id ), [container['Id']] ) @@ -169,6 +171,7 @@ class TestNetworks(BaseAPIIntegrationTest): key for net in network_list for key in net['Containers'].keys() + if net['Id'] == net_id )) with pytest.raises(docker.errors.APIError): @@ -216,6 +219,7 @@ class TestNetworks(BaseAPIIntegrationTest): key for net in network_list for key in net['Containers'].keys() + if net['Id'] == net_id ), [container['Id']] ) diff --git a/tests/integration/models_networks_test.py b/tests/integration/models_networks_test.py index 25fea33e..08d7ad29 100644 --- a/tests/integration/models_networks_test.py +++ b/tests/integration/models_networks_test.py @@ -61,7 +61,7 @@ class NetworkTest(BaseIntegrationTest): assert client.networks.get(network.id).containers == [container] network_containers = list( c - for net in client.networks.list(greedy=True) + for net in client.networks.list(ids=[network.id], greedy=True) for c in net.containers ) assert network_containers == [container] From 36ed843e2bbfd50698c16bfbd898d915019ca94d Mon Sep 17 00:00:00 2001 From: Viktor Adam Date: Tue, 21 Nov 2017 21:59:11 +0000 Subject: [PATCH 3/3] Only allow greedy queries on the model Signed-off-by: Viktor Adam --- docker/api/network.py | 10 ++----- docker/models/networks.py | 8 +++++- tests/integration/api_network_test.py | 41 --------------------------- tests/unit/models_networks_test.py | 4 --- 4 files changed, 9 insertions(+), 54 deletions(-) diff --git a/docker/api/network.py b/docker/api/network.py index 09f5a8bd..79778085 100644 --- a/docker/api/network.py +++ b/docker/api/network.py @@ -6,7 +6,7 @@ from .. import utils class NetworkApiMixin(object): @minimum_version('1.21') - def networks(self, names=None, ids=None, filters=None, greedy=False): + def networks(self, names=None, ids=None, filters=None): """ List networks. Similar to the ``docker networks ls`` command. @@ -18,8 +18,6 @@ class NetworkApiMixin(object): - ``driver=[]`` Matches a network's driver. - ``label=[]`` or ``label=[=]``. - ``type=["custom"|"builtin"]`` Filters networks by type. - greedy (bool): Fetch more details for each network individually. - You might want this to get the containers attached to them. Returns: (dict): List of network objects. @@ -38,11 +36,7 @@ class NetworkApiMixin(object): params = {'filters': utils.convert_filters(filters)} url = self._url("/networks") res = self._get(url, params=params) - result = self._result(res, json=True) - if greedy: - return [self.inspect_network(net['Id']) for net in result] - else: - return result + return self._result(res, json=True) @minimum_version('1.21') def create_network(self, name, driver=None, options=None, ipam=None, diff --git a/docker/models/networks.py b/docker/models/networks.py index 06ff22b1..1c2fbf24 100644 --- a/docker/models/networks.py +++ b/docker/models/networks.py @@ -1,4 +1,5 @@ from ..api import APIClient +from ..utils import version_gte from .containers import Container from .resource import Model, Collection @@ -201,8 +202,13 @@ class NetworkCollection(Collection): :py:class:`docker.errors.APIError` If the server returns an error. """ + greedy = kwargs.pop('greedy', False) resp = self.client.api.networks(*args, **kwargs) - return [self.prepare_model(item) for item in resp] + networks = [self.prepare_model(item) for item in resp] + if greedy and version_gte(self.client.api._version, '1.28'): + for net in networks: + net.reload() + return networks def prune(self, filters=None): self.client.api.prune_networks(filters=filters) diff --git a/tests/integration/api_network_test.py b/tests/integration/api_network_test.py index bb900d45..f4fefde5 100644 --- a/tests/integration/api_network_test.py +++ b/tests/integration/api_network_test.py @@ -112,17 +112,6 @@ class TestNetworks(BaseAPIIntegrationTest): [container['Id']] ) - network_list = self.client.networks(ids=[net_id], greedy=True) - self.assertEqual( - list( - key - for net in network_list - for key in net['Containers'].keys() - if net['Id'] == net_id - ), - [container['Id']] - ) - with pytest.raises(docker.errors.APIError): self.client.connect_container_to_network(container, net_id) @@ -151,29 +140,10 @@ class TestNetworks(BaseAPIIntegrationTest): [container['Id']] ) - network_list = self.client.networks(ids=[net_id], greedy=True) - self.assertEqual( - list( - key - for net in network_list - for key in net['Containers'].keys() - if net['Id'] == net_id - ), - [container['Id']] - ) - self.client.disconnect_container_from_network(container, net_id, True) network_data = self.client.inspect_network(net_id) self.assertFalse(network_data.get('Containers')) - network_list = self.client.networks(ids=[net_id], greedy=True) - self.assertFalse(list( - key - for net in network_list - for key in net['Containers'].keys() - if net['Id'] == net_id - )) - with pytest.raises(docker.errors.APIError): self.client.disconnect_container_from_network( container, net_id, force=True @@ -213,17 +183,6 @@ class TestNetworks(BaseAPIIntegrationTest): list(network_data['Containers'].keys()), [container['Id']]) - network_list = self.client.networks(ids=[net_id], greedy=True) - self.assertEqual( - list( - key - for net in network_list - for key in net['Containers'].keys() - if net['Id'] == net_id - ), - [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')) diff --git a/tests/unit/models_networks_test.py b/tests/unit/models_networks_test.py index df0650a2..58c9fce6 100644 --- a/tests/unit/models_networks_test.py +++ b/tests/unit/models_networks_test.py @@ -36,10 +36,6 @@ class NetworkCollectionTest(unittest.TestCase): client.networks.list(names=["foobar"]) assert client.api.networks.called_once_with(names=["foobar"]) - client = make_fake_client() - client.networks.list(greedy=True) - assert client.api.networks.called_once_with(greedy=True) - class NetworkTest(unittest.TestCase):