Using the Terraform Apply Command

Updated 2 months ago by Michael Cretzman

This topic describes how to use the Terraform Apply step to perform Terraform operations at any point in your Workflow. In this topic:

Terraform Apply Overview

The Terraform Apply step performs a terraform apply command using the Terraform template (config.tf) you set up in a Harness Terraform Infrastructure Provisioner, and can be applied as an independent step to any Workflow. Terraform Apply steps can also be used together to perform multiple operations on the same infrastructure and Terraform workspace.

The Terraform Apply step is separate from the Terraform Provision step used in Pre-deployment steps in a Workflow, although you can have both in the same Workflow and have both run operations on the same infrastructure and Terraform workspace.

Before You Begin

Before reading about the Terraform Apply step, we recommend you read about the Harness Terraform Infrastructure Provisioner and related Terraform Provision step in Terraform Provisioner. This will help you see the scope of Terraform support in Harness.

Also, setting up the Terraform Apply step is nearly identical to setting up the Terraform Provision step, and this document will not repeat the steps. 

What Can I do with Terraform Apply?

Terraform Apply can be used to perform the many tasks offered by Terraform Providers. For example:

  • Provision infrastructure.
  • Execute scripts on local and remote hosts.
  • Copy files from one server to another.
  • Query AWS for resource information.
  • Push files to Git.
  • Read data from APIs as JSON. 
  • Read image metadata from a Docker registry.
  • Create a certificates for a development environment.
  • Create DNS records.
  • Inject containers with sensitive information such as passwords.

Terraform Apply and Terraform Provision Steps

Harness also includes a Terraform Provision step that uses a Harness Infrastructure Provisioner to provision infrastructure, but the Terraform Provision step has the following limitations: 

  • Supported in Canary and Multi-Service Workflows only.
  • Support for AMI Blue/Green Workflows only.
  • May be applied in a Workflow's Pre-deployment Steps only and is intended to provision infrastructure.

The Terraform Apply step can be applied anywhere in your Workflow and can be used to perform most Terraform operations.

Using Terraform Apply with Terraform Provision

While it is not necessary to use the Terraform Apply step with the standard Terraform Provision step in your Workflow, using them together can be an efficient method for provisioning and managing resources. 

This scenario might involve the following steps:

  1. The target environment is dynamically provisioned using the Terraform Provision step in the Pre-Deployment steps of your Workflow. 
  2. The Workflow deploys your application to the dynamically provisioned target infrastructure. 
  3. The Terraform Apply step performs operations on the deployed hosts, services, etc. 

For information on the Terraform Provision step, see Terraform Provisioner.

Using the Terraform Apply Step

This section provides a simple example of how to use the Terraform Apply step. In this example, the step creates an AWS EC2 instance as a completely separate function of a Basic Workflow whose primary function is to deploy an application package in EC2. This example shows the independence of the Terraform Apply step, and how it can be used to augment any Workflow and perform independent functions.

This procedure assumes you have read about the Harness Terraform Infrastructure Provisioner and related Terraform Provision step in Terraform Provisioner. This will help you see the scope of Terraform support in Harness.

To use the Terraform Apply step, do the following:

  1. Create your Terraform configuration file (config.tf) in your Git repo. The file used in this example creates an AWS EC2 instance using an AMI:
variable "region" {}
variable "access_key" {}
variable "secret_key" {}
variable "tag" {}

provider "aws" {
  region  = "${var.region}"
  access_key = "${var.access_key}"
  secret_key = "${var.secret_key}"
}

resource "aws_instance" "tf_instance" {
   subnet_id     = "subnet-05788710b1b06b6b1"
   security_groups = ["sg-05e7b8bxxxxxxxxx"]
   key_name        = "doc-delegate1"
   ami           = "ami-0080e4c5bc078760e"
   instance_type = "t2.micro"
   associate_public_ip_address = "true"
  tags {
    Name = "${var.tag}"
   }
}

The access and secret keys will be provided when you add the Terraform Apply step to your Workflow. In Harness, you create secrets in Harness Secrets Management and then you can use them in other Harness components.

You can also use a Terraform Apply step with the HashiCorp Vault provider to access Vault credentials for a Terraform configuration.
  1. In Harness, add a Terraform Infrastructure Provisioner that uses the Terraform configuration file. This process is described in detail in the Terraform Provisioner topic.

    When you are adding the Terraform Infrastructure Provisioner, the inputs for your config.tf file are added:

Once your Terraform Infrastructure Provisioner is added, you can use it in the Terraform Apply step in your Workflow.

  1. In your Workflow, in any section, click Add Command. The Add Command dialog appears.

  1. In Add Command, select Terraform Apply. The Terraform Apply dialog appears.

  1. The steps for filling out the dialog are the same as those for the Terraform Provision step described in Terraform Provisioner Step. You simply select the Terraform Infrastructure Provisioner you set up earlier using the Terraform script, fill in the input values, and select other settings like Workspace. Refer to Terraform Provisioner Step for details on each setting.

Let's look at an example where the Terraform Apply step is added as an independent step to a Workflow that deploys an application package (TAR file) to an EC2 instance.

The Workflow will deploy the application package as intended, and it will also execute the Terraform Apply step to create a separate EC2 instance.

The steps for installing the application package are described in the Traditional Deployments guide. Let's look at the Terraform Apply Step.

The Terraform script listed earlier will create an EC2 instance. This script is used to configure the Terraform Infrastructure Provisioner that the Terraform Apply step will use.

The Terraform Apply step that uses this Terraform Infrastructure Provisioner supplies the values for the input variables selected in the Terraform Infrastructure Provisioner:

You can see that the AWS access and secret keys are inputs in this configuration. You can use Harness Secrets Management to provide encrypted text secrets in the Terraform Apply step.

When the Workflow is deployed, you can see the traditional deployment of the application package succeed and the Terraform Apply step executed successfully.

Here is the Terraform Apply step output (with some lines omitted):

Branch: master
Normalized Path: create
terraform init
Initializing provider plugins...
...
* provider.aws: version = "~> 2.23"

Terraform has been successfully initialized!
...
terraform apply -input=false tfplan

aws_instance.tf_instance: Creating...
ami: "" => "ami-0080e4c5bc078760e"
arn: "" => "<computed>"
...
instance_type: "" => "t2.micro"
...
key_name: "" => "doc-delegate1"
...
security_groups.#: "" => "1"
security_groups.2062602533: "" => "sg-05e7b8bxxxxxxxxx"
source_dest_check: "" => "true"
subnet_id: "" => "subnet-05788710b1b06b6b1"
tags.%: "" => "1"
tags.Name: "" => "doctfapply"
tenancy: "" => "<computed>"
volume_tags.%: "" => "<computed>"
vpc_security_group_ids.#: "" => "<computed>"

aws_instance.tf_instance: Still creating... (10s elapsed)

aws_instance.tf_instance: Still creating... (20s elapsed)

aws_instance.tf_instance: Still creating... (30s elapsed)

aws_instance.tf_instance: Creation complete after 31s (ID: i-0b20b148aec6c9239)

Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

terraform output --json > /home/ec2-user/harness-delegate/./repository/terraform/lnFZRF6jQO6tQnB9znMALw/Z3B5PqktSViUQgNCjhR5vQ/terraform/create/terraform-eoOIwEfCTw-dTJ8RLC_tcg-99TFSMfVRfOIbqJreffg6g.tfvars

Waiting: [15] seconds for resources to be ready

Script execution finished with status: SUCCESS

The output looks like a standard terraform apply output.

As you can see, the Terraform config.tf file was run on the Delegate using Terraform and created the AWS EC2 instance. This was all performed as an auxiliary step to the Workflow, showing the independence of the Terraform Apply step.

Remote and Local State with Terraform Apply Step

Harness enables you to use Terraform remote and local state files, and you can use multiple Terraform Apply steps with the same state files.

The general guidelines for using the same remote or local state files are:

  • Remote state files - To use the same remote state file, Terraform Apply steps must use the Backend Configuration (Remote state) setting, and the same Terraform Infrastructure Provisioner and workspace.
  • Local state files - To use the same local state file, Terraform Apply steps must use the same Environment,  Terraform Infrastructure Provisioner, and workspace. The Environment is specified when you create the Workflow that will contain the Terraform Apply step(s). 

Using Remote State with Terraform Apply

To use the same remote state file, Terraform Apply steps must use the Backend Configuration (Remote state) setting and the same Terraform Infrastructure Provisioner and workspace.

You add the backend configs (remote state variables) for remote state to your Terraform Provisioner in the Backend Configuration (Remote state) settings when you create the Terraform Infrastructure Provisioner.

In the Terraform Apply step, you provide values for the remote state variables:

If you have two Terraform Apply steps that use the same Terraform Infrastructure Provisioner and the same workspace, then they are both using the same remote state file. 

A workspace is really a different state file. If you have two Terraform Apply steps that use the same Terraform Infrastructure Provisioner but different workspaces, then they are using separate state files.

For example, if you have a Pipeline with a Build Workflow containing a Terraform Apply step followed by a Canary Workflow containing a Terraform Apply step, in order for both steps to use the same remote state file, the following criteria must be met:

  • Both Terraform Apply steps must use the same Infrastructure Provisioner.
  • Both Terraform Apply steps must use the same workspace.

Using Local State with Terraform Apply

If you do not use the Backend Configuration (Remote state) setting, by default, Terraform uses the local backend to manage state in a local Terraform language file named terraform.tfstate on the disk where you are running Terraform (typically, the Harness Delegate(s)). 

An individual local state file is identified by Harness using a combination of the Harness Environment, Terraform Infrastructure Provisioner, and workspace settings. In fact, the local state is stored by Harness using an entity ID in the format EnvironmentID+ProvisionerID+WorkspaceName. This combination uses the Environment selected for the Workflow (or empty), and the Provisioner and workspace (or empty) selected in the Terraform Apply step.

For two Terraform Apply steps to use the same local state file, they must use the same criteria:

  • Environment (via their Workflow settings).
  • Terraform Infrastructure Provisioner.
  • Workspace.

For example, let's imagine one Terraform Apply step in a Build Workflow with no Environment set up and another Terraform Apply step in a Canary Workflow that uses an Environment. The local backend state file that was created in the first Terraform Apply step is not used by the second Terraform Apply step because they do not use the same Environment. In fact, the Build Workflow uses no Environment.

Consequently, a Terraform Destroy step in the Canary Workflow would not effect the Terraform local state created by the Build Workflow. In this case, it is best to use a separate Terraform Infrastructure Provisioner for each Terraform Apply step.

In order for a Terraform Destroy step to work, the Provisioner and Workspace settings in it must match those of the Terraform Apply step whose operation(s) you want destroyed. Consequently, it must also be part of a Workflow using the same Environment.

Local State and Delegates

If the local state file criteria described above are met, Harness ensures that the same local state file is used regardless of which Harness Delegate performs the deployment.

You might have multiple Delegates running and a Workflow containing a Terraform Apply step that uses a local state file. Harness manages the local state file to ensure that if different Delegates are used for different deployments of the Workflow, the same local state file is used. 

This allows you to deploy a Workflow, or even multiple Workflows, using the same local state file and not worry about which Delegate is used by Harness.

If you like, you can ensure that Terraform Apply steps use the same Delegate using the Delegate Tag setting in the Terraform Apply steps:

Next Steps

 


How did we do?