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

Repositories filter and env variables fix #28

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,24 @@ Deletes the images that are not used by running tasks and which are older than t

`python main.py –dryrun False –imagestokeep 20 –region us-west-2 -ignoretagsregex release|archive`


Deletes the images that are not used by running tasks and which are older than the last 20 versions (in foo and bar repositories), in Oregon only, and ignore image tags that contains `release` or `archive`:

`python main.py –dryrun False –imagestokeep 20 –region us-west-2 -ignoretagsregex release|archive -repositories foo bar`

Deletes the images that are not used by running tasks and which are older than the last 20 versions (in foo and bar repositories), in Oregon only, select only images with tag begening by `^re` but ignore image tags that contains `release` or `review`:

`python main.py –dryrun False –imagestokeep 20 –region us-west-2 -ignoretagsregex release|review -filtertagsregex ^re -repositories foo bar`

Environment variables can be used instead of arguments:

```
export REGION=us-west-2
export DRYRUN=False
export IMAGES_TO_KEEP=20
export REPOSITORIES_FILTER='foo bar'
export IGNORE_TAGS_REGEX='release|review'
export FILTER_TAGS_REGEX='^re'

python main.py
```
73 changes: 53 additions & 20 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env python
'''
Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Expand Down Expand Up @@ -26,13 +27,16 @@
DRYRUN = None
IMAGES_TO_KEEP = None
IGNORE_TAGS_REGEX = None

FILTER_TAGS_REGEX = None
REPOSITORIES_FILTER = None

def initialize():
global REGION
global DRYRUN
global IMAGES_TO_KEEP
global IGNORE_TAGS_REGEX
global FILTER_TAGS_REGEX
global REPOSITORIES_FILTER

REGION = os.environ.get('REGION', "None")
DRYRUN = os.environ.get('DRYRUN', "false").lower()
Expand All @@ -42,6 +46,8 @@ def initialize():
DRYRUN = True
IMAGES_TO_KEEP = int(os.environ.get('IMAGES_TO_KEEP', 100))
IGNORE_TAGS_REGEX = os.environ.get('IGNORE_TAGS_REGEX', "^$")
FILTER_TAGS_REGEX = os.environ.get('FILTER_TAGS_REGEX', "")
REPOSITORIES_FILTER = os.environ.get('REPOSITORIES_FILTER', "")

def handler(event, context):
initialize()
Expand All @@ -55,6 +61,20 @@ def handler(event, context):
else:
discover_delete_images(REGION)

def ignore_tags_image(image,running_sha):
skip = False
if (FILTER_TAGS_REGEX != ""):
skip = True

for tag in image['imageTags']:
if ( "latest" in tag
or re.compile(IGNORE_TAGS_REGEX).search(tag) is not None
or (running_sha and image['imageDigest'] in running_sha)):
return True
if (re.compile(FILTER_TAGS_REGEX).search(tag) is not None):
skip=False
return skip


def discover_delete_images(regionname):
print("Discovering images in " + regionname)
Expand All @@ -64,9 +84,11 @@ def discover_delete_images(regionname):
describe_repo_paginator = ecr_client.get_paginator('describe_repositories')
for response_listrepopaginator in describe_repo_paginator.paginate():
for repo in response_listrepopaginator['repositories']:
repositories.append(repo)

# print(repositories)
if REPOSITORIES_FILTER:
if repo['repositoryName'] in REPOSITORIES_FILTER:
repositories.append(repo)
else:
repositories.append(repo)

ecs_client = boto3.client('ecs', region_name=regionname)

Expand Down Expand Up @@ -130,14 +152,17 @@ def discover_delete_images(regionname):

print("Number of running images found {}".format(len(running_sha)))

image_count = 0
for image in tagged_images:
if tagged_images.index(image) >= IMAGES_TO_KEEP:
if ignore_tags_image(image,running_sha):
continue
if image_count >= int(IMAGES_TO_KEEP):
for tag in image['imageTags']:
if "latest" not in tag and re.compile(IGNORE_TAGS_REGEX).search(tag) is None:
if not running_sha or image['imageDigest'] not in running_sha:
append_to_list(deletesha, image['imageDigest'])
append_to_tag_list(deletetag, {"imageUrl": repository['repositoryUri'] + ":" + tag,
"pushedAt": image["imagePushedAt"]})
append_to_list(deletesha, image['imageDigest'])
append_to_tag_list(deletetag, {"imageUrl": repository['repositoryUri'] + ":" + tag,
"pushedAt": image["imagePushedAt"]})
image_count += 1

if deletesha:
print("Number of images to be deleted: {}".format(len(deletesha)))
delete_images(
Expand Down Expand Up @@ -197,19 +222,27 @@ def delete_images(ecr_client, deletesha, deletetag, id, name):
if __name__ == '__main__':
request = {"None": "None"}
parser = argparse.ArgumentParser(description='Deletes stale ECR images')
parser.add_argument('-dryrun', help='Prints the repository to be deleted without deleting them', default='true',
parser.add_argument('-dryrun', help='Prints the repository to be deleted without deleting them', default=os.environ.get('DRYRUN', "true"),
action='store', dest='dryrun')
parser.add_argument('-imagestokeep', help='Number of image tags to keep', default='100', action='store',
parser.add_argument('-imagestokeep', help='Number of image tags to keep', default=os.environ.get('IMAGES_TO_KEEP', "100"), action='store',
dest='imagestokeep')
parser.add_argument('-region', help='ECR/ECS region', default=None, action='store', dest='region')
parser.add_argument('-ignoretagsregex', help='Regex of tag names to ignore', default="^$", action='store', dest='ignoretagsregex')
parser.add_argument('-region', help='ECR/ECS region', default=os.environ.get('REGION', "None"), action='store', dest='region')
parser.add_argument('-repositories', help='Filter for repositories names discovery separated by space', default=os.environ.get('REPOSITORIES_FILTER', "").split(),
nargs='+', action='store', dest='repositories_filter')
parser.add_argument('-ignoretagsregex', help='Regex of tag names to ignore', default=os.environ.get('IGNORE_TAGS_REGEX', "^$"), action='store', dest='ignoretagsregex')
parser.add_argument('-filtertagsregex', help='Regex filter of tag names to limit on images with matching tag', default=os.environ.get('FILTER_TAGS_REGEX', ""), action='store', dest='filtertagsregex')

args = parser.parse_args()
if args.region:
os.environ["REGION"] = args.region

REGION = args.region
if args.dryrun.lower() == "false":
DRYRUN = False
else:
os.environ["REGION"] = "None"
os.environ["DRYRUN"] = args.dryrun.lower()
os.environ["IMAGES_TO_KEEP"] = args.imagestokeep
os.environ["IGNORE_TAGS_REGEX"] = args.ignoretagsregex
DRYRUN = True

IMAGES_TO_KEEP = args.imagestokeep
IGNORE_TAGS_REGEX = args.ignoretagsregex
FILTER_TAGS_REGEX = args.filtertagsregex
REPOSITORIES_FILTER = args.repositories_filter

handler(request, None)