create_stack.py 3.85 KB
Newer Older
1
import argparse
2
import boto
3
import yaml
4 5
from os.path import basename
from time import sleep
6 7
from pprint import pprint

8

9 10 11 12 13 14 15 16 17
FAILURE_STATES = [
    'CREATE_FAILED',
    'ROLLBACK_IN_PROGRESS',
    'ROLLBACK_FAILED',
    'ROLLBACK_COMPLETE',
    'DELETE_IN_PROGRESS',
    'DELETE_FAILED',
    'DELETE_COMPLETE',
    ]
18

19
def upload_file(file_path, bucket_name, key_name):
20 21 22 23 24 25 26 27 28 29 30
    """
    Upload a file to the given s3 bucket and return a template url.
    """
    conn = boto.connect_s3()
    try:
        bucket = conn.get_bucket(bucket_name)
    except boto.exception.S3ResponseError as e:
        conn.create_bucket(bucket_name)
        bucket = conn.get_bucket(bucket_name, validate=False)

    key = boto.s3.key.Key(bucket)
31
    key.key = key_name
32 33
    key.set_contents_from_filename(file_path)

34
    key.set_acl('public-read')
35 36
    url = "https://s3.amazonaws.com/{}/{}".format(bucket.name, key.name)
    print( "URL: {}".format(url))
37
    return url
38

39
def create_stack(stack_name, template, region='us-east-1', blocking=True,
40 41
                 temp_bucket='edx-sandbox-devops', parameters=[],
                 update=False):
42

43 44 45
    cfn = boto.connect_cloudformation()

    # Upload the template to s3
46 47
    key_pattern = 'devops/cloudformation/auto/{}_{}'
    key_name = key_pattern.format(stack_name, basename(template))
Feanil Patel committed
48
    template_url = upload_file(template, temp_bucket, key_name)
49 50 51

    # Reference the stack.
    try:
52 53 54 55 56 57 58 59 60 61 62 63
        if update:
            stack_id = cfn.update_stack(stack_name,
                template_url=template_url,
                capabilities=['CAPABILITY_IAM'],
                tags={'autostack':'true'},
                parameters=parameters)
        else:
            stack_id = cfn.create_stack(stack_name,
                template_url=template_url,
                capabilities=['CAPABILITY_IAM'],
                tags={'autostack':'true'},
                parameters=parameters)
64 65 66 67
    except Exception as e:
        print(e.message)
        raise e

68
    status = None
69 70 71 72 73 74 75 76 77
    while blocking:
        sleep(5)
        stack_instance = cfn.describe_stacks(stack_id)[0]
        status = stack_instance.stack_status
        print(status)
        if 'COMPLETE' in status:
            break

    if status in FAILURE_STATES:
Feanil Patel committed
78
        raise Exception('Creation Failed. Stack Status: {}, ID:{}'.format(
79 80 81 82
            status, stack_id))

    return stack_id

83 84 85
def cfn_params_from(filename):
    params_dict = yaml.safe_load(open(filename))
    return [ (key,value) for key,value in params_dict.items() ]
86 87 88

if __name__ == '__main__':
        description = 'Create a cloudformation stack from a template.'
Feanil Patel committed
89 90
        parser = argparse.ArgumentParser(description=description)

91 92 93
        msg = 'Name for the cloudformation stack.'
        parser.add_argument('-n', '--stackname', required=True, help=msg)

94 95 96
        msg = 'Pass this argument if we are updating an existing stack.'
        parser.add_argument('-u', '--update', action='store_true')

97 98 99 100 101 102 103
        msg = 'Name of the bucket to use for temporarily uploading the \
            template.'
        parser.add_argument('-b', '--bucketname', default="edx-sandbox-devops",
            help=msg)

        msg = 'The path to the cloudformation template.'
        parser.add_argument('-t', '--template', required=True, help=msg)
104

105 106
        msg = 'The AWS region to build this stack in.'
        parser.add_argument('-r', '--region', default='us-east-1', help=msg)
107 108 109 110 111

        msg = 'YAML file containing stack build parameters'
        parser.add_argument('-p', '--parameters', help=msg)

        args = parser.parse_args()
112 113 114
        stack_name = args.stackname
        template = args.template
        region = args.region
Feanil Patel committed
115
        bucket_name = args.bucketname
116
        parameters = cfn_params_from(args.parameters)
117
        update = args.update
118

119
        create_stack(stack_name, template, region, temp_bucket=bucket_name, parameters=parameters, update=update)
120
        print('Stack({}) created.'.format(stack_name))