From 83b45b7d54e7011887b05fc9709ac4338f17339e Mon Sep 17 00:00:00 2001 From: Joffrey F Date: Mon, 30 Jan 2017 18:46:44 -0800 Subject: [PATCH] Add prune_networks method Ensure all integration tests use the same version of the busybox image Signed-off-by: Joffrey F --- docker/api/network.py | 22 ++++++++++++++++++++++ docker/models/networks.py | 5 +++++ tests/integration/api_image_test.py | 16 +++++++++++++++- tests/integration/api_network_test.py | 24 +++++++++++++++--------- tests/integration/api_service_test.py | 26 +++++++++++++------------- tests/integration/base.py | 2 +- 6 files changed, 71 insertions(+), 24 deletions(-) diff --git a/docker/api/network.py b/docker/api/network.py index 9f6d98fe..9652228d 100644 --- a/docker/api/network.py +++ b/docker/api/network.py @@ -133,6 +133,28 @@ class NetworkApiMixin(object): res = self._post_json(url, data=data) return self._result(res, json=True) + @minimum_version('1.25') + def prune_networks(self, filters=None): + """ + Delete unused networks + + Args: + filters (dict): Filters to process on the prune list. + + Returns: + (dict): A dict containing a list of deleted network names and + the amount of disk space reclaimed in bytes. + + Raises: + :py:class:`docker.errors.APIError` + If the server returns an error. + """ + params = {} + if filters: + params['filters'] = utils.convert_filters(filters) + url = self._url('/networks/prune') + return self._result(self._post(url, params=params), True) + @minimum_version('1.21') def remove_network(self, net_id): """ diff --git a/docker/models/networks.py b/docker/models/networks.py index a80c9f5f..a712e9bc 100644 --- a/docker/models/networks.py +++ b/docker/models/networks.py @@ -1,3 +1,4 @@ +from ..api import APIClient from .containers import Container from .resource import Model, Collection @@ -180,3 +181,7 @@ class NetworkCollection(Collection): """ resp = self.client.api.networks(*args, **kwargs) return [self.prepare_model(item) for item in resp] + + def prune(self, filters=None): + self.client.api.prune_networks(filters=filters) + prune.__doc__ = APIClient.prune_networks.__doc__ diff --git a/tests/integration/api_image_test.py b/tests/integration/api_image_test.py index 10e95fee..11146a8a 100644 --- a/tests/integration/api_image_test.py +++ b/tests/integration/api_image_test.py @@ -295,9 +295,23 @@ class PruneImagesTest(BaseAPIIntegrationTest): self.client.remove_image('hello-world') except docker.errors.APIError: pass + + # Ensure busybox does not get pruned + ctnr = self.client.create_container(BUSYBOX, ['sleep', '9999']) + self.tmp_containers.append(ctnr) + self.client.pull('hello-world') self.tmp_imgs.append('hello-world') img_id = self.client.inspect_image('hello-world')['Id'] result = self.client.prune_images() - assert img_id in [img['Deleted'] for img in result['ImagesDeleted']] + assert img_id not in [ + img.get('Deleted') for img in result['ImagesDeleted'] + ] + result = self.client.prune_images({'dangling': False}) assert result['SpaceReclaimed'] > 0 + assert 'hello-world:latest' in [ + img.get('Untagged') for img in result['ImagesDeleted'] + ] + assert img_id in [ + img.get('Deleted') for img in result['ImagesDeleted'] + ] diff --git a/tests/integration/api_network_test.py b/tests/integration/api_network_test.py index 2c297a00..ea6b02ea 100644 --- a/tests/integration/api_network_test.py +++ b/tests/integration/api_network_test.py @@ -3,7 +3,7 @@ from docker.types import IPAMConfig, IPAMPool import pytest from ..helpers import random_name, requires_api_version -from .base import BaseAPIIntegrationTest +from .base import BaseAPIIntegrationTest, BUSYBOX class TestNetworks(BaseAPIIntegrationTest): @@ -100,7 +100,7 @@ class TestNetworks(BaseAPIIntegrationTest): def test_connect_and_disconnect_container(self): net_name, net_id = self.create_network() - container = self.client.create_container('busybox', 'top') + container = self.client.create_container(BUSYBOX, 'top') self.tmp_containers.append(container) self.client.start(container) @@ -128,7 +128,7 @@ class TestNetworks(BaseAPIIntegrationTest): def test_connect_and_force_disconnect_container(self): net_name, net_id = self.create_network() - container = self.client.create_container('busybox', 'top') + container = self.client.create_container(BUSYBOX, 'top') self.tmp_containers.append(container) self.client.start(container) @@ -155,7 +155,7 @@ class TestNetworks(BaseAPIIntegrationTest): def test_connect_with_aliases(self): net_name, net_id = self.create_network() - container = self.client.create_container('busybox', 'top') + container = self.client.create_container(BUSYBOX, 'top') self.tmp_containers.append(container) self.client.start(container) @@ -173,7 +173,7 @@ class TestNetworks(BaseAPIIntegrationTest): net_name, net_id = self.create_network() container = self.client.create_container( - image='busybox', + image=BUSYBOX, command='top', host_config=self.client.create_host_config(network_mode=net_name), ) @@ -194,7 +194,7 @@ class TestNetworks(BaseAPIIntegrationTest): net_name, net_id = self.create_network() container = self.client.create_container( - image='busybox', + image=BUSYBOX, command='top', host_config=self.client.create_host_config( network_mode=net_name, @@ -224,7 +224,7 @@ class TestNetworks(BaseAPIIntegrationTest): ), ) container = self.client.create_container( - image='busybox', command='top', + image=BUSYBOX, command='top', host_config=self.client.create_host_config(network_mode=net_name), networking_config=self.client.create_networking_config({ net_name: self.client.create_endpoint_config( @@ -253,7 +253,7 @@ class TestNetworks(BaseAPIIntegrationTest): ), ) container = self.client.create_container( - image='busybox', command='top', + image=BUSYBOX, command='top', host_config=self.client.create_host_config(network_mode=net_name), networking_config=self.client.create_networking_config({ net_name: self.client.create_endpoint_config( @@ -276,7 +276,7 @@ class TestNetworks(BaseAPIIntegrationTest): @requires_api_version('1.24') def test_create_with_linklocal_ips(self): container = self.client.create_container( - 'busybox', 'top', + BUSYBOX, 'top', networking_config=self.client.create_networking_config( { 'bridge': self.client.create_endpoint_config( @@ -453,3 +453,9 @@ class TestNetworks(BaseAPIIntegrationTest): _, net_id = self.create_network(driver='overlay', attachable=True) net = self.client.inspect_network(net_id) assert net['Attachable'] is True + + @requires_api_version('1.25') + def test_prune_networks(self): + net_name, _ = self.create_network() + result = self.client.prune_networks() + assert net_name in result['NetworksDeleted'] diff --git a/tests/integration/api_service_test.py b/tests/integration/api_service_test.py index 46b0a79e..fe964596 100644 --- a/tests/integration/api_service_test.py +++ b/tests/integration/api_service_test.py @@ -3,7 +3,7 @@ import random import docker from ..helpers import force_leave_swarm, requires_api_version -from .base import BaseAPIIntegrationTest +from .base import BaseAPIIntegrationTest, BUSYBOX class ServiceTest(BaseAPIIntegrationTest): @@ -31,7 +31,7 @@ class ServiceTest(BaseAPIIntegrationTest): name = self.get_service_name() container_spec = docker.types.ContainerSpec( - 'busybox', ['echo', 'hello'] + BUSYBOX, ['echo', 'hello'] ) task_tmpl = docker.types.TaskTemplate(container_spec) return name, self.client.create_service(task_tmpl, name=name) @@ -81,7 +81,7 @@ class ServiceTest(BaseAPIIntegrationTest): def test_create_service_custom_log_driver(self): container_spec = docker.types.ContainerSpec( - 'busybox', ['echo', 'hello'] + BUSYBOX, ['echo', 'hello'] ) log_cfg = docker.types.DriverConfig('none') task_tmpl = docker.types.TaskTemplate( @@ -99,7 +99,7 @@ class ServiceTest(BaseAPIIntegrationTest): def test_create_service_with_volume_mount(self): vol_name = self.get_service_name() container_spec = docker.types.ContainerSpec( - 'busybox', ['ls'], + BUSYBOX, ['ls'], mounts=[ docker.types.Mount(target='/test', source=vol_name) ] @@ -119,7 +119,7 @@ class ServiceTest(BaseAPIIntegrationTest): assert mount['Type'] == 'volume' def test_create_service_with_resources_constraints(self): - container_spec = docker.types.ContainerSpec('busybox', ['true']) + container_spec = docker.types.ContainerSpec(BUSYBOX, ['true']) resources = docker.types.Resources( cpu_limit=4000000, mem_limit=3 * 1024 * 1024 * 1024, cpu_reservation=3500000, mem_reservation=2 * 1024 * 1024 * 1024 @@ -139,7 +139,7 @@ class ServiceTest(BaseAPIIntegrationTest): ] def test_create_service_with_update_config(self): - container_spec = docker.types.ContainerSpec('busybox', ['true']) + container_spec = docker.types.ContainerSpec(BUSYBOX, ['true']) task_tmpl = docker.types.TaskTemplate(container_spec) update_config = docker.types.UpdateConfig( parallelism=10, delay=5, failure_action='pause' @@ -173,7 +173,7 @@ class ServiceTest(BaseAPIIntegrationTest): assert update_config['MaxFailureRatio'] == uc['MaxFailureRatio'] def test_create_service_with_restart_policy(self): - container_spec = docker.types.ContainerSpec('busybox', ['true']) + container_spec = docker.types.ContainerSpec(BUSYBOX, ['true']) policy = docker.types.RestartPolicy( docker.types.RestartPolicy.condition_types.ANY, delay=5, max_attempts=5 @@ -196,7 +196,7 @@ class ServiceTest(BaseAPIIntegrationTest): 'dockerpytest_2', driver='overlay', ipam={'Driver': 'default'} ) self.tmp_networks.append(net2['Id']) - container_spec = docker.types.ContainerSpec('busybox', ['true']) + container_spec = docker.types.ContainerSpec(BUSYBOX, ['true']) task_tmpl = docker.types.TaskTemplate(container_spec) name = self.get_service_name() svc_id = self.client.create_service( @@ -212,7 +212,7 @@ class ServiceTest(BaseAPIIntegrationTest): def test_create_service_with_placement(self): node_id = self.client.nodes()[0]['ID'] - container_spec = docker.types.ContainerSpec('busybox', ['true']) + container_spec = docker.types.ContainerSpec(BUSYBOX, ['true']) task_tmpl = docker.types.TaskTemplate( container_spec, placement=['node.id=={}'.format(node_id)] ) @@ -224,7 +224,7 @@ class ServiceTest(BaseAPIIntegrationTest): {'Constraints': ['node.id=={}'.format(node_id)]}) def test_create_service_with_endpoint_spec(self): - container_spec = docker.types.ContainerSpec('busybox', ['true']) + container_spec = docker.types.ContainerSpec(BUSYBOX, ['true']) task_tmpl = docker.types.TaskTemplate(container_spec) name = self.get_service_name() endpoint_spec = docker.types.EndpointSpec(ports={ @@ -255,7 +255,7 @@ class ServiceTest(BaseAPIIntegrationTest): def test_create_service_with_env(self): container_spec = docker.types.ContainerSpec( - 'busybox', ['true'], env={'DOCKER_PY_TEST': 1} + BUSYBOX, ['true'], env={'DOCKER_PY_TEST': 1} ) task_tmpl = docker.types.TaskTemplate( container_spec, @@ -271,7 +271,7 @@ class ServiceTest(BaseAPIIntegrationTest): def test_create_service_global_mode(self): container_spec = docker.types.ContainerSpec( - 'busybox', ['echo', 'hello'] + BUSYBOX, ['echo', 'hello'] ) task_tmpl = docker.types.TaskTemplate(container_spec) name = self.get_service_name() @@ -284,7 +284,7 @@ class ServiceTest(BaseAPIIntegrationTest): def test_create_service_replicated_mode(self): container_spec = docker.types.ContainerSpec( - 'busybox', ['echo', 'hello'] + BUSYBOX, ['echo', 'hello'] ) task_tmpl = docker.types.TaskTemplate(container_spec) name = self.get_service_name() diff --git a/tests/integration/base.py b/tests/integration/base.py index f0f5a910..7da3aa75 100644 --- a/tests/integration/base.py +++ b/tests/integration/base.py @@ -81,7 +81,7 @@ class BaseAPIIntegrationTest(BaseIntegrationTest): return container - def create_and_start(self, image='busybox', command='top', **kwargs): + def create_and_start(self, image=BUSYBOX, command='top', **kwargs): container = self.client.create_container( image=image, command=command, **kwargs) self.tmp_containers.append(container)