Terraform 0.12 嵌套 for 循环
Terraform 0.12 nested for loops
我正在尝试使用 Terraform 0.12 的新功能实现嵌套 for 循环,以便遍历 AWS IAM 用户,每个用户都可以附加一个或多个策略。用于表示此列表的变量是 map(list(string)) 类型,看起来像这样:
{
"user 1" = [ "policy1", "policy2" ],
"user 2" = [ "policy1" ]
}
通过 keys()
获取要创建的用户列表非常容易,但由于目前在 Terraform 中没有嵌套循环资源创建的机制,策略附件必须作为独立于每个循环的单个循环发生用户。因此,我试图根据上面的示例从地图输入构建一个 user:policy 关联列表,看起来像这样:
[
[ "user1", "policy1" ],
[ "user1", "policy2" ],
[ "user2", "policy1" ]
]
我正在尝试构建该列表并将其存储在局部变量中,其中 var.iam-user-policy-map
是输入映射:
locals {
...
association-list = [
for user in keys(var.iam-user-policy-map):
[
for policy in var.iam-user-policy-map[user]:
[user, policy]
]
]
...
}
但是,我在尝试访问该嵌套列表中的值时遇到错误。我正在尝试使用引用 local.association-list[count.index][0]
访问关联的用户部分,并使用 local.association-list[count.index][1]
访问策略,但是在 运行 terraform plan
上出错:
Error: Incorrect attribute value type
on main.tf line 27, in resource "aws_iam_user_policy_attachment" "test-attach":
27: user = local.association-list[count.index][0]
Inappropriate value for attribute "user": string required.
Error: Incorrect attribute value type
on main.tf line 27, in resource "aws_iam_user_policy_attachment" "test-attach":
27: user = local.association-list[count.index][0]
Inappropriate value for attribute "user": string required.
Error: Invalid index
on main.tf line 28, in resource "aws_iam_user_policy_attachment" "test-attach":
28: policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index][1]}"
|----------------
| count.index is 0
| local.association-list is tuple with 2 elements
The given key does not identify an element in this collection value.
Error: Invalid template interpolation value
on main.tf line 28, in resource "aws_iam_user_policy_attachment" "test-attach":
28: policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index][1]}"
|----------------
| count.index is 1
| local.association-list is tuple with 2 elements
Cannot include the given value in a string template: string required.
我做错了什么?
您的本地值 association-list
中的 for
表达式正在生成一个字符串列表列表的列表,但您对它的引用将其视为一个字符串列表列表。
要获得您想要的扁平化表示,您可以使用 flatten
函数,但因为它会将所有内容分组到一个 单个 扁平列表中,所以我建议使最里面的值成为一个对象。 (这也将使对它的引用更加清晰。)
locals {
association-list = flatten([
for user in keys(var.iam-user-policy-map) : [
for policy in var.iam-user-policy-map[user] : {
user = user
policy = policy
}
]
])
}
该表达式的结果将具有以下形状:
[
{ user = "user1", policy = "policy1" },
{ user = "user1", policy = "policy2" },
{ user = "user2", policy = "policy2" },
]
您对它的引用可以采用以下形式:
user = local.association-list[count.index].user
policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index].policy}"
如果您需要 'for_each' 的地图,'merge' 很方便。
variable "iam-user-policy-map" {
default = {
"user 1" = ["policy1", "policy2"],
"user 2" = ["policy1"]
}
}
locals {
association-map = merge([
for user, policies in var.iam-user-policy-map : {
for policy in policies :
"${user}-${policy}" => {
"user" = user
"policy" = policy
}
}
]...)
}
output "association-map" {
value = local.association-map
}
输出:
association-map = {
"user 1-policy1" = {
"policy" = "policy1"
"user" = "user 1"
}
"user 1-policy2" = {
"policy" = "policy2"
"user" = "user 1"
}
"user 2-policy1" = {
"policy" = "policy1"
"user" = "user 2"
}
}
示例 for_each 用法:
resource "null_resource" "echo" {
for_each = local.association-map
provisioner "local-exec" {
command = "echo 'policy - ${each.value.policy}, user - ${each.value.user}'"
}
}
https://github.com/hashicorp/terraform/issues/22263#issuecomment-969549347
我正在尝试使用 Terraform 0.12 的新功能实现嵌套 for 循环,以便遍历 AWS IAM 用户,每个用户都可以附加一个或多个策略。用于表示此列表的变量是 map(list(string)) 类型,看起来像这样:
{
"user 1" = [ "policy1", "policy2" ],
"user 2" = [ "policy1" ]
}
通过 keys()
获取要创建的用户列表非常容易,但由于目前在 Terraform 中没有嵌套循环资源创建的机制,策略附件必须作为独立于每个循环的单个循环发生用户。因此,我试图根据上面的示例从地图输入构建一个 user:policy 关联列表,看起来像这样:
[
[ "user1", "policy1" ],
[ "user1", "policy2" ],
[ "user2", "policy1" ]
]
我正在尝试构建该列表并将其存储在局部变量中,其中 var.iam-user-policy-map
是输入映射:
locals {
...
association-list = [
for user in keys(var.iam-user-policy-map):
[
for policy in var.iam-user-policy-map[user]:
[user, policy]
]
]
...
}
但是,我在尝试访问该嵌套列表中的值时遇到错误。我正在尝试使用引用 local.association-list[count.index][0]
访问关联的用户部分,并使用 local.association-list[count.index][1]
访问策略,但是在 运行 terraform plan
上出错:
Error: Incorrect attribute value type
on main.tf line 27, in resource "aws_iam_user_policy_attachment" "test-attach":
27: user = local.association-list[count.index][0]
Inappropriate value for attribute "user": string required.
Error: Incorrect attribute value type
on main.tf line 27, in resource "aws_iam_user_policy_attachment" "test-attach":
27: user = local.association-list[count.index][0]
Inappropriate value for attribute "user": string required.
Error: Invalid index
on main.tf line 28, in resource "aws_iam_user_policy_attachment" "test-attach":
28: policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index][1]}"
|----------------
| count.index is 0
| local.association-list is tuple with 2 elements
The given key does not identify an element in this collection value.
Error: Invalid template interpolation value
on main.tf line 28, in resource "aws_iam_user_policy_attachment" "test-attach":
28: policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index][1]}"
|----------------
| count.index is 1
| local.association-list is tuple with 2 elements
Cannot include the given value in a string template: string required.
我做错了什么?
您的本地值 association-list
中的 for
表达式正在生成一个字符串列表列表的列表,但您对它的引用将其视为一个字符串列表列表。
要获得您想要的扁平化表示,您可以使用 flatten
函数,但因为它会将所有内容分组到一个 单个 扁平列表中,所以我建议使最里面的值成为一个对象。 (这也将使对它的引用更加清晰。)
locals {
association-list = flatten([
for user in keys(var.iam-user-policy-map) : [
for policy in var.iam-user-policy-map[user] : {
user = user
policy = policy
}
]
])
}
该表达式的结果将具有以下形状:
[
{ user = "user1", policy = "policy1" },
{ user = "user1", policy = "policy2" },
{ user = "user2", policy = "policy2" },
]
您对它的引用可以采用以下形式:
user = local.association-list[count.index].user
policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index].policy}"
如果您需要 'for_each' 的地图,'merge' 很方便。
variable "iam-user-policy-map" {
default = {
"user 1" = ["policy1", "policy2"],
"user 2" = ["policy1"]
}
}
locals {
association-map = merge([
for user, policies in var.iam-user-policy-map : {
for policy in policies :
"${user}-${policy}" => {
"user" = user
"policy" = policy
}
}
]...)
}
output "association-map" {
value = local.association-map
}
输出:
association-map = {
"user 1-policy1" = {
"policy" = "policy1"
"user" = "user 1"
}
"user 1-policy2" = {
"policy" = "policy2"
"user" = "user 1"
}
"user 2-policy1" = {
"policy" = "policy1"
"user" = "user 2"
}
}
示例 for_each 用法:
resource "null_resource" "echo" {
for_each = local.association-map
provisioner "local-exec" {
command = "echo 'policy - ${each.value.policy}, user - ${each.value.user}'"
}
}
https://github.com/hashicorp/terraform/issues/22263#issuecomment-969549347