lundi 27 juillet 2015

executing python script passed to aws user data through terraform as a file

The Problem: I'm trying to pass a dynamically created python script to an AWS launch_config created with terraform. The script appears in the user data of the instance but doesn't execute. I'm not sure why all of the guides I read about passing scripts through user data say that this should work.

I know the script shows up because I can curl aws user data and it will be there, but it never executed.

What am I missing?

The dynamically created python:

user_data_ins = ('''export CLOUD_ENVIRONMENT=%s\n
                    export CLOUD_MONITOR_BUCKET=%s\n
                    export CLOUD_APP=%s\n
                    export CLOUD_STACK=%s\n
                    export CLOUD_CLUSTER=%s\n
                    export CLOUD_AUTO_SCALE_GROUP=%s\n
                    export CLOUD_LAUNCH_CONFIG=%s\n
                    export EC2_REGION=%s\n
                    export CLOUD_DEV_PHASE=%s\n
                    export CLOUD_REVISION=%s\n
                    export CLOUD_DOMAIN=%s\n
                    export SG_GROUP=%s\n''' % (cloud_environment,
                                                cluster_monitor_bucket,
                                                cluster_name,
                                                cloud_stack,
                                                cloud_cluster,
                                                cloud_auto_scale_group,
                                                cloud_launch_config,
                                                provider_region,
                                                cloud_dev_phase,
                                                cloud_revision,
                                                cloud_domain,
                                                export_env_sg_name))



user_data_ins = ('''
#!/usr/bin/env python

import os
import subprocess
import time
import uuid


def shell_command_execute(command):
    p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
    (output, err) = p.communicate()
    print output
    return output

repo = "%s"
playbook = "%s"


echo_bash_profile = "echo " + %s + " >> ~/.bash_profile"
shell_command_execute(echo_bash_profile)

var_user_data = "%s"

for varb in var_user_data.split('|'):
    echo_bash_profile_passed = "echo " + varb  + " >> ~/.bash_profile"
    shell_command_execute(echo_bash_profile_passed)

command = 'git clone ' + repo
shell_command_execute(command)

folder = repo.split('/')[4].replace('.git','')
#http://ift.tt/1h1juRK
execute_playbook = ('ansible-playbook -i "localhost," -c local' +  '/' + os.path.dirname(os.path.realpath(__file__)) + '/' + folder + '/' + playbook >> ansible.log')
print execute_playbook
shell_command_execute(execute_playbook)
''' % (str(repo), str(playbook),str(user_data_ins), str(in_user_data)))

text_file = open("user-data.py", "wa")
text_file.write(user_data_ins)    
text_file.close()    
lc_user_data = '${file("%s/user-data.py")}' %wd

The Whole Script:

import argparse
import subprocess
import sys
import boto.ec2
import random
import multiprocessing
import time
import collections
import os
import uuid
import base64

parser = argparse.ArgumentParser()    
parser.add_argument('--secret_key', help='', required=False)
parser.add_argument('--wd', help='', required=False)
parser.add_argument('--access_key', help='', required=False)
parser.add_argument('--provider-region', help='', required=False)
parser.add_argument('--autoscale_group', help='', required=False)
parser.add_argument('--min_size', help='', required=False)
parser.add_argument('--max_size', help='', required=False)
parser.add_argument('--asg_name', help='', required=False)
parser.add_argument('--azs', help='', required=False)
parser.add_argument('--env', help='', required=False)
parser.add_argument('--desired_size', help='', required=False)
parser.add_argument('--force_delete', help='', required=False)
parser.add_argument('--hc_type', help='', required=False)
parser.add_argument('--hc_period', help='', required=False)
parser.add_argument('--lc_name', help='', required=False)
parser.add_argument('--lc_image_id', help='', required=False)
parser.add_argument('--lc_instance_type', help='', required=False)
parser.add_argument('--lc_iam_instance_profile', help='', required=False)
parser.add_argument('--lc_key_name', help='', required=False)
parser.add_argument('--in_user_data', help='', required=False)
parser.add_argument('--lc_public_ip', help='', required=False)
parser.add_argument('--launch_config', help='', required=False)
parser.add_argument('--tags', help='', required=False)
parser.add_argument('--block_devices', help='', required=False)
parser.add_argument('--asg_vpc_ident', help='', required=False)
parser.add_argument('--cloud_stack', help='', required=False)
parser.add_argument('--cloud_environment', help='', required=False)
parser.add_argument('--cloud_domain', help='', required=False)
parser.add_argument('--cluster_monitor_bucket', help='', required=False)
parser.add_argument('--cloud_cluster', help='', required=False)
parser.add_argument('--cloud_auto_scale_group', help='', required=False)
parser.add_argument('--cloud_launch_config', help='', required=False)
parser.add_argument('--cloud_dev_phase', help='', required=False)
parser.add_argument('--cloud_revision', help='', required=False)
parser.add_argument('--role', help='', required=False)
parser.add_argument('--security_groups', help='', required=False)
parser.add_argument('--sg_tag', help='', required=False)
parser.add_argument('--vpc_id', help='', required=False)
parser.add_argument('--repo', help='', required=False)
parser.add_argument('--playbook', help='', required=False)
args = parser.parse_args()
#secret_key = os.environ.get('AWS_SECRET_KEY')
#access_key = os.environ.get('AWS_ACCESS_KEY')
sg_tag = args.sg_tag
secret_key = args.secret_key
access_key = args.access_key
vpc_id = args.vpc_id
provider_region = args.provider_region
security_groups = args.security_groups
cloud_stack = args.cloud_stack 
cloud_environment = args.cloud_environment
cloud_domain = args.cloud_domain
cluster_monitor_bucket = args.cluster_monitor_bucket
cloud_cluster =  args.cloud_cluster
cloud_auto_scale_group = args.cloud_auto_scale_group
cloud_launch_config = args.cloud_launch_config
cloud_dev_phase = args.cloud_dev_phase
cloud_revision = args.cloud_revision
role = args.role
env_name = args.env
#asg arguments
min_size = args.min_size
max_size = args.max_size
desired_size = args.desired_size
azs = args.azs
asg_name = args.asg_name
force_delete = args.force_delete
tags = args.tags
hc_type = args.hc_type
hc_period = args.hc_period
az_list = args.azs
vpc_zone_ident = args.asg_vpc_ident

#launch configuration values
lc_name = args.lc_name
lc_image_id = args.lc_image_id
lc_instance_type = args.lc_instance_type
lc_iam_instance_profile = args.lc_iam_instance_profile
lc_key_name = args.lc_key_name
in_user_data = args.in_user_data
lc_public_ip = args.lc_public_ip
block_devices = args.block_devices
security_group_name = []
wd = args.wd
playbook = args.playbook
repo = args.repo


def build_lc(lc_name, lc_name2, lc_image_id, lc_instance_type, lc_public_ip, lc_security_groups, lc_iam_instance_profile, lc_user_data, lc_key_name,block_device_mapping):
    launch_config_dict = collections.OrderedDict()
    if lc_name:
        launch_config_dict['lcname'] = lc_name
    if lc_name2:
        launch_config_dict['name'] = lc_name2
    if lc_image_id:
        launch_config_dict['image_id'] = lc_image_id
    if lc_instance_type:
        launch_config_dict['instance_type'] = lc_instance_type

    launch_config_dict['associate_public_ip_address'] = 'True'

    if lc_security_groups:
        launch_config_dict['security_groups'] = str(lc_security_groups).replace("'",'"')
    if lc_iam_instance_profile:
        launch_config_dict['iam_instance_profile'] = lc_iam_instance_profile
    if lc_user_data:
        launch_config_dict['user_data'] = lc_user_data
    if lc_key_name:
        launch_config_dict['key_name'] = lc_key_name
    if block_device_mapping:
        launch_config_dict['block_device'] = block_device_mapping


    lc_string = '\nresource "aws_launch_configuration" "%s" {\n' % launch_config_dict['lcname']

    for key, value in launch_config_dict.iteritems():
        if value != None:
            if key == 'lcname':
                continue
            if key != 'block_device':
                if key != 'security_groups':
                    lc_string = lc_string + '        %s="%s"\n' % (key, value)
                else:
                    lc_string = lc_string + '        %s=%s\n' % (key, value)
            else:
                lc_string = lc_string + '        %s\n' % (value)
    lc_string = lc_string + '\n    }'
    return lc_string

def build_tags(tags):
    built_tags = ''
    tags = tags.split(',')
    for tag in tags:
        if len(tag) > 5:
            values = tag.split(':')
            built_tags = built_tags + """
            tag {
                key = "%s"
                value = "%s"
                propagate_at_launch = %s
                }                                   
            """ % (values[0],values[1],values[2])
    return built_tags

def build_block_devices(block_devices):

    built_devices = ''
    block_devices = block_devices.split(',')
    for device in block_devices:
        if len(device) > 6:
            values = device.split(':')
            built_devices = built_devices + '''
                ebs_block_device{
                    device_name = "%s"
                    volume_type = "%s"
                    volume_size = %s
                    delete_on_termination = %s
                    iops = %s
                }
            ''' % (values[0].split('=')[1],values[1].split('=')[1],values[2].split('=')[1],values[3].split('=')[1],values[4].split('=')[1])
    return built_devices

def build_az_list(azs):
    az_list = []
    az_values = azs.split(',')
    for az in az_values:
        az_list.append('%s' % az)
    return az_list

def build_rules(rules):
    build_string = ''
    for rule in rules.split(':'):
        name = rule.split('=')[0]
        if len(rule) > 10:
            build_string = build_string + '''
                    %s {
                        from_port = %s
                        to_port = %s
                        protocol = "%s"
                        %s = %s
                        }
                        ''' % (name, 
                               rule.split('=')[1].split(';')[0].split('|')[1], 
                               rule.split('=')[1].split(';')[1].split('|')[1], 
                               rule.split('=')[1].split(';')[2].split('|')[1], 
                               rule.split('=')[1].split(';')[3].split('|')[0],
                               rule.split('=')[1].split(';')[3].split('|')[1])
    return build_string

def build_security_group(security_groups,vpc_id, cluster_name, sg_tag):
    security_group = ''
    flag = False
    for group in security_groups.split(','):
        if len(group) > 6:
            if 'name' in str(group):
                conn = boto.ec2.connect_to_region('us-west-2',aws_access_key_id=access_key, aws_secret_access_key=secret_key)
                rs = conn.get_all_security_groups()
                check_name = cluster_name.split('-')
                check_name = check_name[0]+'-'+check_name[1]+'-'+check_name[2]
                check_name = str(check_name)
                sg_length = len(rs)
                for index, item in enumerate(rs):
                    item_ret = str(item)
                    if check_name in item_ret:
                        name = item_ret.replace('SecurityGroup:', '')
                        name2 = item_ret.replace('SecurityGroup:', '')
                        security_group_name.append(str(item.id))
                        flag = True
                        break
                    else:
                        if not security_group_name and index == (sg_length - 1):
                            name = cluster_name
                            name2 = cluster_name
                            security_group_name.append("${aws_security_group.%s.id}" % name)
                            break

                description = group.split(':')[1].split('=')[1]
                rules = group.split('!')[1]
                rules = build_rules(rules)
                if vpc_id != '0':
                    security_group = security_group + '''
                    resource "aws_security_group" "%s" {
                        name = "%s"
                        vpc_id = "%s"
                        description = "%s"
                        %s
                    }''' % (name, name2,vpc_id, description, rules) 
                else:
                    security_group = security_group + '''
                    resource "aws_security_group" "%s" {
                        name = "%s"
                        description = "%s"
                        %s
                    }''' % (name, name2, description, rules)   
            else:
                break   
    return_list = (security_group,security_group_name, flag, name)    
    return return_list 

#Dynamically builds ASG, and won't include values  if they dont exist. Need to do errors when its required.
def build_asg(**kwargs):
    asg_string = '\nresource "aws_autoscaling_group" "%s" {\n' % kwargs['asgname']
    order_dict = collections.OrderedDict()
    if kwargs['name']:
        order_dict['name'] = kwargs['name']
    if kwargs['availability_zones']:
        order_dict['availability_zones'] = str(kwargs['availability_zones']).replace("'",'"')
    if kwargs['max_size']:
        order_dict['max_size'] = kwargs['max_size']
    else:
        order_dict['max_size'] = 1
    if kwargs['min_size']:
        order_dict['min_size'] = kwargs['min_size']
    else:
        order_dict['min_size'] = 1
    if kwargs['launch_configuration']:
        order_dict['launch_configuration'] = kwargs['launch_configuration']
    if kwargs['health_check_grace_period']:
        order_dict['health_check_grace_period'] = kwargs['health_check_grace_period']
    if kwargs['health_check_type']:
        order_dict['health_check_type'] = kwargs['health_check_type']
    if kwargs['desired_capacity']:
        order_dict['desired_capacity'] = kwargs['desired_capacity']
    if kwargs['force_delete']:
        order_dict['force_delete'] = kwargs['force_delete']
    if kwargs['vpc_zone_identifier']: 
        order_dict['vpc_zone_identifier'] = kwargs['vpc_zone_identifier']
    if kwargs['built_tags']: 
        order_dict['built_tags'] = kwargs['built_tags']

    for key, value in order_dict.iteritems():
        if value != None:
            if key == 'asgname':
                continue
            if key != 'built_tags':
                if key != 'force_delete' and key != 'health_check_grace_period' and key != 'min_size' and key != 'max_size' and key != 'desired_capacity' and key != 'availability_zones' and key != 'vpc_zone_identifier':
                    asg_string = asg_string + '        %s = "%s"\n' % (key, value)
                else:
                    asg_string = asg_string + '        %s = %s\n' % (key, value)
            else:
                asg_string = asg_string + '        %s\n' % (value)
    asg_string = asg_string + '\n    }'
    return asg_string

def get_a_uuid():
    r_uuid = base64.urlsafe_b64encode(uuid.uuid4().bytes)
    return r_uuid.replace('=', '')

uuid = str(get_a_uuid())
asg_name = sg_tag + '-' + asg_name + '-' + env_name + '-' + '-' + uuid[:8]
cluster_name = asg_name
security_groups = security_groups.replace(' ', '')
security_groups = build_security_group(security_groups,vpc_id, cluster_name, sg_tag)
security_group_name = security_groups[1]
export_env_sg_name = security_groups[3]
security_groups = security_groups[0]
security_flag = security_groups[2]


if security_flag == True:
    lc_security_groups = security_group_name[0]
    lc_security_groups = '["%s"],' % lc_security_groups
else:
    lc_security_groups = security_group_name

az_list = build_az_list(azs)
block_devices = block_devices.replace(' ', '')
block_device_mapping = build_block_devices(block_devices)

constant_tag = 'ClusterName:%s:true ' % cluster_name

if tags:
    built_tags = build_tags(tags)
else:
    built_tags = constant_tag


user_data_ins = ('''export CLOUD_ENVIRONMENT=%s\n
                    export CLOUD_MONITOR_BUCKET=%s\n
                    export CLOUD_APP=%s\n
                    export CLOUD_STACK=%s\n
                    export CLOUD_CLUSTER=%s\n
                    export CLOUD_AUTO_SCALE_GROUP=%s\n
                    export CLOUD_LAUNCH_CONFIG=%s\n
                    export EC2_REGION=%s\n
                    export CLOUD_DEV_PHASE=%s\n
                    export CLOUD_REVISION=%s\n
                    export CLOUD_DOMAIN=%s\n
                    export SG_GROUP=%s\n''' % (cloud_environment,
                                                cluster_monitor_bucket,
                                                cluster_name,
                                                cloud_stack,
                                                cloud_cluster,
                                                cloud_auto_scale_group,
                                                cloud_launch_config,
                                                provider_region,
                                                cloud_dev_phase,
                                                cloud_revision,
                                                cloud_domain,
                                                export_env_sg_name))



user_data_ins = ('''
#!/usr/bin/env python

import os
import subprocess
import time
import uuid


def shell_command_execute(command):
    p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
    (output, err) = p.communicate()
    print output
    return output

repo = "%s"
playbook = "%s"


echo_bash_profile = "echo " + %s + " >> ~/.bash_profile"
shell_command_execute(echo_bash_profile)

var_user_data = "%s"

for varb in var_user_data.split('|'):
    echo_bash_profile_passed = "echo " + varb  + " >> ~/.bash_profile"
    shell_command_execute(echo_bash_profile_passed)

command = 'git clone ' + repo
shell_command_execute(command)

folder = repo.split('/')[4].replace('.git','')
#http://ift.tt/1h1juRK
execute_playbook = ('ansible-playbook -i "localhost," -c local' +  '/' + os.path.dirname(os.path.realpath(__file__)) + '/' + folder + '/' + playbook >> ansible.log')
print execute_playbook
shell_command_execute(execute_playbook)
''' % (str(repo), str(playbook),str(user_data_ins), str(in_user_data)))

text_file = open("user-data.py", "wa")
text_file.write(user_data_ins)    
text_file.close()    
lc_user_data = '${file("%s/user-data.py")}' %wd

launch_config_variable = "${aws_launch_configuration.%s.id}" % cluster_name

launch_configuration = build_lc(cluster_name,cluster_name, lc_image_id, lc_instance_type, lc_public_ip, lc_security_groups, lc_iam_instance_profile, lc_user_data, lc_key_name,block_device_mapping)

autoscale_group = build_asg(built_tags = built_tags if built_tags else None,
                              asgname = asg_name, 
                              availability_zones = az_list, 
                              name = asg_name, 
                              max_size = max_size, 
                              min_size = min_size, 
                              launch_configuration = launch_config_variable, 
                              health_check_grace_period = hc_period if hc_period else None, 
                              health_check_type = hc_type if hc_type else None, 
                              desired_capacity = desired_size if desired_size else None, 
                              force_delete = force_delete if force_delete else None,
                              vpc_zone_identifier = vpc_zone_ident if vpc_zone_ident else None
                              )   

provider = """
        provider "aws" {
            access_key = "%s"
            secret_key = "%s"
            region = "%s"
        }
""" % (access_key, secret_key, provider_region)

text_file = open("Output.tf", "wa")
text_file.write(provider)

if security_flag == True:
    print 'nada'
else:
    text_file.write(security_groups)

text_file.write(launch_configuration)
text_file.write(autoscale_group)
text_file.close()




Aucun commentaire:

Enregistrer un commentaire