Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for nested maps in variables #2114

Closed
nevir opened this issue May 28, 2015 · 82 comments
Closed

Support for nested maps in variables #2114

nevir opened this issue May 28, 2015 · 82 comments

Comments

@nevir
Copy link
Contributor

nevir commented May 28, 2015

I'd love to be able to do this:

variable "amis" {
  default = {
    app1 = {
      us-west-2 = "ami-abc123"
    }
    app2 = {
      us-west-2 = "ami-cba321"
    }
  }
}

Currently, you'd get an error like Variable 'amis': must be string or mapping

@nevir
Copy link
Contributor Author

nevir commented May 28, 2015

Interestingly, I can cheat a bit:

variable "amis" {
  default = {
    app.us-west-2 = "ami-abc123"
    app2.us-west-2 = "ami-cba321"
  }
}

@ghost
Copy link

ghost commented Jul 20, 2015

+1

1 similar comment
@bhouse
Copy link

bhouse commented Jul 20, 2015

+1

@ketzacoatl
Copy link
Contributor

+1, I didn't realize this was not possible.

@jbiel
Copy link

jbiel commented Jul 21, 2015

+1

2 similar comments
@ojongerius
Copy link
Contributor

+1

@RBeaudoin
Copy link

+1

@spheromak
Copy link

👍 really need to be able to pass data types other than strings in the DSL.

@alexgervais
Copy link

+1

@sherabi
Copy link

sherabi commented Oct 1, 2015

+1 really need this one

@quater
Copy link

quater commented Oct 6, 2015

+1

3 similar comments
@OleksandrBerchenko
Copy link

+1

@rodlogic
Copy link

rodlogic commented Nov 6, 2015

+1

@Deserved
Copy link

+1

@ephemeral
Copy link

+1

1 similar comment
@craigwatson
Copy link

+1

@bigkraig
Copy link
Contributor

bigkraig commented Feb 1, 2016

Being able to have a list as a value would also be very nice

@giorgioprevitera
Copy link

+1

9 similar comments
@jare19
Copy link

jare19 commented Apr 6, 2016

👍

@mblankleder
Copy link

+1

@vadanx
Copy link

vadanx commented Apr 27, 2016

+1

@ghost
Copy link

ghost commented May 5, 2016

+1

@multiloc
Copy link

+1

@eedwardsdisco
Copy link

+1

@gogs2k
Copy link

gogs2k commented Jun 6, 2016

+1

@JohnDzialo
Copy link

+1

@balooo
Copy link

balooo commented Jun 27, 2016

+1

@mubeta06
Copy link
Contributor

+1

2 similar comments
@sjauld
Copy link
Contributor

sjauld commented Mar 15, 2017

+1

@jtsaito
Copy link
Contributor

jtsaito commented Mar 16, 2017

+1

@tomstockton
Copy link

+1

What are people doing to work around this?

@asciifaceman
Copy link

@tomstockton it's been two years, had to drop terraform originally and then brought it back in a lesser capacity

@hua3721
Copy link

hua3721 commented Mar 17, 2017

Here is what I would do as an alternative for this map of map issue:

variable amis {
    app1 = "app1_map"
    app2 = "app2_map"
}
app1_map = {
      us-west-2 = "ami-abc123"
}
app2_map = {
      us-west-2 = "ami-cba321"
    }
}

@sprutner
Copy link
Contributor

sprutner commented Mar 21, 2017

Here's what I did for multi-environment in one variables.tf file symlinked into each environment folder

variable "subnets" {
    type = "map"
    default = {
        dev             = "10.104.0.0/16"
        qa              = "10.103.0.0/16"
        stage           = "10.102.0.0/16"
        prod            = "10.101.0.0/16"
        app.dev         = "10.104.20.0/23"
        app.qa          = "10.103.20.0/23"
        app.stage       = "10.102.20.0/23"
        app.prod        = "10.101.20.0/23"
        app_1.dev       = "10.104.20.0/24"
        app_1.qa        = "10.103.20.0/24"
        app_1.stage     = "10.102.20.0/24"
        app_1.prod      = "10.101.20.0/24"
        app_2.dev       = "10.104.21.0/24"
        app_2.qa        = "10.103.21.0/24"
        app_2.stage     = "10.102.21.0/24"
        app_2.prod      = "10.101.21.0/24"
        public.dev      = "10.104.10.0/23"
        public.qa       = "10.103.10.0/23"
        public.stage    = "10.102.10.0/23"
        public.prod     = "10.101.10.0/23"
        public_1.dev    = "10.104.10.0/24"
        public_1.qa     = "10.103.10.0/24"
        public_1.stage  = "10.102.10.0/24"
        public_1.prod   = "10.101.10.0/24"
        public_2.dev    = "10.104.11.0/24"
        public_2.qa     = "10.103.11.0/24"
        public_2.stage  = "10.102.11.0/24"
        public_2.prod   = "10.101.11.0/24"
        private_1.dev   = "10.104.xx.0/24"
        private_1.qa    = "10.103.xx.0/24"
        private_1.stage = "10.102.xx.0/24"
        private_1.prod  = "10.101.xx.0/24"
        private_2.dev   = "10.104.xx.0/24"
        private_2.qa    = "10.103.xx.0/24"
        private_2.stage = "10.102.xx.0/24"
        private_2.prod  = "10.101.xx.0/24"
    }
}

and then call it like

module "vpc" {
  source = "../modules/aws_vpc/"

  # we call the environment 'variable' here for the vpc name

  name          = "vpc-${var.environment}"

  cidr                    = "${lookup(var.subnets, var.environment)}"
  private_subnets         = ["${lookup(var.subnets, "private_1.${var.environment}")}", "${lookup(var.subnets, "private_2.${var.environment}")}"]
  public_subnets          = ["${lookup(var.subnets, "public_1.${var.environment}")}", "${lookup(var.subnets, "public_2.${var.environment}")}"]
  app_subnets             = ["${lookup(var.subnets, "app_1.${var.environment}")}", "${lookup(var.subnets, "app_2.${var.environment}")}"]
  enable_dns_hostnames    = true
  enable_dns_support      = true
  enable_nat_gateway      = "true"
}

@ghost
Copy link

ghost commented Apr 26, 2017

+1

2 similar comments
@mossy02
Copy link

mossy02 commented May 5, 2017

+1

@nilo
Copy link

nilo commented May 11, 2017

+1

@apparentlymart
Copy link
Contributor

I just verified that the example given in the original comment on this issue works in Terraform v0.12-alpha1:

variable "amis" {
  default = {
    app1 = {
      us-west-2 = "ami-abc123"
    }
    app2 = {
      us-west-2 = "ami-cba321"
    }
  }
}

output "amis" {
  value = var.amis
}

In addition, Terraform v0.12 introduces the idea of object types which allow specification of variables that expect a specific set of attributes that may be of different types:

variable "regions" {
  type = map(map(object({
    ami = string
  })))

  default = {
    app1 = {
      us-west-2 = {
        ami = "ami-abc123"
      }
    }
    app2 = {
      us-west-2 = {
        ami = "ami-cba321"
      }
    }
  }
}

output "regions" {
  value = var.regions
}

Although there is still a remaining small issue to fix over in #19141, this feature request is now complete. Thanks for your patience, everyone!

@apparentlymart apparentlymart added this to the v0.12.0 milestone Oct 29, 2018
hardys pushed a commit to hardys/terraform-provider-ironic that referenced this issue Mar 27, 2019
Due to limitations in terraform, we can't pass a nested map here
so instead surface the root_device as a top-level interface, then
set the map value internally.

More info at hashicorp/terraform#2114

Fixes: openshift-metal3#8
hardys pushed a commit to hardys/terraform-provider-ironic that referenced this issue Mar 27, 2019
Due to limitations in terraform, we can't pass a nested map here
so instead surface the root_device as a top-level interface, then
set the map value internally.

More info at hashicorp/terraform#2114

Fixes: openshift-metal3#8
hardys pushed a commit to hardys/terraform-provider-ironic that referenced this issue Mar 28, 2019
Due to limitations in terraform, we can't pass a nested map here
so instead surface the root_device as a top-level interface, then
set the map value internally.

More info at hashicorp/terraform#2114

Fixes: openshift-metal3#8
hardys pushed a commit to openshift-metal3/terraform-provider-ironic that referenced this issue Mar 29, 2019
* Handle properties

* Expose root_device as a top-level parameter

Due to limitations in terraform, we can't pass a nested map here
so instead surface the root_device as a top-level interface, then
set the map value internally.

More info at hashicorp/terraform#2114

Fixes: #8
@arbreezy
Copy link

Here's what I did for multi-environment in one variables.tf file symlinked into each environment folder

variable "subnets" {
    type = "map"
    default = {
        dev             = "10.104.0.0/16"
        qa              = "10.103.0.0/16"
        stage           = "10.102.0.0/16"
        prod            = "10.101.0.0/16"
        app.dev         = "10.104.20.0/23"
        app.qa          = "10.103.20.0/23"
        app.stage       = "10.102.20.0/23"
        app.prod        = "10.101.20.0/23"
        app_1.dev       = "10.104.20.0/24"
        app_1.qa        = "10.103.20.0/24"
        app_1.stage     = "10.102.20.0/24"
        app_1.prod      = "10.101.20.0/24"
        app_2.dev       = "10.104.21.0/24"
        app_2.qa        = "10.103.21.0/24"
        app_2.stage     = "10.102.21.0/24"
        app_2.prod      = "10.101.21.0/24"
        public.dev      = "10.104.10.0/23"
        public.qa       = "10.103.10.0/23"
        public.stage    = "10.102.10.0/23"
        public.prod     = "10.101.10.0/23"
        public_1.dev    = "10.104.10.0/24"
        public_1.qa     = "10.103.10.0/24"
        public_1.stage  = "10.102.10.0/24"
        public_1.prod   = "10.101.10.0/24"
        public_2.dev    = "10.104.11.0/24"
        public_2.qa     = "10.103.11.0/24"
        public_2.stage  = "10.102.11.0/24"
        public_2.prod   = "10.101.11.0/24"
        private_1.dev   = "10.104.xx.0/24"
        private_1.qa    = "10.103.xx.0/24"
        private_1.stage = "10.102.xx.0/24"
        private_1.prod  = "10.101.xx.0/24"
        private_2.dev   = "10.104.xx.0/24"
        private_2.qa    = "10.103.xx.0/24"
        private_2.stage = "10.102.xx.0/24"
        private_2.prod  = "10.101.xx.0/24"
    }
}

and then call it like

module "vpc" {
  source = "../modules/aws_vpc/"

  # we call the environment 'variable' here for the vpc name

  name          = "vpc-${var.environment}"

  cidr                    = "${lookup(var.subnets, var.environment)}"
  private_subnets         = ["${lookup(var.subnets, "private_1.${var.environment}")}", "${lookup(var.subnets, "private_2.${var.environment}")}"]
  public_subnets          = ["${lookup(var.subnets, "public_1.${var.environment}")}", "${lookup(var.subnets, "public_2.${var.environment}")}"]
  app_subnets             = ["${lookup(var.subnets, "app_1.${var.environment}")}", "${lookup(var.subnets, "app_2.${var.environment}")}"]
  enable_dns_hostnames    = true
  enable_dns_support      = true
  enable_nat_gateway      = "true"
}

FYI: Terraform v0.12 will complain about the ' . ' in the subnet variables (e.g app.dev) with this error:
Error: Ambiguous attribute key
I changed the ' . ' delimiter and works fine.

@ghost
Copy link

ghost commented Jul 31, 2019

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Jul 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests