terraform icon indicating copy to clipboard operation
terraform copied to clipboard

prevent_destroy should let you succeed

Open ketzacoatl opened this issue 9 years ago • 153 comments

Call me crazy, but I'm willing to call the current implementation of prevent_destroy a bug. Here is why: The current implementation of this flag prevents you from using it for 1/2 the use case.

The net result is more frustration when trying to get Terraform to succeed instead of destroying your resources.. prevent_destroy adds to the frustration more than alleviating it.

prevent_destroy is for these two primary use cases, right?

  1. you don't want this resource to be deleted, and you want to see errors when TF tries to do that
  2. you don't want this resource to be deleted, and you don't want to hear a peep out of TF - TF should skip over its usual prerogative to rm -rf on change.

I see no reason why TF must return an error when using prevent_destroy for the second use case, and in doing so, TF is completely ignoring my utterly clear directive to let me get work done. As a user, I end up feeling as though TF is wasting my time because I am focused on simple end goals which I am unable to attain while I spin my wheels begging TF to create more resources without destroying what exists.

You might say the user should update their plan to not be in conflict, and I would agree that is what you want to do in most cases.. but, honestly, that is not always the right solution for the situation at hand when using a tool like TF for the real-world. I believe in empowering users, and the current implementation of this flag prevents sensible use of the tool.

ketzacoatl avatar Nov 12 '15 08:11 ketzacoatl

Hi @ketzacoatl - thanks for opening this! Based on your description I'm certainly sympathetic to the idea that Terraform should not terminate with an error code if the user intent is to prevent resources being deleted, but I'm inclined to say that the output should indicate that resources where prevent_destroy was a factor in the execution should indicate this. @phinze, do you have any thoughts on this?

jen20 avatar Nov 12 '15 15:11 jen20

Definitely sympathetic about this use-case too. I think a concern is that if Terraform fails to include one part of the update then that may have downstream impact in the dependency graph, which can be fine if you're intentionally doing it but would be confusing if Terraform just did it "by default".

Do you think having the ability to exclude resources from plan, as proposed in #3366, would address your use-case? I'm imagining the following workflow:

  • Run terraform plan and see the error you described.
  • Study the plan and understand why the error occured and decide whether it's ignorable.
  • If it's ignorable, re-run terraform plan with an exclude argument for the resource in question, thus allowing the plan to succeed for all of the remaining resources.

I'm attracted to this solution because it makes the behavior explicit while still allowing you to proceed as you said. It requires you to still do a little more work to understand what is failing and thus what you need to exclude, but once you're sure about it you only need to modify your command line rather than having to potentially rebuild a chunk of your config.

apparentlymart avatar Nov 12 '15 16:11 apparentlymart

I'd agree @jen20, I am primarily looking for the ability to tell TF that it does not need to quit/error out hard. Same on @apparentlymart's comment on default behavior - I agree, this is a specific use case and not meant as a default.

Do you think having the ability to exclude resources from plan, as proposed in #3366, would address your use-case?

I had to re-read that a few times to make enough sense out of how that works (the doc addition helps: Prefixing the resource with ! will exclude the resource. - this is for the -target arg). That is close, but if my understanding is correct, no it would not get me through.

In my nuanced situation, I have an aws_instance resource, and I increased count, and modified user_data. I tell TF to ignore user_data, but #3555 is preventing that from working, and so TF wants to destroy my instance before creating additional ones. All I want is for TF to create more resources that fit the current spec, leaving the existing node alone (I'm changing user_data, just leave it be..) I would like to see the same if I change EBS volumes.

#3366 is to use exclude with -target, which would have TF skip that resource.. which does not help when you want to modify/update the resource TF wants to destroy - TF wants to destroy a resource, and I want that resource both left alone, and included in the plan to apply.

When I found prevent_destroy in the docs, it sounded perfect, except it was clear that it would not work because it would throw an error if it ran into a situation where TF wanted to destroy, but prevent_destroy was enabled. I believe a user should be able to tell TF that hard error/exit can be skipped this time.

ketzacoatl avatar Nov 13 '15 01:11 ketzacoatl

Would it be possible to get an additional flag when calling: terraform plan -destroy [ -keep-prevent-destroy ]

I have the same problem, I have a few EIP associated with some instances. I want to be able to destroy every but keep the EIP for obvious reasons like whitelisting but I get the same kind of problem. I understand what destroy is all about, but in some cases it would be nice getting a warning saying this and that didn't get destroyed because of lifecycle.prevent_destroy = true.

@ketzacoatl exclude would be nice!

mrfoobar1 avatar Nov 16 '15 16:11 mrfoobar1

+1, I need something along these lines as well.

Would #3366 allow you to skip destroying a resource, but modify it instead? My specific use case is that I have a staging RDS instance I want to persist (never be destroyed), but I want the rest of my staging infrastructure to disappear. As a side effect of the staging environment disappearing, I need to modify the security groups on the RDS instance, since it is being deleted.

So, if I had

  • two AWS instances
  • one rds security group
  • one rds instance.

Upon running "terraform destroy -force" I'd see:

  • two AWS instances shutting down
  • one RDS security group disappearing
  • one RDS instance would change to remove the RDS security group associated with it, but the instance itself would persist (but essentially be unreachable).

erichmond avatar Nov 19 '15 04:11 erichmond

Hey folks,

Good discussion here. It does sound like there's enough real world use cases to warrant a feature here.

What about maintaining the current semantics of prevent_destroy and adding a new key called something like skip_destroy indicating: any plan that would destroy this resource should be automatically modified to not destroy it.

Would something like this address all the needs expressed in this thread? If so, we can spec out the feature more formally and get it added.

phinze avatar Dec 03 '15 16:12 phinze

@phinze, that sounds good, yes.. I'd hope that in most cases, TF would be able to let the apply proceed, and let the user flag some resources as being left alone/not destroyed, and your proposal seems to provide the level of control needed, while retaining sensible semantics.

ketzacoatl avatar Dec 03 '15 18:12 ketzacoatl

:+1: to what @ketzacoatl said

erichmond avatar Dec 03 '15 20:12 erichmond

:+1: to what @phinze proposed. This would be very convenient for me right now. :)

trmitchell7 avatar Dec 22 '15 23:12 trmitchell7

I keep running in to this, I would like the ability for TF to only create if it does not exist and do not delete it. I would like to keep some ebs or rds data around and keep the rest of my stack as ephemeral (letting TF apply/destroy at will).

Currently been doing this with different projects/directories. But it would be nice to keep the entire stack together as one piece.

I too thought the prevent_destroy would not create an error and have been hacking my way around it quite a bit :(

chadgrant avatar Jan 09 '16 19:01 chadgrant

:+1: to what @phinze said. During apply, I want it to be created but ignored during destroy. Currently, I have to explicitly define the rest of the targets just to ignore 1 s3 resource.

tsailiming avatar Mar 14 '16 16:03 tsailiming

+1 - just ran into this. Another example are key pairs. I want to create (import) them if they don't exist, but if I destroy, I don't want to delete the keypair as other instances may be using the shared keypair.

Is there a way around this for now?

gservat avatar Mar 27 '16 12:03 gservat

Yes, split your terraform project into multiple parts.

Example:

  • base
  • core (like persistent data)
  • application stack

Le dimanche 27 mars 2016, gservat [email protected] a écrit :

+1 - just ran into this. Another example are key pairs. I want to create them if they don't exist, but if I destroy, I don't want to delete the keypair as other instances may be using the shared keypair.

Is there a way around this for now?

— You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/hashicorp/terraform/issues/3874#issuecomment-202054221

Sent from Gmail Mobile

mrfoobar1 avatar Mar 28 '16 20:03 mrfoobar1

this is a must for me to be able to work with the digitalocean_volume

cescoferraro avatar Sep 29 '16 03:09 cescoferraro

+1

colutti avatar Oct 05 '16 17:10 colutti

Changing the flags here to enhancement, but still agree this is a good idea.

mitchellh avatar Oct 27 '16 16:10 mitchellh

+1

bbakersmith avatar Dec 08 '16 17:12 bbakersmith

Is this being looked at? I can't imagine there are many use cases that would NOT benefit from it. One example is 'Anyone using key pairs ever'.

jbrown-rp avatar Dec 14 '16 17:12 jbrown-rp

This is absolutely one of the banes of my life too. I've got dozens of resources I want to preserve from accidental overwrites - such as DynamoDB tables. A pair of flags for:

  • Keeping items that you prevent_destroy on (i.e. Don't delete the users from DynamoDB, ever - just skip it during a routine destroy)
  • Destroy, force.

The flags could be something explicit like:

  • terraform destroy --skip-protected
  • terraform destroy --force-destroy-protected

This would allow us to have the desired behaviour and only require an operator intervention in the case where the resource still exists, but is not mutatable into the target state during a terraform apply (i.e. If you've still got the same table, but the keys are now incompatible or some other potentially destructive update).

steve-gray avatar Jan 04 '17 05:01 steve-gray

Here's the use case we'd like this for: we have a module that we can use either for production (where some resources like Elastic IPs should not be accidentally deleted) or for running integration tests (where all resources should be destroyed afterwards).

Because of #10730/#3116, we can't set these resources to be conditionally prevent_destroy, which would be the ideal solution. As a workaround, we'd be happy to have our integration test scripts run terraform destroy --ignore-prevent-destroy if that existed.

glasser avatar Jan 19 '17 02:01 glasser

This would defintely be a useful feature.

I've been using terraform for less than a month and ran into this required feature in order to protect DNS Managed zone ... everything else in my infrastucture is transient but dealing with a new DNS zone comes with it computed ( potentially new ) Name Servers on what is a delegated zone, and this would introduce an unnecessary manual step to update the parent DNS managed zone - not to mention the DNS change time delay permeating making any auto testing have a much higher latency.

Reading above looks like the workaround is to split my project into different parts. Not sure I can pass in a resource from one project into another ... but I guess I can use variables in worst case scenario.

andyjcboyle avatar Jan 24 '17 12:01 andyjcboyle

I'm hitting a slightly different use case with Vault. I'm not 100% sure whether this belongs here. Might be best handled in the Vault resource itself.

Example:

resource "vault_generic_secret" "github_auth_enable" {
  path      = "sys/auth/github"
  data_json = "...some json..."
}

resource "vault_generic_secret" "github_auth_config" {
  path      = "auth/github/config"
  data_json = "...some json..."
  depends_on = ["vault_generic_secret.github_auth_enable"]
}

The problem is that the 'auth/github/config' path does not even support the delete operation: the entire 'auth/github' prefix gets wiped as soon as 'sys/auth/github' is deleted. Not only does this result in an error, but also a broken state: a subsequent apply would assume that key still exists.

kaii-zen avatar Jan 25 '17 01:01 kaii-zen

So my instance and issue would be things like rapid development and say docker_image / docker_container usage.

I set prevent_destroy = true on the docker_image resources because I don't want terraform deleting the image from my disk so that I can rapidly destroy/create and run through development. When I set that, now I have to use a fancy scripting method to execute my targeted destroy list to destroy everything BUT the docker_image resources:

TARGETS=$(for I in $(terraform state list | grep -v docker_image); do echo " -target $I"; done); echo terraform destroy $TARGETS

What I would like would be two methods. One that allows me to still succeed because the plan says "hey, don't destroy this", and if I am bold and say -force what I mean is "yeah... I said to not destroy it, but I'm forcing you to do it anyway... OBEY ME!"

mengesb avatar Feb 24 '17 23:02 mengesb

Any update on this. This has been open for 1.5 years and it is not fun to try to organize terraform around this shortcoming.

The workaround for this is pretty ridiculous, I have a separate modules for "persistent", "ephemeral" in every project, but still need to use target or some way of skipping of and not running destroying modules that are persistent (or they spew errors).

bradenwright avatar May 22 '17 22:05 bradenwright

Is there any work being done on this? It feels like this feature "prevent_destroy" is designed as "annoy you because you put this flag in if you want to destroy resources" rather than... destroy what I want to destroy except for the things I don't want to destroy, notated by the "prevent_destroy" flag. Use case 1 in the original post seems like a silly use case because it's only designed to alert you and error out. In reality, adding prevent_destroy on a resource actually seems to mean prevent destroy on your entire infrastructure, unless you want to muddle together a fancy, hacky script to create a series of target flags.

Not a fun way to manage infrastructure that needs to have persistent and non-persistent pieces.

HighwayofLife avatar Jun 06 '17 22:06 HighwayofLife

Agree: terraform destroy -force -force

ghost avatar Jul 17 '17 22:07 ghost

To echo what @andyjcboyle said; when creating an aws_route53_zone you get a delegation set of 4 random name servers. I use the zone to define a subdomain, my domain is however not managed by terraform and I must insert the ns records manually. If I want to teardown my environment and then redeploy it (which I do often) I must manually reinsert the new name servers.

It would be much nicer if I could have lifecycle flag like ignore_destroy/skip_destroy that allowed everything else in the plan to be destroyed but not the marked resource.

This seems like a core ability that terraform is missing, I would really like to see this added soon.

Harrison-Miller avatar Jul 17 '17 23:07 Harrison-Miller

Hashicorp does not want this. It's the only explanation why it has not been implemented yet. On Mon, 17 Jul 2017 at 20:12 Verrazano [email protected] wrote:

To echo what @andyjcboyle https://github.com/andyjcboyle said; when creating an aws_route53_zone you get a delegation set of 4 random name servers. I use the zone to define a subdomain, my domain is however not managed by terraform and I must insert the ns records manually. If I want to tear down my environment and then redeploy it (which I do often) I must manually reinsert the new name servers.

It would be much nicer if I could have lifecycle flag like ignore_destroy/skip_destroy that allowed everything else in the plan to be destroyed but not that.

This seems like a core ability that terraform is missing, I would really like to see this added soon.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/hashicorp/terraform/issues/3874#issuecomment-315911357, or mute the thread https://github.com/notifications/unsubscribe-auth/AF-FE8OKlQq_eWj20CjsJon3Us47o4oFks5sO-pVgaJpZM4Gg173 .

cescoferraro avatar Jul 22 '17 18:07 cescoferraro

This feature was added originally more as a "prevent replace", to avoid accidentally changing a "forces new resource" attribute on a critical object.

Its current interaction with terraform destroy is not a critical part of that, so I think it would be reasonable to strike a compromise here:

  • If a diff contains a replacement of a prevent_destroy instance, that is a fatal error since there is no way to make the changes indicated without violating the constraint.
  • If the diff would contain just a destroy for such an instance, this produces a warning explaining that the instance can't be destroyed but produces a diff that takes all of the other requested actions. The warning explains that removing the flag is required to actually destroy the resource.

I think as long as that warning is present there is no harm in allowing the operation to continue. Just need to make sure that Terraform explains its behavior since we don't want people to think they destroyed everything but still have something running.

apparentlymart avatar Jul 22 '17 19:07 apparentlymart

That doesn't satisfy the use case in my comment above (which is honestly really an argument for the ability to set prevent_destroy conditionally rather than for this precise feature).

glasser avatar Jul 23 '17 03:07 glasser