Parsing Terraform Plan Output

A typical scenario when using Terraform in a Harness workflow is to first execute a plan and then have an approval step so that someone can verify what changes are about to happen prior to running the apply step. Sometimes though, you may want to skip this approval step automatically if there are no changes to be applied. In order to do this we need to be able to inspect and parse the plan output. So let’s create a workflow that does this. Here’s what it will look like when we’re done.

Note: This article assumes you already have a Terraform Provisioner configured. If you need help setting that up you can read about it here.

Enable the EXPORT_TF_PLAN feature Flag

Currently the Terraform plan output is only available through the EXPORT_TF_PLAN feature flag. You will need to ask your customer success team to enabled this for you. Once this is turned on you will have access to the ${terraformApply.tfplan} variable in your workflows. There are a few limitations here to be aware of.

Create a Terraform plan step

In your workflow add a new step and choose the Terraform Apply action.

Be sure and check the Set as Terraform Plan box here.

Parsing the output

Next, we’ll need to add a Shell Script action that we can use to parse the Terraform plan. The data is in JSON format so you’ll need to make sure you have jq installed on your delegate to achieve this.

# Write the terraform plan to a temporary file so we can parse it
cat > plan.json <<EOF

# We need to strip the single quotes that are wrapping it so we can parse it with JQ
plan=$(cat plan.json | sed "s/^'//g" | sed "s/'$//g")

# Get the count of the number of resources being created
create=$(echo "$plan" | jq -r ".resource_changes[].change.actions[]" | grep "create" | wc -l | sed 's/^[[:space:]]*//g')

# Get the count of the number of resources being updated
update=$(echo "$plan" | jq -r ".resource_changes[].change.actions[]" | grep "update" | wc -l | sed 's/^[[:space:]]*//g')

# Get the count of the number of resources being deleted
delete=$(echo "$plan" | jq -r ".resource_changes[].change.actions[]" | grep "delete" | wc -l | sed 's/^[[:space:]]*//g')

# Cleanup after ourselves
rm -f plan.json

What we did here was parse out how many create, update, and delete actions were in the plan and make them variables in the shell script. Now we’ll publish them as a Harness variable called terraformChanges that will be available to the rest of our workflow or pipeline.

Automate the approval process

Add a new Approval step to the workflow.

Now we’re going to conditionally skip this step in the event there are no changes to apply.

Open up the menu for the section of the workflow your approval step is in and choose the Execution → Conditional option.

Here we’ll choose the Selected Steps option under the Define the skip conditions for section.

Now click the Add link and choose Approval as the step and then paste this in for the Skip condition:

${terraformChanges.delete} == "0" && ${terraformChanges.create} == "0" && ${terraformChanges.update} == "0"

This will only skip the approval step in the event there are no changes at all in the plan.

Add the Terraform apply step

Finally, we’ll go ahead and add another Terraform Apply step to the workflow. This time we’ll make sure the Inherit following configurations from Terraform Plan box is checked.

Wrapping up

Now you can successfully skip the approval step when there are no changes to be applied. In the future we we’ll likely have these variables available to use natively and not need to have the extra parsing step.