本文へスキップ

setproduct関数

setproduct関数は、デカルト積を計算することにより、与えられたすべての集合の要素のすべての可能な組み合わせを見つけます。

コードブロック
setproduct(sets...)

この関数は、アプリケーションごと、環境ごとのリソースなど、複数の集合のメンバのすべての組み合わせの網羅的な集合を見つける際に特に役立ちます。

コードブロック
> setproduct(["development", "staging", "production"], ["app1", "app2"])
[
[
"development",
"app1",
],
[
"development",
"app2",
],
[
"staging",
"app1",
],
[
"staging",
"app2",
],
[
"production",
"app1",
],
[
"production",
"app2",
],
]

この関数には、少なくとも2つの引数を渡す必要があります。

主に集合用に定義されていますが、この関数はリストでも機能します。与えられたすべての引数がリストの場合、結果はリストになり、与えられたリストの順序が保持されます。それ以外の場合は、結果は集合になります。いずれの場合も、結果の要素型は、与えられた各引数に対応する値のリストです。

上記の関数の一般的使用方法の例を示します。手書きではあまり一般的ではありませんが、再利用可能なモジュールの状況で発生する可能性のある、その他の状況もあります。

引数のいずれかが空の場合、結果は常に空になります。これは、任意の数をゼロで掛けるとゼロになる方法に似ています。

コードブロック
> setproduct(["development", "staging", "production"], [])
[]

同様に、すべての引数が1つの要素しか持たない場合、結果は1つの要素しか持たず、それは各引数の最初の要素になります。

コードブロック
> setproduct(["a"], ["b"])
[
[
"a",
"b",
],
]

各引数は、そのすべての要素に対して一貫した型を持たなければなりません。そうでない場合、OpenTofuは最も一般的な型への変換を試行するか、そのような変換が不可能な場合はエラーを生成します。たとえば、文字列と数値の両方を混ぜると、結果の要素の型がすべて一貫するように、数値が文字列に変換されます。

コードブロック
> setproduct(["staging", "production"], ["a", 2])
[
[
"staging",
"a",
],
[
"staging",
"2",
],
[
"production",
"a",
],
[
"production",
"2",
],
]

for_eachのための組み合わせの検索

リソースfor_eachdynamicブロック言語機能の両方では、繰り返しごとに1つの要素を持つコレクション値が必要です。

入力データがfor_each引数で直接使用できない個別の値で提供される場合があり、setproductは、多数の異なるコレクション内の要素のすべての固有の組み合わせを見つけたい場合に役立つヘルパー関数になります。

たとえば、次のような変数を宣言するモジュールを考えてみましょう。

コードブロック
variable "networks" {
type = map(object({
base_cidr_block = string
}))
}

variable "subnets" {
type = map(object({
number = number
}))
}

目標が定義された各ネットワークごとに定義された各サブネットを作成することであれば、トップレベルのネットワークの作成は、結果のインスタンスがマップ要素と1対1で一致する形式であるため、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リストは、入力変数内のネットワークとサブネットの要素の組み合わせごとに1つのサブネットインスタンスを作成します。したがって、この例の入力では

コードブロック
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 は、階層化されたデータを単一のリストにフラット化するために役立ちます。これは、2つのオブジェクトタイプ間の関係が明示的に定義されている場合に便利です。
  • setintersection は、複数のセットの *積集合* を計算します。
  • setsubtract は、2つのセットの *相対補集合* を計算します。
  • setunion は、複数のセットの *和集合* を計算します。