@@ -21,6 +21,7 @@ def destroy_bedrock_agentcore(
21
21
agent_name : Optional [str ] = None ,
22
22
dry_run : bool = False ,
23
23
force : bool = False ,
24
+ delete_ecr_repo : bool = False ,
24
25
) -> DestroyResult :
25
26
"""Destroy Bedrock AgentCore resources.
26
27
@@ -29,6 +30,7 @@ def destroy_bedrock_agentcore(
29
30
agent_name: Name of the agent to destroy (default: use default agent)
30
31
dry_run: If True, only show what would be destroyed without actually doing it
31
32
force: If True, skip confirmation prompts
33
+ delete_ecr_repo: If True, also delete the ECR repository after removing images
32
34
33
35
Returns:
34
36
DestroyResult: Details of what was destroyed or would be destroyed
@@ -38,7 +40,8 @@ def destroy_bedrock_agentcore(
38
40
ValueError: If agent is not found or not deployed
39
41
RuntimeError: If destruction fails
40
42
"""
41
- log .info ("Starting destroy operation for agent: %s (dry_run=%s)" , agent_name or "default" , dry_run )
43
+ log .info ("Starting destroy operation for agent: %s (dry_run=%s, delete_ecr_repo=%s)" ,
44
+ agent_name or "default" , dry_run , delete_ecr_repo )
42
45
43
46
try :
44
47
# Load configuration
@@ -65,8 +68,8 @@ def destroy_bedrock_agentcore(
65
68
# 2. Destroy Bedrock AgentCore agent
66
69
_destroy_agentcore_agent (session , agent_config , result , dry_run )
67
70
68
- # 3. Remove ECR images (specific tags only)
69
- _destroy_ecr_images (session , agent_config , result , dry_run )
71
+ # 3. Remove ECR images and optionally the repository
72
+ _destroy_ecr_images (session , agent_config , result , dry_run , delete_ecr_repo )
70
73
71
74
# 4. Remove CodeBuild project
72
75
_destroy_codebuild_project (session , agent_config , result , dry_run )
@@ -179,8 +182,9 @@ def _destroy_ecr_images(
179
182
agent_config : BedrockAgentCoreAgentSchema ,
180
183
result : DestroyResult ,
181
184
dry_run : bool ,
185
+ delete_ecr_repo : bool = False ,
182
186
) -> None :
183
- """Remove ECR images for this specific agent."""
187
+ """Remove ECR images and optionally the repository for this specific agent."""
184
188
if not agent_config .aws .ecr_repository :
185
189
result .warnings .append ("No ECR repository configured, skipping image cleanup" )
186
190
return
@@ -204,7 +208,14 @@ def _destroy_ecr_images(
204
208
# Fix: use correct response key 'imageIds' instead of 'imageDetails'
205
209
all_images = response .get ("imageIds" , [])
206
210
if not all_images :
207
- result .warnings .append (f"No images found in ECR repository: { repo_name } " )
211
+ if delete_ecr_repo :
212
+ # Repository exists but is empty, we can delete it
213
+ if dry_run :
214
+ result .resources_removed .append (f"ECR repository: { repo_name } (empty, DRY RUN)" )
215
+ else :
216
+ _delete_ecr_repository (ecr_client , repo_name , result )
217
+ else :
218
+ result .warnings .append (f"No images found in ECR repository: { repo_name } " )
208
219
return
209
220
210
221
if dry_run :
@@ -214,6 +225,8 @@ def _destroy_ecr_images(
214
225
result .resources_removed .append (
215
226
f"ECR images in repository { repo_name } : { tagged_count } tagged, { untagged_count } untagged (DRY RUN)"
216
227
)
228
+ if delete_ecr_repo :
229
+ result .resources_removed .append (f"ECR repository: { repo_name } (DRY RUN)" )
217
230
return
218
231
219
232
# Prepare images for deletion - imageIds are already in the correct format
@@ -264,6 +277,12 @@ def _destroy_ecr_images(
264
277
result .warnings .append (
265
278
f"Some ECR images could not be deleted: { failed_count } out of { len (images_to_delete )} failed"
266
279
)
280
+
281
+ # Delete the repository if requested and all images were deleted successfully
282
+ if delete_ecr_repo and total_deleted == len (images_to_delete ):
283
+ _delete_ecr_repository (ecr_client , repo_name , result )
284
+ elif delete_ecr_repo and total_deleted < len (images_to_delete ):
285
+ result .warnings .append (f"Cannot delete ECR repository { repo_name } : some images failed to delete" )
267
286
else :
268
287
result .warnings .append (f"No valid image identifiers found in { repo_name } " )
269
288
@@ -282,6 +301,36 @@ def _destroy_ecr_images(
282
301
log .warning ("Error during ECR cleanup: %s" , e )
283
302
284
303
304
+ def _delete_ecr_repository (ecr_client , repo_name : str , result : DestroyResult ) -> None :
305
+ """Delete an ECR repository after ensuring it's empty."""
306
+ try :
307
+ # Verify repository is empty before deletion
308
+ response = ecr_client .list_images (repositoryName = repo_name )
309
+ remaining_images = response .get ("imageIds" , [])
310
+
311
+ if remaining_images :
312
+ result .warnings .append (f"Cannot delete ECR repository { repo_name } : repository is not empty" )
313
+ return
314
+
315
+ # Delete the empty repository
316
+ ecr_client .delete_repository (repositoryName = repo_name )
317
+ result .resources_removed .append (f"ECR repository: { repo_name } " )
318
+ log .info ("Deleted ECR repository: %s" , repo_name )
319
+
320
+ except ClientError as e :
321
+ error_code = e .response ["Error" ]["Code" ]
322
+ if error_code == "RepositoryNotFoundException" :
323
+ result .warnings .append (f"ECR repository { repo_name } not found (may have been deleted already)" )
324
+ elif error_code == "RepositoryNotEmptyException" :
325
+ result .warnings .append (f"Cannot delete ECR repository { repo_name } : repository is not empty" )
326
+ else :
327
+ result .warnings .append (f"Failed to delete ECR repository { repo_name } : { e } " )
328
+ log .warning ("Failed to delete ECR repository: %s" , e )
329
+ except Exception as e :
330
+ result .warnings .append (f"Error deleting ECR repository { repo_name } : { e } " )
331
+ log .warning ("Error deleting ECR repository: %s" , e )
332
+
333
+
285
334
def _destroy_codebuild_project (
286
335
session : boto3 .Session ,
287
336
agent_config : BedrockAgentCoreAgentSchema ,
0 commit comments