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

Unable to use var for ignore_changes or prevent_destroy #10730

Closed
djandruczyk opened this issue Dec 14, 2016 · 7 comments
Closed

Unable to use var for ignore_changes or prevent_destroy #10730

djandruczyk opened this issue Dec 14, 2016 · 7 comments

Comments

@djandruczyk
Copy link

Terraform Version

Terraform v0.7.13

Affected Resource(s)

  • aws_resource
    lifecycle block
    ignore_changes and prevent_destroy arguments

Terraform Configuration Files

lifecycle block within aws_instance

lifecycle {
prevent_destroy = "${var.prevent_destroy}"
ignore_changes = "${var.ignore_changes}"
}

vars.tf
variable "prevent_destroy" {
description = "Block destruction of this resource, typically for DB boxes"
default = true
}
variable "ignore_changes" {
description = "list of strings to ignore differences of"
type = "list"
default = [ "ami", "user_data" ]
}
NOTE: Tried with 'true' both quoted and unquoted, same issue

Expected Behavior

should have applied with no error, ignore changes in the ami or user_data variables

Actual Behavior

Error parsing lifecycle for aws_instance[gis]: 2 error(s) decoding:

  • 'ignore_changes': source data must be an array or slice, got string
  • cannot parse 'prevent_destroy' as bool: strconv.ParseBool: parsing "${var.prevent_destroy}": invalid syntax
    exit status 1

Steps to Reproduce

Please list the steps required to reproduce the issue, for example:

  1. terraform plan

NOTE: not using variables and using:
lifecycle {
prevent_destroy = true
ignore_changes = [ "ami", "user_data" ]
}
in main.tf results in no error and correct behavior (ignoring changes in AMI anduser_data)

@mitchellh
Copy link
Contributor

We don't support variables in those since they need to be parsed and handled very early on in Terraform (before interpolations can be processed). We hope to loosen this requirement one day.

In the mean time, I'm going to change the issue to be a bug in order to add better validation and error messages to this case.

@gdubicki
Copy link

gdubicki commented Jan 8, 2017

It sucks that you can't use a variable here as after you introduced create_timeout and then #10823 got resolved, we have to edit each of our MANY GCE google_compute_instances with adding create_timeout to ignore_changes... It's not a lot of work with find and sed, but it's ugly. So please consider implementing this soon.

@glasser
Copy link
Contributor

glasser commented Jan 19, 2017

Is this a duplicate of #3116?

@adamdecaf
Copy link
Contributor

adamdecaf commented Mar 21, 2018

#3116 is locked, otherwise I would have replied over there. These two issues do seem to be duplicates.

I was trying to use prevent_destroy to protect some important resources I don't want accidentally deleted and ran into this bug (and well #3116).

@zero-below offers a potential solution in that you can create a random_id which allows you to protect any given resource.

The problem is that I'd still like to be able to really override prevent_destroy, but not accidently destroy resources. We need an escape hatch.

It turns out you can terraform state rm random_id.protector and then you've got the ability to taint or destroy the protected resources.

$ terraform apply 
null_resource.foo[1]: Creating...
null_resource.foo[0]: Creating...
null_resource.foo[1]: Provisioning with 'local-exec'...
null_resource.foo[0]: Provisioning with 'local-exec'...
null_resource.foo[1] (local-exec): Executing: ["/bin/sh" "-c" "date"]
null_resource.foo[0] (local-exec): Executing: ["/bin/sh" "-c" "date"]
null_resource.foo[0] (local-exec): Wed Mar 21 14:11:42 CDT 2018
null_resource.foo[0]: Creation complete after 0s (ID: 4489514678136010214)
null_resource.foo[1] (local-exec): Wed Mar 21 14:11:42 CDT 2018
null_resource.foo[1]: Creation complete after 0s (ID: 3245413214449441631)
random_id.protector: Creating...
  b64:         "" => "<computed>"
  b64_std:     "" => "<computed>"
  b64_url:     "" => "<computed>"
  byte_length: "" => "8"
  dec:         "" => "<computed>"
  hex:         "" => "<computed>"
  keepers.%:   "" => "1"
  keepers.ids: "" => "4489514678136010214,3245413214449441631"
random_id.protector: Creation complete after 0s (ID: fk_WthGJY6I)

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
# Verify we can't destroy 
$ terraform destroy -target null_resource.foo[0] 
null_resource.foo[0]: Refreshing state... (ID: 4489514678136010214)

Error: Error running plan: 1 error(s) occurred:

* random_id.protector: random_id.protector: the plan would destroy this resource, but it currently has lifecycle.prevent_destroy set to true. To avoid this error and continue with the plan, either disable lifecycle.prevent_destroy or adjust the scope of the plan using the -target flag.

$ terraform destroy 
null_resource.foo[1]: Refreshing state... (ID: 3245413214449441631)
null_resource.foo[0]: Refreshing state... (ID: 4489514678136010214)
random_id.protector: Refreshing state... (ID: fk_WthGJY6I)

Error: Error running plan: 1 error(s) occurred:

* random_id.protector: random_id.protector: the plan would destroy this resource, but it currently has lifecycle.prevent_destroy set to true. To avoid this error and continue with the plan, either disable lifecycle.prevent_destroy or adjust the scope of the plan using the -target flag.
# Delete our protector 
$ terraform state rm random_id.protector
1 items removed.
Item removal successful.

$ terraform plan 
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

null_resource.foo[0]: Refreshing state... (ID: 4489514678136010214)
null_resource.foo[1]: Refreshing state... (ID: 3245413214449441631)

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + random_id.protector
      id:          <computed>
      b64:         <computed>
      b64_std:     <computed>
      b64_url:     <computed>
      byte_length: "8"
      dec:         <computed>
      hex:         <computed>
      keepers.%:   "1"
      keepers.ids: "4489514678136010214,3245413214449441631"


Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
# Taint a resource 
$ terraform taint null_resource.foo.0
The resource null_resource.foo.0 in the module root has been marked as tainted!

$ terraform plan 
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

null_resource.foo[0]: Refreshing state... (ID: 4489514678136010214)
null_resource.foo[1]: Refreshing state... (ID: 3245413214449441631)

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
-/+ destroy and then create replacement

Terraform will perform the following actions:

-/+ null_resource.foo[0] (tainted) (new resource required)
      id:          "4489514678136010214" => <computed> (forces new resource)

  + random_id.protector
      id:          <computed>
      b64:         <computed>
      b64_std:     <computed>
      b64_url:     <computed>
      byte_length: "8"
      dec:         <computed>
      hex:         <computed>
      keepers.%:   <computed>


Plan: 2 to add, 0 to change, 1 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

$ terraform apply 
null_resource.foo[1]: Refreshing state... (ID: 3245413214449441631)
null_resource.foo[0]: Refreshing state... (ID: 4489514678136010214)
null_resource.foo[0]: Destroying... (ID: 4489514678136010214)
null_resource.foo[0]: Destruction complete after 0s
null_resource.foo[0]: Creating...
null_resource.foo[0]: Provisioning with 'local-exec'...
null_resource.foo[0] (local-exec): Executing: ["/bin/sh" "-c" "date"]
null_resource.foo[0] (local-exec): Wed Mar 21 14:12:03 CDT 2018
null_resource.foo[0]: Creation complete after 0s (ID: 6511311000836372604)
random_id.protector: Creating...
  b64:         "" => "<computed>"
  b64_std:     "" => "<computed>"
  b64_url:     "" => "<computed>"
  byte_length: "" => "8"
  dec:         "" => "<computed>"
  hex:         "" => "<computed>"
  keepers.%:   "" => "1"
  keepers.ids: "" => "6511311000836372604,3245413214449441631"
random_id.protector: Creation complete after 0s (ID: bQx-fJV2ywQ)

Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
# Because we re-created with prevent_machine_destroy=true we can't destroy the new resources. 
$ terraform destroy
null_resource.foo[1]: Refreshing state... (ID: 3245413214449441631)
null_resource.foo[0]: Refreshing state... (ID: 6511311000836372604)
random_id.protector: Refreshing state... (ID: bQx-fJV2ywQ)

Error: Error running plan: 1 error(s) occurred:

* random_id.protector: random_id.protector: the plan would destroy this resource, but it currently has lifecycle.prevent_destroy set to true. To avoid this error and continue with the plan, either disable lifecycle.prevent_destroy or adjust the scope of the plan using the -target flag.
variable "prevent_machine_destroy" {
  description = "Set lifecycle.prevent_destroy on machines"
  default = true
}

resource "random_id" "protector" {
  count = "${ var.prevent_machine_destroy ? 1 : 0 }"
  byte_length = 8
  keepers = {
    ids = "${join(",", null_resource.foo.*.id)}"
  }
  lifecycle {
    prevent_destroy = true
  }
}

resource "null_resource" "foo" {
  count = "2"

  provisioner "local-exec" {
    command = "date"
  }
}

@apparentlymart apparentlymart added config and removed core labels Nov 7, 2018
@MMarulla
Copy link

MMarulla commented Jan 9, 2019

I'd also like to see variables usable in lifecycle blocks, not for prevent_destroy, but for AMI updates. It would be nice to have ignore_changes = ["ami"] set so that Amazon releasing a new AMI doesn't surprise me, then setting an "ok_to_update_ami" variable in the tfvars file when I am ready to have all my instances rebuilt with the latest AMI.

@teamterraform
Copy link
Contributor

Hi all!

Looking back at the history here, it seems that the intended distinction between this issue and #3116 is that #3116 represents the feature request of supporting dynamic ignore_changes and prevent_destroy values while this issue represented the bug that Terraform was producing bad error messages when reporting that it isn't supported today.

Since Terraform 0.12 includes specialized error messages for these scenarios, we're going to close out this one and leave #3116 to represent the feature request.

@ghost
Copy link

ghost commented Sep 27, 2019

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.

@ghost ghost locked and limited conversation to collaborators Sep 27, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants