for_each 循环中的引用计数资源
Reference count resources within a for_each loop
我目前正在尝试利用 for_each 函数创建 aws_route 资源,并将这些路由与使用计数函数构建的许多 aws_route_table 资源相关联。我想知道是否有办法让我仍然在 aws_route 资源中使用 for_each 函数并引用 aws_route_table 资源。
我的最终目标是创建 ~5 条路由并将其应用到 ~7 条路由表。
这是我的代码供参考:
resource "aws_route_table" "private" {
vpc_id = aws_vpc.vpc.id
count = length(split(",", var.private_subnets))
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = join(",", aws_nat_gateway.nat.*.id)
}
route {
cidr_block = var.stage_vpc_cidr
vpc_peering_connection_id = var.stage_peering_connection_id
}
route {
cidr_block = var.production_vpc_cidr
vpc_peering_connection_id = var.production_peering_connection_id
}
tags = {
Name = "${var.name}-private.${element(split(",", var.azs), count.index)}"
Department = var.tag_department
Lifecycle = var.tag_lifecycle
Account = var.tag_account
Application = var.tag_application
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_route" "vpn-route" {
for_each = toset(var.vpn_subnets)
route_table_id = element(aws_route_table.private.*.id, count.index)
gateway_id = var.vpn_gateway_id
destination_cidr_block = each.value
}
和我的变量
variable "vpn_subnets" {
type = list
default = ["192.168.0.0/24","192.168.2.0/24","192.168.4.0/24","192.168.5.0/24","192.168.10.0/24","192.168.253.0/24"]
}
听起来您的要求是每个路由 table 实例和 var.vpn_subnets
元素的组合都有一个 aws_route
实例。
查找两个集合的所有元素组合的操作称为笛卡尔积,Terraform 有setproduct
function 来计算它。
locals {
route_table_vpn_subnets = [
for pair in setproduct(aws_route_table.private, var.vpn_subnets) : {
route_table_name = pair[0].tags.Name
route_table_id = pair[0].id
destination_cidr_block = pair[1]
}
]
}
这是将 setproduct
与 for
expression 结合使用来生成一系列对象,这些对象描述了路由 table ID 和目标 CIDR 块的所有组合,如下所示:
[
{
route_table_name = "example-private.0"
route_table_id = "rtb-12323453"
destination_cidr_block = "192.168.0.0/24"
},
{
route_table_name = "example-private.0"
route_table_id = "rtb-12323453"
destination_cidr_block = "192.168.2.0/24"
},
# ...
{
route_table_name = "example-private.1"
route_table_id = "rtb-abcd"
destination_cidr_block = "192.168.0.0/24"
},
{
route_table_name = "example-private.1"
route_table_id = "rtb-abcd"
destination_cidr_block = "192.168.2.0/24"
},
# ...
]
此数据结构现在满足 for_each
的两个关键要求:
我们要创建的每个实例都有一个此集合的元素。
每个对象都有一组属性,这些属性可以一起作为一个唯一标识符,该标识符由在配置中决定的值构建,而不是由 决定的值远程系统。
在这种情况下,通过包含 route_table_name
和 route_table_id
来实现,因为名称由您的配置选择,而 id 由远程系统选择,因此 id 不会被 suitable 用作实例标识符。
要在 for_each
中使用它,我们只需要再执行一个步骤,将其投影到地图中,其中那些唯一的属性值被组合成唯一的字符串键:
resource "aws_route" "vpn" {
for_each = {
for obj in local.route_table_vpn_subnets :
"${obj.route_table_name}:${obj.destination_cidr_block}" => obj
}
route_table_id = each.value.route_table_id
gateway_id = var.vpn_gateway_id
destination_cidr_block = each.value.destination_cidr_block
}
这里的for
表达式中的关键表达式告诉Terraform分配这些实例地址如下,这应该满足在所有实例中唯一的要求:
aws_route.vpn["example-private.0:192.168.0.0/24"]
aws_route.vpn["example-private.0:192.168.0.2/24"]
...
aws_route.vpn["example-private.1:192.168.0.0/24"]
aws_route.vpn["example-private.1:192.168.0.2/24"]
...
请注意,因为您在路线 table 中使用数字索引,所以如果您更改 var.private_subnets
拆分中的元素数量,则可能会导致路线 tables 重新编号。因为数字是名称的一部分,而名称是每个路由实例的唯一键的一部分,这也会导致路由实例重新编号,我提到这一点只是因为使用 for_each
的典型原因是为了避免那种重新编号。
您可能会采用不同的设计来描述您的路线 tables 使用满足我上面描述的 for_each
的两个标准的对象集合,因此路线 table 实例也可以使用 for_each
和有意义的唯一键来声明,但这将是一个非常重要的变化,超出了你所要求的范围,所以我不会在这里详细介绍。
我目前正在尝试利用 for_each 函数创建 aws_route 资源,并将这些路由与使用计数函数构建的许多 aws_route_table 资源相关联。我想知道是否有办法让我仍然在 aws_route 资源中使用 for_each 函数并引用 aws_route_table 资源。
我的最终目标是创建 ~5 条路由并将其应用到 ~7 条路由表。
这是我的代码供参考:
resource "aws_route_table" "private" {
vpc_id = aws_vpc.vpc.id
count = length(split(",", var.private_subnets))
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = join(",", aws_nat_gateway.nat.*.id)
}
route {
cidr_block = var.stage_vpc_cidr
vpc_peering_connection_id = var.stage_peering_connection_id
}
route {
cidr_block = var.production_vpc_cidr
vpc_peering_connection_id = var.production_peering_connection_id
}
tags = {
Name = "${var.name}-private.${element(split(",", var.azs), count.index)}"
Department = var.tag_department
Lifecycle = var.tag_lifecycle
Account = var.tag_account
Application = var.tag_application
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_route" "vpn-route" {
for_each = toset(var.vpn_subnets)
route_table_id = element(aws_route_table.private.*.id, count.index)
gateway_id = var.vpn_gateway_id
destination_cidr_block = each.value
}
和我的变量
variable "vpn_subnets" {
type = list
default = ["192.168.0.0/24","192.168.2.0/24","192.168.4.0/24","192.168.5.0/24","192.168.10.0/24","192.168.253.0/24"]
}
听起来您的要求是每个路由 table 实例和 var.vpn_subnets
元素的组合都有一个 aws_route
实例。
查找两个集合的所有元素组合的操作称为笛卡尔积,Terraform 有setproduct
function 来计算它。
locals {
route_table_vpn_subnets = [
for pair in setproduct(aws_route_table.private, var.vpn_subnets) : {
route_table_name = pair[0].tags.Name
route_table_id = pair[0].id
destination_cidr_block = pair[1]
}
]
}
这是将 setproduct
与 for
expression 结合使用来生成一系列对象,这些对象描述了路由 table ID 和目标 CIDR 块的所有组合,如下所示:
[
{
route_table_name = "example-private.0"
route_table_id = "rtb-12323453"
destination_cidr_block = "192.168.0.0/24"
},
{
route_table_name = "example-private.0"
route_table_id = "rtb-12323453"
destination_cidr_block = "192.168.2.0/24"
},
# ...
{
route_table_name = "example-private.1"
route_table_id = "rtb-abcd"
destination_cidr_block = "192.168.0.0/24"
},
{
route_table_name = "example-private.1"
route_table_id = "rtb-abcd"
destination_cidr_block = "192.168.2.0/24"
},
# ...
]
此数据结构现在满足 for_each
的两个关键要求:
我们要创建的每个实例都有一个此集合的元素。
每个对象都有一组属性,这些属性可以一起作为一个唯一标识符,该标识符由在配置中决定的值构建,而不是由 决定的值远程系统。
在这种情况下,通过包含
route_table_name
和route_table_id
来实现,因为名称由您的配置选择,而 id 由远程系统选择,因此 id 不会被 suitable 用作实例标识符。
要在 for_each
中使用它,我们只需要再执行一个步骤,将其投影到地图中,其中那些唯一的属性值被组合成唯一的字符串键:
resource "aws_route" "vpn" {
for_each = {
for obj in local.route_table_vpn_subnets :
"${obj.route_table_name}:${obj.destination_cidr_block}" => obj
}
route_table_id = each.value.route_table_id
gateway_id = var.vpn_gateway_id
destination_cidr_block = each.value.destination_cidr_block
}
这里的for
表达式中的关键表达式告诉Terraform分配这些实例地址如下,这应该满足在所有实例中唯一的要求:
aws_route.vpn["example-private.0:192.168.0.0/24"]
aws_route.vpn["example-private.0:192.168.0.2/24"]
...
aws_route.vpn["example-private.1:192.168.0.0/24"]
aws_route.vpn["example-private.1:192.168.0.2/24"]
...
请注意,因为您在路线 table 中使用数字索引,所以如果您更改 var.private_subnets
拆分中的元素数量,则可能会导致路线 tables 重新编号。因为数字是名称的一部分,而名称是每个路由实例的唯一键的一部分,这也会导致路由实例重新编号,我提到这一点只是因为使用 for_each
的典型原因是为了避免那种重新编号。
您可能会采用不同的设计来描述您的路线 tables 使用满足我上面描述的 for_each
的两个标准的对象集合,因此路线 table 实例也可以使用 for_each
和有意义的唯一键来声明,但这将是一个非常重要的变化,超出了你所要求的范围,所以我不会在这里详细介绍。