在Terraform 0.12-concat()中连接两个列表
我想在Terraform 0.12中连接两个数组。在我的示例中,有公共子网和私有子网。我想将它们都分配到相同的网络访问列表。以下代码缩短:在Terraform 0.12-concat()中连接两个列表,terraform,Terraform,我想在Terraform 0.12中连接两个数组。在我的示例中,有公共子网和私有子网。我想将它们都分配到相同的网络访问列表。以下代码缩短: data "aws_subnet_ids" "private" { vpc_id = aws_vpc.main.id tags = { subnet-type = "private" } } data "aws_subnet_ids" "public" { vpc_id = aws_vpc.main.id
data "aws_subnet_ids" "private" {
vpc_id = aws_vpc.main.id
tags = {
subnet-type = "private"
}
}
data "aws_subnet_ids" "public" {
vpc_id = aws_vpc.main.id
tags = {
subnet-type = "public"
}
}
resource "aws_network_acl" "networks" {
vpc_id = aws_vpc.main.id
subnet_ids = concat(data.aws_subnet_ids.private.ids, data.aws_subnet_ids.public.ids)
[...]
}
如果我使用以下输出:
output "private_subnets" {
value = data.aws_subnet_ids.private.ids
}
output "public_subnets" {
value = data.aws_subnet_ids.public.ids
}
生成以下输出:
private_subnets = [
"subnet-243zr427rhhfjseb9",
"subnet-we789rh2438fchb6e",
"subnet-092rz7g82fhhkui74",
]
public_subnets = [
"subnet-12230qegvg764e9d",
"subnet-123465svgvgf0d7e",
]
因此,一切都应该起作用。但给出了以下错误:
iptizer@machine:~/src/infra$ terraform12 apply
[...]
Error: Invalid function argument
on nacls.tf line 19, in resource "aws_network_acl" "networks":
19: subnet_ids = concat(data.aws_subnet_ids.private.ids, data.aws_subnet_ids.public.ids)
|----------------
| data.aws_subnet_ids.private.ids is set of string with 3 elements
Invalid value for "seqs" parameter: all arguments must be lists or tuples; got
set of string.
臭虫。。或者我遗漏了什么?在terraform providers/terraform provider aws问题中已经有类似的问题报告 同时也提到了同样的解决方法。对于您的场景,您可以像下面这样解决问题 在1点左右工作 在2点左右工作
Terraform 0.12比0.11对列表值和设置值进行了更强的区分,并包含了一些类似这样的附加检查 在这种特殊情况下,concat以这种方式失败,因为串联要求所有元素都具有定义良好的顺序,这样结果也可以具有定义良好的顺序。集合未排序,因此此检查用于提醒您在转换为列表时显式选择合适的排序,或者根本不转换为列表 在这种特殊情况下,排序似乎并不特别重要,因此由实现的词汇排序就足够了:
subnet_ids = concat(
sort(data.aws_subnet_ids.private.ids),
sort(data.aws_subnet_ids.public.ids),
)
因为从字符串列表集到字符串列表的转换也会施加词法顺序,所以这在功能上等同于字符串列表。我通常更喜欢这里的排序,因为这是未来读者的一个线索,结果将按词汇顺序排列
另一种选择是在集合的世界中说,并使用:
由于这两个列表之间不应存在重复项,因此此处使用哪种方法并不重要,但为了完整性,我将注意,如果这两个集合都包含相同的子网id,setunion操作将对其进行重复,因为每个唯一值在一个集合中只能出现零次或一次
在我写这篇文章时,count仍然是为集合中的每个项创建一个资源实例的主要方式,因此通常需要最终转换为列表,以便各个实例可以具有所需的顺序,在这样的情况下,使用集合而不是列表会有好处:
resource "aws_instance" "per_subnet_example" {
# resource-level for_each is not implemented at the time of writing,
# but planned for a future release.
for_each = setunion(
data.aws_subnet_ids.private.ids,
data.aws_subnet_ids.public.ids,
)
# ...
}
在集合上使用for_each而不是count时,Terraform将通过集合中的值而不是连续索引来标识每个实例,因此此资源中的一个实例可能具有地址aws_instance。每个子网_示例[subnet-abc123],这意味着,当元素从该集合中添加和删除时,Terraform只需创建/销毁相应的单个实例,而不必在有序序列发生更改后重新创建所有内容
Terraform提供商在有意义的地方使用这样的集合,以便在每个模式到达后更易于使用,但不幸的是,这意味着我们需要同时编写一些额外的显式类型转换,以明确我们正在以类似于序列的方式而不是类似于集合的方式处理这些值。这看起来像Terraform core中一个有趣的bug,concat只对列表而不是集合有效。除了类型检查之外,我看不出它不能在集合而不是列表上工作的明显原因,但是你可能想提出这个问题,因为它确实非常奇怪。当您深入研究这个问题时,您可以尝试将结果转换为列表。
subnet_ids = concat(
sort(data.aws_subnet_ids.private.ids),
sort(data.aws_subnet_ids.public.ids),
)
subnet_ids = setunion(
data.aws_subnet_ids.private.ids,
data.aws_subnet_ids.public.ids,
)
resource "aws_instance" "per_subnet_example" {
# resource-level for_each is not implemented at the time of writing,
# but planned for a future release.
for_each = setunion(
data.aws_subnet_ids.private.ids,
data.aws_subnet_ids.public.ids,
)
# ...
}