在 terraform 中使用嵌套变量的正确方法
proper way to use nested variables in terraform
在我的 terraform 脚本中,我有
resource "azuread_application" "main" {
count = "${length(var.sp_names)}"
name = "${sp_prefix}-${var.sp_names[count.index]}"
available_to_other_tenants = false
}
resource "azuread_service_principal" "main" {
count = "${length(var.sp_names)}"
application_id = "${azuread_application.main.["${sp_prefix}"-"${var.sp_names[count.index]}"].application_id}"
}
当我 运行 terraform init
我得到以下错误:
An attribute name is required after a dot.
使用嵌套变量和列表对象的正确方法是什么?
为了将资源表示为实例映射而不是实例列表,您需要使用 for_each
instead of count
:
resource "azuread_application" "main" {
for_each = { for n in var.sp_names : n => "${var.sp_prefix}-${n}" }
name = each.value
available_to_other_tenants = false
}
上面的 for_each
表达式是一个 for
expression,它将您的列表或名称集转换为从给定名称到前缀名称的映射。因此,在该块的其他表达式中,each.key
将生成原始给定名称,而 each.value
将生成前缀名称。
然后您可以类似地使用 for_each
来声明意图 "create one service principal per application",方法是将应用程序资源的映射本身用作服务主体资源的 for_each
表达式:
resource "azuread_service_principal" "main" {
for_each = azuread_application.main
application_id = each.value.application_id
}
在这种情况下,azuread_application.main
值是从无前缀名称到表示每个已声明应用程序的对象的映射。因此 this 块中的 each.key
再次是无前缀名称,但 each.value
是相应的应用程序对象,我们可以从中访问 application_id
值。
如果您的 var.sp_names
中有一个字符串 "example"
,那么 Terraform 会将上述内容解释为创建两个名为 azuread_application.main["example"]
和 azuread_service_principal.main["example"]
的对象的请求,标识这些实例由 var.sp_names
值。这与 count
不同,其中实例的地址如 azuread_application.main[0]
和 azuread_service_principal.main[0]
。通过使用 for_each
,我们确保在 var.sp_names
中添加和删除项目将从这些资源中添加和删除相应的实例,而不是更新碰巧共享相同数字索引的现有实例。
我假设您使用的是 0.12.x 之前的版本。如果不是,Martin 的回答是最好的。
你需要利用 splatting。
resource "azuread_service_principal" "main" {
count = "${length(var.sp_names)}"
application_id = "${azuread_application.main.*.application_id}"
}
在我的 terraform 脚本中,我有
resource "azuread_application" "main" {
count = "${length(var.sp_names)}"
name = "${sp_prefix}-${var.sp_names[count.index]}"
available_to_other_tenants = false
}
resource "azuread_service_principal" "main" {
count = "${length(var.sp_names)}"
application_id = "${azuread_application.main.["${sp_prefix}"-"${var.sp_names[count.index]}"].application_id}"
}
当我 运行 terraform init
我得到以下错误:
An attribute name is required after a dot.
使用嵌套变量和列表对象的正确方法是什么?
为了将资源表示为实例映射而不是实例列表,您需要使用 for_each
instead of count
:
resource "azuread_application" "main" {
for_each = { for n in var.sp_names : n => "${var.sp_prefix}-${n}" }
name = each.value
available_to_other_tenants = false
}
上面的 for_each
表达式是一个 for
expression,它将您的列表或名称集转换为从给定名称到前缀名称的映射。因此,在该块的其他表达式中,each.key
将生成原始给定名称,而 each.value
将生成前缀名称。
然后您可以类似地使用 for_each
来声明意图 "create one service principal per application",方法是将应用程序资源的映射本身用作服务主体资源的 for_each
表达式:
resource "azuread_service_principal" "main" {
for_each = azuread_application.main
application_id = each.value.application_id
}
在这种情况下,azuread_application.main
值是从无前缀名称到表示每个已声明应用程序的对象的映射。因此 this 块中的 each.key
再次是无前缀名称,但 each.value
是相应的应用程序对象,我们可以从中访问 application_id
值。
如果您的 var.sp_names
中有一个字符串 "example"
,那么 Terraform 会将上述内容解释为创建两个名为 azuread_application.main["example"]
和 azuread_service_principal.main["example"]
的对象的请求,标识这些实例由 var.sp_names
值。这与 count
不同,其中实例的地址如 azuread_application.main[0]
和 azuread_service_principal.main[0]
。通过使用 for_each
,我们确保在 var.sp_names
中添加和删除项目将从这些资源中添加和删除相应的实例,而不是更新碰巧共享相同数字索引的现有实例。
我假设您使用的是 0.12.x 之前的版本。如果不是,Martin 的回答是最好的。
你需要利用 splatting。
resource "azuread_service_principal" "main" {
count = "${length(var.sp_names)}"
application_id = "${azuread_application.main.*.application_id}"
}