Spec-Zone.ru › OpenTofu 1.10

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.10/language/functions/setproduct/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API