How To Manage Infrastructure Data with Terraform Outputs

Introduction

Terraform outputs are used to extract information about the infrastructure resources from the project state. Using other features of the Hashicorp Configuration Language (HCL), which Terraform uses, resource information can be queried and transformed into more complex data structures, such as lists and maps. Outputs are useful for providing information to external software, which can operate on the created infrastructure resources.

In this tutorial, you’ll learn about Terraform output syntax and its parameters by creating a simple infrastructure that deploys Droplets. You’ll also parse the outputs programmatically by converting them to JSON.

Prerequisites

  • A DigitalOcean Personal Access Token, which you can create via the DigitalOcean control panel. Instructions to do that can be found in this link: How to Generate a Personal Access Token.
  • Terraform installed on your local machine and a project set up with the DigitalOcean provider. Complete Step 1 and Step 2 of the How To Use Terraform with DigitalOcean tutorial, and be sure to name the project folder terraform-outputs, instead of loadbalance. During Step 2, do not include the pvt_key variable and the SSH key resource.
  • Familiarity with HCL data types and loops. For more information, see the How To Improve Flexibility Using Terraform Variables, Dependencies, and Conditionals tutorial.

Note: This tutorial has specifically been tested with Terraform 0.13.

Defining Outputs

In this section, you’ll declare a Droplet, deploy it to the cloud, and learn about outputs by defining one that will show the Droplet’s IP address.

Assuming you are in the terraform-outputs directory, create and open the droplets.tf file for editing:

  • nano droplets.tf

Add the following Droplet resource and output definition:

terraform-outputs/droplets.tf

resource "digitalocean_droplet" "web" {   image  = "ubuntu-18-04-x64"   name   = "test-droplet"   region = "fra1"   size   = "s-1vcpu-1gb" }  output "droplet_ip_address" {   value = digitalocean_droplet.web.ipv4_address } 

You first declare a Droplet resource, called web. Its actual name in the cloud will be test-droplet, in the region fra1, running Ubuntu 18.04.

Then, you declare an output called droplet_ip_address. In Terraform, outputs are used to export and show internal and computed values and information about the resources. Here, you set the value parameter, which accepts the data to output, to the IP address of the declared Droplet. At declare time, it’s unknown, but it will become available once the Droplet is deployed. Outputs are shown and accessible after each deployment.

Save and close the file, then deploy the project by running the following command:

  • terraform apply -var "do_token=${DO_PAT}"

Enter yes to apply when prompted. The end of the output you’ll see will be similar to this:

Output... digitalocean_droplet.web: Creating... ... digitalocean_droplet.web: Creation complete after 32s [id=207631771]  Apply complete! Resources: 1 added, 0 changed, 0 destroyed.  Outputs:  droplet_ip_address = ip_address 

The highlighted IP address belongs to your newly deployed Droplet. Applying the project deploys the resources to the cloud and shows the outputs at the end, when all resource attributes are available. Without the droplet_ip_address output, Terraform would show no further information about the Droplet, except that it’s deployed.

Outputs can also be shown using the output command:

  • terraform output

The output will list all outputs in the project:

Outputdroplet_ip_address = ip_address 

You can also query a specific output by name by specifying it as an argument:

  • terraform output output_name

For droplet_ip_address, the output will consist of the IP address only:

Outputip_address 

Except for specifying the mandatory value, outputs have a few optional parameters:

  • description: embeds short documentation detailing what the output shows.
  • sensitive: accepts a boolean value, which prevents the content of the output from being shown after deploying if set to true.
  • depends_on: a meta parameter available at each resource that allows you to explicitly specify resources the output depends on, that Terraform is not able to automatically deduce during planning.

The sensitive parameter is useful when the logs of the Terraform deployment will be publicly available, but the output contents should be kept hidden. You’ll now add it to your Droplet resource definition.

Open droplets.tf for editing and add the highlighted line:

terraform-outputs/droplets.tf

resource "digitalocean_droplet" "web" {   image  = "ubuntu-18-04-x64"   name   = "test-droplet"   region = "fra1"   size   = "s-1vcpu-1gb" }  output "droplet_ip_address" {   value      = digitalocean_droplet.web.ipv4_address   sensitive = true } 

Save and close the file when you’re done. You can try deploying the project again by running:

  • terraform apply -var "do_token=${DO_PAT}"

You’ll see that the output is redacted:

Outputdigitalocean_droplet.web: Refreshing state... [id=207631771]  Apply complete! Resources: 0 added, 0 changed, 0 destroyed.  Outputs:  droplet_ip_address = <sensitive> 

Even if it’s marked as sensitive, the output and its contents will still be available through other channels, such as viewing the Terraform state or querying the outputs directly.

In the next step, you’ll create a different Droplet and output structure, so destroy the currently deployed ones by running:

  • terraform destroy -var "do_token=${DO_PAT}"

The output at the very end will be:

Output... Destroy complete! Resources: 1 destroyed. 

You’ve declared and deployed a Droplet and created an output that shows its IP address. You’ll now learn about using outputs to show more complex structures, such as lists and maps.

Outputting Complex Structures

In this section, you’ll deploy multiple Droplets from the same definition using the count keyword, and output their IP addresses in various formats.

Using the for loop

You’ll need to modify the Droplet resource definition, so open it for editing:

  • nano droplets.tf

Modify it to look like this:

terraform-outputs/droplets.tf

resource "digitalocean_droplet" "web" {   count  = 3   image  = "ubuntu-18-04-x64"   name   = "test-droplet-${count.index}"   region = "fra1"   size   = "s-1vcpu-1gb" } 

You’ve specified that three Droplets should be created using the count key and added the current index to the Droplet name, so that you’ll be able to later discern between them. When you’re done, save and close the file.

Apply the code by running:

  • terraform apply -var "do_token=${DO_PAT}"

Terraform will plan the creation of three numbered Droplets, called test-droplet-0, test-droplet-1, and test-droplet-2. Enter yes when prompted to finish the process. You’ll see the following output in the end:

Output... Apply complete! Resources: 3 added, 0 changed, 0 destroyed. 

This means that all three Droplets are successfully deployed and that all information about them is stored in the project state.

The easiest way to access their resource attributes is to use outputs, though creating one for each of the Droplets is not scalable. The solution is to use the for loop to traverse through the list of Droplets and gather their attributes, or to alternatively use splat expressions. You’ll learn about them later in this step.

You’ll first define an output that will output the IP addresses of the three Droplets, paired with their names. Open droplets.tf for editing:

  • nano droplets.tf

Add the following lines:

terraform-outputs/droplets.tf

resource "digitalocean_droplet" "web" {   count  = 3   image  = "ubuntu-18-04-x64"   name   = "test-droplet-${count.index}"   region = "fra1"   size   = "s-1vcpu-1gb" }  output "droplet_ip_addresses" {   value = {     for droplet in digitalocean_droplet.web:     droplet.name => droplet.ipv4_address   } } 

The output value of droplet_ip_addresses is constructed using a for loop. Because it’s surrounded by braces, the resulting type will be a map. The loop traverses the list of Droplets, and for each instance, pairs its name with its IP address and appends it to the resulting map.

Save and close the file, then try applying the project again:

  • terraform apply -var "do_token=${DO_PAT}"

Enter yes when prompted and you’ll receive the output contents at the end:

OutputApply complete! Resources: 0 added, 0 changed, 0 destroyed.  Outputs:  droplet_ip_addresses = {   "test-droplet-0" = "ip_address"   "test-droplet-1" = "ip_address"   "test-droplet-2" = "ip_address" } 

The droplet_ip_addresses output details the IP addresses of the three deployed droplets.

Using the Terraform output command, you can get the contents of the output as JSON using its command argument:

  • terraform output -json droplet_ip_addresses

The result will be similar to the following:

Output{"test-droplet-0":"ip_address","test-droplet-1":"ip_address","test-droplet-2":"ip_address"} 

JSON parsing is widely used and supported in many programming languages. This way, you can programmatically parse the information about the deployed Droplet resources.

Using Splat Expressions

Splat expressions offer a compact way of iterating over all elements of a list, and collecting contents of an attribute from each of them, resulting in a list. A splat expression that would extract the IP addresses of the three deployed droplets would have the following syntax:

digitalocean_droplet.web[*].ipv4_address 

The [*] symbol traverses the list on its left and for each of the elements, takes the contents of its attribute specified on the right. If the reference on the left is not a list by itself, it will be converted to one where it will be the sole element.

You can open droplets.tf for editing and modify the following lines to implement this:

terraform-outputs/droplets.tf

resource "digitalocean_droplet" "web" {   count  = 3   image  = "ubuntu-18-04-x64"   name   = "test-droplet-${count.index}"   region = "fra1"   size   = "s-1vcpu-1gb" }  output "droplet_ip_addresses" {   value = digitalocean_droplet.web[*].ipv4_address } 

After saving the file, apply the project by running the following command:

  • terraform apply -var "do_token=${DO_PAT}"

You’ll receive output that is now a list, and contains only the IP addresses of the Droplets:

OutputApply complete! Resources: 0 added, 0 changed, 0 destroyed.  Outputs:  droplet_ip_addresses = [   "ip_address",   "ip_address",   "ip_address", ] 

To receive the output as JSON, run the following command:

  • terraform output -json droplet_ip_addresses

The output will be a single array:

Output["ip_address","ip_address","ip_address"] 

You’ve used outputs together with splat expressions and for loops to export IP addresses of the deployed Droplets. You’ve also received the output contents as JSON, and you’ll now use jq—a tool for dynamically filtering JSON according to given expressions—to parse them.

Parsing Outputs Using jq

In this step, you’ll install and learn the basics of jq, a tool for manipulating JSON documents. You’ll use it to parse the outputs of your Terraform project.

If you’re on Ubuntu, run the following command to install jq:

  • sudo snap install jq

On macOS, you can use Homebrew to install it:

  • brew install jq

jq applies the provided processing expression on given input, which can be piped in. The easiest task in jq is to pretty print the input:

  • terraform output -json droplet_ip_addresses | jq '.'

Passing in the identity operator (.) means that the whole JSON document parsed from the input should be outputted without modifications:

Output[   "first_ip_address",   "second_ip_address",   "third_ip_address" ] 

You can request just the second IP address using the array bracket notation, counting from zero:

  • terraform output -json droplet_ip_addresses | jq '.[1]'

The output will be:

Output"second_ip_address" 

To make the result of the processing an array, wrap the expression in brackets:

  • terraform output -json droplet_ip_addresses | jq '[.[1]]'

You’ll get a pretty printed JSON array:

Output[   "second_ip_address" ] 

You can retrieve parts of arrays instead of single elements by specifying a range of indexes inside the brackets:

  • terraform output -json droplet_ip_addresses | jq '.[0:2]'

The output will be:

Output[   "first_ip_address",   "second_ip_address" ] 

The range 0:2 returns the first two elements—the upper part of the range (2) is not inclusive, so only elements at positions 0 and 1 are fetched.

You can now destroy the deployed resources by running:

  • terraform destroy -var "do_token=${DO_PAT}"

In this step, you have installed jq and used it to parse and manipulate the output of your Terraform project, which deploys three Droplets.

Conclusion

You have learned about Terraform outputs, how they are used to show details about the deployed resources, and how they can be used to export data structures for later external processing. You’ve also seen how to use outputs to show attributes of a single resource, as well as for showing constructed maps and lists containing resource attributes.

For more detailed information about the features of jq, visit the official docs.

To learn more about Terraform check out the series: How To Manage Infrastructure with Terraform.