Last active
December 27, 2016 15:29
-
-
Save nestoru/46d3e7797eb638c33f2abe8906c1fd8a to your computer and use it in GitHub Desktop.
AWS cross region replication lambda service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# aws-cross-region-replicate-all-lambda.py | |
# @author: Nestor Urquiza | |
# @date: 20161226 | |
# @description: Cross Region replication script. Use at your own risk! | |
# Customize this lambda looking for TOCHANGETHIS: identifier | |
import boto3 | |
import botocore | |
from pprint import pprint | |
# TOCHANGETHIS: | |
# Environment specific constants | |
SOURCE_REGION = 'us-east-1' | |
TARGET_REGION = 'us-west-1' | |
# Define clients for the two regions | |
source_ec2 = boto3.client('ec2', region_name=SOURCE_REGION) | |
target_ec2 = boto3.client('ec2', region_name=TARGET_REGION) | |
# Define the array to keep track of valid descriptions to be replicated | |
snapshot_descriptions = [] | |
def lambda_handler(event, context): | |
# TOCHANGETHIS: | |
# Define what specific instance tags should be scanned for replication | |
# In this case test and production instances are tagged for in region backups (BCP) | |
# We use those same in region backup tags to drive the cross region replication (DR) | |
reservations_test = source_ec2.describe_instances( | |
Filters=[ | |
{'Name': 'tag:scheduler:ebs-snapshot:test', 'Values': ['true']}, | |
] | |
).get( | |
'Reservations', [] | |
) | |
reservations_prod = source_ec2.describe_instances( | |
Filters=[ | |
{'Name': 'tag:scheduler:ebs-snapshot:prod', 'Values': ['true']}, | |
] | |
).get( | |
'Reservations', [] | |
) | |
reservations = reservations_test + reservations_prod | |
instances = sum( | |
[ | |
[i for i in r['Instances']] | |
for r in reservations | |
], []) | |
# A list of replicated snapshots will be printed | |
print "Replicated:" | |
print "InstanceName\tInstanceId\tVolumeName\tVolumeId\tSnapshotId\tSnapshotState" | |
for instance in instances: | |
instance_id = instance['InstanceId'] | |
try: | |
instance_name = [ | |
str(t.get('Value')) for t in instance['Tags'] | |
if t['Key'] == 'Name'][0] | |
except IndexError: | |
instance_name = 'None' | |
# Find volumes in used by qualified for replication instances | |
for dev in instance['BlockDeviceMappings']: | |
if dev.get('Ebs', None) is None: | |
continue | |
volume_id = dev['Ebs']['VolumeId'] | |
# Get the volume name | |
volume = source_ec2.describe_volumes( | |
Filters = [ | |
{ | |
'Name': 'volume-id', | |
'Values': [ | |
volume_id, | |
] | |
} | |
] | |
)['Volumes'][0] | |
try: | |
volume_name = [ | |
str(t.get('Value')) for t in volume['Tags'] | |
if t['Key'] == 'Name'][0] | |
except IndexError: | |
volume_name = 'None' | |
# Find the snapshots for the volume | |
source_snapshots = source_ec2.describe_snapshots( | |
Filters = [ | |
{ | |
'Name': 'volume-id', | |
'Values': [ | |
volume_id, | |
] | |
} | |
] | |
)['Snapshots'] | |
for snapshot in source_snapshots: | |
snapshot_id = snapshot['SnapshotId'] | |
snapshot_state = snapshot['State'] | |
# Snapshots that are not completed do not qualify for replication | |
if(snapshot_state != 'completed'): | |
continue | |
snapshot_description = instance_name + ':' + volume_name + ':' + snapshot_id | |
# Keep track of those snapshots description we do want in the target | |
snapshot_descriptions.append(snapshot_description) | |
# Find any target snapshot that is already a replica | |
target_snapshots = target_ec2.describe_snapshots( | |
Filters = [ | |
{ | |
'Name': 'description', | |
'Values': [ | |
snapshot_description, | |
] | |
} | |
] | |
)['Snapshots'] | |
# Replicate only those snapshots that were not replicated before | |
if not target_snapshots: | |
try: | |
target_snapshot = target_ec2.copy_snapshot( | |
SourceRegion=SOURCE_REGION, | |
SourceSnapshotId=snapshot_id, | |
Description=snapshot_description, | |
DestinationRegion=TARGET_REGION | |
) | |
except botocore.exceptions.ClientError: | |
# Swallow the exception. Most likely more than 5 snapshots are being replicated | |
target_snapshot = None | |
if(target_snapshot): | |
print '%s\t%s\t%s\t%s\t%s\t%s' % ( | |
instance_name, instance_id, volume_name, volume_id, snapshot_id, snapshot_state) | |
# TOCHANGETHIS: Feel free to activate all the following code but be aware of possible accidental deletion of target snapshots | |
# Delete the target snapshots that are not in the source | |
''' | |
OWNER_ID = '000000000000' | |
target_snapshots = target_ec2.describe_snapshots( | |
Filters = [ | |
{ | |
'Name': 'owner-id', | |
'Values': [ | |
OWNER_ID, | |
] | |
} | |
] | |
)['Snapshots'] | |
for snapshot in target_snapshots: | |
if snapshot['Description'] not in snapshot_descriptions and snapshot['State'] == 'completed': | |
snapshot_id = snapshot['SnapshotId'] | |
target_ec2.delete_snapshot( | |
SnapshotId = snapshot_id | |
) | |
print "Snapshot %s deleted from %s" % ( | |
snapshot_id, TARGET_REGION) | |
''' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment