Terraform for-each with list of objects
What you are looking for is a dynamic block: https://www.terraform.io/docs/configuration/expressions.html#dynamic-blocks
Original:
site_associations {
site_id = each.value.site
}
Dynamic:
dynamic "site_associations"{
for_each = each.value.site
content {
site_id = site_associations.value
}
}
The dynamic
block allows you to create another for_each
loop over the each.value.site
.
Note: the value inside the dynamic block is referenced using the block name site_associations.value
Whole main.tf:
variable tenants {
description = "Map of project names to configuration."
type = list(object({
name = string
dname = string
desc = string
site = list(string)
}))
default = [{
name = "Tenant-1",
dname = "Tenant-1",
desc = "Test Tenant 1",
site = ["site1", "site2"]
},
{
name = "Tenant-2",
dname = "Tenant-2",
desc = "Test Tenant 2",
site = ["site1"]
}]
}
resource "mso_tenant" "restenant" {
for_each = {for i, v in var.tenants: i => v}
name = each.value.name
display_name = each.value.dname
description = each.value.desc
dynamic "site_associations"{
for_each = each.value.site
content {
site_id = site_associations.value
}
}
}
Plan Output:
# mso_tenant.restenant["0"] will be created
+ resource "mso_tenant" "restenant" {
+ description = "Test Tenant 1"
+ display_name = "Tenant-1"
+ id = (known after apply)
+ name = "Tenant-1"
+ site_associations {
+ aws_access_key_id = (known after apply)
+ aws_account_id = (known after apply)
+ aws_secret_key = (known after apply)
+ azure_access_type = (known after apply)
+ azure_active_directory_id = (known after apply)
+ azure_application_id = (known after apply)
+ azure_client_secret = (known after apply)
+ azure_subscription_id = (known after apply)
+ is_aws_account_trusted = (known after apply)
+ site_id = "site1"
+ vendor = (known after apply)
}
+ site_associations {
+ aws_access_key_id = (known after apply)
+ aws_account_id = (known after apply)
+ aws_secret_key = (known after apply)
+ azure_access_type = (known after apply)
+ azure_active_directory_id = (known after apply)
+ azure_application_id = (known after apply)
+ azure_client_secret = (known after apply)
+ azure_subscription_id = (known after apply)
+ is_aws_account_trusted = (known after apply)
+ site_id = "site2"
+ vendor = (known after apply)
}
+ user_associations {
+ user_id = (known after apply)
}
}
# mso_tenant.restenant["1"] will be created
+ resource "mso_tenant" "restenant" {
+ description = "Test Tenant 2"
+ display_name = "Tenant-2"
+ id = (known after apply)
+ name = "Tenant-2"
+ site_associations {
+ aws_access_key_id = (known after apply)
+ aws_account_id = (known after apply)
+ aws_secret_key = (known after apply)
+ azure_access_type = (known after apply)
+ azure_active_directory_id = (known after apply)
+ azure_application_id = (known after apply)
+ azure_client_secret = (known after apply)
+ azure_subscription_id = (known after apply)
+ is_aws_account_trusted = (known after apply)
+ site_id = "site1"
+ vendor = (known after apply)
}
+ user_associations {
+ user_id = (known after apply)
}
}
Plan: 2 to add, 0 to change, 0 to destroy.
wiwa1978
Updated on June 14, 2022Comments
-
wiwa1978 almost 2 years
I have the following variable in variables.tf file:
variable tenants { description = "Map of project names to configuration." type = list(object({ name = string dname = string desc = string site = list(string) })) default = [{ name = "Tenant-1", dname = "Tenant-1", desc = "Test Tenant 1", site = ["site1", "site2"] }, { name = "Tenant-2", dname = "Tenant-2", desc = "Test Tenant 2", site = ["site1"] }] }
In my main.tf file, I would like to loop over this list. I have the following code in main.tf file:
resource "mso_tenant" "restenant" { for_each = {for i, v in var.tenants: i => v} name = each.value.name display_name = each.value.dname description = each.value.desc site_associations { site_id = each.value.site } }
So the end result should be that 2 tenants get created with the attributes as specified in the variable file. So tenant1 will have 2 site_associations and tenant2 will have 1 association once created.
Result should be:
name = "Tenant-1" display_name = "Tenant-1" description = "Test Tenant 1" site_associations { site_id = site1 site_id = site2 }
and
name = "Tenant-2" display_name = "Tenant-2" description = "Test Tenant 2" site_associations { site_id = site1 }
I tried the following:
resource "mso_tenant" "restenant" { for_each = {for i, v in var.tenants: i => v} name = each.value.name display_name = each.value.dname description = each.value.desc site_associations { site_id = each.value.site } }
This works for the
name
,dname
anddesc
but it does not iterate over the site variable (which is a list). This results in the error message:each.value.site is list of string with 1 element Inappropriate value for attribute "site_id": string required.
Tried to solve as follows:
resource "mso_tenant" "restenant" { for_each = {for i, v in var.tenants: i => v} name = each.value.name display_name = each.value.dname description = each.value.desc site_associations { site_id = [for site in each.value.site: site] } }
but this also gives:
each.value.site is list of string with 2 elements Inappropriate value for attribute "site_id": string required.
-
Grzegorz Oledzki over 3 yearsDoes this answer your question? How to for_each through a list(objects) in Terraform 0.12
-
Marcin over 3 yearsUse
for_each = { for idx, v in var.tenants: idx=>v}
-
wiwa1978 over 3 yearsI edited the question to make it more clear. Your suggestion is working for the non-list items but does not iterate over the list itself (e.g. site)
-