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
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
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