【问题标题】:Terraform: how to get elements from a data typeTerraform:如何从数据类型中获取元素
【发布时间】: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 代码?
  • 您应该编辑您的问题以包含错误,而不是在评论中发布。

标签: terraform terraform-provider-aws


【解决方案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 中创建)
    猜你喜欢
    • 1970-01-01
    • 2015-03-19
    • 2013-02-15
    • 2012-06-17
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 2015-09-06
    相关资源
    最近更新 更多