Skip to content

Instantly share code, notes, and snippets.

@gavsmi
Last active August 29, 2015 14:03
Show Gist options
  • Save gavsmi/dd31746e5847300b62da to your computer and use it in GitHub Desktop.
Save gavsmi/dd31746e5847300b62da to your computer and use it in GitHub Desktop.
Find snapshot by tag, create volume from it and mount.
#! /usr/bin/python
from boto.utils import get_instance_metadata
import boto.ec2
import argparse, logging, time, os
def parsed_args():
# parse cmd line args
parser = argparse.ArgumentParser(description='Find snapshot by tag, create volume from it and mount.')
parser.add_argument('--id',
help='ID of existing snapshot to mount')
parser.add_argument('--tag-name',
help='Name of tag to filter snapshots on')
parser.add_argument('--tag-value',
help='Value of tag to filter snapshots on')
parser.add_argument('--aws-mount-point',
help='The desired mount point as defined by AWS. default is /dev/sdf',
default='/dev/sdf')
parser.add_argument('--os-mount-point',
help='The desired mount point as defined by the OS, default is /dev/xvdf',
default='/dev/xvdf')
parser.add_argument('--volume-type',
help='Type of volume to create, default is gp2',
default='gp2')
return parser.parse_args();
def main():
args = parsed_args();
snapshot = find_snapshot(args.tag_name, args.tag_value)
if(snapshot is None):
snapshot = get_snapshot(args.id)
volume = create_volume(snapshot, args.volume_type)
attach_volume(volume, args.aws_mount_point, args.os_mount_point)
set_volume_delete(args.aws_mount_point)
logging.info('Volume attached!')
exit(0)
def find_snapshot(tag_name, tag_value):
logging.info('Finding snapshot for tag...')
conn = boto.ec2.connect_to_region(current_region())
snapshots = conn.get_all_snapshots(filters={'tag:' + tag_name: tag_value})
snapshots.sort(date_compare)
if(len(snapshots) > 0):
logging.info('Snapshot found with tag %s:%s' % (tag_name, tag_value))
return snapshots[0]
else:
return None
def get_snapshot(id):
logging.info('Getting snapshot by id...')
conn = boto.ec2.connect_to_region(current_region())
snapshots = conn.get_all_snapshots(snapshot_ids=[id])
if(len(snapshots) > 0):
logging.info('Snapshot found')
return snapshots[0]
else:
raise Exception('No snapshot found with id %s' % id)
def create_volume(snapshot, volume_type):
logging.info('Creating new volume from snapshot: %s' % snapshot)
conn = boto.ec2.connect_to_region(current_region())
volume = conn.create_volume(zone=current_zone(), size=snapshot.volume_size, volume_type=volume_type, snapshot=snapshot)
wait_for_volume(volume, 'available')
return volume
def set_volume_delete(mount_point):
logging.info('Setting volume to delete on termination...')
metadata = get_instance_metadata()
instanceId = metadata['instance-id']
conn = boto.ec2.connect_to_region(current_region())
reservations = conn.get_all_instances(instance_ids=[instanceId])
instance = reservations[0].instances[0]
instance.modify_attribute('blockDeviceMapping', [mount_point + '=1'])
def attach_volume(volume, aws_mount_point, os_mount_point):
logging.info('Attaching volume to instance')
conn = boto.ec2.connect_to_region(current_region())
metadata = get_instance_metadata()
volume_status = conn.attach_volume(volume_id=volume.id, instance_id=metadata['instance-id'], device=aws_mount_point)
wait_for_volume(volume, 'in-use')
wait_for_fstab(os_mount_point, 'present')
return True
def wait_for_volume(volume, expected_status):
volume_status = 'waiting'
sleep_seconds = 2
sleep_intervals = 30
for counter in range(sleep_intervals):
logging.info('elapsed: %s. status: %s.' % (sleep_seconds * counter, volume_status))
conn = boto.ec2.connect_to_region(current_region())
volume_status = conn.get_all_volumes(volume_ids=[volume.id])[0].status
if volume_status == expected_status:
break
time.sleep(sleep_seconds)
if volume_status != expected_status:
raise Exception('Unable to get %s status for volume %s' % (expected_status, volume.id))
logging.info('Volume now in %s state' % expected_status)
def wait_for_fstab(mount_point, expected_status):
volume_status = 'not present'
sleep_seconds = 2
sleep_intervals = 30
for counter in range(sleep_intervals):
logging.info('elapsed: %s. status: %s.' % (sleep_seconds * counter, volume_status))
try:
os.stat(mount_point)
volume_status = expected_status
except: OSError
# mount does not exist yet, try again later...
if volume_status == expected_status:
break
time.sleep(sleep_seconds)
if volume_status != expected_status:
raise Exception('Unable to get %s status for volume %s' % (expected_status, volume.id))
logging.info('Volume now in %s state' % expected_status)
def current_zone():
metadata = get_instance_metadata()
return metadata['placement']['availability-zone']
def current_region():
zone = current_zone()
return zone[:-1]
def date_compare(snap1, snap2):
if snap1.start_time < snap2.start_time:
return 1
elif snap1.start_time == snap2.start_time:
return 0
return -1
if __name__ == '__main__':
logging.getLogger().setLevel(logging.INFO)
main()
@leitsu
Copy link

leitsu commented Apr 17, 2015

Hi Gavin, I like what your script does. What should I be put in for --tag-name and --tag-value ? Where I can find the name and value of the tag in AWS console?

@gavsmi
Copy link
Author

gavsmi commented Apr 29, 2015

Hi, --tag-name and --tag-value should match any tags you have set on the snapshot so the script will filter snapshots by those tags. You can view / edit the tags on the Tags tab in the 'Snapshots' section of the EC2 console.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment