我有一个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]
我无法理解实际错误是什么以及如何纠正它。
答案 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"
}
}
}
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
一起使用,以为每个资源组产生一个对象。