setproduct Function
Функция 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вычисляет объединение нескольких наборов.
Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.9/language/functions/setproduct/