You can also slice a set by first casting it to a list and then accessing it as a list.
As an example:
variable "set" {
type = set(string)
default = [
"foo",
"bar",
]
}
output "set" {
value = var.set
}
output "set_first_element" {
value = var.set[0]
}
This will error because sets can't be directly accessed by an index:
Error: Invalid index
on main.tf line 14, in output "set_first_element":
14: value = var.set[0]
This value does not have any indices.
If you instead cast it with the tolist
function then you can access it as expected:
output "set_to_list_first_element" {
value = tolist(var.set)[0]
}
Outputs:
set = [
"bar",
"foo",
]
set_to_list_first_element = bar
Note that this returns bar
instead of foo
. Strictly speaking sets are unordered in Terraform so you can't rely on the order at all and are only consistent during a single run of Terraform but in practice they are stable and in the the case of set(string)
they are sorted in lexicographical order:
When a set is converted to a list or tuple, the elements will be in an arbitrary order. If the set's elements were strings, they will be in lexicographical order; sets of other element types do not guarantee any particular order of elements.
The main place this comes up is if you are dealing with a resource or data source that returns a set type in Terraform 0.12 but need to use a singular value. A basic example might be something like this:
data "aws_subnet_ids" "private" {
vpc_id = var.vpc_id
tags = {
Tier = "Private"
}
}
resource "aws_instance" "app" {
ami = var.ami
instance_type = "t2.micro"
subnet_id = tolist(data.aws_subnet_ids.example.ids)[0]
}
This would create an EC2 instance in a subnet tagged with Tier = Private
but set no other constraint on where it should be.
While you referenced being able to access values with for_each
you can also loop through a set with a for
expression:
variable "set_of_objects" {
type = set(object({
port = number
service = string
}))
default = [
{
port = 22
service = "ssh"
},
{
port = 80
service = "http"
},
]
}
output "set_of_objects" {
value = var.set_of_objects
}
output "list_comprehension_over_set" {
value = [ for obj in var.set_of_objects : upper(obj.service) ]
}
This then outputs the following:
list_comprehension_over_set = [
"SSH",
"HTTP",
]
set_of_objects = [
{
"port" = 22
"service" = "ssh"
},
{
"port" = 80
"service" = "http"
},
]
for_each
is not a meta variable (sorry to be pedantic). – Matt Schuchardfor_each
is not a meta variable? terraform.io/docs/configuration/resources.html#meta-arguments lists it as one of the meta arguments available for all resources although it's more complex than that as it also appears indynamic
blocks where the others are not (mostly becausedynamic
requires it). – ydaetskcoR