slide

Terraform fot d merge()

Ned Bellavance
3 min read

Cover

This is part of an ongoing series of posts documenting the built-in interpolation functions in Terraform. For more information, check out the beginning post. In this post I am going to cover the merge() function. The example file is on GitHub here.

What is it?

Function name: merge(map1, map2, map3, …)

Returns: Takes one or more maps and merges them into a single map by performing a union operation. Duplicate keys are overwritten.

Example:

# Returns {m1k1:m1v1 m2k1:m2v1}
output "max_output" {
  value = "${merge(map("m1k1","m1v1"),map("m2k1","m2v1"))}"
}

Example file:

##############################################
# Function: merge
##############################################
##############################################
# Variables
##############################################
variable "map_1_value" {
  type = "map"

  default = {
    "m1k1"       = "m1v1"
    "m1k2"       = "m1v2"
    "m1k3"       = "m1v3"
  }
}

variable "map_2_value" {
  type = "map"

  default = {
    "m2k1"       = "m2v1"
    "m2k2"       = "m2v2"
    "m2k3"       = "m2v3"
  }
}

variable "empty_map" {
  type = "map"

  default = {}
}

variable "nested_map_1" {
  type = "map"

  default = {
    "n1m1" = {
      "n1m1k1" = "n1m1v1"
      "n1m1k2" = "n1m1v2"
      "n1m1k3" = "n1m1v3"
    }

    "n1m2" = {
      "n1m2k1" = "n1m2v1"
      "n1m2k2" = "n1m2v2"
      "n1m2k3" = "n1m2v3"
    }
  }
}

variable "nested_map_2" {
  type = "map"

  default = {
    "n2m1" = {
      "n2m1k1" = "n2m1v1"
      "n2m1k2" = "n2m1v2"
      "n2m1k3" = "n2m1v3"
    }

    "n2m2" = {
      "n2m2k1" = "n2m2v1"
      "n2m2k2" = "n2m2v2"
      "n2m2k3" = "n2m2v3"
    }
  }
}

##############################################
# Resources
##############################################

##############################################
# Outputs
##############################################

output "1_merge_basic" {
  value = "${merge(var.map_1_value,var.map_2_value)}"
}

output "2_merge_empty" {
  value = "${merge(var.map_1_value,var.empty_map)}"
}

output "3_merge_duplicates" {
  value = "${merge(var.map_1_value,var.map_2_value,map("m1k1","m1v1-alt"))}"
}

output "4_merge_nested" {
  value = "${merge(var.nested_map_1,var.nested_map_2)}"
}

output "5_merge_mixed" {
  value = "${merge(var.map_1_value,var.nested_map_2)}"
}

output "5_merge_mega" {
  value = "${merge(var.map_1_value,var.map_2_value,var.nested_map_1,var.nested_map_2)}"
}

output "6_merge_null" {
  value = "${merge(var.empty_map)}"
}

Run the following from the merge folder to get example output for a number of different cases:

#All examples are in variables
terraform apply

Why use it?

Makes sense that if you have maps from disparate sources and you want to merge them together that you would have a function to do that. I could see using this with tagging. Maybe you’ve got a set of standard tags and then some custom tags for a specific project. Both tag sets are stored in maps, so you use the merge function to stitch them together and apply to all the resources in the project. Now that I think about it, I’m pretty sure that is exactly what I used this for in the past. Huzzah!

Lessons Learned

I learned a couple of fun things. First, you can provide a single map value and the function will still run. Not that it has anything to do, but it won’t throw an error either. The function doesn’t care about nested maps. It just merges the top level keys and maintains the nested maps as values. The one important thing I learned is the order of overwrite for duplicate keys. If you have duplicate keys in your maps, the last map wins. In the example file above, I have a map with key m1k1 and value m1v1. I also have a map with key m1k1 and value m1v1-alt. Since the map with the m1v1-alt value is last in the merge order, that value is what ends up in the key m1k1. That could be hell to debug if you don’t know that’s how the function merges keys.

Coming up next is the min() function.