sage
sage

Reputation: 33

Nested Map data in Terraform

Let's say I have an string type variable called "env" (the value can be "dev" or "production")

With the following data, how can I get the value of setting1 for the first element in "dev" or "production"?

locals{
   environments = {
      dev = {
         "hello001" = {
            setting1 = "abc"
            setting2 = "def"
            setting3 = "ghi"
         }
         "hello002" = {
            setting1 = "jkl"
            setting2 = "mno"
            setting3 = "pqr"
         }
      }
      production = {
         "hello003" = {
            setting1 = "abc"
            setting2 = "def"
            setting3 = "ghi"
         }
         "hello004" = {
            setting1 = "jkl"
            setting2 = "mno"
            setting3 = "pqr"
         }
      }
   }
}

I tried with

local.environments[var.env][0].setting1

but getting the error "This value does not have any indices"

Upvotes: 3

Views: 6307

Answers (1)

Grzegorz Oledzki
Grzegorz Oledzki

Reputation: 24291

First of all the error message I get is slightly different:

│ Error: Invalid index
[...]
│ The given key does not identify an element in this collection value. An object only supports looking up attributes by name, not by numeric index.

but I guess that's because of a different Terraform version. I have 1.0.7.

Explanation / context

Nevertheless, the problem is exactly as mentioned by Matt in the comment - maps in Terraform HCL don't support integer-indexing. I.e. you cannot do a [0] on a map. Some programming languages offer that possibility, Terraform does not.

See:

locals {
 my_dictionary = {
   "one" = 1
   "two" = 2
 }
}

If I try local.someMapping[0] it fails with the same error.

Way out

It depends on how you want to access your hello001, hello002s, etc.

Either change the most-inner map to a list, e.g.

locals{
   environments = {
      dev = [
         {
            setting1 = "abc"
            setting2 = "def"
            setting3 = "ghi"
         },
         {
            setting1 = "jkl"
            setting2 = "mno"
            setting3 = "pqr"
         }
      ]
      production = [
         {
            setting1 = "abc"
            setting2 = "def"
            setting3 = "ghi"
         },
         {
            setting1 = "jkl"
            setting2 = "mno"
            setting3 = "pqr"
         }
      ]
   }
}

and then you can local.environments["dev"][0].setting1

... or stick with maps, but then you need to iterate over the map somehow, e.g. use for_each to define a resource for each hello00x:

locals{
   environments = {
      dev = {
         "hello001" = {
            setting1 = "ami-0c55b159cbfafe1f0"
            setting2 = "t3.micro"
         }
         "hello002" = {
            setting1 = "ami-01d7c2b5c4fc0218a"
            setting2 = "m4.large"
         }
      }
   }
}

resource "aws_instance" "my_server" {
 for_each = local.environments["dev"]
 
 ami = each.value.setting1
 instance_type = each.value.setting2

 tags = {
  Name = each.key
 }
}

Here I defined a single aws_instance for each of the two hellos.

Upvotes: 6

Related Questions