Terraform 在地图列表中循环
Terraform looping in list of map
我有一个生成地图输出列表的 Terraform 模块:
object_ids = [
{
"object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
"upn" = "john@domain.com"
"user" = "john"
},
{
"object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
"upn" = "martin@domain.com"
"user" = "martin"
},
]
使用 for_each 我可以循环一个值来构建此资源:
resource "azurerm_role_assignment" "subread" {
for_each = toset(module.user.map_object_ids[*].object_id)
scope = data.azurerm_subscription.primary.id
role_definition_name = "Reader"
principal_id = each.value
}
但是我不知道如何循环多个值。
我对另一个需要 2 个不同输出值的资源尝试了以下操作:
resource "azurerm_role_assignment" "contribrg" {
scope = [for map in module.user.map_object_ids[*]: "${data.azurerm_subscription.primary.id}/resourceGroups/${lookup(map,"user")}"]
role_definition_name = "Contributor"
principal_id = [for map in module.user.map_object_ids[*]: lookup(map,"object_id")]
}
出现以下错误:
Error: Incorrect attribute value type
module.user.map_object_ids is tuple with 2 elements
Inappropriate value for attribute "scope": string required.
Inappropriate value for attribute "principal_id": string required.
资源 for_each
的一项基本要求是您正在使用的集合必须为每个要创建的实例包含一个元素,因此不可能基于多个值重复,但幸运的是我认为这实际上不是您在这里要问的。
相反,您似乎希望 module.user.map_object_ids
的每个元素都有一个实例,因此我们需要处理的唯一额外问题是 for_each
期望获得一张地图对象而不是对象列表,因此它可以使用映射键作为每个实例的标识符。
我们可以使用 for
expression 将对象列表转换为对象映射,但我们需要确定嵌套对象的一个属性,该属性将用作每个嵌套对象的唯一键元素。我将在这里使用 user
,因为它似乎是一个很好的人类可理解的、配置选择的唯一标识符:
resource "azurerm_role_assignment" "contribrg" {
for_each = { for obj in module.user.map_object_ids : obj.user => obj }
scope = "${data.azurerm_subscription.primary.id}/resourceGroups/${each.value.user}"
role_definition_name = "Contributor"
principal_id = each.value.object_id
}
上面的 for
表达式会将您的对象列表投影到对象映射中,如下所示:
{
"john" = {
"object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
"upn" = "john@domain.com"
"user" = "john"
}
"martin" = {
"object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
"upn" = "martin@domain.com"
"user" = "martin"
}
}
然后在资源参数表达式中 each.key
将引用用户名(因为它们现在是键)而 each.value
将引用对象,因此我们可以使用 each.value.object_id
得到对应的对象标识。
据此,Terraform 将计划创建具有以下地址的资源实例:
azurerm_role_assignment.contribrg["john"]
azurerm_role_assignment.contribrg["martin"]
旁注:我发现您的输出被命名为 object_ids
当它不只是返回 ID 时有点令人困惑。将其命名为 objects
.
可能更清楚
我有一个生成地图输出列表的 Terraform 模块:
object_ids = [
{
"object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
"upn" = "john@domain.com"
"user" = "john"
},
{
"object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
"upn" = "martin@domain.com"
"user" = "martin"
},
]
使用 for_each 我可以循环一个值来构建此资源:
resource "azurerm_role_assignment" "subread" {
for_each = toset(module.user.map_object_ids[*].object_id)
scope = data.azurerm_subscription.primary.id
role_definition_name = "Reader"
principal_id = each.value
}
但是我不知道如何循环多个值。
我对另一个需要 2 个不同输出值的资源尝试了以下操作:
resource "azurerm_role_assignment" "contribrg" {
scope = [for map in module.user.map_object_ids[*]: "${data.azurerm_subscription.primary.id}/resourceGroups/${lookup(map,"user")}"]
role_definition_name = "Contributor"
principal_id = [for map in module.user.map_object_ids[*]: lookup(map,"object_id")]
}
出现以下错误:
Error: Incorrect attribute value type
module.user.map_object_ids is tuple with 2 elements
Inappropriate value for attribute "scope": string required.
Inappropriate value for attribute "principal_id": string required.
资源 for_each
的一项基本要求是您正在使用的集合必须为每个要创建的实例包含一个元素,因此不可能基于多个值重复,但幸运的是我认为这实际上不是您在这里要问的。
相反,您似乎希望 module.user.map_object_ids
的每个元素都有一个实例,因此我们需要处理的唯一额外问题是 for_each
期望获得一张地图对象而不是对象列表,因此它可以使用映射键作为每个实例的标识符。
我们可以使用 for
expression 将对象列表转换为对象映射,但我们需要确定嵌套对象的一个属性,该属性将用作每个嵌套对象的唯一键元素。我将在这里使用 user
,因为它似乎是一个很好的人类可理解的、配置选择的唯一标识符:
resource "azurerm_role_assignment" "contribrg" {
for_each = { for obj in module.user.map_object_ids : obj.user => obj }
scope = "${data.azurerm_subscription.primary.id}/resourceGroups/${each.value.user}"
role_definition_name = "Contributor"
principal_id = each.value.object_id
}
上面的 for
表达式会将您的对象列表投影到对象映射中,如下所示:
{
"john" = {
"object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
"upn" = "john@domain.com"
"user" = "john"
}
"martin" = {
"object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
"upn" = "martin@domain.com"
"user" = "martin"
}
}
然后在资源参数表达式中 each.key
将引用用户名(因为它们现在是键)而 each.value
将引用对象,因此我们可以使用 each.value.object_id
得到对应的对象标识。
据此,Terraform 将计划创建具有以下地址的资源实例:
azurerm_role_assignment.contribrg["john"]
azurerm_role_assignment.contribrg["martin"]
旁注:我发现您的输出被命名为 object_ids
当它不只是返回 ID 时有点令人困惑。将其命名为 objects
.