Terraform 如何输出使用计数创建的对象 ID

Terraform how to output object id that were created using count

我有一个创建 2 个子网的 terraform 模块。 我需要以某种方式获取每个子网的输出。当使用 [count.index] 作为输出块的一部分时,出现无法使用计数的错误。

那么解决方案应该是什么,因为我需要将 ec2 关联到特定子网。

module "private_subnet" {
     source = "./modules/private_subnet"
     vpc_id = module.vpc.vpcid
     number_of_subnets = 2
     private-subnet-block = var.private-subnet-block
     tag_enviroment= var.tag_enviroment
     project_name = var.project_name }



 resource "aws_subnet" "private_subnet" {
        count = var.number_of_subnets
        cidr_block = var.private-subnet-block[count.index]
        availability_zone = var.availability_zone[count.index]
        vpc_id = var.vpc_id   
        map_public_ip_on_launch = false
        tags = {
        Name = "${var.project_name}-private-subnet-${count.index+1}"
        env = var.tag_enviroment   } }

output "privatesubnetid"{
    value = aws_subnet.private_subnet[count.index].id }

错误信息:

Error: Reference to "count" in non-counted context │ │ on modules/private_subnet/output.tf line 2, in output "privatesubnetid": │ 2: value = aws_subnet.private_subnet[count.index].id │ │ The "count" object can only be used in "module", "resource", and "data" blocks, and only when the "count" argument is set

这可以帮助你:

output "database_subnets" {
  description = "IDs of database subnets"
  value       = aws_subnet.database.*.id
}

output "database_subnet_group" {
  description = "ID of database subnet group"
  value       = concat(aws_db_subnet_group.database.*.id, [""])[0]
}

您可以使用 Terraform splat 表达式 [1]:

output "privatesubnetid" {
    value = aws_subnet.private_subnet[*].id 
}

[1] https://www.terraform.io/language/expressions/splat

为了在此处继续,您需要决定在没有该子网实例的情况下要在该输出值中放置什么值。


最直接的答案是 return 所有 ID 的列表,如果有 none:

,那么它将是一个空列表
output "private_subnet_ids" {
  value = aws_subnet.private_subnet[*].id
}

这里的[*]the splat operator,简明的说法是取左边列表的每个元素的.id属性来构造一个列表[*],即 aws_subnet.private_subnet -- 该资源的所有实例的列表 -- 在您的例子中。


另一种选择是 return 从可用区名称到子网 ID 的映射,以防您的模块的调用者出于某种原因需要能够区分不同的 ID:

output "private_subnet_ids" {
  value = tomap({
    for s in aws_subnet.private_subnet : s.availability_zone => s.id
  })
}

这是一个 for expression,这可能是我们之前看到的 splat 表达式的更一般形式:它将生成一个映射,其中 aws_subnet.private_subnet s 的每个元素生成键为 s.availability_zone 且值为 s.id.

的映射元素

与前面的示例类似,如果没有任何子网,这将生成一个空映射。


另一个可能最接近您在问题中给出的示例的选项是 return 仅 第一个 子网或 return null 如果有零个子网:

output "private_subnet_id" {
  value = length(aws_subnet.private_subnet) > 0 ? aws_subnet.private_subnet[0] : null
}

这是一个 conditional expression,它根据第三个布尔表达式 (length(aws_subnet.private_subnet) > 0).

这似乎不是一个特别有用的选项,因为它将无法访问后续子网。我包含它只是因为在您的示例中您使用了单数名称“私有子网 ID”而不是复数名称“私有子网 ID”,所以我想知道您是否打算以某种方式 select 只是其中一个子网 ID。


这里还有很多其他排列。一般的答案是 aws_subnet.private_subnet 是一个对象列表,因此您可以编写任何在处理对象列表时有效的 Terraform 表达式,以任何对您想要生成的结果有意义的方式转换该列表。但是,您必须编写对任意数量的子网(包括零个子网)都有效的表达式,以确保该模块适用于 number_of_subnets.

的所有值

要输出使用计数创建的资源 ID,请按以下步骤操作:

output "private_subnet_ids" {
  value = one(aws_subnet.private_subnet[*].id)
}

上面的表达式首先使用 splat operator 将对象列表转换为仅包含 id 值的列表,根据资源计数,该列表也将包含零个或一个元素。

one函数然后处理两种情况:

  • 如果列表只有一个值,它将return那个值。
  • 如果列表没有值,它将 return null 表示没有值。

Refernce