-
Notifications
You must be signed in to change notification settings - Fork 9.5k
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
Variable interpolation doesn't work in tags of aws_subnet_ids #14516
Comments
Hi @dvishniakov! Sorry things didn't work as expected here. It is a limitation of the configuration language that attribute names must be constants. This is true for all attribute names, not specifically the ones in this However, it should be possible to work around this by dynamically producing a map using the tags = "${map(var.myvar, var.mymap["internal_subnet_tag.value"])}" In future we may extend the configuration language to have dynamic keys for maps. At present this isn't possible because it doesn't have enough information during parsing to recognize the difference between a map (where keys are arbitrarily chosen by you) and other objects (where the keys are fixed, defined by the resource schema). Let's consider this issue to be a feature request for this working with the more intuitive syntax. |
@apparentlymart thanks! This workaround helps at this point, however such feature still could be useful so please keep this enhancement open. |
This is currently painful for Kubernetes clusters, since K8s typically uses tags like:
So what I really need is a set of tags like this: resource "aws_subnet" "sn-backend" {
...
count = "${length(var.zones)}"
tags {
"Name" = "sn-backend-${element(var.zones, count.index)}"
"Contact" = "${var.contact}"
"Environment" = "${var.environment}-${var.region}"
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
"kubernetes.io/role/internal-elb" = ""
}
} This isn't possible of course. Producing these tags as a map is hard, because I have interpolation required for keys and values. This requires a lot of variables to be defined because if I use the syntax The best solution I've found is to define all tags that have interpolation in their value as a map in one var ( resource "aws_subnet" "sn-backend" {
...
tags = "${merge(var.subnettags, map(var.clustertag, "shared"))}"
} but wow is this verbose. I feel like this issue should be reopened and fixed as it is really awkward to work around. |
It seems like a simple workaround here would be to let people specify tags as lists of keys and values like: resource "aws_subnet" "sn-backend" {
tags = [
{
key = "Name"
value = "sn-backend-${element(var.zones, count.index)}"
},
{
key = "kubernetes.io/cluster/${var.cluster_name}"
value = "shared"
}
]
} It would avoid having to change the fundamentally static nature of keys in the configuration language. Is that viable? Does terraform support lists of maps in its syntax? |
Hi all, The new improved parser/interpreter we are currently integrating has support for interpolation into map keys, so once that is released the configurations discussed in this issue should work as expected. Integrating this is a big project that addresses a number of different configuration limitations, so I can't yet say exactly when it will be done but it is the current focus for the Terraform team at HashiCorp. |
For anyone who is still struggling with the best way to do this, and waiting for the map interpolation to be supported, here's the way I'm doing it now. This is about as clean as I've been able to get it, and is specifically for dealing with the
locals {
common_tags = "${map(
"Project", "openshift",
"KubernetesCluster", "${var.cluster_id}",
"kubernetes.io/cluster/${var.cluster_name}", "${var.cluster_id}"
)}"
}
resource "aws_instance" "master" {
// Use our common tags and add a specific name.
tags = "${merge(
local.common_tags,
map(
"Name", "OpenShift Master"
)
)}"
} Reference: |
Another option here is to use lifecycle ignore_changes to avoid unwanted plan diffs: resource "aws_vpc" "vpc" {
...
# Ignore k8s tag and tag count
lifecycle {
ignore_changes = ["tags.kubernetes", "tags.%"]
}
tags {
# Other tags
}
} |
Hi all! Sorry for the long silence here. I took the example in the initial comment on this issue and adapted it a little to use a variable "mymap" {
type = "map"
default = {
"internal_subnet_tag.key" = "associate_public_ip_address"
"internal_subnet_tag.value" = "no"
}
}
resource "null_resource" "example" {
triggers = {
(var.mymap["internal_subnet_tag.key"]) = var.mymap["internal_subnet_tag.value"]
}
} This example uses the new ability for a map constructor to have arbitrary expressions for keys. Because we allow "naked" identifiers to be used as literal keys, a more complex expression like this one must be placed in parentheses so the parser can understand our intent. (It would also work to use a quoted string with an interpolation sequence as in the original example, but I used simple parentheses because they are less visually "noisy".) I can see this working as expected in Terraform v0.12.0-alpha1:
In order to make this work, the new language parser makes a stronger distinction between attributes that happen to have map/object values (where dynamic keys are allowed) and nested blocks (where only literal keys are allowed, so that they can be validated early). The practical implication of this is that it is now required to use the equals sign to define a value for a map attribute, where before omitting this was just non-idiomatic. As an example of what I mean, I've also included some of the examples shown in this issue updated to use the attribute definition syntax where previously they used nested block syntax: data "aws_subnet_ids" "our_vpc" {
vpc_id = "real-vpc-id"
tags = {
"${var.myvar}" = "${var.mymap["internal_subnet_tag.value"]}"
}
} resource "aws_subnet" "sn-backend" {
...
count = "${length(var.zones)}"
tags = {
"Name" = "sn-backend-${element(var.zones, count.index)}"
"Contact" = "${var.contact}"
"Environment" = "${var.environment}-${var.region}"
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
"kubernetes.io/role/internal-elb" = ""
}
} The configuration upgrade tool that will be included with the v0.12.0 final release will be able to fix this usage automatically across your whole configuration, if you wish. The technique of merging a set of common tags with some override tags will still work, and can now be expressed more clearly due to first-class expression syntax: tags = merge(
local.common_tags,
{
Name = "OpenShift Master"
}
) With all of that said, it looks like the use-cases covered by this issue have been addressed in the |
@apparentlymart - this is awesome, thank you! And thanks for the detailed update and usage examples. Really cool 😄 |
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. |
Community Note
Note: this block was copy-pasted from terraform-provider-aws
Terraform Version
0.9.5
Affected Resource(s)
Terraform Configuration Files
Debug Output
--Cut of bad debug
data.aws_subnet_ids.our_vpc: Refreshing state...
2017/05/15 15:49:12 [DEBUG] plugin: terraform: aws-provider (internal) 2017/05/15 15:49:12 [DEBUG] Matching ^aws: with ${var.myvar}
2017/05/15 15:49:12 [DEBUG] plugin: terraform: aws-provider (internal) 2017/05/15 15:49:12 [DEBUG] DescribeSubnets {
2017/05/15 15:49:12 [DEBUG] plugin: terraform: Filters: [{
2017/05/15 15:49:12 [DEBUG] plugin: terraform: Name: "vpc-id",
2017/05/15 15:49:12 [DEBUG] plugin: terraform: Values: ["real-vpc-id"]
2017/05/15 15:49:12 [DEBUG] plugin: terraform: },{
2017/05/15 15:49:12 [DEBUG] plugin: terraform: Name: "tag:${var.myvar}",
2017/05/15 15:49:12 [DEBUG] plugin: terraform: Values: [""]
2017/05/15 15:49:12 [DEBUG] plugin: terraform: }]
2017/05/15 15:49:12 [DEBUG] plugin: terraform: }
--Cut of good debug
data.aws_subnet_ids.our_vpc: Refreshing state...
2017/05/15 15:48:26 [DEBUG] plugin: terraform: aws-provider (internal) 2017/05/15 15:48:26 [DEBUG] Matching ^aws: with associate_public_ip_address
2017/05/15 15:48:26 [DEBUG] plugin: terraform: aws-provider (internal) 2017/05/15 15:48:26 [DEBUG] DescribeSubnets {
2017/05/15 15:48:26 [DEBUG] plugin: terraform: Filters: [{
2017/05/15 15:48:26 [DEBUG] plugin: terraform: Name: "vpc-id",
2017/05/15 15:48:26 [DEBUG] plugin: terraform: Values: ["real-vpc-id"]
2017/05/15 15:48:26 [DEBUG] plugin: terraform: },{
2017/05/15 15:48:26 [DEBUG] plugin: terraform: Name: "tag:associate_public_ip_address",
2017/05/15 15:48:26 [DEBUG] plugin: terraform: Values: ["no"]
2017/05/15 15:48:26 [DEBUG] plugin: terraform: }]
2017/05/15 15:48:26 [DEBUG] plugin: terraform: }
Expected Behavior
Actual Behavior
Tag name is not interpolated
Steps to Reproduce
terraform plan
Important Factoids
Your AWS account should have vpc and subnet(s). At least one subnet with the specified tag key and value for the successful refresh
Additional question
The text was updated successfully, but these errors were encountered: