cleanup_ec2.py 6.59 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
'''
Find and delete AWS resources matching the provided --match string.  Unless
--yes|-y is provided, the prompt for confirmation prior to deleting resources.
Please use caution, you can easily delete you're *ENTIRE* EC2 infrastructure.
'''

import os
import re
import sys
import boto
import optparse
import yaml
13
import os.path
14
import boto.ec2.elb
15
import time
16 17 18 19 20

def delete_aws_resources(get_func, attr, opts):
    for item in get_func():
        val = getattr(item, attr)
        if re.search(opts.match_re, val):
21
            prompt_and_delete(item, "Delete matching %s? [y/n]: " % (item,), opts.assumeyes)
22

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
def delete_autoscaling_group(get_func, attr, opts):
    assumeyes = opts.assumeyes
    group_name = None
    for item in get_func():
        group_name = getattr(item, attr)
        if re.search(opts.match_re, group_name):
            if not opts.assumeyes:
                assumeyes = raw_input("Delete matching %s? [y/n]: " % (item).lower()) == 'y'
            break
    if assumeyes and group_name:
        groups = asg.get_all_groups(names=[group_name])
        if groups:
            group = groups[0]
            group.max_size = 0
            group.min_size = 0
            group.desired_capacity = 0
            group.update()
            instances = True
            while instances:
                tmp_groups = asg.get_all_groups(names=[group_name])
                if tmp_groups:
                    tmp_group = tmp_groups[0]
                    if not tmp_group.instances:
                       instances = False
                time.sleep(10)

            group.delete()
            while len(asg.get_all_groups(names=[group_name])):
                time.sleep(5)
            print ("Terminated ASG: %s" % group_name)

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
def delete_aws_eips(get_func, attr, opts):

    # the file might not be there if the integration test wasn't run
    try:
      eip_log = open(opts.eip_log, 'r').read().splitlines()
    except IOError:
      print opts.eip_log, 'not found.'
      return

    for item in get_func():
        val = getattr(item, attr)
        if val in eip_log:
          prompt_and_delete(item, "Delete matching %s? [y/n]: " % (item,), opts.assumeyes)

def delete_aws_instances(reservation, opts):
    for list in reservation:
        for item in list.instances:
            prompt_and_delete(item, "Delete matching %s? [y/n]: " % (item,), opts.assumeyes)

73 74 75
def prompt_and_delete(item, prompt, assumeyes):
    if not assumeyes:
        assumeyes = raw_input(prompt).lower() == 'y'
76
    assert hasattr(item, 'delete') or hasattr(item, 'terminate') , "Class <%s> has no delete or terminate attribute" % item.__class__
77
    if assumeyes:
78 79 80 81 82 83
        if  hasattr(item, 'delete'):
            item.delete()
            print ("Deleted %s" % item)
        if  hasattr(item, 'terminate'):
            item.terminate()
            print ("Terminated %s" % item)
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

def parse_args():
    # Load details from credentials.yml
    default_aws_access_key = os.environ.get('AWS_ACCESS_KEY', None)
    default_aws_secret_key = os.environ.get('AWS_SECRET_KEY', None)
    if os.path.isfile('credentials.yml'):
        credentials = yaml.load(open('credentials.yml', 'r'))

        if default_aws_access_key is None:
            default_aws_access_key = credentials['ec2_access_key']
        if default_aws_secret_key is None:
            default_aws_secret_key = credentials['ec2_secret_key']

    parser = optparse.OptionParser(usage="%s [options]" % (sys.argv[0],),
                description=__doc__)
    parser.add_option("--access",
        action="store", dest="ec2_access_key",
        default=default_aws_access_key,
        help="Amazon ec2 access id.  Can use EC2_ACCESS_KEY environment variable, or a values from credentials.yml.")
    parser.add_option("--secret",
        action="store", dest="ec2_secret_key",
        default=default_aws_secret_key,
        help="Amazon ec2 secret key.  Can use EC2_SECRET_KEY environment variable, or a values from credentials.yml.")
107 108 109 110 111 112 113 114
    parser.add_option("--eip-log",
        action="store", dest="eip_log",
        default = None,
        help = "Path to log of EIPs created during test.")
    parser.add_option("--integration-config",
        action="store", dest="int_config",
        default = "integration_config.yml",
        help = "path to integration config")
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    parser.add_option("--credentials", "-c",
        action="store", dest="credential_file",
        default="credentials.yml",
        help="YAML file to read cloud credentials (default: %default)")
    parser.add_option("--yes", "-y",
        action="store_true", dest="assumeyes",
        default=False,
        help="Don't prompt for confirmation")
    parser.add_option("--match",
        action="store", dest="match_re",
        default="^ansible-testing-",
        help="Regular expression used to find AWS resources (default: %default)")

    (opts, args) = parser.parse_args()
    for required in ['ec2_access_key', 'ec2_secret_key']:
        if getattr(opts, required) is None:
            parser.error("Missing required parameter: --%s" % required)

133

134 135 136 137 138 139
    return (opts, args)

if __name__ == '__main__':

    (opts, args) = parse_args()

140 141 142 143 144
    int_config = yaml.load(open(opts.int_config).read())
    if not opts.eip_log:
        output_dir = os.path.expanduser(int_config["output_dir"])
        opts.eip_log = output_dir + '/' + opts.match_re.replace('^','') + '-eip_integration_tests.log'

145 146 147 148
    # Connect to AWS
    aws = boto.connect_ec2(aws_access_key_id=opts.ec2_access_key,
            aws_secret_access_key=opts.ec2_secret_key)

149 150 151
    elb = boto.connect_elb(aws_access_key_id=opts.ec2_access_key,
            aws_secret_access_key=opts.ec2_secret_key)

152 153 154
    asg = boto.connect_autoscale(aws_access_key_id=opts.ec2_access_key,
            aws_secret_access_key=opts.ec2_secret_key)

155 156 157
    try:
        # Delete matching keys
        delete_aws_resources(aws.get_all_key_pairs, 'name', opts)
158

159
        # Delete matching security groups
160
        delete_aws_resources(aws.get_all_security_groups, 'name', opts)
161

162
        # Delete matching ASGs
163
        delete_autoscaling_group(asg.get_all_groups, 'name', opts)
164 165 166 167

        # Delete matching launch configs
        delete_aws_resources(asg.get_all_launch_configurations, 'name', opts)

168 169 170
        # Delete ELBs
        delete_aws_resources(elb.get_all_load_balancers, 'name', opts)

171 172 173 174 175 176 177
        # Delete recorded EIPs
        delete_aws_eips(aws.get_all_addresses, 'public_ip', opts)

        # Delete temporary instances
        filters = {"tag:Name":opts.match_re.replace('^',''), "instance-state-name": ['running', 'pending', 'stopped' ]}
        delete_aws_instances(aws.get_all_instances(filters=filters), opts)

178 179
    except KeyboardInterrupt, e:
        print "\nExiting on user command."