Terraform:如何从数据类型中获取元素

Posted

技术标签:

【中文标题】Terraform:如何从数据类型中获取元素【英文标题】:Terraform: how to get elements from a data type 【发布时间】:2020-09-28 12:56:54 【问题描述】:

我对 terraform 有一个不寻常的问题。

我创建了两个 VPC,并在同一个 terraform 脚本中添加了一个私有托管区域。

我执行以下操作: data "aws_vpcs" "foo" 这让我获得了在该地区创建的 VPC。

通常我可以输出 VPC 的 ID,例如:

output "test" 
  value = data.aws_vpcs.foo.ids

这给了我一个类似的列表:

[ “vpc-0c8446a2164b7d0af”, “vpc-0e7c63c3f383d115d”, ]

现在,我想从此列表中获取第一个 VPC id:“vpc-0c8446a2164b7d0af”

问题是它不起作用。 我尝试使用元素函数,如: element(data.aws_vpcs.foo.ids, 0) element([data.aws_vpcs.foo.ids], 0)

我也尝试将其分配给如下值:data.aws_vpcs.foo.ids[0]

它不起作用,我在 terraform 上找不到任何其他选项来帮助我解决这个问题。

我想使用第一个 VPC id 创建资源:

resource "aws_route53_zone" "private" 
 name = "example.com"

 vpc 
   vpc_id = data.aws_vpcs.foo.ids[0]
   

所以我可以从我在该地区获得的 VPC 列表中获得第一个 VPC(顺序无关紧要)。

当我运行 terraform plan 时出现错误:

Error: Invalid index

 on main.tf line 25, in resource "aws_route53_zone" "private":
 25:     vpc_id = data.aws_vpcs.foo.ids[0]

This value does not have any indices.

【问题讨论】:

当你说它不起作用时你得到什么错误?您能否编辑您的问题以显示 aws_vpcs 数据源的 Terraform 代码? 您应该编辑您的问题以包含错误,而不是在评论中发布。 【参考方案1】:

Terraform 区分 list 值和 set 值,其中 set 类似于 the mathematical idea of a set,它是值的无序集合,您可以询问特定元素是否为存在于集合中,并且您可以枚举集合中的所有元素,但没有索引或键可以用来查找单个项目。

aws_vpcs 数据源返回一组字符串,因为 AWS 中的 VPC 没有固有的排序:您不能在不强加自己的排序标准的情况下使用一对 VPC 来决定哪个是“第一”。

但是,如果您没有任何特定的排序标准并且只想获取 任何一个返回的 VPC,则可以使用 sort 函数来指示 Terraform 应该对 VPC 进行排序id 字符串lexically,然后将生成一个列表,您可以获取以下第一个元素:

resource "aws_route53_zone" "private" 
  name = "example.com"

  vpc 
    vpc_id = sort(data.aws_vpcs.foo.ids)[0]
  

请注意,尽管这实际上只是从集合中任意选择一项,因此只要列表永不更改,结果将是一致的,但是如果将新项目添加到列表中,则最终可能会选择不同的元素它恰好排在它之前选择的那个之前。

因此,在使用数据源检索 VPC 时,我们通常希望使用 aws_vpc 数据源检索特定的单个 VPC,使用足够具体的查询,它只会返回我们需要的单个 VPC。在此模型下,如果结果不完全一致,Terraform 将返回错误,这通常比隐式做出错误选择更可取。

【讨论】:

现在我很困惑。我同意输出是一个集合是有意义的,但是在文档terraform.io/docs/providers/aws/d/vpcs.html 中它说返回了一个列表,甚至还提供了一个使用索引访问输出的示例。这个文档有错吗? 是的,该文档似乎确实不正确。看起来它是为 Terraform 0.11 编写的,其中 element 函数可以将集合隐式转换为列表;本质上,它自动调用了sort,使得结果看起来像是一个有序列表,即使它实际上只是选择了一个任意元素。【参考方案2】:

element 不起作用,因为 vpc id list 不是一个列表,而是一组字符串。因此,以下内容不起作用。否则这个命令没有问题。

 "$element(data.aws_vpcs.foo.ids, 0)"

但是,我找到了另一种方法来使元素脱离使用排序。但同样,它是排序的。如果您对任何 vpc id 都满意,那么应该没问题。

我还是更喜欢 Falk 的建议,因为您尝试在同一脚本中提取 vpc id,因此您可以直接访问 vpc 然后获取 id。

作为一个练习,我将脚本放在下面以多种方式访问​​ id。快乐的脚本!

resource "aws_vpc" "vpc1" 
  cidr_block = "10.20.0.0/16"
  tags = 
    name = "tf_vpc"
  


resource "aws_vpc" "vpc2" 
  cidr_block = "10.30.0.0/16"
  tags = 
    name = "tf_vpc_2"
  



data "aws_vpcs" foo

output "test" 
  value = "$data.aws_vpcs.foo.ids"

output "test1" 
  value = "$aws_vpc.vpc1.id"


output "test2" 
  value = "$aws_vpc.vpc2.id"


output "counter" 
  value = "$length(data.aws_vpcs.foo.ids)"




output "myvpcID" 
  value = sort(data.aws_vpcs.foo.ids)[0]

【讨论】:

【参考方案3】:

如果您在同一脚本中使用 terraform 创建了 VPC,则不需要数据提供程序。相反,您应该直接从资源中访问 id。请参阅this answer 了解类似情况以及有关如何解决此问题的更多详细信息。

【讨论】:

这是正确的 - 您可能应该直接引用 vpc 资源:vpc_id = aws_vpc.vpc_one.idvpc_id = aws_vpc.vpc_two.id。使用数据源可能有助于循环(即使用 for_eachcount)其他类型的资源(您希望在所有 vpc 中创建)

以上是关于Terraform:如何从数据类型中获取元素的主要内容,如果未能解决你的问题,请参考以下文章

Terraform:从对象列表中检索值

如何使用布尔类型获取 DataMemberAttribute

从 API Gateway 获取 terraform 中 AWS lambda 的端点

如何在 terraform 中获取 k8s 作业的输出

从 Spark 数据框列中 ArrayType 类型的行中获取不同的元素

python中数据类型