Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
AWS EBS - Find unused snapshots - this script generates csv raport about snapshot usage
import re
import boto3
import csv
from botocore.exceptions import ClientError
ec2 = boto3.client('ec2')
def get_snapshots():
return ec2.describe_snapshots(OwnerIds=['self'])['Snapshots']
def volume_exists(volume_id):
if not volume_id: return ''
try:
ec2.describe_volumes(VolumeIds=[volume_id])
return True
except ClientError:
return False
def instance_exists(instance_id):
if not instance_id: return ''
try:
ec2.describe_instances(InstanceIds=[instance_id])
return True
except ClientError:
return False
def image_exists(image_id):
if not image_id: return ''
try:
requestObj = ec2.describe_images(ImageIds=[image_id,])
if not requestObj["Images"]:
return False
return True
except ClientError:
return False
def parse_description(description):
regex = r"^Created by CreateImage\((.*?)\) for (.*?) "
matches = re.finditer(regex, description, re.MULTILINE)
for matchNum, match in enumerate(matches):
return match.groups()
return '', ''
def main():
with open('raport.csv', 'w') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([
'snapshot id',
'description',
'started',
'size',
'volume',
'volume exists',
'instance',
'instance exists',
'ami',
'ami exists'])
for snap in get_snapshots():
instance_id, image_id = parse_description(snap['Description'])
writer.writerow([
snap['SnapshotId'],
snap['Description'],
snap['StartTime'],
str(snap['VolumeSize']),
snap['VolumeId'],
str(volume_exists(snap['VolumeId'])),
instance_id,
str(instance_exists(instance_id)),
image_id,
str(image_exists(image_id)),
])
if __name__ == '__main__':
main()
@alanwds

This comment has been minimized.

Copy link

commented Dec 2, 2016

Work's like a charm. Thank you. You save a lot of time (and money) here!

Regards!

@jordanmance

This comment has been minimized.

Copy link

commented Jan 10, 2017

Thank you for this script! It is great, however I would like to report a bug. It appears that sometimes the AWS API can return an empty array for a describe-images request (perhaps b/c an image was recently deleted), for instance:

aws ec2 describe-images --image-id ami-e1f3d98b
{
"Images": []
}

Since your python script is looking for an exception thrown, and otherwise it assumes the image exists, it will mark the "ami exists" column as true when it should actually be false since an empty list was returned for images matching that ami id. The image_exists method would need to be updated to check for an empty list.

I was able to get it working properly by modifying the image_exists method like so:

def image_exists(image_id):
if not image_id: return ''
try:
requestObj = ec2.describe_images(ImageIds=[image_id,])
if not requestObj["Images"]:
return False
return True
except ClientError:
return False

It seems it's possible that the other exists methods may also need to be updated.

Sorry, it looks like the indentation of the code is broken in the comment, but you get the idea =]

@nicbor

This comment has been minimized.

Copy link

commented Jul 18, 2017

Thanks for the warning @jordanmance. Forked to include your changes.

@niknkson

This comment has been minimized.

Copy link

commented Aug 28, 2017

Thanks for this lovely script. it really saves lots of human efforts. Can you help me to modify this python script like old snapshots queried first. As I am totally new to python.

@eran658

This comment has been minimized.

Copy link

commented Aug 6, 2018

This is very useful, Thank You!
What would be really great is to include also the following:
Instance Name, Volume Name, Image Name

Currently the IDs alone are out of context when you deal with a massive old images cleanup backlog work and without the name it is very difficult to understand what you are viewing.
Any idea how to improve the code to also include the Names columns for those 3 objects?

Thanks!

@eran658

This comment has been minimized.

Copy link

commented Aug 6, 2018

I was able to also add the names by these 3 functions:

def get_instance_name(instance_id):
try:
instance=ec2_client.describe_instances(InstanceIds=[instance_id])
for tag in instance.tags:
if tag['Key'] == 'Name':
return tag['Value']
except ClientError:
return 'Instance does not exist'

def get_volume_name(volume_id):
try:
volume = ec2_client.describe_volumes(VolumeIds=[volume_id])
for tag in volume.tags:
if tag['Key'] == 'Name':
return tag['Value']
except ClientError:
return 'Volume does not exist'

def get_image_name(image_id):
try:
image = ec2_client.describe_images(ImageIds=[image_id,])
return image['Images'][0]['Name']
except ClientError:
return 'AMI does not exist'

@hiripitiyage

This comment has been minimized.

Copy link

commented Aug 20, 2018

I am new to scripting. I tried this script on our test environment and got the following error. I run this script on a W10 machine configuring AWS CLI.
Traceback (most recent call last):
File "C:\AWS\snapshots.py", line 72, in
main()
File "C:\AWS\snapshots.py", line 56, in main
for snap in get_snapshots():
File "C:\AWS\snapshots.py", line 9, in get_snapshots
return ec2.describe_snapshots(OwnerIds=['self'])['Snapshots']
File "C:\Users\roshan.hiripitiyaga\AppData\Local\Programs\Python\Python37\lib\site-packages\botocore\client.py", line 314, in _api_call
return self._make_api_call(operation_name, kwargs)
File "C:\Users\roshan.hiripitiyaga\AppData\Local\Programs\Python\Python37\lib\site-packages\botocore\client.py", line 612, in _make_api_call
raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (AuthFailure) when calling the DescribeSnapshots operation: AWS was not able to validate the provided access credentials

@torrencer

This comment has been minimized.

Copy link

commented Oct 9, 2018

How could I convert this to PowerShell?

@uolter

This comment has been minimized.

Copy link

commented Nov 14, 2018

Could it be the csv file name should be: report.csv instead of raport.csv :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.