Skip to content

Instantly share code, notes, and snippets.

@smajda
Last active January 15, 2022 18:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save smajda/4e2c80c7b5e199c3663c to your computer and use it in GitHub Desktop.
Save smajda/4e2c80c7b5e199c3663c to your computer and use it in GitHub Desktop.
Python script to delete any untagged Docker containers and images.
import re
import subprocess
import sys
from collections import namedtuple
def first_to_last(items):
"Return a new list where last item in items is moved to the front"
return items[-1:] + items[:-1]
def pad_list(items, pad_to=10, pad_with=''):
"If items is shorter than pad_to, return a new list appending pad_with up to pad_to"
if len(items) >= pad_to:
return items
return items + [pad_with for i in range(0, pad_to - len(items))]
def namedtuplify(headers, rows):
"""
Takes a list of headers and a list of lists that are rows
and returns a list of namedtuples.
- removes any whitespaces in column names in headers
- pads any rows that aren't long enough with empty strings
"""
max_cols = len(headers)
Row = namedtuple('Row', [col_name.replace(' ', '') for col_name in headers])
rows = [Row(*pad_list(row, pad_to=max_cols)) for row in rows]
return rows
def get_docker_ps():
# save output of ps -a as list of lists, split by whitespace, and re-organized
# so that the last column is first because ports and status columns alone are
# optionally empty, and we only have spaces to delimit columns, so we want
# those at the end so we can easily just pad them
output = [
first_to_last([i.strip() for i in line.split(' ') if i.strip()])
for line in subprocess.check_output(['docker', 'ps', '-a']).splitlines()
]
headers, rows = output[0], output[1:]
return namedtuplify(headers, rows)
def get_docker_images():
output = [
[i.strip() for i in line.split(' ') if i.strip()]
for line in subprocess.check_output(['docker', 'images']).splitlines()
]
headers, rows = output[0], output[1:]
return namedtuplify(headers, rows)
def untagged_containers(rows=None):
"List of container ids using untagged images"
rows = rows or get_docker_ps()
return [i.CONTAINERID for i in rows if re.match('[0-9a-f]{12}', i.IMAGE)]
def untagged_images(rows=None):
"List of image ids that are not tagged"
rows = rows or get_docker_images()
return [row.IMAGEID for row in rows if row.REPOSITORY == '<none>']
if __name__ == '__main__':
container_ids = untagged_containers()
image_ids = untagged_images()
if not container_ids and not image_ids:
print "Nothing to cleanup!"
sys.exit()
if container_ids:
print "Removing containers using untagged images..."
for container_id in container_ids:
try:
output = subprocess.check_output(['docker', 'rm', container_id])
except subprocess.CalledProcessError as e:
print e
sys.exit()
print output
if image_ids:
print "Removing untagged images..."
for image_id in image_ids:
try:
output = subprocess.check_output(['docker', 'rmi', image_id])
except subprocess.CalledProcessError as e:
print e
sys.exit()
print output
print "BOOM"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment