Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform - if within for_each. Can I filter for_each?

With the following I can loop through a resource block to add route table associations to "all" of my subnets easily. However I need to create associations only for my public subnets.

How can I make this "if" statement work? Or any other way to filter on each.value.class == "pub" for that matter.

resource "aws_route_table_association" "rtb-pub" {
  for_each =  local.subnets_map 
  if each.value.class == "pub"    ## <---- how?

  route_table_id = aws_route_table.rtb-pub.id
  subnet_id      = aws_subnet.map["${each.value.subnet}"].id
}

Thanks in advance!

like image 604
dc12078 Avatar asked Mar 19 '21 01:03

dc12078


People also ask

Can we use if condition in Terraform?

Terraform doesn't support if-statements, so this code won't work. However, you can accomplish the same thing by using the count parameter and taking advantage of two properties: If you set count to 1 on a resource, you get one copy of that resource; if you set count to 0, that resource is not created at all.

How do you use count and foreach together in Terraform?

What is count in Terraform? When you define a resource block in Terraform, by default, this specifies one resource that will be created. To manage several of the same resources, you can use either count or for_each , which removes the need to write a separate block of code for each one.

Is a list of object known only after apply Terraform?

The fields which have known only after apply is not an error, but just informs the user that these fields only get populated in terraform state after its applied. The dependency order is handled by Terraform and hence referring values (even those which have known only after apply ) will be resolved at run time. Thanks.

How does for loop work in Terraform?

Using the count meta-argument The count meta-argument is the simplest of the looping constructs within Terraform. By either directly assigning a whole number or using the length function on a list or map variable, Terraform creates this number of resources based on the resource block it is assigned to.


2 Answers

It depends on exactly what is the structure of your local.subnets_map. But the for_each should be something like the following one:

resource "aws_route_table_association" "rtb-pub" {

  for_each =  {for key, val in local.subnets_map: 
               key => val if val.class == "pub"}

  route_table_id = aws_route_table.rtb-pub.id
  subnet_id      = aws_subnet.map["${each.value.subnet}"].id
}
like image 128
Marcin Avatar answered Oct 20 '22 04:10

Marcin


One weakness of the for loop filtering is that AFAIK you are stuck with a single match value.

If you need to filter for multiple values in the map or list, try the matchkeys() function: https://www.terraform.io/docs/language/functions/matchkeys.html

When using a map, you'll need to use the keys() and values() functions to supply the list parameters:

local {
users = { user1 = "value1", user2 = "value2", user3 = "value3", user4 = "value4" }
}

output user_subset {
  value = matchkeys(values(local.users), keys(local.users), ["user1", "user3"])
}

The resulting output can be used in a for_each loop in a resource block. In this example case I'd use it to add the subset of users to a group.

like image 42
Chris Thompson Avatar answered Oct 20 '22 04:10

Chris Thompson