Skip to content

Commit 98e68e6

Browse files
committed
check also lambda for running images awslabs#40
1 parent c8f413c commit 98e68e6

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Automated Image Cleanup for Amazon ECR
2-
The Python script and Lambda function described here help clean up images in [Amazon ECR](https://aws.amazon.com/ecr). The script looks for images that are not used in running [Amazon ECS](https://aws.amazon.com/ecs) tasks that can be deleted. You can configure the script to print the image list first to confirm deletions, specify a region, or specify a number of images to keep for potential rollbacks.
2+
The Python script and Lambda function described here help clean up images in [Amazon ECR](https://aws.amazon.com/ecr).
3+
The script looks for images that are not used in running
4+
[Amazon ECS](https://aws.amazon.com/ecs) tasks,
5+
[Amazon EKS](https://aws.amazon.com/eks) tasks and
6+
[Amazon Lambda](https://aws.amazon.com/lambda) container images that can be deleted.
7+
You can configure the script to print the image list first to confirm deletions, specify a region,
8+
or specify a number of images to keep for potential rollbacks.
39

410
## Authenticate with AWS
511
[Configuring the AWS Command Line Interface.](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html)

main.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class Inputs:
4343
protect_tags_regex: re.Pattern | None = None
4444
protect_latest: bool | None = None
4545
check_ecs: bool | None = None
46+
check_lambda: bool | None = None
4647
check_eks: bool | None = None
4748
connect_timeout: int | None = None
4849
read_timeout: int | None = None
@@ -105,6 +106,12 @@ def __post_init__(self):
105106
else:
106107
raise Exception(f"Unexpected {type(self.check_ecs)=}")
107108

109+
if not isinstance(self.check_lambda, bool):
110+
if isinstance(self.check_lambda, str):
111+
self.check_lambda = (self.check_lambda or "false").lower() != 'false'
112+
else:
113+
raise Exception(f"Unexpected {type(self.check_lambda)=}")
114+
108115
if not isinstance(self.check_eks, bool):
109116
if isinstance(self.check_eks, str):
110117
self.check_eks = (self.dryrun or "false").lower() != 'false'
@@ -126,6 +133,7 @@ def from_env(cls):
126133
protect_tags_regex=os.environ.get('PROTECT_TAGS_REGEX'),
127134
protect_latest=os.environ.get('PROTECT_LATEST'),
128135
check_ecs=os.environ.get('CHECK_ECS'),
136+
check_lambda=os.environ.get('CHECK_LAMBDA'),
129137
check_eks=os.environ.get('CHECK_EKS'),
130138
connect_timeout=os.environ.get('CONNECT_TIMEOUT'),
131139
read_timeout=os.environ.get('READ_TIMEOUT'),
@@ -165,6 +173,8 @@ def from_parser(cls):
165173
dest="protect_latest", action='store_false')
166174
parser.add_argument('-no-ecs', help="Don't search ECS for running images",
167175
dest="check_ecs", action='store_false')
176+
parser.add_argument('-no-lambda', help="Don't search Lambda for running images",
177+
dest="check_lambda", action='store_false')
168178
parser.add_argument('-no-eks', help="Don't search EKS for running images",
169179
dest="check_eks", action='store_false')
170180

@@ -185,6 +195,7 @@ def from_parser(cls):
185195
protect_tags_regex=args.protect_tags_regex,
186196
protect_latest=args.protect_latest,
187197
check_ecs=args.check_ecs,
198+
check_lambda=args.check_lambda,
188199
check_eks=args.check_eks,
189200
connect_timeout=args.connect_timeout,
190201
read_timeout=args.read_timeout,
@@ -432,6 +443,14 @@ def get_running_containers(ecs_client, inputs: Inputs):
432443
running_containers_ecs = []
433444
logger.info('Skip checking running containers on ECS...')
434445

446+
if inputs.check_lambda:
447+
running_containers_lambda = get_running_containers_from_lambda(inputs.region, logger)
448+
logger.info(f"{len(running_containers_lambda)} running containers "
449+
f"from Lambda: {sorted(running_containers_lambda)}...")
450+
else:
451+
running_containers_lambda = []
452+
logger.info('Skip checking running containers on Lambda...')
453+
435454
if inputs.check_eks:
436455
running_containers_eks = get_running_containers_from_eks(logger)
437456
logger.info(f"{len(running_containers_eks)} running containers "
@@ -440,11 +459,25 @@ def get_running_containers(ecs_client, inputs: Inputs):
440459
running_containers_eks = []
441460
logger.info('Skip checking running containers on EKS...')
442461

443-
running_containers_ecs = sorted(running_containers_ecs | running_containers_eks)
462+
running_containers_ecs = sorted(running_containers_ecs | running_containers_eks | running_containers_lambda)
444463
logger.info(f"{len(running_containers_ecs)} total running containers: {running_containers_ecs}...")
445464
return running_containers_ecs
446465

447466

467+
def get_running_containers_from_lambda(region_name: str, logger: logging.Logger):
468+
running_containers = set()
469+
lambda_client = boto3.client('lambda', region_name=region_name)
470+
listlambdas_paginator = lambda_client.get_paginator('list_functions')
471+
for response_listlambdapaginator in listlambdas_paginator.paginate():
472+
for function in response_listlambdapaginator['Functions']:
473+
if function["PackageType"] == "Image":
474+
function_config = lambda_client.get_function(FunctionName=function["FunctionName"])
475+
if function_config["Code"]["ImageUri"] not in running_containers:
476+
running_containers.add(function_config["Code"]["ImageUri"])
477+
478+
return running_containers
479+
480+
448481
def get_running_containers_from_ecs(ecs_client, logger: logging.Logger):
449482
running_containers = set()
450483
list_clusters_paginator = ecs_client.get_paginator('list_clusters')

0 commit comments

Comments
 (0)