在 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}"
}