def sync_terraform(config):
    """
    Clone all terraform git repositories to the workdir.

    Args:
        config: dictionary containing all variable settings required
                to run terraform with
    Returns:
        nothing
    """

    # if we've already run terraform here, we don't need to check it out again.
    if config.get('tf_root') and os.path.isdir(
            os.path.join(config['tf_root'], '.terraform')):
        log_msg = "Terraform code already checked out to this location: {}"
        logger.debug(log_msg.format(config['tf_root']))

        return

    workdir.options.path = config['tmpdir']
    workdir.create()
    (repo, branch, subdir) = utils.parse_git_url(config['terraform'])
    clone_cmd = utils.git_clone(repo, branch)
    utils.run_command(clone_cmd, config['tmpdir'])

    return
def _precheck(config, action):
    """
    Run through preflight checklist before running terraform apply/destroy.

    Args:
        config: dictionary containing all variable settings required
                to run terraform with

        action: string (create | destroy)

    Returns:
        Nothing

    Raises:
        InvalidCommandException exception on unknown command.
    """
    # Instantiate remote state only if:
    # - the terraform code isn't already checked out
    # - and we haven't already run 'terraform remote config...'
    if not os.path.isfile(
            os.path.join(config['tf_root'], '.terraform',
                         'terraform.tfstate')):
        log_msg = "Configuring terraform remote state in: {}"
        logger.debug(log_msg.format(config['tf_root']))
        tf_command = tf.remote_state(config)
        return_code = utils.run_command(tf_command, cwd=config['tf_root'])
        if return_code != 0:
            raise BaseException("{} failed with code {}.".format(
                tf_command, return_code))

    # Grab all the tf modules required
    tf_command = tf.get()
    utils.run_command(tf_command, cwd=config['tf_root'])

    # validate env_name
    utils.validate_env_name(config['env_name'])
    tf_command = tf.validate(config)
    utils.run_command(tf_command, cwd=config['tf_root'])

    # Push remote state
    push_or_pull = {
        'create': tf.remote_push,
        'plan': tf.remote_pull,
        'destroy': tf.remote_pull,
    }
    try:
        tf_command = push_or_pull[action]()
    except KeyError:
        raise InvalidCommandException("Invalid Command: {}".format(action))

    utils.run_command(tf_command, cwd=config['tf_root'])

    # Run Plan
    tf_command = tf.plan(config, action)
    utils.run_command(tf_command, cwd=config['tf_root'])

    return
def output(config, tf_var):
    """
    Output the value of the specified variable.

    Args:
        config: dictionary containing all variable settings required
                to run terraform with

        tf_var: name of terraform output variable to return the output of.

    Returns:
        True

    """
    tf_command = tf.output(tf_var)
    utils.run_command(tf_command, cwd=config['tf_root'])

    return True
Exemple #4
0
def test_run_command():

    import platform
    systype = platform.system()

    truefalse = {'Darwin': '/usr/bin', 'Linux': '/bin'}

    command = ["{}/true".format(truefalse[systype])]
    # pytest.set_trace()
    expected_code = 0
    return_code = utils.run_command(command, cwd='/tmp')
    assert return_code == expected_code

    command = ["{}/false".format(truefalse[systype])]
    # pytest.set_trace()
    expected_code = 1
    return_code = utils.run_command(command, cwd='/tmp')
    assert return_code == expected_code
def destroy(config):
    """
    Destroy the environment by running 'terraform destroy'.

    Args:
        config: dictionary containing all variable settings required
                to run terraform with

    Returns:
        True

    Raises:
        EnvironmentExistsException if environment does not exist.
    """

    # Check if env already exists
    env_name = config['environment'].get('name')
    env_vers = config['environment'].get('version', None)
    env = env_name

    if env_vers:
        env = "-".join([env_name, env_vers])

    system_type = config['tags'].get('system_type', None)
    if not aws.environment_exists(env_name, env_vers, system_type):
        msg = "No such environment with the name {} exists."
        if system_type:
            env = "-".join([system_type, env])
        raise EnvironmentExistsException(msg.format(env))

    tf_root = _precheck(config, 'destroy')

    # Tag the resources as ready to destroy
    aws.tag_resources(config)

    # Run destroy
    tf_command = tf.destroy(config)
    return_code = utils.run_command(tf_command, cwd=config['tf_root'])

    # Double check the make sure we don't have anything left running
    # before destroying the S3 resources.
    if not aws.environment_exists(env_name, env_vers,
                                  system_type) and return_code == 0:
        # Destroy the per-environment S3 folder in
        msg = "Destroying S3 env folder: {}".format(config['env_folder'])
        logger.debug(msg)
        s3.destroy_folder(config['project_config'], config['env_folder'])

        # Destroy the state file in S3
        msg = "Destroying S3 State file: {}".format(config['tf_state'])
        logger.debug(msg)
        s3.delete_object(config['tf_state_bucket'], config['tf_state'])

    return True
def create(config):
    """
    Create the environment by running 'terraform apply'.

    Args:
        config: dictionary containing all variable settings required
                to run terraform with

    Returns:
        True

    Raises:
        EnvironmentExistsException if environment already exists.
    """
    # Check if env already exists
    env_name = config['environment'].get('name')
    env_vers = config['environment'].get('version', None)
    env = env_name

    if env_vers:
        env = "-".join([env_name, env_vers])

    system_type = config['tags'].get('system_type', None)
    resources = aws.environment_exists(env_name, env_vers, system_type)
    if (resources):
        if system_type:
            env = "-".join([system_type, env])

        from termcolor import colored

        msg = "\n\nAn environment with the name {} already exists."
        msg += "\nPlease tear it down before trying to rebuild."
        msg += "\n\n{}"
        resources_json = json.dumps(resources, indent=4)
        message = colored(msg.format(env, resources_json), 'red')
        raise EnvironmentExistsException(message)

    _precheck(config, 'create')

    # Run Apply
    tf_command = tf.apply(config)
    logger.debug("Command: {}".format(" ".join(tf_command)))
    logger.debug("In: {}".format(config['tf_root']))

    try:
        return_code = utils.run_command(tf_command, cwd=config['tf_root'])
    except:
        aws.tag_resources(config)
        return False

    aws.tag_resources(config)
    return True
def pre_setup(config, sync=True):

    config['public_zone_id'] = config.get('public_zone_id', "<computed>")
    #create tmp dir to stage a deployment from
    config['tmpdir'] = config.get('tmpdir',
                                  os.path.join('/tmp', str(uuid.uuid4())))

    logger.debug("{}: Creating tmpdir: {}".format(__name__, config['tmpdir']))
    workdir.options.path = config['tmpdir']
    workdir.create()

    config['tfvars'] = os.path.join(workdir.options.path,
                                    config.get('tfvars_file', 'vars.tf'))

    config['tf_root'] = config.get('tf_root', utils.get_tf_location(config))

    # If the tf location is set to a local directory, we need to deal
    # with things like the possibility of the actual tf location being
    # in a subdir and a specified branch.
    if not utils.git_url(config['terraform']):
        (repo, branch, subdir) = utils.parse_git_url(config['terraform'])
        config['tf_root'] = repo
        if branch:
            msg = "Setting branch to: {}".format(branch)
            logger.debug(msg)
            if sync:
                git_pull_cmd = utils.git_pull(repo)
                utils.run_command(git_pull_cmd, repo)
                git_set_branch_cmd = utils.git_set_branch(branch)
                utils.run_command(git_set_branch_cmd, repo)

        if subdir:
            tf_root = os.path.join(config.get('tf_root', repo), subdir)
            msg = "Setting tf_root to: {}".format(tf_root)
            logger.debug(msg)
            config['tf_root'] = tf_root

    return config
Exemple #8
0
def setup(config, sync=True):
    """
    Get ready to run 'terraform apply' for this environment.
    Modifies the dictionary passed in, then returns it.

    Args:
        config: dictionary containing all variable settings required
                to run terraform with

        sync: boolean. Toggles setting the branch on/off. Defaults to on.

    Returns:
        config with updated values.

    Raises:
        MissingConfigurationParameterException for missing config file entries.
    """
    #create tmp dir to stage a deployment from
    config['tmpdir'] = config.get('tmpdir',
                                  os.path.join('/tmp', str(uuid.uuid4())))

    logger.debug("{}: Creating tmpdir: {}".format(__name__, config['tmpdir']))
    workdir.options.path = config['tmpdir']
    workdir.create()

    config['tfvars'] = os.path.join(workdir.options.path,
                                    config.get('tfvars_file', 'vars.tf'))

    # Create the per-environment S3 folder in pre-flight
    logmsg = "{}: Creating per-environment folder : {}:{}"
    logger.debug(
        logmsg.format(__name__, config['project_config'],
                      config['env_folder']))
    s3.create_folder(config['project_config'], config['env_folder'])

    if not config.get('route53_tld', None):
        msg = "route53_tld variable is not set in config file."
        raise MissingConfigurationParameterException(msg)

    zone_id = r53.get_zone_id(config['route53_tld'])
    if not zone_id:
        msg = "zone_id not set."
        raise MissingConfigurationParameterException(msg)

    config['public_zone_id'] = config.get('public_zone_id', zone_id)
    config['tf_root'] = config.get('tf_root', utils.get_tf_location(config))

    # If the tf location is set to a local directory, we need to deal
    # with things like the possibility of the actual tf location being
    # in a subdir and a specified branch.
    if not utils.git_url(config['terraform']):
        (repo, branch, subdir) = utils.parse_git_url(config['terraform'])
        config['tf_root'] = repo
        if branch:
            msg = "Setting branch to: {}".format(branch)
            logger.debug(msg)
            if sync:
                git_pull_cmd = utils.git_pull(repo)
                utils.run_command(git_pull_cmd, repo)
                git_set_branch_cmd = utils.git_set_branch(branch)
                utils.run_command(git_set_branch_cmd, repo)

        if subdir:
            tf_root = os.path.join(config.get('tf_root', repo), subdir)
            msg = "Setting tf_root to: {}".format(tf_root)
            logger.debug(msg)
            config['tf_root'] = tf_root

    return config