- OpenTofu 语言
- 函数
- setproduct
setproduct
函数
setproduct
函数通过计算 笛卡尔积,查找所有给定集合中元素的所有可能组合。
setproduct(sets...)
此函数对于查找多个集合成员的所有组合的穷举集合特别有用,例如每个应用程序每个环境的资源。
> setproduct(["development", "staging", "production"], ["app1", "app2"])
[
[
"development",
"app1",
],
[
"development",
"app2",
],
[
"staging",
"app1",
],
[
"staging",
"app2",
],
[
"production",
"app1",
],
[
"production",
"app2",
],
]
您必须至少向此函数传递两个参数。
虽然主要为集合定义,但此函数也可以与列表一起使用。如果所有给定的参数都是列表,则结果为列表,保留给定列表的顺序。否则,结果为集合。在这两种情况下,结果的元素类型都是一个值列表,依次对应于每个给定的参数。
示例
上面有一个此函数常用用法示例。在手动编写时,还有一些不太常见的情况,但可能在可重用模块中出现。
如果任何参数为空,则结果始终为空,类似于将任何数字乘以零得到零。
> setproduct(["development", "staging", "production"], [])
[]
类似地,如果所有参数都只有一个元素,则结果只有一个元素,它是每个参数的第一个元素。
> setproduct(["a"], ["b"])
[
[
"a",
"b",
],
]
每个参数必须对其所有元素具有一致的类型。如果不是,OpenTofu 将尝试转换为最通用的类型,或者如果无法进行此类转换,则产生错误。例如,混合字符串和数字会导致数字转换为字符串,以便结果元素都具有相同的类型。
> setproduct(["staging", "production"], ["a", 2])
[
[
"staging",
"a",
],
[
"staging",
"2",
],
[
"production",
"a",
],
[
"production",
"2",
],
]
为 for_each
查找组合
资源 for_each
和 dynamic
块 语言特性都要求一个集合值,该值对每个重复都有一个元素。
有时您的输入数据以单独的值形式出现,不能直接在 for_each
参数中使用,而 setproduct
可以作为一种有用的辅助函数,用于您希望查找多个不同集合中元素的所有唯一组合的情况。
例如,考虑一个声明如下变量的模块
variable "networks" {
type = map(object({
base_cidr_block = string
}))
}
variable "subnets" {
type = map(object({
number = number
}))
}
如果目标是为每个定义的网络创建每个定义的子网,则创建顶级网络可以直接使用 var.networks
,因为它已经处于结果实例与映射元素一一匹配的形式。
resource "aws_vpc" "example" {
for_each = var.networks
cidr_block = each.value.base_cidr_block
}
但是,要使用单个 resource
块声明所有子网,您必须首先生成一个集合,其元素表示网络和子网的所有组合,以便每个元素本身表示一个子网。
locals {
# setproduct works with sets and lists, but the variables are both maps
# so convert them first.
networks = [
for key, network in var.networks : {
key = key
cidr_block = network.cidr_block
}
]
subnets = [
for key, subnet in var.subnets : {
key = key
number = subnet.number
}
]
network_subnets = [
# in pair, element zero is a network and element one is a subnet,
# in all unique combinations.
for pair in setproduct(local.networks, local.subnets) : {
network_key = pair[0].key
subnet_key = pair[1].key
network_id = aws_vpc.example[pair[0].key].id
# The cidr_block is derived from the corresponding network. Refer to the
# cidrsubnet function for more information on how this calculation works.
cidr_block = cidrsubnet(pair[0].cidr_block, 4, pair[1].number)
}
]
}
resource "aws_subnet" "example" {
# local.network_subnets is a list, so project it into a map
# where each key is unique. Combine the network and subnet keys to
# produce a single unique key per instance.
for_each = {
for subnet in local.network_subnets : "${subnet.network_key}.${subnet.subnet_key}" => subnet
}
vpc_id = each.value.network_id
availability_zone = each.value.subnet_key
cidr_block = each.value.cidr_block
}
上面示例中的 network_subnets
列表为输入变量中网络和子网元素的每个组合创建一个子网实例。因此,对于此示例输入
networks = {
a = {
base_cidr_block = "10.1.0.0/16"
}
b = {
base_cidr_block = "10.2.0.0/16"
}
}
subnets = {
a = {
number = 1
}
b = {
number = 2
}
c = {
number = 3
}
}
network_subnets
输出将类似于以下内容:
[
{
"cidr_block" = "10.1.16.0/20"
"network_id" = "vpc-0bfb00ca6173ea5aa"
"network_key" = "a"
"subnet_key" = "a"
},
{
"cidr_block" = "10.1.32.0/20"
"network_id" = "vpc-0bfb00ca6173ea5aa"
"network_key" = "a"
"subnet_key" = "b"
},
{
"cidr_block" = "10.1.48.0/20"
"network_id" = "vpc-0bfb00ca6173ea5aa"
"network_key" = "a"
"subnet_key" = "c"
},
{
"cidr_block" = "10.2.16.0/20"
"network_id" = "vpc-0d193e011f6211a7d"
"network_key" = "b"
"subnet_key" = "a"
},
{
"cidr_block" = "10.2.32.0/20"
"network_id" = "vpc-0d193e011f6211a7d"
"network_key" = "b"
"subnet_key" = "b"
},
{
"cidr_block" = "10.2.48.0/20"
"network_id" = "vpc-0d193e011f6211a7d"
"network_key" = "b"
"subnet_key" = "c"
},
]
相关函数
contains
测试给定的列表或集合是否包含给定的元素值。flatten
用于将分层数据展平为单个列表,用于两种对象类型之间的关系明确定义的情况。setintersection
计算多个集合的交集。setsubtract
计算两个集合的相对补集。setunion
计算多个集合的并集。