3

Consider I have a variable -

[
  {
    "outer_key_1" = [
      {
        "ip_cidr" = "172.16.6.0/24"
        "range_name" = "range1"
      },
      {
        "ip_cidr" = "172.16.7.0/24"
        "range_name" = "range2"
      },
      {
        "ip_cidr" = "172.17.6.0/24"
        "range_name" = "range3"
      },
      {
        "ip_cidr" = "172.17.7.0/24"
        "range_name" = "range4"
      },
    ]
  },
  {
    "outer_key_2" = [
      {
        "ip_cidr" = "172.16.5.0/24"
        "range_name" = "range5"
      },
      {
        "ip_cidr" = "172.17.5.0/24"
        "range_name" = "range6"
      },
    ]
  },
]

I am able to merge the maps inside the list to get this output -

{
    "outer_key_1" = [
      {
        "ip_cidr" = "172.16.6.0/24"
        "range_name" = "range1"
      },
      {
        "ip_cidr" = "172.16.7.0/24"
        "range_name" = "range2"
      },
      {
        "ip_cidr" = "172.17.6.0/24"
        "range_name" = "range3"
      },
      {
        "ip_cidr" = "172.17.7.0/24"
        "range_name" = "range4"
      },
    ]

    "outer_key_2" = [
      {
        "ip_cidr" = "172.16.5.0/24"
        "range_name" = "range5"
      },
      {
        "ip_cidr" = "172.17.5.0/24"
        "range_name" = "range6"
      },
    ]
}

I have done this using

result = merge(variable[0], variable[1])

But when I try this

result = merge(variable[*])

I get an error saying

Call to function "merge" failed: arguments must be maps or objects, got "tuple".

Why does merge fail when I use the splat operator? Is there a better way to merge maps in list as required above?

leoOrion
  • 1,833
  • 2
  • 26
  • 52

1 Answers1

10

The merge function is defined to take one or more separate arguments that are each map or object values. When you call merge(variable) (which is the same as merge(variable[*]) if variable is already a list) you're instead giving it one list argument, leading to this error.

To pass the elements of a list or tuple as multiple individual arguments, you can use argument expansion syntax:

result = merge(variable...)

The ... symbol, when given after the last argument in a function call, tells Terraform to evaluate the expression as a list or tuple before calling the function, and then use the elements in that result a separate argument each.

In other words, merge(variable...) is the same as merge(variable[0], variable[1], variable[2]) etc for each element in the list, without needing to know ahead of time how many elements are in the list.


Applying the splat operator [*] to a value that is already a list is redundant; the splat operator is useful in this situation only when it's followed by at least one additional attribute name or index, like example[*].id or example[*][0].

There is one situation where a lonely [*] with no following steps can be useful: if you apply it to anything that isn't a list or tuple then Terraform will either wrap it in a single-element list (if it's non-null) or return an empty list (if it's null), which can be useful in some unusual cases where you're given a single value that might be null and need to adapt it into a zero-or-one length list to use with features like resource for_each and in dynamic blocks.

Martin Atkins
  • 62,420
  • 8
  • 120
  • 138
  • 2
    Thanks. But with `...` I get this error - `The expanding argument (indicated by ...) must be of a tuple, list, or set type.` – leoOrion Aug 09 '19 at 03:23