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

Replace multiple resource instances with a single -replace=... planning argument #1768

Open
alexlouden opened this issue May 1, 2015 · 69 comments

Comments

@alexlouden
Copy link

Hey guys,

I've got an AWS instance resource for my workers in a module (mymodule):

resource "aws_instance" "worker" {
  count = "12"
 ...
}

Is it possible to taint all 12 resources? I've tried the following:

❯ terraform taint -module=mymodule "aws_instance.worker.*"
The resource aws_instance.worker.* couldn't be found in the module root.mymodule.

Rather than having to do this:

❯ terraform taint -module=mymodule "aws_instance.worker.0"
The resource aws_instance.worker.0 in the module root.mymodule has been marked as tainted!

❯ terraform taint -module=mymodule "aws_instance.worker.1"
The resource aws_instance.worker.1 in the module root.mymodule has been marked as tainted!

...

Cheers,
Alex

@ketzacoatl
Copy link
Contributor

+1

4 similar comments
@jamiemoore
Copy link

+1

@tomwilkie
Copy link
Contributor

+1

@meson10
Copy link

meson10 commented Aug 18, 2015

+1

@JorritSalverda
Copy link

+1

@apparentlymart
Copy link
Contributor

This seems like it wouldn't be too hard to implement.

The code that finds the resource to taint is here:

// Get the resource we're looking for

If there were a rule that the wildcard can only be a * and it may only be the entirety of the last part of the resource path (so e.g. no aws_instance.foo* or *.baz) then this would just entail iterating over the mod.Resources map looking for keys that have the right prefix.

@listenrightmeow
Copy link

+1

2 similar comments
@jmahowald
Copy link

+1

@levenaux
Copy link

+1

@jonapich
Copy link

#2444 is similar to this and would be awesome!

@jseaidou
Copy link

jseaidou commented Apr 6, 2016

has there been any progress on this? this would be very helpful for us at Box.

@Kuberchaun
Copy link

+1

6 similar comments
@noresjo
Copy link

noresjo commented Jun 16, 2016

+1

@igormoochnick
Copy link

+1

@JohnDzialo
Copy link

+1

@dabdine-r7
Copy link

+1

@ghost
Copy link

ghost commented Jul 28, 2016

+1

@nicusX
Copy link

nicusX commented Aug 13, 2016

+1

@sachincab
Copy link

this would be really needed for resources created using count :)

@ghost
Copy link

ghost commented Sep 6, 2016

+1

@abadyan-vonage
Copy link

Very useful, especially with count.

@onlyanegg
Copy link

+1

2 similar comments
@ryanrapp
Copy link

+1

@ilijaljubicic
Copy link

+1

artburkart pushed a commit to artburkart/terraform that referenced this issue Nov 20, 2016
This implementation of wildcard functionality enables the following:

Given resources:
- test_instance.foo.a
- test_instance.foo.b
- test_instance.bar.a

Matches:

`test_instance.*`
- test_instance.foo.a
- test_instance.foo.b
- test_instance.bar.a

`test_instance.*.a`
- test_instance.foo.a
- test_instance.bar.a

`test_instance.foo.*`
- test_instance.foo.a
- test_instance.foo.b

`test_instance.foo*`
- Doesn't match anything
artburkart pushed a commit to artburkart/terraform that referenced this issue Dec 2, 2016
This implementation of wildcard functionality enables the following:

Given resources:
- test_instance.foo.a
- test_instance.foo.b
- test_instance.bar.a

Matches:

`test_instance.*`
- test_instance.foo.a
- test_instance.foo.b
- test_instance.bar.a

`test_instance.*.a`
- test_instance.foo.a
- test_instance.bar.a

`test_instance.foo.*`
- test_instance.foo.a
- test_instance.foo.b

`test_instance.foo*`
- Doesn't match anything
@benglewis
Copy link

+1

@queglay
Copy link

queglay commented Jan 14, 2019

+1 for the ability to taint a whole module or multiple resources

I just got absolutely crushed by not having this ability to taint multiple resources. I was tainting an instance, and not realising that the downstream null resource file provisioners weren't working because they weren't tainted. face palm.

@koesper
Copy link

koesper commented Jan 23, 2020

Is there a workaround for this in the meanwhile?

edit: in #23023 (comment) I found a suggestion to do a 'state rm' on all nodes. We can change that to do a taint on all elements.
terraform state list | cut -f 1 -d '[' | xargs -L 1 terraform taint

@gchamon
Copy link

gchamon commented Feb 28, 2020

I needed to taint a whole module, and this function can help here too:

terraform-taint-all () {
  resource_prefix=$1
  for resource in $(terraform state list | grep -oP "$resource_prefix.*"); do
    terraform taint $resource;
  done
}

So if you want to taint all resources created with count, lets say a security_group_rule inside a module, just do:

terraform-taint-all module.mymodule.security_group_rule

@artburkart
Copy link
Contributor

artburkart commented May 6, 2020

@apparentlymart – In 2016, I implemented this feature. My PR was closed because–although it worked–it added tech debt to Terraform, because there was secret state work going on behind the scenes and my PR wouldn't blend well. Given that it's 4 years later, has the situation changed? If I were to implement this today, would my PR be closed again?

#10256

@shantanugadgil
Copy link

My use case is to taint the elements of the array, given its base name
The regex approach could be enhanced to add something like "\[\d+\]" to the regex ?!?

Also, the "state rm" sub-command supports it, so the code to do this would be somewhere in core already, me-thinks! :)

$ /opt/terraform-0.12/bin/terraform state list
aws_launch_configuration.worker[0]
aws_launch_configuration.worker[1]
aws_launch_configuration.worker[2]

Try to taint it ... no joy

$ /opt/terraform-0.12/bin/terraform taint aws_launch_configuration.worker

Error: No such resource instance

There is no resource instance in the state with the address
aws_launch_configuration.worker. If the resource configuration has just been
added, you must run "terraform apply" once to create the corresponding
instance(s) before they can be tainted.

But state rm works fine ...

$ /opt/terraform-0.12/bin/terraform state rm aws_launch_configuration.worker
Removed aws_launch_configuration.worker[0]
Removed aws_launch_configuration.worker[1]
Removed aws_launch_configuration.worker[2]
Successfully removed 3 resource instance(s).

@queglay
Copy link

queglay commented Jun 1, 2020

could you grep and filter from -
terraform state list
possibly?

@pselle pselle changed the title Taint with wildcard? Taint multiple resource instances at once with wildcard Nov 10, 2020
@pselle pselle changed the title Taint multiple resource instances at once with wildcard Taint multiple resource instances at once Nov 10, 2020
@pselle
Copy link
Contributor

pselle commented Nov 10, 2020

I've updated the title of the issue here to clarify the goal of tainting multiple resource instances at once, without specifying a particular solution (wildcard, or multiple addresses as proposed in #22117). This is not any declaration of intent on the part of the Core team, but some issue consolidation on our side.

@sorin-costea
Copy link

Taint by tag?

@nijave
Copy link

nijave commented Mar 18, 2021

Here, we use terraform taint pretty frequently in lower test/engineering environments to "reset" infrastructure--especially databases--back to the vanilla Terraform defined state. For something like a database, the alternative would be to use database specific commands to try to undo any state/schema changes (these are managed outside Terraform) so in engineering environments it's easiest to just taint huge lists of resources and rebuild them from scratch.

In some cases, it's actually fastest to convert from S3 backend to local, apply the taint commands, then convert back again since it's so much faster. We're using S3 backend + DynamoDB in our setup

@alemairebe
Copy link

as taint is deprecated , should we update this ticket to expect the same kind of behavior with "-replace" when performing a plan/apply ?

@frittentheke
Copy link

as taint is deprecated , should we update this ticket to expect the same kind of behavior with "-replace" when performing a plan/apply ?

While -replace is mentioned on the taint documentation page (https://www.terraform.io/docs/cli/commands/taint.html) already and as the replacement to achieve the defined resource to be replaced, this option is actually not even listed for the apply sub command at https://www.terraform.io/docs/cli/commands/apply.html yet - even though this is merged with #28574

But I did a quick test with multiple -replace parameters (just like with -target) for plan and apply and this seems to work and would also likely be a solution to this very issue (slow, individual calls for taint instead of a single call to have multiple resources replaced.

@dodwmd
Copy link

dodwmd commented Sep 23, 2021

+1

@jbg
Copy link

jbg commented Nov 4, 2021

But I did a quick test with multiple -replace parameters (just like with -target) for plan and apply and this seems to work and would also likely be a solution to this very issue.

It would be really nice to be able to use a splat expression in target (and I guess replace as well) rather than having to name every resource. E.g. -target='module.foo[*].resourcetype.resource'. It's tedious building up a cmdline with xargs to achieve the same, and despite -target being "disrecommended" it's hard to avoid it completely due to terraform's various limitations.

@sfuerte
Copy link

sfuerte commented Feb 8, 2022

But I did a quick test with multiple -replace parameters (just like with -target) for plan and apply and this seems to work and would also likely be a solution to this very issue (slow, individual calls for taint instead of a single call to have multiple resources replaced.

it's still an annoying solution to do multiple -replace params, especially in a dynamic env with unknown number of instances by default, i.e. that requires to do an extra call to TF state (and S3 in most cases = expensive time wise) and then build that param list (which adds another point for potential mess)

Would've been so much easier with a single command but no...

$ AWS_PROFILE=dev terraform apply -target=module.my_test -replace=module.my_test
Acquiring state lock. This may take a few moments...
module.my_test[0]: Refreshing state... [id=xxx]
module.my_test[1]: Refreshing state... [id=xxx]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
╷
│ Warning: Incompletely-matched force-replace resource instance
│
│ Your force-replace request for module.my_test doesn't match any resource instances because it lacks an instance key.

│ To force replacement of particular instances, use one or more of the following options instead:
│   -replace="module.my_test[0]"
│   -replace="module.my_test[1]"


Releasing state lock. This may take a few moments...

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

@jmrobles
Copy link

jmrobles commented Mar 3, 2022

I don't know the reasoning why this wildcard use is an error instead of a feature.

Anyway, it's pretty straightforward to patch terraform code to use it. Obviously, it's a workaround, not a solid solution.

Just to modify the file terraform/internal/terraform/node_resource_plan.go, expanding the "replace" array with the expansion list.

image

@apparentlymart apparentlymart changed the title Taint multiple resource instances at once Replace multiple resource instances with a single -replace=... planning argument Mar 9, 2022
@dough29
Copy link

dough29 commented Aug 12, 2022

Any news on this ?

I need to replace multiple instances that depend on a "count" variable.

For now with my_instances.* I get doesn't match any resource instances because it lacks an instance key using Terraform 1.2.7

@jbg
Copy link

jbg commented Aug 12, 2022

@dough29

You have to do e.g. -replace=foo.bar[0] -replace=foo.bar[1]. If you have a lot of them you could generate the command line, for example with seq + xargs:

seq -f '-replace=foo.bar[%.0f]' 0 9 | xargs terraform plan

Ugly but effective.

@vincentclee
Copy link

@jbg solution works great for terraform plan, but for terraform apply i had to use this to avoid printing a newline when seq completes.

terraform apply $(seq -f '-replace=foo.bar[%.0f]' 0 9)

@holms
Copy link

holms commented Mar 26, 2023

It's 2023 and still no updates :(

@michaelmoopenn
Copy link

+1

@kingnarmer
Copy link

Checking if you have updates on this.

@anishsedhaii
Copy link

+1

@crw
Copy link
Collaborator

crw commented Oct 31, 2023

Thanks for your interest in this issue! This is just a reminder to please avoid "+1" comments, and to use the upvote mechanism (click or add the 👍 emoji to the original post) to indicate your support for this issue. This helps avoid notification spam for issues with high numbers of participants while enabling the maintainers to prioritize issues.

We do not have any update to share at this time. We maintain a list of top 25 community upvoted issues (you can see a basic version of this with this issue search). Issues on this list get reviewed and discussed frequently, especially when we are planning new releases. This issue is just off the list at 28, however after the next few releases, the top 25 should have a bit more room as we close some of those other issues. This issue also has a similar theme to #2182, which is sitting at #7 as of this post.

Issues that have been open for many, many years such as this one are often still open because their implementation is not as trivial or obvious as it may at first appear.

Thanks again for the feedback!

@ei-grad
Copy link

ei-grad commented Nov 5, 2024

Since the title of this issue has changed, issue #22117, which was closed in favor of this one, should be reopened.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.