3

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"

1
  • If the keys do not matter for the specific environment maps, then you could convert those to lists. Essentially, could you convert this from map(map(map(object(...string...))) to map(map(list(object(...string...)))? Commented Sep 27, 2021 at 14:46

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I just like to drop my gratitude for this solution. Thank you very much.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.