Azure terraform报告缺少资源实例密钥

时间:2019-11-12 01:53:43

标签: terraform terraform-provider-azure

我有一个Terraform 模块,如下所示

main.tf

resource "azurerm_resource_group" "test1"{
    count    = "${length(var.azurerm_resource_group_name)}"
    name     = "${element(var.azurerm_resource_group_name, count.index)}"
    location = "${element(var.azurerm_resource_group_location, count.index)}"
}

我已如下定义 output.tf

output "resource_gp" {
    value = "${azurerm_resource_group.test1[count.index]}"
}

对于同一模块, variables.tf 如下:

variable "azurerm_resource_group_name" {
    type = "list"
    default = ["SimpleMoon-Terra"]
}
variable "azurerm_resource_group_location" {
    type = "list"
    default = ["Central US"]
}

按如下所示调用模块:

variable "azurerm_resource_group" {

    default={
    name     = "simpletestrg"
    location = "Central US"
    }
}

# Create Resource Group
module "Test_Resource_Groups" {
    source ="../../Modules/Test_Resource_Groups"
    #name                ="${var.azurerm_resource_group.name}"
    #location            ="${var.azurerm_resource_group.location}"
}

但是,出现如下错误:

Error: Missing resource instance key

  on ../../Modules/Test_Resource_Groups/output.tf line 2, in output "resource_gp":
   2:     value = "${azurerm_resource_group.test1.name[count.index]}"

Because azurerm_resource_group.test1 has "count" set, its attributes must be
accessed on specific instances.

For example, to correlate with indices of a referring resource, use:
    azurerm_resource_group.test1[count.index]

我无法理解实际错误是什么以及如何纠正它。

1 个答案:

答案 0 :(得分:1)

错误消息中显示的源代码片段与您为outputs.tf共享的源代码不同:

    value = "${azurerm_resource_group.test1.name[count.index]}" # in the error message
    value = "${azurerm_resource_group.test1[count.index]}"      # in the given source code

这里有一些问题,其中一个仅在错误消息中显示的源代码中出现:

  • 由于azurerm_resource_group.test1设置了count,因此它在表达式中显示为对象列表。因此,对其执行的第一个操作必须是索引操作,并给出类似azurerm_resource_group.test1[count.index].name的表达式:采用name列表的count.index元素的azurerm_resource_group.test1属性。
  • 您不能在输出值表达式内使用count.index,因为该范围内没有count自变量来知道要使用什么count.index值。如果您的目标是返回所有资源组的所有名称的列表,则可以将其写为azurerm_resource_group.test1[*].name,即splat expression

在这种特殊情况下,output "resource_gp"的值将始终与var.azurerm_resource_group_name的值相同,因为名称是从那里填充的。但是,通过资源进行这种引用很有用,因为它告诉Terraform引用该输出值的任何内容都必须依赖于azurerm_resource_group.test1,从而有助于确保所有操作都会以适当的顺序应用。


有一种不同的方式来编写您在此处编写的内容,该方法在初次创建时会达到类似的结果,但对于随后对var.azurerm_resource_group_name进行的更改也会更好。

首先,我们将变量定义为对象映射,以便只能使用单个变量来指定资源组。

variable "azurerm_resource_groups" {
  type = map(object({
    location = string
  }))
  default = {
    SimpleMoon-Terra = {
      location = "Central US"
    }
  }
}

然后在定义资源组时可以使用for_each代替count

resource "azurerm_resource_group" "test1"{
  for_each = var.azurerm_resource_groups

  name     = each.key
  location = each.value.location
}

这不仅使表达式更简单,而且还具有另一个重要的作用:Terraform将使用地址azurerm_resource_group.test1["SimpleMoon-Terra"]而不是azurerm_resource_group.test1[0]来标识资源组,因此在{{ 1}} Terraform可以跟踪哪个远程资源组对象属于地图的哪个元素。

var.azurerm_resource_groups还会使for_each在表达式中作为地图而不是列表出现,因此我们需要更改输出azurerm_resource_group.test1来使用它。因为映射键是资源组名称,所以我们可以使用the keys function来获取它们。我们还将使用toset将其转换为集合,以反映它们没有任何特定的顺序,因此具有此值的用户不应依赖于该顺序:

value

您的调用模块随后可以像下面的示例一样调用此模块:

output "resource_group_names" {
  value = toset(keys(azurerm_resource_group.test1))
}

在该调用模块中,对module "test_resource_groups" { source = "../../Modules/Test_Resource_Groups" azurerm_resource_groups = { simpletestrg = { location = "Central US" } } } 的引用将产生一组资源组名称,然后可以将其与配置中其他位置的module.test_resource_groups.resource_group_names一起使用,以为每个资源组产生一个对象。