Skip to content

Instantly share code, notes, and snippets.

@nestoru
Last active December 27, 2016 15:29
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 nestoru/46d3e7797eb638c33f2abe8906c1fd8a to your computer and use it in GitHub Desktop.
Save nestoru/46d3e7797eb638c33f2abe8906c1fd8a to your computer and use it in GitHub Desktop.
AWS cross region replication lambda service
# 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