Skip to content

Commit

Permalink
Merge pull request #40 from ymilki/dangling_volumes
Browse files Browse the repository at this point in the history
Remove dangling volumes
  • Loading branch information
solarkennedy authored Dec 1, 2016
2 parents dc4ed27 + fee79d9 commit 4925cb0
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
33 changes: 33 additions & 0 deletions docker_custodian/docker_gc.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ def get_all_images(client):
return images


def get_dangling_volumes(client):
log.info("Getting dangling volumes")
volumes = client.volumes({'dangling': True})['Volumes']
log.info("Found %s dangling volumes", len(volumes))
return volumes


def cleanup_images(client, max_image_age, dry_run, exclude_set):
# re-fetch container list so that we don't include removed containers
image_tags_in_use = set(
Expand Down Expand Up @@ -141,6 +148,25 @@ def remove_image(client, image_summary, min_date, dry_run):
api_call(client.remove_image, image=image_tag)


def remove_volume(client, volume, dry_run):
if not volume:
return

log.info("Removing volume %s" % volume['Name'])
if dry_run:
return

api_call(client.remove_volume, name=volume['Name'])


def cleanup_volumes(client, dry_run):
dangling_volumes = get_dangling_volumes(client)

for volume in reversed(dangling_volumes):
log.info("Removing dangling volume %s", volume['Name'])
remove_volume(client, volume, dry_run)


def api_call(func, **kwargs):
try:
return func(**kwargs)
Expand Down Expand Up @@ -192,6 +218,9 @@ def main():
args.exclude_image_file)
cleanup_images(client, args.max_image_age, args.dry_run, exclude_set)

if args.dangling_volumes:
cleanup_volumes(client, args.dry_run)


def get_args(args=None):
parser = argparse.ArgumentParser()
Expand All @@ -207,6 +236,10 @@ def get_args(args=None):
help="Maxium age for an image. Images older than this age will be "
"removed. Age can be specified in any pytimeparse supported "
"format.")
parser.add_argument(
'--dangling-volumes',
action="store_true",
help="Dangling volumes will be removed.")
parser.add_argument(
'--dry-run', action="store_true",
help="Only log actions, don't remove anything.")
Expand Down
38 changes: 38 additions & 0 deletions tests/docker_gc_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,32 @@ def test_cleanup_images(mock_client, now):
]


def test_cleanup_volumes(mock_client):
mock_client.volumes.return_value = volumes = {
'Volumes': [
{
'Mountpoint': 'unused',
'Labels': None,
'Driver': 'unused',
'Name': u'one'
},
{
'Mountpoint': 'unused',
'Labels': None,
'Driver': 'unused',
'Name': u'two'
},
],
'Warnings': None,
}

docker_gc.cleanup_volumes(mock_client, False)
assert mock_client.remove_volume.mock_calls == [
mock.call(name=volume['Name'])
for volume in reversed(volumes['Volumes'])
]


def test_filter_images_in_use():
image_tags_in_use = set([
'user/one:latest',
Expand Down Expand Up @@ -355,6 +381,18 @@ def test_get_all_images(mock_client):
mock_log.info.assert_called_with("Found %s images", count)


def test_get_dangling_volumes(mock_client):
count = 4
mock_client.volumes.return_value = {
'Volumes': [mock.Mock() for _ in range(count)]
}
with mock.patch('docker_custodian.docker_gc.log',
autospec=True) as mock_log:
volumes = docker_gc.get_dangling_volumes(mock_client)
assert volumes == mock_client.volumes.return_value['Volumes']
mock_log.info.assert_called_with("Found %s dangling volumes", count)


def test_build_exclude_set():
image_tags = [
'some_image:latest',
Expand Down

0 comments on commit 4925cb0

Please sign in to comment.