github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/website/docs/language/functions/setproduct.html.md (about)

     1  ---
     2  layout: "language"
     3  page_title: "setproduct - Functions - Configuration Language"
     4  sidebar_current: "docs-funcs-collection-setproduct"
     5  description: |-
     6    The setproduct function finds all of the possible combinations of elements
     7    from all of the given sets by computing the cartesian product.
     8  ---
     9  
    10  # `setproduct` Function
    11  
    12  The `setproduct` function finds all of the possible combinations of elements
    13  from all of the given sets by computing the
    14  [Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product).
    15  
    16  ```hcl
    17  setproduct(sets...)
    18  ```
    19  
    20  This function is particularly useful for finding the exhaustive set of all
    21  combinations of members of multiple sets, such as per-application-per-environment
    22  resources.
    23  
    24  ```
    25  > setproduct(["development", "staging", "production"], ["app1", "app2"])
    26  [
    27    [
    28      "development",
    29      "app1",
    30    ],
    31    [
    32      "development",
    33      "app2",
    34    ],
    35    [
    36      "staging",
    37      "app1",
    38    ],
    39    [
    40      "staging",
    41      "app2",
    42    ],
    43    [
    44      "production",
    45      "app1",
    46    ],
    47    [
    48      "production",
    49      "app2",
    50    ],
    51  ]
    52  ```
    53  
    54  You must pass at least two arguments to this function.
    55  
    56  Although defined primarily for sets, this function can also work with lists.
    57  If all of the given arguments are lists then the result is a list, preserving
    58  the ordering of the given lists. Otherwise the result is a set. In either case,
    59  the result's element type is a list of values corresponding to each given
    60  argument in turn.
    61  
    62  ## Examples
    63  
    64  There is an example of the common usage of this function above. There are some
    65  other situations that are less common when hand-writing but may arise in
    66  reusable module situations.
    67  
    68  If any of the arguments is empty then the result is always empty itself,
    69  similar to how multiplying any number by zero gives zero:
    70  
    71  ```
    72  > setproduct(["development", "staging", "production"], [])
    73  []
    74  ```
    75  
    76  Similarly, if all of the arguments have only one element then the result has
    77  only one element, which is the first element of each argument:
    78  
    79  ```
    80  > setproduct(["a"], ["b"])
    81  [
    82    [
    83      "a",
    84      "b",
    85    ],
    86  ]
    87  ```
    88  
    89  Each argument must have a consistent type for all of its elements. If not,
    90  Terraform will attempt to convert to the most general type, or produce an
    91  error if such a conversion is impossible. For example, mixing both strings and
    92  numbers results in the numbers being converted to strings so that the result
    93  elements all have a consistent type:
    94  
    95  ```
    96  > setproduct(["staging", "production"], ["a", 2])
    97  [
    98    [
    99      "staging",
   100      "a",
   101    ],
   102    [
   103      "staging",
   104      "2",
   105    ],
   106    [
   107      "production",
   108      "a",
   109    ],
   110    [
   111      "production",
   112      "2",
   113    ],
   114  ]
   115  ```
   116  
   117  ## Finding combinations for `for_each`
   118  
   119  The
   120  [resource `for_each`](/docs/language/meta-arguments/for_each.html)
   121  and
   122  [`dynamic` block](/docs/language/expressions/dynamic-blocks.html)
   123  language features both require a collection value that has one element for
   124  each repetition.
   125  
   126  Sometimes your input data comes in separate values that cannot be directly
   127  used in a `for_each` argument, and `setproduct` can be a useful helper function
   128  for the situation where you want to find all unique combinations of elements in
   129  a number of different collections.
   130  
   131  For example, consider a module that declares variables like the following:
   132  
   133  ```hcl
   134  variable "networks" {
   135    type = map(object({
   136      base_cidr_block = string
   137    }))
   138  }
   139  
   140  variable "subnets" {
   141    type = map(object({
   142      number = number
   143    }))
   144  }
   145  ```
   146  
   147  If the goal is to create each of the defined subnets per each of the defined networks, creating the top-level networks can directly use `var.networks` because it is already in a form where the resulting instances match one-to-one with map elements:
   148  
   149  ```hcl
   150  resource "aws_vpc" "example" {
   151    for_each = var.networks
   152  
   153    cidr_block = each.value.base_cidr_block
   154  }
   155  ```
   156  
   157  However, to declare all of the _subnets_ with a single `resource` block, you must first produce a collection whose elements represent all of the combinations of networks and subnets, so that each element itself represents a subnet:
   158  
   159  ```hcl
   160  locals {
   161    # setproduct works with sets and lists, but the variables are both maps
   162    # so convert them first.
   163    networks = [
   164      for key, network in var.networks : {
   165        key        = key
   166        cidr_block = network.cidr_block
   167      }
   168    ]
   169    subnets = [
   170      for key, subnet in var.subnets : {
   171        key    = key
   172        number = subnet.number
   173      }
   174    ]
   175  
   176    network_subnets = [
   177      # in pair, element zero is a network and element one is a subnet,
   178      # in all unique combinations.
   179      for pair in setproduct(local.networks, local.subnets) : {
   180        network_key = pair[0].key
   181        subnet_key  = pair[1].key
   182        network_id  = aws_vpc.example[pair[0].key].id
   183  
   184        # The cidr_block is derived from the corresponding network. Refer to the
   185        # cidrsubnet function for more information on how this calculation works.
   186        cidr_block = cidrsubnet(pair[0].cidr_block, 4, pair[1].number)
   187      }
   188    ]
   189  }
   190  
   191  resource "aws_subnet" "example" {
   192    # local.network_subnets is a list, so project it into a map
   193    # where each key is unique. Combine the network and subnet keys to
   194    # produce a single unique key per instance.
   195    for_each = {
   196      for subnet in local.network_subnets : "${subnet.network_key}.${subnet.subnet_key}" => subnet
   197    }
   198  
   199    vpc_id            = each.value.network_id
   200    availability_zone = each.value.subnet_key
   201    cidr_block        = each.value.cidr_block
   202  }
   203  ```
   204  
   205  The `network_subnets` list in the example above creates one subnet instance per combination of network and subnet elements in the input variables. So for this example input:
   206  
   207  ```hcl
   208  networks = {
   209    a = {
   210      base_cidr_block = "10.1.0.0/16"
   211    }
   212    b = {
   213      base_cidr_block = "10.2.0.0/16"
   214    }
   215  }
   216  subnets = {
   217    a = {
   218      number = 1
   219    }
   220    b = {
   221      number = 2
   222    }
   223    c = {
   224      number = 3
   225    }
   226  }
   227  ```
   228  
   229  The `nework_subnets` output would look similar to the following:
   230  
   231  ```hcl
   232  [
   233    {
   234      "cidr_block" = "10.1.16.0/20"
   235      "network_id" = "vpc-0bfb00ca6173ea5aa"
   236      "network_key" = "a"
   237      "subnet_key" = "a"
   238    },
   239    {
   240      "cidr_block" = "10.1.32.0/20"
   241      "network_id" = "vpc-0bfb00ca6173ea5aa"
   242      "network_key" = "a"
   243      "subnet_key" = "b"
   244    },
   245    {
   246      "cidr_block" = "10.1.48.0/20"
   247      "network_id" = "vpc-0bfb00ca6173ea5aa"
   248      "network_key" = "a"
   249      "subnet_key" = "c"
   250    },
   251    {
   252      "cidr_block" = "10.2.16.0/20"
   253      "network_id" = "vpc-0d193e011f6211a7d"
   254      "network_key" = "b"
   255      "subnet_key" = "a"
   256    },
   257    {
   258      "cidr_block" = "10.2.32.0/20"
   259      "network_id" = "vpc-0d193e011f6211a7d"
   260      "network_key" = "b"
   261      "subnet_key" = "b"
   262    },
   263    {
   264      "cidr_block" = "10.2.48.0/20"
   265      "network_id" = "vpc-0d193e011f6211a7d"
   266      "network_key" = "b"
   267      "subnet_key" = "c"
   268    },
   269  ]
   270  ```
   271  
   272  ## Related Functions
   273  
   274  - [`contains`](./contains.html) tests whether a given list or set contains
   275    a given element value.
   276  - [`flatten`](./flatten.html) is useful for flattening hierarchical data
   277    into a single list, for situations where the relationships between two
   278    object types are defined explicitly.
   279  - [`setintersection`](./setintersection.html) computes the _intersection_ of
   280    multiple sets.
   281  - [`setsubtract`](./setsubtract.html) computes the _relative complement_ of two sets
   282  - [`setunion`](./setunion.html) computes the _union_ of multiple
   283    sets.