Skip to content

Commit e269997

Browse files
committed
check also lambda for running images awslabs#40
1 parent 77fb05c commit e269997

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
@@ -42,6 +42,7 @@ class Inputs:
4242
protect_tags_regex: re.Pattern | None = None
4343
protect_latest: bool | None = None
4444
check_ecs: bool | None = None
45+
check_lambda: bool | None = None
4546
check_eks: bool | None = None
4647
connect_timeout: int | None = None
4748
read_timeout: int | None = None
@@ -104,6 +105,12 @@ def __post_init__(self):
104105
else:
105106
raise Exception(f"Unexpected {type(self.check_ecs)=}")
106107

108+
if not isinstance(self.check_lambda, bool):
109+
if isinstance(self.check_lambda, str):
110+
self.check_lambda = (self.check_lambda or "false").lower() != 'false'
111+
else:
112+
raise Exception(f"Unexpected {type(self.check_lambda)=}")
113+
107114
if not isinstance(self.check_eks, bool):
108115
if isinstance(self.check_eks, str):
109116
self.check_eks = (self.dryrun or "false").lower() != 'false'
@@ -125,6 +132,7 @@ def from_env(cls):
125132
protect_tags_regex=os.environ.get('PROTECT_TAGS_REGEX'),
126133
protect_latest=os.environ.get('PROTECT_LATEST'),
127134
check_ecs=os.environ.get('CHECK_ECS'),
135+
check_lambda=os.environ.get('CHECK_LAMBDA'),
128136
check_eks=os.environ.get('CHECK_EKS'),
129137
connect_timeout=os.environ.get('CONNECT_TIMEOUT'),
130138
read_timeout=os.environ.get('READ_TIMEOUT'),
@@ -164,6 +172,8 @@ def from_parser(cls):
164172
dest="protect_latest", action='store_false')
165173
parser.add_argument('-no-ecs', help="Don't search ECS for running images",
166174
dest="check_ecs", action='store_false')
175+
parser.add_argument('-no-lambda', help="Don't search Lambda for running images",
176+
dest="check_lambda", action='store_false')
167177
parser.add_argument('-no-eks', help="Don't search EKS for running images",
168178
dest="check_eks", action='store_false')
169179

@@ -184,6 +194,7 @@ def from_parser(cls):
184194
protect_tags_regex=args.protect_tags_regex,
185195
protect_latest=args.protect_latest,
186196
check_ecs=args.check_ecs,
197+
check_lambda=args.check_lambda,
187198
check_eks=args.check_eks,
188199
connect_timeout=args.connect_timeout,
189200
read_timeout=args.read_timeout,
@@ -422,6 +433,14 @@ def get_running_containers(ecs_client, inputs: Inputs):
422433
running_containers_ecs = []
423434
logger.info('Skip checking running containers on ECS...')
424435

436+
if inputs.check_lambda:
437+
running_containers_lambda = get_running_containers_from_lambda(inputs.region, logger)
438+
logger.info(f"{len(running_containers_lambda)} running containers "
439+
f"from Lambda: {sorted(running_containers_lambda)}...")
440+
else:
441+
running_containers_lambda = []
442+
logger.info('Skip checking running containers on Lambda...')
443+
425444
if inputs.check_eks:
426445
running_containers_eks = get_running_containers_from_eks(logger)
427446
logger.info(f"{len(running_containers_eks)} running containers "
@@ -430,11 +449,25 @@ def get_running_containers(ecs_client, inputs: Inputs):
430449
running_containers_eks = []
431450
logger.info('Skip checking running containers on EKS...')
432451

433-
running_containers_ecs = sorted(running_containers_ecs | running_containers_eks)
452+
running_containers_ecs = sorted(running_containers_ecs | running_containers_eks | running_containers_lambda)
434453
logger.info(f"{len(running_containers_ecs)} total running containers: {running_containers_ecs}...")
435454
return running_containers_ecs
436455

437456

457+
def get_running_containers_from_lambda(region_name: str, logger: logging.Logger):
458+
running_containers = set()
459+
lambda_client = boto3.client('lambda', region_name=region_name)
460+
listlambdas_paginator = lambda_client.get_paginator('list_functions')
461+
for response_listlambdapaginator in listlambdas_paginator.paginate():
462+
for function in response_listlambdapaginator['Functions']:
463+
if function["PackageType"] == "Image":
464+
function_config = lambda_client.get_function(FunctionName=function["FunctionName"])
465+
if function_config["Code"]["ImageUri"] not in running_containers:
466+
running_containers.add(function_config["Code"]["ImageUri"])
467+
468+
return running_containers
469+
470+
438471
def get_running_containers_from_ecs(ecs_client, logger: logging.Logger):
439472
running_containers = set()
440473
list_clusters_paginator = ecs_client.get_paginator('list_clusters')

0 commit comments

Comments
 (0)