Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add script to clean up quay.io. #3772

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions contrib/admin/quay_container_cleanup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env python3
"""
Script to scan and delete unnecessary (non-Toil Release) quay.io containers/tags.

Long tag names in 'ucsc_cgl/toil' with the 'a1-' denoting a dev version will be printed as a list and
the user asked to confirm their deletion.

NOTE TO USER: Try not to delete images for currently running tests. Check CI/CD first before running.
"""
import requests
import os


# more of a comment; this list really doesn't need to be updated since we filter by length.
whitelist = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name could be a bit more descriptive, and I think the semantics are backward. These are the ones we always keep, and never delete, so we should call this ALWAYS_KEEP or IGNORED_TAGS or BLOCKLIST or something. The way it is now it looks a bit like these are the ones that the deleter is allowed to delete.

'3.5.0',
'3.5.0-py2.7',
'3.5.1',
'3.5.1-py2.7',
'3.5.2',
'3.5.2-py2.7',
'3.5.3',
'3.5.3-py2.7',
'3.6.0',
'3.6.0-py2.7',
'3.7.0',
'3.7.0-py2.7',
'3.8.0',
'3.8.0-py2.7',
'3.9.0',
'3.9.0-py2.7',
'3.9.1',
'3.9.1-py2.7',
'3.10.0',
'3.10.0-py2.7',
'3.10.1',
'3.10.1-py2.7',
'3.11.0',
'3.11.0-py2.7',
'3.12.0',
'3.12.0-py2.7',
'3.13.0',
'3.13.0-py2.7',
'3.13.1',
'3.13.1-py2.7',
'3.14.0',
'3.14.0-py2.7',
'3.15.0',
'3.15.0-py2.7',
'3.16.0',
'3.16.0-py2.7',
'3.17.0',
'3.17.0-py2.7',
'3.18.0',
'3.18.0-py2.7',
'3.19.0',
'3.19.0-py2.7',
'3.20.0',
'3.20.0-py2.7',
'3.21.0',
'3.21.0-py2.7',
'3.22.0',
'3.22.0-py2.7',
'3.23.0',
'3.23.0-py2.7',
'3.23.0-py3.6',
'3.23.1',
'3.23.1-py2.7',
'3.23.1-py3.6',
'3.24.0',
'3.24.0-py2.7',
'3.24.0-py3.6',
'4.0.0',
'4.0.0-py3.6',
'4.0.0-py3.7',
'4.0.0-py3.8',
'4.1.0',
'4.1.0-py3.6',
'4.1.0-py3.7',
'4.1.0-py3.8',
'4.2.0',
'4.2.0-py3.6',
'4.2.0-py3.7',
'4.2.0-py3.8',
'5.0.0',
'5.0.0-py3.6',
'5.0.0-py3.7',
'5.0.0-py3.8',
'5.1.0',
'5.1.0-py3.6',
'5.1.0-py3.7',
'5.1.0-py3.8',
'5.2.0-py3.6',
'5.2.0-py3.7',
'5.2.0-py3.8',
'5.3.0',
'5.3.0-py3.6',
'5.3.0-py3.7',
'5.3.0-py3.8',
'5.4.0',
'5.4.0-py3.6',
'5.4.0-py3.7',
'5.4.0-py3.8',
'latest'
]

QUAY_AUTH_TOKEN = os.environ.get('QUAY_AUTH_TOKEN')
if not QUAY_AUTH_TOKEN:
raise RuntimeError('Please set QUAY_AUTH_TOKEN to run this script. '
'Mint the token here: https://quay.io/organization/ucsc_cgl?tab=applications')

headers = {'Authorization': f'Bearer {QUAY_AUTH_TOKEN}'}
repo = 'ucsc_cgl/toil'
total_tags_deleted = 0

response = requests.get(f'https://quay.io/api/v1/repository/{repo}', headers=headers)

tags = []
for tag in response.json()['tags']:
tag = tag.strip()
dev_version = tag.split('-')[0].endswith('a1')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we ever going to actually release an a1 and get bumped to a2?

non_release_minimum_tag_length = len('5.5.0a1-dce7a69af77da45c4ab1939e304ec92865ad9c57-py3.7')
if len(tag) >= non_release_minimum_tag_length and tag not in whitelist and dev_version:
Comment on lines +122 to +123
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing in the list is as long as this minimum tag length; do we even need the list at all?

tags.append(tag)
print(tag)

user_reply = input('\nDo you wish to delete these tags?\n\n')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have a (y/n), or someone will type yes or Y and be annoyed.

print('\n')

if user_reply == 'y':
for tag in tags:
response = requests.delete(f'https://quay.io/api/v1/repository/{repo}/tag/{tag}', headers=headers)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the list is meant to be a second safety interlock, maybe we should check against it here instead?

print(f'Deletion {response}: {tag}')
print(f'\n{len(tags)} Tags Deleted.')