Skip to content
This repository has been archived by the owner on Jun 13, 2024. It is now read-only.

Commit

Permalink
Added backup management to create-(images|snapshots) scripts.
Browse files Browse the repository at this point in the history
Removed obsolete backup-(instances|volumes) scripts.

[Issue(s) #26]
  • Loading branch information
sopel committed Dec 14, 2012
1 parent 501c43e commit a2fee11
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 207 deletions.
26 changes: 20 additions & 6 deletions botocross/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,30 @@ def build_region_parser():

def build_filter_parser(resource_name, add_ids=True):
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("-f", "--filter", action="append", help="A {0} filter. [can be used multiple times]".format(resource_name))
parser.add_argument("-x", "--exclude", action="append", help="A {0} filter (matching ones are excluded). [can be used multiple times]".format(resource_name))
parser.add_argument("-f", "--filter", action="append",
help="A {0} filter. [can be used multiple times]".format(resource_name))
parser.add_argument("-x", "--exclude", action="append",
help="A {0} filter (matching ones are excluded). [can be used multiple times]".format(resource_name))
if add_ids:
parser.add_argument("-i", "--id", dest="resource_ids", action="append", help="A {0} id. [can be used multiple times]".format(resource_name))
parser.add_argument("-i", "--id", dest="resource_ids", action="append",
help="A {0} id. [can be used multiple times]".format(resource_name))
return parser

def build_timeout_parser():
def build_backup_parser(resource_name, expire_only=False, backup_retention=None):
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("--timeout", default='P1D',
help="An ISO 8601 duration [default: 'P1D', i.e. one day]")
if not expire_only:
parser.add_argument("-d", "--description",
help="A description for the {0} [default: <provided>]".format(resource_name))
default_retention_help = str(backup_retention) if backup_retention else "None, i.e. don't expire"
parser.add_argument("-br", "--backup_retention", type=int, default=backup_retention,
help="The number of backups to retain (correlated via backup_set). [default: {0}]".format(default_retention_help))
parser.add_argument("-bs", "--backup_set", default='default',
help="A backup set name (determines retention correlation). [default: 'default'")
if not expire_only:
parser.add_argument("-bt", "--backup_timeout", default=None,
help="Maximum duration to await successful resource creation - an ISO 8601 duration, e.g. 'PT8H' (8 hours). [default: None, i.e. don't await]")
parser.add_argument("-ns", "--no_origin_safeguard", action="store_true",
help="Allow deletion of images originating from other tools. [default: False]")
return parser

def parse_credentials(args):
Expand Down
1 change: 0 additions & 1 deletion botocross/ec2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

AWAIT_TRANSITION_DELAY = 4
AWAIT_TRANSITION_TIMEOUT = "P1D"
DEFAULT_BACKUP_SET = "default"
CREATED_BY_BOTO_EBS_SNAPSHOT_SCRIPT_SIGNATURE = "Created by Botocross EBS Snapshot Script from "
CREATED_BY_BOTO_EC2_IMAGE_SCRIPT_SIGNATURE = "Created by Botocross EC2 Image Script from "
IMAGE_STATES_PROGRESSING = { 'pending' }
Expand Down
83 changes: 0 additions & 83 deletions scripts/backup-instances.py

This file was deleted.

81 changes: 0 additions & 81 deletions scripts/backup-volumes.py

This file was deleted.

34 changes: 26 additions & 8 deletions scripts/create-images.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@
import boto.ec2
import botocross as bc
import logging
import sys

# configure command line argument parsing
parser = argparse.ArgumentParser(description='Create images of EC2 instances in all/some available EC2 regions',
parents=[bc.build_region_parser(), bc.build_filter_parser('EC2 instance'), bc.build_common_parser()])
parser.add_argument("-d", "--description", help="A description for the EC2 image [default: <provided>]")
parents=[bc.build_region_parser(), bc.build_filter_parser('EC2 instance'),
bc.build_backup_parser('EC2 instance'), bc.build_common_parser()])
parser.add_argument("-nr", "--no_reboot", action="store_true", help="Prevent shut down of instance before creating the image. [default: False]")
parser.add_argument("-bs", "--backup_set", default=DEFAULT_BACKUP_SET, help="A backup set name (determines retention correlation). [default: 'default'")
args = parser.parse_args()

# process common command line arguments
Expand All @@ -42,14 +42,12 @@
credentials = bc.parse_credentials(args)
regions = bc.filter_regions(boto.ec2.regions(), args.region)
filter = bc.build_filter(args.filter, args.exclude)
log.info(args.resource_ids)

# execute business logic
log.info("Imaging EC2 instances:")

backup_set = args.backup_set if args.backup_set else DEFAULT_BACKUP_SET
log.debug(backup_set)

# REVIEW: For backup purposes it seems reasonable to only consider all OK vs. FAIL?!
exit_code = bc.ExitCodes.OK
for region in regions:
try:
ec2 = boto.connect_ec2(region=region, **credentials)
Expand All @@ -58,7 +56,27 @@
exclusions = ec2.get_all_instances(filters=filter['excludes'])
reservations = bc.filter_list_by_attribute(reservations, exclusions, 'id')
instances = [instance for reservation in reservations for instance in reservation.instances]

print region.name + ": " + str(len(instances)) + " instances"
create_images(ec2, instances, backup_set, args.description, no_reboot=args.no_reboot)
images = create_images(ec2, instances, args.backup_set, args.description, no_reboot=args.no_reboot)

if args.backup_timeout:
try:
states = await_images(ec2, images, timeout=args.backup_timeout)
if not bc.ec2.IMAGE_STATES_SUCCEEDED.issuperset(states):
message = "FAILED to create some images: {0}!".format(format_states(states))
log.error(message)
exit_code = bc.ExitCodes.FAIL
except bc.BotocrossAwaitTimeoutError, e:
log.error(e.message)
exit_code = bc.ExitCodes.FAIL

if args.backup_retention:
instance_ids = [instance.id for instance in instances]
expire_images(ec2, instance_ids, args.backup_set, args.backup_retention, args.no_origin_safeguard)

except boto.exception.BotoServerError, e:
log.error(e.error_message)
exit_code = bc.ExitCodes.FAIL

sys.exit(exit_code)
34 changes: 26 additions & 8 deletions scripts/create-snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
import boto.ec2
import botocross as bc
import logging
import sys

# configure command line argument parsing
parser = argparse.ArgumentParser(description='Create snapshots of EBS volumes in all/some available EC2 regions',
parents=[bc.build_region_parser(), bc.build_filter_parser('EBS volume'), bc.build_common_parser()])
parser.add_argument("-d", "--description", help="A description for the EBS snapshot [default: <provided>]")
parser.add_argument("-bs", "--backup_set", default=DEFAULT_BACKUP_SET, help="A backup set name (determines retention correlation). [default: 'default'")
parents=[bc.build_region_parser(), bc.build_filter_parser('EBS volume'),
bc.build_backup_parser('EBS volume'), bc.build_common_parser()])
args = parser.parse_args()

# process common command line arguments
Expand All @@ -41,22 +41,40 @@
credentials = bc.parse_credentials(args)
regions = bc.filter_regions(boto.ec2.regions(), args.region)
filter = bc.build_filter(args.filter, args.exclude)
log.info(args.resource_ids)

# execute business logic
log.info("Snapshotting EBS volumes:")

backup_set = args.backup_set if args.backup_set else DEFAULT_BACKUP_SET
log.debug(backup_set)

# REVIEW: For backup purposes it seems reasonable to only consider all OK vs. FAIL?!
exit_code = bc.ExitCodes.OK
for region in regions:
try:
ec2 = boto.connect_ec2(region=region, **credentials)
volumes = ec2.get_all_volumes(volume_ids=args.resource_ids, filters=filter['filters'])
if filter['excludes']:
exclusions = ec2.get_all_volumes(filters=filter['excludes'])
volumes = bc.filter_list_by_attribute(volumes, exclusions, 'id')

print region.name + ": " + str(len(volumes)) + " volumes"
create_snapshots(ec2, volumes, backup_set, args.description)
snapshots = create_snapshots(ec2, volumes, args.backup_set, args.description)

if args.backup_timeout:
try:
states = await_snapshots(ec2, snapshots, timeout=args.backup_timeout)
if not bc.ec2.SNAPSHOT_STATES_SUCCEEDED.issuperset(states):
message = "FAILED to create some snapshots: {0}!".format(format_states(states))
log.error(message)
exit_code = bc.ExitCodes.FAIL
except bc.BotocrossAwaitTimeoutError, e:
log.error(e.message)
exit_code = bc.ExitCodes.FAIL

if args.backup_retention:
volume_ids = [volume.id for volume in volumes]
expire_snapshots(ec2, volume_ids, args.backup_set, args.backup_retention, args.no_origin_safeguard)

except boto.exception.BotoServerError, e:
log.error(e.error_message)
exit_code = bc.ExitCodes.FAIL

sys.exit(exit_code)
12 changes: 3 additions & 9 deletions scripts/expire-images.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,8 @@

# configure command line argument parsing
parser = argparse.ArgumentParser(description='Expire images of EC2 instances in all/some available EC2 regions',
parents=[bc.build_region_parser(), bc.build_filter_parser('EC2 instance'), bc.build_common_parser()])
parser.add_argument("-br", "--backup_retention", type=int, default=1, help="The number of backups to retain (correlated via backup_set). [default: 1]")
parser.add_argument("-bs", "--backup_set", default=DEFAULT_BACKUP_SET, help="A backup set name (determines retention correlation). [default: 'default]'")
parser.add_argument("-ns", "--no_origin_safeguard", action="store_true", help="Allow deletion of images originating from other tools. [default: False]")
parents=[bc.build_region_parser(), bc.build_filter_parser('EC2 instance'),
bc.build_backup_parser('EC2 instance', True, 1), bc.build_common_parser()])
args = parser.parse_args()

# process common command line arguments
Expand All @@ -42,14 +40,10 @@
credentials = bc.parse_credentials(args)
regions = bc.filter_regions(boto.ec2.regions(), args.region)
filter = bc.build_filter(args.filter, args.exclude)
log.info(args.resource_ids)

# execute business logic
log.info("Expire EC2 images:")

backup_set = args.backup_set if args.backup_set else DEFAULT_BACKUP_SET
log.debug(backup_set)

for region in regions:
try:
ec2 = boto.connect_ec2(region=region, **credentials)
Expand All @@ -63,6 +57,6 @@
if args.resource_ids:
instance_ids.extend(args.resource_ids)
print region.name + ": " + str(num_instances) + " instances / " + str(len(instance_ids)) + " instance IDs"
expire_images(ec2, instance_ids, backup_set, args.backup_retention, args.no_origin_safeguard)
expire_images(ec2, instance_ids, args.backup_set, args.backup_retention, args.no_origin_safeguard)
except boto.exception.BotoServerError, e:
log.error(e.error_message)
Loading

0 comments on commit a2fee11

Please sign in to comment.