Set Terraform Resource properties from an element in a list retrieved by a Data Source – using a local value

Lucas Jellema

Terraform is a platform for implementing Infrastructure as Code. Terraform defines a syntax for describing resources and provides an engine that interprets the resources definitions, compares this desired state with the existing state in the destination environment and subsequently attempts to bring the destination in line with the desired state.

I was struggling with the following challenge:

  • I need a specific property in a managed resource to be derived from a characteristic of the destination environment
  • I have defined a data source to read the characteristic
  • this data source returns a list object; using a filter, I have ensured that the list contains only the element I need
  • EDIT: 28 February 2020: this article was mainly based on the following premises that has been found to be incorrect: in the definition of the resource property, I cannot refer to a list or an element in a list; the [index] notation is not allowed in a resource property

So how can I get to a property of an element in the (single element) list returned by the data source?

The best solution I could come up with is through a local value. A local value (aka local) in Terraform is a local variable (local in the scope of the module in which it is defined) whose value is defined through an expression. One or more references can be made to the local value in resource definitions within the same module.

The expression used to define the local can make use of references to specific elements in a list. That allowed me to create the following definitions:

data "oci_functions_applications" "lab_application" {
    compartment_id = "var.compartment_id"
    # display_name is unique; this filter ensures that the list contains only one element (or zero)
    filter {
        name   = "display_name"
        values  = [ "lab1" ]
    }
}

locals {
  # store the first (and only) element returned from the data source in the local variable
  lab_app = data.oci_functions_applications.lab_application.applications[0]
}

The data source lab_application returns a list of applications. The filter restricts the list to a single element. Then the solution I had been looking for: the local value lab_app. It is defined using a reference to the data source; from the value provided by the data source it takes the first element (.[0]). Now the local contains a single element (an application object) and in the resource definition hello_function I can refer to properties on this object:

resource "oci_functions_function" "hello_function" {
    # the OCID of a functions application that the current user can make use of, derived from the local value lab_app
    application_id = "local.lab_app.id"
    display_name = "my-hello-function-tf"
}

Note: Data sources are like read only queries that allow data to be fetched or computed for use elsewhere in Terraform configuration. Use of data sources allows a Terraform configuration to make use of information defined outside of Terraform, or defined by another separate Terraform configuration.

EDIT: 28 February 2020 – What I described here is correct. What I did not know at the time of writing is that a resource property’s definition can use the same expression as I am using here for the local value. See this article for a more thorough discussion.

Resources

Terraform Documentation on

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Next Post

Setup and use of oVirt on CentOS7

Facebook0TwitterLinkedinToday, I’ll explain how to install and use oVirt: a nice virtualization tool for Linux, which is based on KVM. I installed the current production version 4.3.8 on a test machine, a Medion machine with an extra SSD drive. As usual, you’ll find the installation file for pxe that I […]