github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/website/docs/configuration/functions/setproduct.html.md (about)

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