I am trying to use a nested loop in terraform. I have two list variables list_of_allowed_accounts
and list_of_images
, and looking to iterate over list list_of_images
and then iterate over list list_of_allowed_accounts
.
Here is my terraform code.
variable "list_of_allowed_accounts" {
type = "list"
default = ["111111111", "2222222"]
}
variable "list_of_images" {
type = "list"
default = ["alpine", "java", "jenkins"]
}
data "template_file" "ecr_policy_allowed_accounts" {
template = "${file("${path.module}/ecr_policy.tpl")}"
vars {
count = "${length(var.list_of_allowed_accounts)}"
account_id = "${element(var.list_of_allowed_accounts, count.index)}"
}
}
resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
count = "${length(var.list_of_images)}"
repository = "${element(aws_ecr_repository.images.*.id, count.index)}"
count = "${length(var.list_of_allowed_accounts)}"
policy = "${data.template_file.ecr_policy_allowed_accounts.rendered}"
}
This is a bash equivalent of what I am trying to do.
for image in alpine java jenkins
do
for account_id in 111111111 2222222
do
// call template here using variable 'account_id' and 'image'
done
done
Terraform doesn't have direct support for this sort of nested iteration, but we can fake it with some arithmetic.
Since we want to create a policy template for every combination of account and image, the
count
on thetemplate_file
data block is the two multiplied together. We can then use the division and modulo operations to get back fromcount.index
to the separate indices into each list.Since I didn't have a copy of your policy template I just used a placeholder one; this configuration thus gave the following plan:
Each policy instance applies to a different pair of account id and image, covering all combinations.
The answers here do work (I used them initially), but I think I have a better solution using Terraform's setproduct function. I haven't seen many examples of it used around the interwebs, but setproduct takes two sets (or more importantly, two lists) and produces a list of sets with every permutation of the inputs. In my case I am creating SSM parameters:
This creates SSM parameters named:
My wimpy little brain can parse this a little easier than the modulo magic in the other answers!
FYI if anyone comes here from Google, if you are using terraform 0.12, you will need to use the floor function anywhere you do divide, or else you will get an error about partial indexes.
While solutions with setproduct and using modulo work in some cases, there is a more elegant solution: using terraform modules (not to be confused with the modulo operator). By using a terraform module an extra opportunity arises to use the count meta-argument.
This solution is especially useful if not all combinations of inputs apply. For example, I used this solution to handle a list of projects, where each project has a list of unique roles.
For example, on the top-level you can use this:
And then have an additional terraform module in the
../accounts
directory with this content.I find this approach easier to understand.
Basically the problem is in the data "template_file", the account_id can not be set the way you think it will since the count in your case is just another var that never gets incremented/changed. Just saying since I miss to see what is your question exactly.
I don't have enough reputation points to add a comment to the answer provided by @Martin Atkins, so I am posting his answer with a slight modification, which works around Terraform issue 20567