0.11.3
I would like to be able to add or update specific tag names in a pre-existing resource that was not created by Terraform. In my case the network infrastructure is managed by another team, not using terraform. However, I need to manage one or more tag names on that resource. And only those tag names.
To configure a Kubernetes cluster the public subnets where internet-facing load balancers are created are often shared across several clusters. The subnets need to be tagged like: "kubernetes.io/cluster/cluster-name" = "shared". But this is the only tag on the subnet I want to manage from my Terraform. I also do not want to manage anything else about the subnet.
A more general solution would allow managing any argument of the pre-existing resource.
An example:
resource ""aws_subnet" "public" {
subnet_id = "subnet-1234abcd"
# Set transparent to true indicating that the resource exists, and we wish to
# manage only the parts we configure here. Perhaps the transparent argument
# is redundant if subnet_id is provided.
transparent = true
tags {
# This method of interpolating in a tag name does not work yet,
# but there is another issue to address that.
"kubernetes.io/cluster/${var.clusterName}" = "shared"
# Here we only manage the named tag. All other tags are left alone.
}
# Only provide arguments for the parts you want to manage. Leave everything
# else as is.
}
Or instead of providing a subnet-id, it would be useful to search for a subnet using filters like a data source.
None, this is not possible today.
Hi @dlaidlaw! Thanks for this feature request.
As you know, right now Terraform's model is that it either manages a resource or it doesn't. We do not currently have support for partial management as you suggest here.
It seems plausible in theory that we could have a special diffing mode which only considers attributes that are explicitly mentioned in the configuration. There are some details that make this trickier than it first appears:
ignore_changes
(in some sense, the _opposite_ of this requested feature) that there are some confusing interactions when you try to interpolate an attribute whose changes are ignored, since Terraform interpolates from different contexts during different phases. While I believe many of the bugs of this type have been addressed by now, ignore_changes
took many iterations to get right and I expect the same would be true for this feature.With that in mind, I've tagged this as "thinking" to represent the fact that the idea is interesting but that we're not going to be able to make any changes in this direction in the short term due to the need for some design/prototyping work to understand exactly how this mechanism should work.
Thanks again for suggesting this, and sorry we're not able to be more definitive about it right now.
OK, while you are thinking about it, notice that AWS specifically added this ability for tags on EC2 resources with the aws ec2 create-tags/delete-tags/describe-tags CLI command. Managing tags on resources is far simpler than trying to manage the whole resource.
I understand your point on how reasoning about shared objects can be difficult. But I am seldom given easy jobs ;) Managing a set of tags on shared resources should not be too difficult, if you wanted to reduce the scope of this enhancement to just tags on shared resources.
New resource types for adding tags to existing objects could be a reasonable thing for the AWS provider itself to support, I agree. It'd be a bit like the distinction between nesting rule blocks directly inside aws_security_group
vs. using separate aws_security_group_rule
resources.
That could be a good topic for an issue in the AWS provider repository. The folks who maintain that provider will have a better sense of whether there are any drawbacks to that which I'm not aware of.
FWIW, as a workaround I did this to add or update tags of existing VPC:
resource "null_resource" "tag-vpc" {
provisioner "local-exec" {
command = "aws ec2 create-tags --resources ${var.vpc-id} --tags Key=kubernetes.io/cluster/${var.cluster-name},Value=shared"
}
}
It of course assumes you have aws-cli installed locally where you run TF.
And as you can see, it's possible to use TF interpolation ${}
Sure, but this only works for a very limited set of resources, such as EC2 instances. I actually have the need for other things in the VPC, such as subnets and security groups and ELBs. All of our EC2 instances are managed by ASGs, so we do not get the opportunity to use the aws ec2 create-tags command for those either.
What if you also own the terraform code and have access to the tf state for the VPC? Is it possible to just extend the current tags for an existing resource in another module?
No, you can't do that. The resource DSL for any specific resource needs to be specified in whole in one definition. You can't spread it across several definitions for the same resource ID.
If you have a resource for a subnet, everything about the subnet must be defined in that resource, and nowhere else. You can reference the resource attributes in other resources, but you cannot add or change anything.
This is very unfortunate for automating the setup of Kubernetes clusters. It is frequently required to add tags to a shared resource for each cluster. It is possible for kubernetes clusters to share subnets, for example, but the subnet must be tagged with cluster-specific tags. Impossible to do with terraform.
@rantav this solution doesn't work well, on the second terraform apply
the resource aws_vpc
will override tags. To workaround this you may taint null_resource
before terraform apply
, but it's not a good solution.
One way (hack) of doing this is to ignore_changes
on tags when creating the aws_subnet
resource.
lifecycle {
ignore_changes = ["tags"]
}
You can use now null_resource
to add and remove tags
resource "null_resource" "subnet_tags" {
count = "${local.az_count}"
provisioner "local-exec" {
command = "aws --region ${var.aws_region} --profile ${var.aws_profile} ec2 create-tags --resources ${element(data.aws_subnet.private_elb.*.id, count.index)} --tags Key=kubernetes.io/role/internal-elb,Value="
}
provisioner "local-exec" {
when = "destroy"
command = "aws --region ${var.aws_region} --profile ${var.aws_profile} ec2 delete-tags --resources ${element(data.aws_subnet.private_elb.*.id, count.index)} --tags Key=kubernetes.io/role/internal-elb,Value="
}
}
Another use case is to tag Main route table after creating AWS VPC. Or there is a way to do it?
The AWS provider has a resource type aws_default_route_table
that allows putting the default route table for a particular VPC under Terraform's management by violating the usual rule that Terraform won't adopt any object it didn't create. There are some caveats for that as described in the documentation, but the AWS provider team added this resource type (and some similar ones) as a pragmatic way to work around the fact that some aspects of the EC2 API design are incompatible with Terraform's usual usage pattern.
For a proposal like this where the behavior would likely need to be different per use-case (due to differences in the underlying APIs) we prefer to try for resource-type-specific solutions within individual providers first because they can then be tailored to the problem at hand, as we see with aws_default_route_table
.
For that reason, we'd suggest opening more specific feature request issues for the use-cases shared here within the specific providers they relate to. The provider teams can evaluate whether there's a possible resource-type-specific or provider-specific solution to a specific problem, which makes it easier to apply pragmatism to find a solution. For example, the AWS provider team is already working on terraform-providers/terraform-provider-aws#10689, which includes some generalizations of how tags are handled in the AWS provider that could make it easier to support other generalized tag management features in future.
We're going to close this issue for now, because in order to make progress on it we'd need to analyze a variety of different use-cases and see how (and whether) they generalize to something Terraform Core could solve generically, and the best way to do that is to discuss the individual use-cases within the context of individual providers first and then look for commonalities in how the different problems have been solved. We'll open an new issue if experience implementing provider-specific features leads us towards a generalized design proposal.
Thanks, everyone!
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.
Most helpful comment
FWIW, as a workaround I did this to add or update tags of existing VPC:
It of course assumes you have aws-cli installed locally where you run TF.
And as you can see, it's possible to use TF interpolation
${}