Fixed bug for containers that were never started and not old

This commit is contained in:
Semir Patel 2015-12-15 09:12:57 -08:00
parent f19f7a4430
commit c92d4cc24d
2 changed files with 20 additions and 36 deletions

View File

@ -21,14 +21,13 @@ log = logging.getLogger(__name__)
YEAR_ZERO = "0001-01-01T00:00:00Z" YEAR_ZERO = "0001-01-01T00:00:00Z"
def cleanup_containers(client, max_container_age, min_container_age, dry_run): def cleanup_containers(client, max_container_age, dry_run):
all_containers = get_all_containers(client) all_containers = get_all_containers(client)
for container_summary in reversed(all_containers): for container_summary in reversed(all_containers):
container = api_call(client.inspect_container, container_summary['Id']) container = api_call(client.inspect_container, container_summary['Id'])
if not container or not should_remove_container(container, if not container or not should_remove_container(container,
max_container_age, max_container_age):
min_container_age):
continue continue
log.info("Removing container %s %s %s" % ( log.info("Removing container %s %s %s" % (
@ -40,25 +39,22 @@ def cleanup_containers(client, max_container_age, min_container_age, dry_run):
api_call(client.remove_container, container['Id']) api_call(client.remove_container, container['Id'])
def should_remove_container(container, min_date, max_date=None): def should_remove_container(container, min_date):
state = container.get('State', {}) state = container.get('State', {})
if state.get('Running'): if state.get('Running'):
return False return False
if state.get('Ghost'): if state.get('Ghost'):
return True return True
# Container was created, but never started
if state.get('FinishedAt') == YEAR_ZERO:
created_date = dateutil.parser.parse(container['Created']) created_date = dateutil.parser.parse(container['Created'])
return created_date < min_date
# Don't delete recently created containers finished_date = dateutil.parser.parse(state['FinishedAt'])
if max_date and created_date > max_date: return finished_date < min_date
return False
# Container was created, but never used
if state.get('FinishedAt') == YEAR_ZERO and created_date < min_date:
return True
return dateutil.parser.parse(state['FinishedAt']) < min_date
def get_all_containers(client): def get_all_containers(client):
@ -180,8 +176,8 @@ def main():
client = docker.Client(version='auto', timeout=args.timeout) client = docker.Client(version='auto', timeout=args.timeout)
if args.max_container_age: if args.max_container_age:
cleanup_containers(client, args.max_container_age, cleanup_containers(client, args.max_container_age, args.dry_run)
args.min_container_age, args.dry_run)
if args.max_image_age: if args.max_image_age:
exclude_set = build_exclude_set( exclude_set = build_exclude_set(
args.exclude_image, args.exclude_image,
@ -197,12 +193,6 @@ def get_args(args=None):
help="Maximum age for a container. Containers older than this age " help="Maximum age for a container. Containers older than this age "
"will be removed. Age can be specified in any pytimeparse " "will be removed. Age can be specified in any pytimeparse "
"supported format.") "supported format.")
parser.add_argument(
'--min-container-age',
type=timedelta_type,
help="Minimum age for a container when --max-container-age is used. "
"Containers younger than this age will not be removed. Age can "
"be specified in any pytimeparse supported format.")
parser.add_argument( parser.add_argument(
'--max-image-age', '--max-image-age',
type=timedelta_type, type=timedelta_type,

View File

@ -21,10 +21,16 @@ class TestShouldRemoveContainer(object):
container['State']['Ghost'] = True container['State']['Ghost'] = True
assert docker_gc.should_remove_container(container, now) assert docker_gc.should_remove_container(container, now)
def test_old_never_run(self, container, now): def test_old_never_run(self, container, now, earlier_time):
container['Created'] = str(earlier_time)
container['State']['FinishedAt'] = docker_gc.YEAR_ZERO container['State']['FinishedAt'] = docker_gc.YEAR_ZERO
assert docker_gc.should_remove_container(container, now) assert docker_gc.should_remove_container(container, now)
def test_not_old_never_run(self, container, now, earlier_time):
container['Created'] = str(now)
container['State']['FinishedAt'] = docker_gc.YEAR_ZERO
assert not docker_gc.should_remove_container(container, now)
def test_old_stopped(self, container, now): def test_old_stopped(self, container, now):
assert docker_gc.should_remove_container(container, now) assert docker_gc.should_remove_container(container, now)
@ -32,16 +38,6 @@ class TestShouldRemoveContainer(object):
container['State']['FinishedAt'] = '2014-01-21T00:00:00Z' container['State']['FinishedAt'] = '2014-01-21T00:00:00Z'
assert not docker_gc.should_remove_container(container, now) assert not docker_gc.should_remove_container(container, now)
def test_recently_created(self, container, now, earlier_time, later_time):
container['Created'] = str(later_time)
assert not docker_gc.should_remove_container(container, earlier_time,
now)
def test_not_recently_created(self, container, now, earlier_time,
later_time):
container['Created'] = str(earlier_time)
assert docker_gc.should_remove_container(container, now, later_time)
def test_cleanup_containers(mock_client, now): def test_cleanup_containers(mock_client, now):
max_container_age = now max_container_age = now
@ -53,16 +49,14 @@ def test_cleanup_containers(mock_client, now):
dict( dict(
Id='abcd', Id='abcd',
Name='one', Name='one',
Created=str(now),
State=dict(Running=False, FinishedAt='2014-01-01T01:01:01Z')), State=dict(Running=False, FinishedAt='2014-01-01T01:01:01Z')),
dict( dict(
Id='abbb', Id='abbb',
Name='two', Name='two',
Created=str(now),
State=dict(Running=True, FinishedAt='2014-01-01T01:01:01Z')) State=dict(Running=True, FinishedAt='2014-01-01T01:01:01Z'))
] ]
mock_client.inspect_container.side_effect = iter(mock_containers) mock_client.inspect_container.side_effect = iter(mock_containers)
docker_gc.cleanup_containers(mock_client, max_container_age, None, False) 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('abcd')