我有一个aws_route
资源,我想用新路由更新列表中的所有路由表。以下是相关代码:
resource "aws_route" "private_route" {
for_each = data.aws_route_tables.private_route_tables.ids
route_table_id = each.key
destination_cidr_block = var.tgw_destination_cidr_block
transit_gateway_id = module.tgw.ec2_transit_gateway_id
}
当变量tgw_destination_cidr_block
中定义了一个CIDR时,上面的代码可以正常工作,因为aws_route
需要destination_cidr_block
属性的字符串类型。
tgw_destination_cidr_block = "10.255.160.0/20"
现在我想在这个变量中添加多个CIDR范围,并遍历它。
tgw_destination_cidr_block = ["10.255.160.0/20", "10.255.176.0/22"]
,以便在每个路由表中创建两条新路由。所以,我想我需要变量中的字符串列表,并迭代CIDR范围列表。
知道如何做到这一点吗?
在考虑for_each
表达式时,我总是首先考虑可能结束句子的内容"为每个…声明一个实例",在这种情况下,句子似乎是:
为每对私有路由表和目的CIDR块声明一个实例
这告诉我们,我们需要一个集合,其中每个元素代表这些对中的一个。
查找多个项目集的所有组合的常用方法是setproduct
函数,其文档中有一节查找for_each
的组合,该节显示了为许多不同的基本网络声明系统子网集的工作示例。
我们可以把那个例子应用到你的问题下面。文档中的示例已经完成了一个小步骤,所以为了简单起见,我将在这里将所有的局部值表达式合并为一个:
locals {
route_table_routes = [
for pair in setproduct(data.aws_route_tables.private_route_tables.ids, var.tgw_destination_cidr_blocks) : {
route_table_id = pair[0]
destination_cidr_block = pair[1]
}
]
}
resource "aws_route" "private_route" {
for_each = {
for rtr in local.route_table_routes : "${rtr.route_table_id}:${rtr.destination_cidr_block}" => rtr
}
route_table_id = each.value.route_table_id
destination_cidr_block = each.value.destination_cidr_block
transit_gateway_id = module.tgw.ec2_transit_gateway_id
}
上面将声明aws_route.private_route
实例,其密钥是路由表ID和目的CIDR块的组合。
请注意,使用远程系统分配的id作为Terraform中实例密钥的一部分可能会有问题,因为Terraform需要在整个计划和应用过程中完全知道这些实例密钥。但是,在您的情况下,您正在使用数据源检索这些路由表id,因此只要在规划期间可以完全了解您的数据资源配置本身,它们就会在规划期间被知道。
通常我建议使用相同的配置来负责声明路由表和这些路由,从而能够给每个路由表一个完全由配置知道的静态键(根本不是由远程系统决定的),但这种设计在分解系统中并不总是实用的。所以你在这里做的事情可以是好的,只要你注意确保你以正确的顺序将更改应用到你单独的Terraform配置中,以便更改将按照你想要的方式级联,即使Terraform无法看到整个依赖结构,因此不能保证顺序本身。