Terraform provides a greater ability to define Infrastructure as Code (IaC) through its support of Expressions. Expressions are lines of code that define configuration and attributes on resources in the Terraform HCL code as the Terraform code is executed with the terraform plan
command. This enables a rich ability to dynamically configure resources based on passed input variables to the Terraform Project, or even via looking up other resources managed by the same Terraform Project. There is a huge variety to the different code expressions that can be written in Terraform to suit the requirements of different Infrastructure as Code projects.
Terraform expressions support many built-in functions to help writing the expression code needed for a solutions infrastructure definition. When using a Terraform list
type to define an Array of value or objects, it may be necessary at times to lookup those values programmatically.
Basic use of index()
Function
The Terraform index()
function can be used to lookup the index location of a value in a list
. The function accepts an argument that is a reference to the list
to search, and an argument that is the value to lookup the index for within the list
.
The following is an example usage of the index()
function to find the index of a value in a simple list of string
values:
locals {
myList = ["a", "b", "c", "d", "e"]
# Get index for "c" value in list
myValueIndex = index(local.myList, "c")
# myValueIndex will equal 2
}
The previous example shows how simple it is to use the index()
function to retrieve the index of a value within a list of strings (aka list(string)
). This can be used exactly the same way to lookup the index of values in a list of numbers (aka list(number)
) too.
The following is an example usage of the index()
function to find the index of a value in a simple list of numbers:
locals {
myList = [1966, 2063, 1989]
# Get index for 2063 value in list
myValueIndex = index(local.myList, 2063)
# myValueIndex will equal 1
}
Get Index of Object in List via Attribute Value
It’s probably most common to lookup values within a Terraform list
that contains numbers or strings. There are also times when the list may contain objects that have their own attributes. Using the index()
method to lookup a values index in an object list (aka list(object)
) doesn’t work by passing the object itself as the value to the index()
function.
To use the index()
function on a list of objects (list(object)
) to find the index of an object in the list by looking up the value of an attribute on the object is performed with the help of a splat expression that that converts the list(object)
to a list of the values needed for the lookup.
The following is an example of using a splat lookup on a list of objects to lookup the index of the object in the list with the name
attribute set to the value being looked up:
locals {
objList = [
{ name = "Chris" },
{ name = "Dan" }
]
# Get index for Object with name equal to "Dan" in list
myObjIndex = index(local.objList.*.name, "Dan")
# nameIndex will equal 1
}
The previous example shows the use of a splat expression using the *
symbol that iterates over all the objects / elements in the list to the left of the *
symbol and accesses the attribute given to the right of it. This splat expression is a shorthand for using a for
expression to create a list
of the values of the given attribute on the objects / elements in the source list
.
The following is an expanded example of the previous example of a splat expression that uses the for
expression instead to help better understand how this works:
locals {
objList = [
{ name = "Chris" },
{ name = "Dan" }
]
# Create List of 'name' values from source objet list
listOfNames = [for v in local.objList : v.name]
# Get index for 'name' equal to "Dan"
nameIndex = index(local.listOfNames, "Dan")
# nameIndex will equal 1
}
To compress the for
expression usage into a single line expression that performs the same index value lookup as the splat expression is as follows:
locals {
objList = [
{ name = "Chris" },
{ name = "Dan" }
]
# splat expression index lookup
myObjIndexSplat = index(local.objList.*.name, "Dan")
# for expression index lookup
myObjIndexFor = index([for v in local.objList : v.name], "Dan")
}
Retrieve List Element by Index
Once the index of an element in a list
is known, then the value of that element can be retrieved from the list. This can be performed in a similar syntax to retrieving array elements in other programming languages by their index. Also, just as Arrays in most other programming languages start with an index of zero (0
) for the first element in the Array, so is the list
type in Terraform.
The following is the syntax for retrieving an element from a list by index:
list[index]
The following is an example of retrieving an element from a list
by index:
locals {
myList = ["a", "b", "c", "d"]
value = local.myList[1]
# value is equal to "b"
}
To close things off, the following are several examples of retrieving elements from lists using the previous index()
function code examples of looking up the element index values:
locals {
myList = ["a", "b", "c", "d"]
# lookup value by index of specific value
stringValue = local.myList(index(local.myList, "b"))
objList = [
{ name = "Chris" },
{ name = "Dan" }
]
# splat expression index lookup of object list
objValue1 = local.objList[index(local.objList.*.name, "Dan")]
# for expression index lookup of object list
objValue2 = local.objList(index([for v in local.objList : v.name], "Dan"))
}
Retrieve Resource in List by Attribute Value
The previous examples show how to use the index()
function to look up and retrieve elements from a list by their value, including by the value of an attribute on objects within a list. The later method of list value lookup can be extremely useful when you need to get an object reference from a list of objects managed by a Terraform Provider.
This scenario can be useful to get a single resource reference from a list of resources managed by Terraform using the count
or for_each
expression to create multiple resource
instances using a single block of Terraform code. The following is a simple example of this that retrieves a specific resource and then sets an output
variable to the value of the id
attribute of the object:
locals {
subnets = ["public", "default", "private"]
}
resource "azurerm_subnet" "subnet" {
count = length(local.subnets)
name = local.subnets[count.index].name
# other resource attributes here
}
output "default_subnet_id" {
value = azurerm_subnet.subnet[index(azurerm_subnet.subnet.*.name, "default")].id
}
life changing, wish i had seen this 5 hours ago, thank you!