snippetModerate
How to clean up orphaned AWS EC2 snapshots?
Viewed 0 times
orphanedec2snapshotsawshowclean
Problem
We end up with a fair amount of AWS EC2 snapshots where the AMI has been deleted, but the snapshot is left behind to rot. I'd like a non-manual way of identifying and deleting these orphans to save us money and space.
Ideally I'm thinking a bash script leveraging the CLI, but my AWS-fu is weak. I assume someone's done this before but I can't find a script that actually works.
In the best-case scenario this will also check volumes and clean those as well, but that may be better suited for a second question.
Ideally I'm thinking a bash script leveraging the CLI, but my AWS-fu is weak. I assume someone's done this before but I can't find a script that actually works.
In the best-case scenario this will also check volumes and clean those as well, but that may be better suited for a second question.
Solution
Largely inspired by the blog posts and gist already linked in the other answers, here is my take to the problem.
I did use some convoluted JMESpath functions to get a list of snapshots and not require
Disclaimer: Use at your own risks, I did my best to avoid any problem and keep sane defaults, but I won't take any blame if it cause problem to you.
I hope the script itself is commented enough.
Default usage (no-params) will list delete commands of orphaned snapshots for the current account and region eu-west-1, extract:
You can redirect this output to a file for review before sourcing it to execute all the commands.
If you want the script to execute the command instead of printing them, replace
Usage is as follow with a script named
for dry-run commands in us-west-1 region
for usable commands in eu-central-1
A third parameter can be used to access another account (I do prefer to switch role to another account before).
Stripped down version of the script with awk script as a oneliner:
I did use some convoluted JMESpath functions to get a list of snapshots and not require
tr.Disclaimer: Use at your own risks, I did my best to avoid any problem and keep sane defaults, but I won't take any blame if it cause problem to you.
#!/bin/sh
# remove x if you don't want to see the commands
set -ex
# Some variable initialisation with sane defaults
DRUN='--dry-run'
DO_DELETE=${1:-'no'}
REGION=${2:-'eu-west-1'}
ACCOUNTID=${3:-'self'}
# Get two temporary files
SNAP_FILE=$(mktemp)
IMAGE_FILE=$(mktemp)
# Get the snapshot list and the volume list
aws --region "$REGION" ec2 describe-snapshots --owner-ids "$ACCOUNTID" --query 'Snapshots[*].[SnapshotId]' --output text > "$SNAP_FILE"
aws --region "$REGION" ec2 describe-images --owners "$ACCOUNTID" --filters Name=state,Values=available --query 'Images[].BlockDeviceMappings[].Ebs.[SnapshotId]' --output text > "$IMAGE_FILE"
# Check if the outputed command should be dry-run (default) or not
if [ "$DO_DELETE" = "IAMSURE" ]
then
DRUN=''
fi
# count each snapshot id, decrease when a volume reference it, print delete command for those with no volumes
awk -v REGION="$REGION" -v DRUN="$DRUN" '
FNR==NR { snap[$1]++; next } # increment snapshots and get to next line in file immediately
{ snap[$1]-- } # we changed file, decrease the snap counter when a volume reference it
END {
for (s in snap) { # loop over the snapshots
if (snap[s] > 0) { # if we did not decrese under 1 that means there is no volume referencing this snapshot
cmd="aws --region " REGION " " DRUN " ec2 delete-snapshot --snapshot-id " s
print(cmd)
}
}
}
' "$SNAP_FILE" "$IMAGE_FILE"
# Clean up the temp files
rm "$SNAP_FILE" "$IMAGE_FILE"
I hope the script itself is commented enough.
Default usage (no-params) will list delete commands of orphaned snapshots for the current account and region eu-west-1, extract:
aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-81e5856a
aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-95c68c7e
aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-a3bf50bdYou can redirect this output to a file for review before sourcing it to execute all the commands.
If you want the script to execute the command instead of printing them, replace
print(cmd) by system(cmd).Usage is as follow with a script named
snap_cleaner:for dry-run commands in us-west-1 region
./snap_cleaner no us-west-1for usable commands in eu-central-1
./snap_cleaner IAMSURE eu-central-1A third parameter can be used to access another account (I do prefer to switch role to another account before).
Stripped down version of the script with awk script as a oneliner:
#!/bin/sh
set -ex
# Some variable initialisation with sane defaults
DRUN='--dry-run'
DO_DELETE=${1:-'no'}
REGION=${2:-'eu-west-1'}
ACCOUNTID=${3:-'self'}
# Get two temporary files
SNAP_FILE=$(mktemp)
IMAGE_FILE=$(mktemp)
# Get the snapshot list and the volume list
aws --region "$REGION" ec2 describe-snapshots --owner-ids "$ACCOUNTID" --query 'Snapshots[*].[SnapshotId]' --output text > "$SNAP_FILE"
aws --region "$REGION" ec2 describe-images --owners "$ACCOUNTID" --filters Name=state,Values=available --query 'Images[*].BlockDeviceMappings[*].Ebs.[SnapshotId]' --output text > "$IMAGE_FILE"
# Check if the outputed command should be dry-run (default) or not
if [ "$DO_DELETE" = "IAMSURE" ]
then
DRUN=''
fi
# count each snapshot id, decrease when a volume reference it, print delete command for those with no volumes
awk -v REGION="$REGION" -v DRUN="$DRUN" 'FNR==NR { snap[$1]++; next } { snap[$1]-- } END { for (s in snap) { if (snap[s] > 0) { cmd="aws --region " REGION " " DRUN " ec2 delete-snapshot --snapshot-id " s; print(cmd) } } }' "$SNAP_FILE" "$IMAGE_FILE"
# Clean up the temp files
rm "$SNAP_FILE" "$IMAGE_FILE"Code Snippets
aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-81e5856a
aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-95c68c7e
aws --region eu-west-1 --dry-run ec2 delete-snapshot --snapshot-id snap-a3bf50bd./snap_cleaner no us-west-1./snap_cleaner IAMSURE eu-central-1#!/bin/sh
set -ex
# Some variable initialisation with sane defaults
DRUN='--dry-run'
DO_DELETE=${1:-'no'}
REGION=${2:-'eu-west-1'}
ACCOUNTID=${3:-'self'}
# Get two temporary files
SNAP_FILE=$(mktemp)
IMAGE_FILE=$(mktemp)
# Get the snapshot list and the volume list
aws --region "$REGION" ec2 describe-snapshots --owner-ids "$ACCOUNTID" --query 'Snapshots[*].[SnapshotId]' --output text > "$SNAP_FILE"
aws --region "$REGION" ec2 describe-images --owners "$ACCOUNTID" --filters Name=state,Values=available --query 'Images[*].BlockDeviceMappings[*].Ebs.[SnapshotId]' --output text > "$IMAGE_FILE"
# Check if the outputed command should be dry-run (default) or not
if [ "$DO_DELETE" = "IAMSURE" ]
then
DRUN=''
fi
# count each snapshot id, decrease when a volume reference it, print delete command for those with no volumes
awk -v REGION="$REGION" -v DRUN="$DRUN" 'FNR==NR { snap[$1]++; next } { snap[$1]-- } END { for (s in snap) { if (snap[s] > 0) { cmd="aws --region " REGION " " DRUN " ec2 delete-snapshot --snapshot-id " s; print(cmd) } } }' "$SNAP_FILE" "$IMAGE_FILE"
# Clean up the temp files
rm "$SNAP_FILE" "$IMAGE_FILE"Context
StackExchange DevOps Q#623, answer score: 16
Revisions (0)
No revisions yet.