From d2cb9c467dfd193ce14e5deae7485b45898915d2 Mon Sep 17 00:00:00 2001 From: Paul O'Connor Date: Wed, 5 Oct 2016 09:18:56 +0100 Subject: [PATCH] Remove volumes when removing containers --- debian/changelog | 6 ++++++ docker_custodian/__about__.py | 2 +- docker_custodian/docker_gc.py | 22 +++++++++++++--------- requirements.txt | 2 +- tests/docker_gc_test.py | 35 ++++++++++++++++++----------------- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/debian/changelog b/debian/changelog index 095848a..2ab3ecd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +docker-custodian (0.7.0) lucid; urgency=low + + * Delete volumes along with containers + + -- Paul O'Connor Wed, 05 Oct 2016 00:58:10 -0700 + docker-custodian (0.6.1) lucid; urgency=low * New release for pypi diff --git a/docker_custodian/__about__.py b/docker_custodian/__about__.py index d4353a2..95245e3 100644 --- a/docker_custodian/__about__.py +++ b/docker_custodian/__about__.py @@ -1,4 +1,4 @@ # -*- coding: utf8 -*- -__version_info__ = (0, 6, 1) +__version_info__ = (0, 7, 0) __version__ = '%d.%d.%d' % __version_info__ diff --git a/docker_custodian/docker_gc.py b/docker_custodian/docker_gc.py index aa458a7..2d5e04d 100644 --- a/docker_custodian/docker_gc.py +++ b/docker_custodian/docker_gc.py @@ -25,7 +25,8 @@ def cleanup_containers(client, max_container_age, dry_run): all_containers = get_all_containers(client) for container_summary in reversed(all_containers): - container = api_call(client.inspect_container, container_summary['Id']) + container = api_call(client.inspect_container, + container=container_summary['Id']) if not container or not should_remove_container(container, max_container_age): continue @@ -36,7 +37,8 @@ def cleanup_containers(client, max_container_age, dry_run): container['State']['FinishedAt'])) if not dry_run: - api_call(client.remove_container, container['Id']) + api_call(client.remove_container, container=container['Id'], + v=True) def should_remove_container(container, min_date): @@ -116,7 +118,7 @@ def no_image_tags(image_tags): def remove_image(client, image_summary, min_date, dry_run): - image = api_call(client.inspect_image, image_summary['Id']) + image = api_call(client.inspect_image, image=image_summary['Id']) if not image or not is_image_old(image, min_date): return @@ -127,21 +129,23 @@ def remove_image(client, image_summary, min_date, dry_run): image_tags = image_summary.get('RepoTags') # If there are no tags, remove the id if no_image_tags(image_tags): - api_call(client.remove_image, image_summary['Id']) + api_call(client.remove_image, image=image_summary['Id']) return # Remove any repository tags so we don't hit 409 Conflict for image_tag in image_tags: - api_call(client.remove_image, image_tag) + api_call(client.remove_image, image=image_tag) -def api_call(func, id): +def api_call(func, **kwargs): try: - return func(id) + return func(**kwargs) except requests.exceptions.Timeout as e: - log.warn("Failed to call %s %s %s" % (func.__name__, id, e)) + params = ','.join('%s=%s' % item for item in kwargs.items()) + log.warn("Failed to call %s %s %s" % (func.__name__, params, e)) except docker.errors.APIError as ae: - log.warn("Error calling %s %s %s" % (func.__name__, id, ae)) + params = ','.join('%s=%s' % item for item in kwargs.items()) + log.warn("Error calling %s %s %s" % (func.__name__, params, ae)) def format_image(image, image_summary): diff --git a/requirements.txt b/requirements.txt index 35faae8..f6584b8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ argparse==1.3.0 backports.ssl-match-hostname==3.4.0.2 -docker-py==1.7.2 +docker-py==1.8.1 future==0.14.3 python-dateutil==2.4.0 pytimeparse==1.1.2 diff --git a/tests/docker_gc_test.py b/tests/docker_gc_test.py index 1a6caf1..77cdbd8 100644 --- a/tests/docker_gc_test.py +++ b/tests/docker_gc_test.py @@ -65,7 +65,8 @@ def test_cleanup_containers(mock_client, now): ] mock_client.inspect_container.side_effect = iter(mock_containers) docker_gc.cleanup_containers(mock_client, max_container_age, False) - mock_client.remove_container.assert_called_once_with('abcd') + mock_client.remove_container.assert_called_once_with(container='abcd', + v=True) def test_cleanup_images(mock_client, now): @@ -88,7 +89,7 @@ def test_cleanup_images(mock_client, now): docker_gc.cleanup_images(mock_client, max_image_age, False, set()) assert mock_client.remove_image.mock_calls == [ - mock.call(image['Id']) for image in reversed(images) + mock.call(image=image['Id']) for image in reversed(images) ] @@ -191,7 +192,7 @@ def test_remove_image_no_tags(mock_client, image, now): mock_client.inspect_image.return_value = image docker_gc.remove_image(mock_client, image_summary, now, False) - mock_client.remove_image.assert_called_once_with(image_id) + mock_client.remove_image.assert_called_once_with(image=image_id) def test_remove_image_new_image_not_removed(mock_client, image, later_time): @@ -214,15 +215,15 @@ def test_remove_image_with_tags(mock_client, image, now): docker_gc.remove_image(mock_client, image_summary, now, False) assert mock_client.remove_image.mock_calls == [ - mock.call(tag) for tag in repo_tags + mock.call(image=tag) for tag in repo_tags ] def test_api_call_success(): func = mock.Mock() - id = "abcd" - result = docker_gc.api_call(func, id) - func.assert_called_once_with(id) + container = "abcd" + result = docker_gc.api_call(func, container=container) + func.assert_called_once_with(container="abcd") assert result == func.return_value @@ -230,17 +231,17 @@ def test_api_call_with_timeout(): func = mock.Mock( side_effect=requests.exceptions.ReadTimeout("msg"), __name__="remove_image") - id = "abcd" + image = "abcd" with mock.patch( 'docker_custodian.docker_gc.log', autospec=True) as mock_log: - docker_gc.api_call(func, id) + docker_gc.api_call(func, image=image) - func.assert_called_once_with(id) - mock_log.warn.assert_called_once_with( - 'Failed to call remove_image abcd msg' - ) + func.assert_called_once_with(image="abcd") + mock_log.warn.assert_called_once_with('Failed to call remove_image ' + + 'image=abcd msg' + ) def test_api_call_with_api_error(): @@ -250,16 +251,16 @@ def test_api_call_with_api_error(): mock.Mock(status_code=409, reason="Conflict"), explanation="failed"), __name__="remove_image") - id = "abcd" + image = "abcd" with mock.patch( 'docker_custodian.docker_gc.log', autospec=True) as mock_log: - docker_gc.api_call(func, id) + docker_gc.api_call(func, image=image) - func.assert_called_once_with(id) + func.assert_called_once_with(image="abcd") mock_log.warn.assert_called_once_with( - 'Error calling remove_image abcd ' + 'Error calling remove_image image=abcd ' '409 Client Error: Conflict ("failed")')