Skip to content

Instantly share code, notes, and snippets.

@bdpdx
Created December 7, 2016 07:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bdpdx/0ebb6e0849564153e34f2733c03114ae to your computer and use it in GitHub Desktop.
Save bdpdx/0ebb6e0849564153e34f2733c03114ae to your computer and use it in GitHub Desktop.
import boto3
import collections
import datetime
ec = boto3.client('ec2')
# inspired by https://serverlesscode.com/post/lambda-schedule-ebs-snapshot-backups/
#
# snapshot deletion lambda
# this function deletes snapshots backed up by the EBSSnapshotterCreator
# prerequisites:
# only snapshots for attached volumes are considered
# the instance that owns the volume must have a Backup=true tag
# the instance may optionally have a BackupRetentionDays=n tag where n
# is an integer specifying the number of days to retain backups.
# if not present, the default is 0
# this script only considers completed EBS backups for deletion, and it
# will always retain the most current complete backup. Only snapshots
# that have the createdByEBSSnapshotter=true tag will be considered.
def lambda_handler(event, context):
now = datetime.datetime.now()
volumeIds = {}
reservations = ec.describe_instances()['Reservations']
for reservation in reservations:
for instance in reservation['Instances']:
backup = False
backupRetentionDays = 0
for tag in instance['Tags']:
key = tag['Key']
value = tag['Value']
if key == 'Backup':
backup = tag['Value'] == 'true'
elif key == 'BackupRetentionDays':
backupRetentionDays = int(tag['Value'])
if not backup: continue
retentionDate = (now - datetime.timedelta(days=backupRetentionDays)).date()
for device in instance['BlockDeviceMappings']:
if device.get('Ebs', None) is None: continue
volumeId = device['Ebs']['VolumeId']
info = ec.describe_volumes(VolumeIds=[volumeId])['Volumes'][0]
name = volumeId
skip = False
for tag in info['Tags']:
key = tag['Key']
if key == 'Backup':
skip = tag['Value'] == 'false'
elif key == 'Name':
name += ' (' + tag['Value'] + ')'
if skip:
print 'Ignoring snapshots for volume %s due to Backup=false tag' % (name)
continue
else:
volumeIds[volumeId] = {
'name': name,
'retentionDate': retentionDate,
'snapshotsToDelete': []
}
accountId = '000000000000' # your 12-digit AWS account id here
snapshots = ec.describe_snapshots(OwnerIds=[accountId])['Snapshots']
for snapshot in snapshots:
if not snapshot['State'] == 'completed': continue
volumeId = snapshot['VolumeId']
if volumeId not in volumeIds: continue
createdByEBSSnapshotter = False
tags = snapshot.get('Tags', None)
if tags is None: continue
for tag in tags:
if tag['Key'] == 'createdByEBSSnapshotter':
createdByEBSSnapshotter = tag['Value'] == 'true'
break
if not createdByEBSSnapshotter: continue
creationDate = snapshot['StartTime'].date()
retentionDate = volumeIds[volumeId]['retentionDate']
if creationDate > retentionDate: continue
snapshotId = snapshot['SnapshotId']
volumeIds[volumeId]['snapshotsToDelete'].append((snapshotId, creationDate))
for volumeId in volumeIds.keys():
name = volumeIds[volumeId]['name']
snapshotsToDelete = volumeIds[volumeId]['snapshotsToDelete']
if len(snapshotsToDelete) < 2:
print 'Ignoring snapshots for volume %s because there are fewer than 2 snapshots' % (name)
continue # always leave one complete snapshot
snapshotsToDelete = sorted(snapshotsToDelete, key=lambda creationDate: creationDate[1])
snapshotsToDelete.pop()
for snapshot in snapshotsToDelete:
snapshotId = snapshot[0]
print 'Deleting snapshot %s for volume %s' % (snapshotId, name)
ec.delete_snapshot(SnapshotId=snapshotId)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment