-
-
Save brikis98/f3fe2ae06f996b40b55eebcb74ed9a9e to your computer and use it in GitHub Desktop.
# The goal: create a list of maps of subnet mappings so we don't have to statically hard-code them in aws_lb | |
# https://www.terraform.io/docs/providers/aws/r/lb.html#subnet_mapping | |
locals { | |
# These represent dynamic data we fetch from somewhere, such as subnet IDs and EIPs from a VPC module | |
subnet_ids = ["subnet-1", "subnet-2", "subnet-3"] | |
eips = ["eip-1", "eip-2", "eip-3"] | |
} | |
# Here's the hack! The null_resource has a map called triggers that we can set to arbitrary values. | |
# We can also use count to create a list of null_resources. By accessing the triggers map inside of | |
# that list, we get our list of maps! See the output variable below. | |
resource "null_resource" "subnet_mappings" { | |
count = "${length(local.subnet_ids)}" | |
triggers { | |
subnet_id = "${element(local.subnet_ids, count.index)}" | |
allocation_id = "${element(local.eips, count.index)}" | |
} | |
} | |
# And here's the result! We have a dynamic list of maps. I'm just outputting it here, but we should | |
# be able to take the same value and set it as the input to aws_lb's subnet_mapping param. | |
output "subnet_mappings" { | |
value = "${null_resource.subnet_mappings.*.triggers}" | |
} |
brikis98
commented
Mar 8, 2018
•
Update: it turns out that while this approach works for static values (i.e., hard-coded values, variables, local vars), it does not work in the general case for anything with "dynamic" or "computed" data such as a data source or resource. That's due to a Terraform limitation where it tries to validate the structure of the maps before doing any of the computations, and you'll get an error such as "required field is not set".
👍
very useful thanks
sweet trick
https://www.terraform.io/docs/configuration/expressions.html#for-expressions For Loop is coming up natively in Terraform 0.12.x . Hope that solves our problem ..
👍
@brikis98 thanks for this trick. Turns out I was looking for exactly this but I want to use the o/p of subnet_mappings as a input to a variable inside a resource. You did mention that it wont work with a resource, so what are my options?
Why not use the zipmap() function instead?
zipmap constructs a map from a list of keys and a corresponding list of values.
Currently doing this successfully with Terraform 0.12:
dynamic "subnet_mapping" {
for_each = zipmap(subnet_ids, eips)
content {
subnet_id = subnet_mapping.key
allocation_id = subnet_mapping.value
}
}
This Gist was written pre-Terraform 0.12. It is no longer necessary.
Sorry for not being clear, I didn’t mean this as a 0.12 thing, zipmap
works with < 0.12 too, it was added in version 0.7.8 (changelog).
Thanks for posting this,
True.. dynamic and for_each didn't exist before 0.12 either.
For cases where zipmap()
is not appropriate, for example you have a list(string)
type and need to produce a list(object({}))
, try this syntax in Terraform 0.12:
locals {
macs = [
"aa:bb:cc:dd:ee:ff",
"aa:bb:de:ad:be:ef",
]
}
module "servers" {
source = "./app-cluster"
workers = [
for index, x in local.macs : {
name = "node${index}"
mac = x
}
]
}
👍
After I have switched from Terraform 0.11 to Terraform 0.12.. It's really got simple and easy to work with loops and other stuff. Try using this syntax
locals {
parameters = [
{
name : "rds.force_ssl",
value : "1"
apply_method : "pending-reboot"
},
{
name : "ssl",
value : "1",
apply_method : "pending-reboot"
}
]
}
resource "aws_db_parameter_group" "parameter_group" {
name = var.name
family = var.family
dynamic "parameter" {
for_each = var.parameters
content {
name = parameter.value["name"]
value = parameter.value["value"]
apply_method = parameter.value["apply_method"]
}
}
}`
```