Commit 2af69181 by Kevin Falcone

Neither of these has been touched in a long time

Anyone using cloudformation to stand up edX should probably have custom
templates/scripts at this point.
parent 6b817024
import argparse
import boto
import yaml
from os.path import basename
from time import sleep
from pprint import pprint
FAILURE_STATES = [
'CREATE_FAILED',
'ROLLBACK_IN_PROGRESS',
'ROLLBACK_FAILED',
'ROLLBACK_COMPLETE',
'DELETE_IN_PROGRESS',
'DELETE_FAILED',
'DELETE_COMPLETE',
]
def upload_file(file_path, bucket_name, key_name):
"""
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)
key.key = key_name
key.set_contents_from_filename(file_path)
key.set_acl('public-read')
url = "https://s3.amazonaws.com/{}/{}".format(bucket.name, key.name)
print( "URL: {}".format(url))
return url
def create_stack(stack_name, template, region='us-east-1', blocking=True,
temp_bucket='edx-sandbox-devops', parameters=[],
update=False):
cfn = boto.connect_cloudformation()
# Upload the template to s3
key_pattern = 'devops/cloudformation/auto/{}_{}'
key_name = key_pattern.format(stack_name, basename(template))
template_url = upload_file(template, temp_bucket, key_name)
# Reference the stack.
try:
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)
except Exception as e:
print(e.message)
raise e
status = None
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:
raise Exception('Creation Failed. Stack Status: {}, ID:{}'.format(
status, stack_id))
return stack_id
def cfn_params_from(filename):
params_dict = yaml.safe_load(open(filename))
return [ (key,value) for key,value in params_dict.items() ]
if __name__ == '__main__':
description = 'Create a cloudformation stack from a template.'
parser = argparse.ArgumentParser(description=description)
msg = 'Name for the cloudformation stack.'
parser.add_argument('-n', '--stackname', required=True, help=msg)
msg = 'Pass this argument if we are updating an existing stack.'
parser.add_argument('-u', '--update', action='store_true')
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)
msg = 'The AWS region to build this stack in.'
parser.add_argument('-r', '--region', default='us-east-1', help=msg)
msg = 'YAML file containing stack build parameters'
parser.add_argument('-p', '--parameters', help=msg)
args = parser.parse_args()
stack_name = args.stackname
template = args.template
region = args.region
bucket_name = args.bucketname
parameters = cfn_params_from(args.parameters)
update = args.update
create_stack(stack_name, template, region, temp_bucket=bucket_name, parameters=parameters, update=update)
print('Stack({}) created.'.format(stack_name))
"""VPC Tools.
Usage:
vpc-tools.py ssh-config (vpc <vpc_id> | stack-name <stack_name>) [(identity-file <identity_file>)] user <user> [(config-file <config_file>)] [(strict-host-check <strict_host_check>)] [(jump-box <jump_box>)]
vpc-tools.py (-h --help)
vpc-tools.py (-v --version)
Options:
-h --help Show this screen.
-v --version Show version.
"""
import boto
from docopt import docopt
from vpcutil import vpc_for_stack_name
from vpcutil import stack_name_for_vpc
from collections import defaultdict
VERSION="vpc tools 0.1"
DEFAULT_USER="ubuntu"
DEFAULT_HOST_CHECK="ask"
BASTION_CONFIG = """Host {jump_box}
HostName {ip}
ForwardAgent yes
User {user}
StrictHostKeyChecking {strict_host_check}
{identity_line}
"""
HOST_CONFIG = """# Instance ID: {instance_id}
Host {name}
ProxyCommand ssh -q {config_file} -W %h:%p {jump_box}
HostName {ip}
ForwardAgent yes
User {user}
StrictHostKeyChecking {strict_host_check}
{identity_line}
"""
DIRECT_HOST_CONFIG = """# Instance ID: {instance_id}
Host {name}
HostName {ip}
ForwardAgent yes
User {user}
StrictHostKeyChecking {strict_host_check}
{identity_line}
"""
BASTION_HOST_CONFIG = """# Instance ID: {instance_id}
Host {name}
HostName {ip}
ForwardAgent yes
User {user}
StrictHostKeyChecking {strict_host_check}
{identity_line}
"""
def dispatch(args):
if args.get("ssh-config"):
_ssh_config(args)
def _ssh_config(args):
if args.get("vpc"):
vpc_id = args.get("<vpc_id>")
stack_name = stack_name_for_vpc(vpc_id)
elif args.get("stack-name"):
stack_name = args.get("<stack_name>")
vpc_id = vpc_for_stack_name(stack_name)
else:
raise Exception("No vpc_id or stack_name provided.")
vpc = boto.connect_vpc()
identity_file = args.get("<identity_file>", None)
if identity_file:
identity_line = "IdentityFile {}".format(identity_file)
else:
identity_line = ""
user = args.get("<user>")
config_file = args.get("<config_file>")
strict_host_check = args.get("<strict_host_check>")
if not user:
user = DEFAULT_USER
if not strict_host_check:
strict_host_check = DEFAULT_HOST_CHECK
if config_file:
config_file = "-F {}".format(config_file)
else:
config_file = ""
if args.get("jump-box"):
jump_box = args.get("<jump_box>")
else:
jump_box = "{stack_name}-bastion".format(stack_name=stack_name)
friendly = "{stack_name}-{logical_id}-{instance_number}"
id_type_counter = defaultdict(int)
reservations = vpc.get_all_instances(filters={'vpc-id' : vpc_id})
for reservation in reservations:
for instance in reservation.instances:
if 'play' in instance.tags:
logical_id = instance.tags['play']
elif 'role' in instance.tags:
# deprecated, use "play" instead
logical_id = instance.tags['role']
elif 'group' in instance.tags:
logical_id = instance.tags['group']
elif 'aws:cloudformation:logical-id' in instance.tags:
logical_id = instance.tags['aws:cloudformation:logical-id']
else:
continue
instance_number = id_type_counter[logical_id]
id_type_counter[logical_id] += 1
if logical_id == "BastionHost" or logical_id == 'bastion':
print BASTION_CONFIG.format(
jump_box=jump_box,
ip=instance.ip_address,
user=user,
strict_host_check=strict_host_check,
identity_line=identity_line)
print BASTION_HOST_CONFIG.format(
name=instance.private_ip_address,
ip=instance.ip_address,
user=user,
instance_id=instance.id,
strict_host_check=strict_host_check,
identity_line=identity_line)
#duplicating for convenience with ansible
name = friendly.format(stack_name=stack_name,
logical_id=logical_id,
instance_number=instance_number)
print BASTION_HOST_CONFIG.format(
name=name,
ip=instance.ip_address,
user=user,
strict_host_check=strict_host_check,
instance_id=instance.id,
identity_line=identity_line)
else:
# Print host config even for the bastion box because that is how
# ansible accesses it.
if jump_box == "none":
print DIRECT_HOST_CONFIG.format(
name=instance.private_ip_address,
ip=instance.private_ip_address,
user=user,
config_file=config_file,
strict_host_check=strict_host_check,
instance_id=instance.id,
identity_line=identity_line)
#duplicating for convenience with ansible
name = friendly.format(stack_name=stack_name,
logical_id=logical_id,
instance_number=instance_number)
print DIRECT_HOST_CONFIG.format(
name=name,
ip=instance.private_ip_address,
user=user,
config_file=config_file,
strict_host_check=strict_host_check,
instance_id=instance.id,
identity_line=identity_line)
else:
print HOST_CONFIG.format(
name=instance.private_ip_address,
jump_box=jump_box,
ip=instance.private_ip_address,
user=user,
config_file=config_file,
strict_host_check=strict_host_check,
instance_id=instance.id,
identity_line=identity_line)
#duplicating for convenience with ansible
name = friendly.format(stack_name=stack_name,
logical_id=logical_id,
instance_number=instance_number)
print HOST_CONFIG.format(
name=name,
jump_box=jump_box,
ip=instance.private_ip_address,
user=user,
config_file=config_file,
strict_host_check=strict_host_check,
instance_id=instance.id,
identity_line=identity_line)
if __name__ == '__main__':
args = docopt(__doc__, version=VERSION)
dispatch(args)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment