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.id
或 vpc_id = aws_vpc.vpc_two.id
。使用数据源可能有助于循环(即使用 for_each
或 count
)其他类型的资源(您希望在所有 vpc 中创建)以上是关于Terraform:如何从数据类型中获取元素的主要内容,如果未能解决你的问题,请参考以下文章
如何使用布尔类型获取 DataMemberAttribute
从 API Gateway 获取 terraform 中 AWS lambda 的端点