Skip to content

Instantly share code, notes, and snippets.

@brikis98 brikis98/main.tf
Last active Dec 6, 2019

Embed
What would you like to do?
A hacky way to create a dynamic list of maps in Terraform
# 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

This comment has been minimized.

Copy link
Owner Author

brikis98 commented Mar 8, 2018

$ terraform init
$ terraform apply

null_resource.subnet_mappings[2]: Refreshing state... (ID: 5492324315923717110)
null_resource.subnet_mappings[0]: Refreshing state... (ID: 6342483238685385197)
null_resource.subnet_mappings[1]: Refreshing state... (ID: 238793807379032397)

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

subnet_mappings = [
    {
        allocation_id = eip-1,
        subnet_id = subnet-1
    },
    {
        allocation_id = eip-2,
        subnet_id = subnet-2
    },
    {
        allocation_id = eip-3,
        subnet_id = subnet-3
    }
]
@brikis98

This comment has been minimized.

Copy link
Owner Author

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".

@zeyuye-airwallex

This comment has been minimized.

Copy link

zeyuye-airwallex commented Mar 5, 2019

👍

@bdashrad

This comment has been minimized.

Copy link

bdashrad commented Mar 12, 2019

very useful thanks

@elvis-cai

This comment has been minimized.

Copy link

elvis-cai commented May 6, 2019

sweet trick

@rajrajen-juul

This comment has been minimized.

Copy link

rajrajen-juul commented May 9, 2019

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 ..

@Behoston

This comment has been minimized.

Copy link

Behoston commented May 30, 2019

👍

@rivlinp

This comment has been minimized.

Copy link

rivlinp commented Jun 9, 2019

@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?

@atrepca

This comment has been minimized.

Copy link

atrepca commented Aug 8, 2019

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
    }
  }
@brikis98

This comment has been minimized.

Copy link
Owner Author

brikis98 commented Aug 8, 2019

This Gist was written pre-Terraform 0.12. It is no longer necessary.

@atrepca

This comment has been minimized.

Copy link

atrepca commented Aug 8, 2019

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,

@fv-ian

This comment has been minimized.

Copy link

fv-ian commented Dec 6, 2019

True.. dynamic and for_each didn't exist before 0.12 either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.