klappi
klappi

Reputation: 23

Creating a restructured map from list of maps

I'm coming with a problem I cannot solve for a few days now. I have a data structure defining data disks, consisting of a list of maps per disk:

variable "data_disks_node" {
  description = "Data disk configuration lun, size in gib, mountpoint"
  default = [
    {
      lun = 0
      size = 200
      mount = "/opt/mount1"
    },
    {
      lun = 1
      size = 32
      mount = "/opt/mount2"
    },
  ]
}

I am using this structure to create data disks using a dynamic block and for_each (which is working great) but need to create a map of tags with values sourced from the same data structure.

I need to tag created resources with their configured data disks and mount points (don't ask, cant change that requirement) and need the following map result:

data_disk_tags = {
  lun0 = "/opt/mount1"
  lun1 = "/opt/mount2"
}

so not only do I need to create a map from the list of maps but also need to filter results, map one value as key and another value as value, and also need to prefix the new key with a string "lun". I'm at my wits end with this as I only worked here and there with Terraform and am unable to find any documented cases where this issue was solved. Terraform used is 0.12.20 if it matters. The closest (and it's not even close) that I came so far is this:

locals {
  vm_joined_tags = merge(var.vm_tags, zipmap(flatten([for item in var.vm_data_disk_configuration : keys(item)]), flatten([for item in var.vm_data_disk_configuration : values(item)])))
}

which works but creates a map of only the first sourced map and key values like

{
  lun = 1
  size = 200
  mount = "/opt/mount1"
}

with the second map not even present. I'm very grateful for any help or pointers towards a possible solution. Changing the data structure is possible but should be avoided if possible since other module code relies on it. Ff any further input is needed tell me and I will provide.

Upvotes: 2

Views: 4229

Answers (1)

ydaetskcoR
ydaetskcoR

Reputation: 56987

You look like you were on the right path with trying to loop over the list but there's a simpler way to get that:

variable "data_disks_node" {
  description = "Data disk configuration lun, size in gib, mountpoint"
  default = [
    {
      lun   = 0
      size  = 200
      mount = "/opt/mount1"
    },
    {
      lun   = 1
      size  = 32
      mount = "/opt/mount2"
    },
  ]
}

locals {
  vm_joined_tags = { for disk in var.data_disks_node : format("lun%s", disk.lun) => disk.mount }
}

output "vm_joined_tags" {
  value = local.vm_joined_tags
}

Applying this outputs your desired structure:

Outputs:

vm_joined_tags = {
  "lun0" = "/opt/mount1"
  "lun1" = "/opt/mount2"
}

Putting braces around the for expression means that it creates a map (it shares a similar syntax to Python's dictionary comprehensions):

The type of brackets around the for expression decide what type of result it produces. The above example uses [ and ], which produces a tuple. If { and } are used instead, the result is an object, and two result expressions must be provided separated by the => symbol:

{for s in var.list : s => upper(s)}

So then the above example loops over the disks in var.data_disks_node and creates a map with a key with the lun of each disk, prefixed with the string "lun" and a value of the mount of each disk.

Upvotes: 3

Related Questions