从 terraform 中的嵌套地图按程序生成单项地图
Produce single item maps procedurally from nested map in terraform
我有一个按 OU 划分的帐户名称和 ID 的嵌套映射变量,例如:
variable "aws_accounts" {
type = map(map(any))
default = {
first_ou = {
first_account = "111111111"
second_account = "222222222"
}
second_ou = {
third_account = "333333333"
fourth_account = "444444444"
}
}
}
这非常适合将 account_name 的映射作为子变量传递给 account_id 以供您执行操作,并且所讨论的模块被构造为接受映射输入。
我还想渲染一个本地,这样我也可以引用单个帐户,但可以为它们获取映射值,而无需维护单独的变量列表,例如
local.first_account = {
first_account = "111111111"
}
local.second_account = {
second_account = "222222222"
}
local.third_account = {
third_account = "33333333"
}
等等
我尝试了各种技术但没有成功:
我不知道如何迭代地引用数组中的每个映射 - 大多数文档似乎都是基于列表的,当我尝试执行 for_each
时,我得到
The "each" object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set.
可能不是您要找的东西,但可能会有所帮助:
locals {
accounts = merge(var.aws_accounts["first_ou"], var.aws_accounts["second_ou"])
}
如果您需要以更动态的方式执行此操作:
locals {
accounts = zipmap(
flatten([for item in var.aws_accounts : keys(item)]),
flatten([for item in var.aws_accounts : values(item)])
)
}
现在您可以使用 local.accounts["first_account"]
等访问每个帐户
根据你的例子,你似乎想把你的两级映射变成一个单级映射,其中键是账户名,“OU 名称”只是被丢弃。
这是实现该目标的一种方法:
locals {
account_ids = merge(values(var.aws_accounts)...)
}
这首先使用 values
从顶级地图中获取值,生成地图列表。
然后它使用 merge
从每个地图中获取所有元素并将它们组合成一个新地图。我使用 ...
符号告诉 Terraform 它应该将列表中的每个元素视为 merge
的单独参数,而不是将整个列表作为单个参数传递。
将它们合并在一起后,您可能会再次将它们分开,使用 for
表达式分别创建一个单独的地图。
locals {
account_maps = tomap({
for k, id in local.account_ids :
k => { (k) = id }
})
}
好的 所以在 Martin Atkins and Bryan Heden 的帮助下我找到了这个问题的答案。它不是很漂亮,但确实有效:
variable "aws_accounts" {
type = map(map(any))
default = {
first_ou = {
first_account = "111111111"
second_account = "222222222"
}
second_ou = {
third_account = "333333333"
fourth_account = "444444444"
}
}
}
locals {
# gives single map from nested map
account_ids = merge(values(var.aws_accounts)...)
# gives separate structured map for each key
single_accounts_maps = {
for account, id in local.account_ids :
account => {
account = account
id = id
}
}
# gives map where values = keys plus values
single_accounts_maps_joined = zipmap(
flatten([for item in var.aws_accounts : keys(item)]),
[for item in local.single_accounts_maps :
join(" = ", values(item))]
)
# gives nested map by key = {key = "value"}
single_accounts_maps_keys_values = {
for item in local.single_accounts_maps_joined :
(split(" = ", item)[0]) => {
(split(" = ", item)[0]) = (split(" = ", item)[1])
}
}
}
我想要的输出:
terraform console
> local.single_accounts_maps_keys_values
{
"first_account" = {
"first_account" = "111111111"
}
"fourth_account" = {
"fourth_account" = "444444444"
}
"second_account" = {
"second_account" = "222222222"
}
"third_account" = {
"third_account" = "333333333"
}
}
在与 Martin Atkins 的讨论和他随后在下面进行的编辑之后,我建议他的答案更简单、更清晰、更优雅,尽管 tomap()
嵌套似乎是不必要的,即做
locals {
account_ids = merge(values(var.aws_accounts)...)
account_maps = {
for k, id in local.account_ids :
k => { (k) = id }
}
}
我有一个按 OU 划分的帐户名称和 ID 的嵌套映射变量,例如:
variable "aws_accounts" {
type = map(map(any))
default = {
first_ou = {
first_account = "111111111"
second_account = "222222222"
}
second_ou = {
third_account = "333333333"
fourth_account = "444444444"
}
}
}
这非常适合将 account_name 的映射作为子变量传递给 account_id 以供您执行操作,并且所讨论的模块被构造为接受映射输入。
我还想渲染一个本地,这样我也可以引用单个帐户,但可以为它们获取映射值,而无需维护单独的变量列表,例如
local.first_account = {
first_account = "111111111"
}
local.second_account = {
second_account = "222222222"
}
local.third_account = {
third_account = "33333333"
}
等等
我尝试了各种技术但没有成功:
我不知道如何迭代地引用数组中的每个映射 - 大多数文档似乎都是基于列表的,当我尝试执行 for_each
时,我得到
The "each" object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set.
可能不是您要找的东西,但可能会有所帮助:
locals {
accounts = merge(var.aws_accounts["first_ou"], var.aws_accounts["second_ou"])
}
如果您需要以更动态的方式执行此操作:
locals {
accounts = zipmap(
flatten([for item in var.aws_accounts : keys(item)]),
flatten([for item in var.aws_accounts : values(item)])
)
}
现在您可以使用 local.accounts["first_account"]
等访问每个帐户
根据你的例子,你似乎想把你的两级映射变成一个单级映射,其中键是账户名,“OU 名称”只是被丢弃。
这是实现该目标的一种方法:
locals {
account_ids = merge(values(var.aws_accounts)...)
}
这首先使用 values
从顶级地图中获取值,生成地图列表。
然后它使用 merge
从每个地图中获取所有元素并将它们组合成一个新地图。我使用 ...
符号告诉 Terraform 它应该将列表中的每个元素视为 merge
的单独参数,而不是将整个列表作为单个参数传递。
将它们合并在一起后,您可能会再次将它们分开,使用 for
表达式分别创建一个单独的地图。
locals {
account_maps = tomap({
for k, id in local.account_ids :
k => { (k) = id }
})
}
好的 所以在 Martin Atkins and Bryan Heden 的帮助下我找到了这个问题的答案。它不是很漂亮,但确实有效:
variable "aws_accounts" {
type = map(map(any))
default = {
first_ou = {
first_account = "111111111"
second_account = "222222222"
}
second_ou = {
third_account = "333333333"
fourth_account = "444444444"
}
}
}
locals {
# gives single map from nested map
account_ids = merge(values(var.aws_accounts)...)
# gives separate structured map for each key
single_accounts_maps = {
for account, id in local.account_ids :
account => {
account = account
id = id
}
}
# gives map where values = keys plus values
single_accounts_maps_joined = zipmap(
flatten([for item in var.aws_accounts : keys(item)]),
[for item in local.single_accounts_maps :
join(" = ", values(item))]
)
# gives nested map by key = {key = "value"}
single_accounts_maps_keys_values = {
for item in local.single_accounts_maps_joined :
(split(" = ", item)[0]) => {
(split(" = ", item)[0]) = (split(" = ", item)[1])
}
}
}
我想要的输出:
terraform console
> local.single_accounts_maps_keys_values
{
"first_account" = {
"first_account" = "111111111"
}
"fourth_account" = {
"fourth_account" = "444444444"
}
"second_account" = {
"second_account" = "222222222"
}
"third_account" = {
"third_account" = "333333333"
}
}
在与 Martin Atkins 的讨论和他随后在下面进行的编辑之后,我建议他的答案更简单、更清晰、更优雅,尽管 tomap()
嵌套似乎是不必要的,即做
locals {
account_ids = merge(values(var.aws_accounts)...)
account_maps = {
for k, id in local.account_ids :
k => { (k) = id }
}
}