How to get an object from a list of objects in Terraform?

Viewed 78798

I have the following list of objects variable:

variable "objects" {
  type = "list"
  description = "list of objects
  default = [
      {
        id = "name1"
        attribute = "a"
      },
      {
        id = "name2"
        attribute = "a,b"
      },
      {
        id = "name3"
        attribute = "d"
      }
  ]
}

How do I get element with id = "name2" ?

3 Answers

You get the map with id="name2" with the following expression:

var.objects[index(var.objects.*.id, "name2")]

For a quick test, run the following one-liner in terraform console:

[{id = "name1", attribute = "a"}, {id = "name2", attribute = "a,b"}, {id = "name3", attribute = "d"}][index([{id = "name1", attribute = "a"}, {id = "name2", attribute = "a,b"}, {id = "name3", attribute = "d"}].*.id, "name2")]

You can't nested multiple levels of square brackets to get n levels inside a data structure. However you can use the interpolation functions to retrieve such values. In this case you'll want to use the lookup function to retrieve the value from the map which itself has been accessed with square brackets, that will look like this...

${lookup(var.objects[1], "id")}

Rowan is correct, complex data structures are difficult to work with in current versions of Terraform. However it looks like it won't be too long before we can expect better support in this area. The upcoming version 0.12 will include rich types adding improvements to lists and maps.

If you're looking to create a set of vsphere_virtual_machine resources from a list of IPs and hostnames, I might try this:

resource "vsphere_virtual_machine" "vm" {
  count = "${length(var.virtual_machine_ips)}"

  // the rest of your virtual machine config
  // such as template ID, CPUs, memory, disks...

  vapp {
    properties {
      // your vApp properties may vary based on what your template actually is.
      // these examples are for the CoreOS template.

      "guestinfo.hostname" = "${index(var.virtual_machine_hostnames, count.index)}"
      "guestinfo.interface.0.ip.0.address" = "${index(var.virtual_machine_ips, count.index)}"
    }
  }
}

(This is assuming that you are setting IP and hostname via vApp config; if not then it may look similar but put the hostname and IP addresses somewhere outside the vsphere_virtual_machine.vapp.properties block.)

Where the terraform.tfvars file might look like this:

virtual_machine_ips = ["10.0.2.2", "10.0.2.3", "10.0.2.4"]
virtual_machine_hostnames = ["banana", "pineapple", "coconut"]

This is a simpler and more idiomatic way of accomplishing what you're trying to do, since working with complex objects in Terraform interpolation syntax is not easy.

Related