In Terraform, I'm trying to create a module with that includes a map with variable keys. I'm not sure if this is possible but I've tried the following without success.
resource "aws_instance" "web" {
ami = "${var.base_ami}"
availability_zone = "${var.region_a}"
instance_type = "${var.ec2_instance_size}"
security_groups = ["sec1"]
count = "${var.ec2_instance_count}"
tags {
Name = "${var.role} ${var_env}"
role = "${var.app_role}"
${var.app_role} = "${var_env}"
}
}
and this:
tags {
Name = "${var.role} ${var_env}"
}
tags."${var.role}" = "${var.env}"
Any ideas? Is this not possible with Terraform currently?
terraform-map-variable.tfA variable can have a map type assigned explicitly, or it can be implicitly declared as a map by specifying a default value that is a map. The above demonstrates both. Then, replace the aws_instance with the following: resource "aws_instance" "example" { ami = var.
Using the -var Command-line Flag The -var flag is used to pass values for Input Variables to Terraform commands. This flag can be used with both of the Terraform plan and apply commands. The argument passed to the -var flag is a string surrounded by either single or double quotes.
Variables in Terraform are a great way to define centrally controlled reusable values. The information in Terraform variables is saved independently from the deployment plans, which makes the values easy to read and edit from a single file.
Basic Syntaxfor_each is a meta-argument defined by the Terraform language. It can be used with modules and with every resource type. The for_each meta-argument accepts a map or a set of strings, and creates an instance for each item in that map or set.
There's (now) a lookup
function supported in the terraform interpolation syntax, that allows you to lookup dynamic keys in a map.
Using this, I can now do stuff like:
output "image_bucket_name" {
value = "${lookup(var.image_bucket_names, var.environment, "No way this should happen")}"
}
where:
variable "image_bucket_names" {
type = "map"
default = {
development = "bucket-dev"
staging = "bucket-for-staging"
preprod = "bucket-name-for-preprod"
production = "bucket-for-production"
}
}
and environment
is a simple string variable.
The accepted answer describes how to do dynamic lookups in an existing map. For constructing maps with dynamic keys, in HCL2 (0.12), you can use a quoted interpolation expression in the key:
resource "aws_instance" "web" {
count = "${var.ec2_instance_count}"
ami = "${var.base_ami}"
availability_zone = "${var.region_a}"
instance_type = "${var.ec2_instance_size}"
security_groups = ["sec1"]
tags = {
Name = "${var.role} ${var.env}"
role = "${var.app_role}"
"${var.app_role}" = "${var.env}" # <------ like this
}
}
And once issue #21566 is fixed, you can replace "${var.app_role}"
with (var.app_role)
, which is the method described in the documentation.
(The same caveat as below applies here as well: if var.app_role
contains one of those literal keys as its value, then it will replace it.)
The accepted answer describes how to do dynamic lookups in an existing map. For constructing maps with dynamic keys, in HCL2 (0.12), you have two ways:
merge
You can use for expressions to dynamically build a map from one or more variables for your keys, and then use that in combination with the merge
function to build a new map with a mix of static and dynamic keys:
variable "app_role" {
type = string
}
locals {
tags = merge(
{
Name = "${var.role} ${var.env}"
role = "${var.app_role}"
},
{
for k in [var.app_role]: k => "${var.env}"
}
)
}
zipmap
Alternatively, you can use zipmap
to construct it in one shot:
locals {
tags = zipmap(
[
"Name",
"role",
var.app_role
],
[
"${var.role} ${var.env}",
var.app_role,
var.env
]
)
}
You can then use this map in a resource:
resource "aws_instance" "web" {
count = "${var.ec2_instance_count}"
ami = "${var.base_ami}"
availability_zone = "${var.region_a}"
instance_type = "${var.ec2_instance_size}"
security_groups = ["sec1"]
tags = local.tags // or inline the above here
}
One caveat is that if var.app_role
is equal to either "Name"
or "role"
, then it'll overwrite your static value. You can avoid this by swapping the arguments in merge
or reordering the lists in zipmap
, though such a collision would more likely be a configuration error that should be caught & fixed before applying.
The following works with terraform version 0.11.7. This solution uses the map function.
resource "aws_instance" "web" {
...
tags = "${map(
"Name", "${var.role} ${var_env}",
"role", "${var.app_role}",
"${var.app_role}", "${var_env}"
)}"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With