terraform icon indicating copy to clipboard operation
terraform copied to clipboard

destroy --force asking for user input when variables have values

Open gravelander opened this issue 6 years ago • 26 comments

When destroying infrastructure with terraform destroy --force the variable asks for input, although the input does not matter. I don't need to type in its value for it to be destroyed; any string works.

This is re: #2443 which has been locked to contributors only.

The code below is outdated/throws errors but still creates/destroys as planned. The new v0.12.17 syntax updates broke this hard. >:(

Terraform Version

Terraform v0.12.17

Terraform Configuration Files

variable "HostName" {
  type = string
  description = "Input desired hostname"
  }

provider "aws" {
  profile    = "default"
  region     = "us-east-1"
  access_key = "myaccesskeyhere"
  secret_key = "mysecretkeyhere"
}
resource "aws_instance" "example" {
  ami           = "ami-04b9e92b5572fa0d1"
  instance_type = "t2.micro"
  key_name      = "AWS-Ultra"
  security_groups = ["primary"]
  tags ={
    Name = "${var.HostName}"
  }
  provisioner "remote-exec"{
    inline = [
      "sudo hostnamectl set-hostname ${var.HostName}",
      "sudo adduser hutch --gecos '' --disabled-password",
      "usermod -aG sudo hutch",
      "sudo mkdir /home/hutch/.ssh",
      "sudo cp /home/ubuntu/.ssh/authorized_keys /home/hutch/.ssh",
      "sudo chown -R hutch:hutch /home/hutch/.ssh",
      "echo 'hutch ALL=(ALL:ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/hutch"
    ]
  }
  connection {
    type     = "ssh"
    host     = self.public_dns
    user     = "ubuntu"
    private_key = "/home/hutch/.ssh/AWS-Ultra.pem"
  }

Expected Behavior

Don't ask for input on variable, just delete the infrastructure.

Actual Behavior

var.HostName
  Input desired hostname

  Enter a value:

is printed. Input does not matter, does not require correct hostname.

Steps to Reproduce

  1. Create infrastructure with this script: terraform apply
  2. On prompt, input hostname
  3. terraform destroy --force

References

  • #2443 "destroy -force should not ask for user input when variables have values or defaults"

gravelander avatar Dec 03 '19 19:12 gravelander

@danieldreier per your request on #2443

gravelander avatar Dec 03 '19 19:12 gravelander

thanks @xelarate86! I've put it on my list to reproduce. I'll follow up when I've tried.

danieldreier avatar Dec 05 '19 19:12 danieldreier

Just taking beginner course in TF and ran into this. My main.tf is —

provider "aws" {
    region="us-west-1"
}

variable "inputname" {
    type = string
    description = "set the VPC name"
}

resource "aws_vpc" "myvpc" {
    cidr_block = "10.0.0.0/16"

    tags = {
        Name = var.inputname
    }
}

CLI output is —

% terraform apply --var 'inputname=asdf'

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:

  # aws_vpc.myvpc will be created
  + resource "aws_vpc" "myvpc" {
      + arn                              = (known after apply)
      + assign_generated_ipv6_cidr_block = false
      + cidr_block                       = "10.0.0.0/16"
      + default_network_acl_id           = (known after apply)
      + default_route_table_id           = (known after apply)
      + default_security_group_id        = (known after apply)
      + dhcp_options_id                  = (known after apply)
      + enable_classiclink               = (known after apply)
      + enable_classiclink_dns_support   = (known after apply)
      + enable_dns_hostnames             = (known after apply)
      + enable_dns_support               = true
      + id                               = (known after apply)
      + instance_tenancy                 = "default"
      + ipv6_association_id              = (known after apply)
      + ipv6_cidr_block                  = (known after apply)
      + main_route_table_id              = (known after apply)
      + owner_id                         = (known after apply)
      + tags                             = {
          + "Name" = "asdf"
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_vpc.myvpc: Creating...
aws_vpc.myvpc: Creation complete after 2s [id=vpc-0b773ef14b2245944]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
% terraform destroy -force              
var.inputname
  set the VPC name

  Enter a value: qwer

aws_vpc.myvpc: Refreshing state... [id=vpc-0b773ef14b2245944]
aws_vpc.myvpc: Destroying... [id=vpc-0b773ef14b2245944]
aws_vpc.myvpc: Destruction complete after 1s

Destroy complete! Resources: 1 destroyed.

This is really surprising, as it asked for input, then ignored it and happily read the TF state instead, destroying a VPC that did not match the given input.

anfedorov avatar Sep 13 '20 02:09 anfedorov

Same issue here

watcher00090 avatar Jan 11 '21 22:01 watcher00090

Same for me.

Terraform asks me for variables, I can type anything (just have to respect type string, etc.) and it works since vars are already in state.

patrick-mota avatar Mar 14 '21 00:03 patrick-mota

I also just came across this weird behaviour in Terraform v1.0.3 As @xelarate86 already mentioned, omitting the default parameter in the variable resource causes terraform to ask for a value instead of just deleting the resource.

variable "foo" {
  type = string
}

resource "local_file" "foo" {
    content = "${var.foo}"
    filename = "${path.module}/foo.bar"
}

The expected behaviour would be that destroy does not ask for a value as it destroys the existing resource defined in the .tfstate instead of asking for a value that is not used anyway. However, the actual behaviour differs:

$ terraform apply -auto-approve
var.foo
  Enter a value: foo


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # local_file.foo will be created
  + resource "local_file" "foo" {
      + content              = "foo"
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./foo.bar"
      + id                   = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.
local_file.foo: Creating...
local_file.foo: Creation complete after 0s [id=0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
% terraform destroy -auto-approve
var.foo
  Enter a value: WhyIsSettingThisValueNecessary?

local_file.foo: Refreshing state... [id=0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  - destroy

Terraform will perform the following actions:

  # local_file.foo will be destroyed
  - resource "local_file" "foo" {
      - content              = "foo" -> null
      - directory_permission = "0777" -> null
      - file_permission      = "0777" -> null
      - filename             = "./foo.bar" -> null
      - id                   = "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33" -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.
local_file.foo: Destroying... [id=0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33]
local_file.foo: Destruction complete after 0s

Destroy complete! Resources: 1 destroyed.

As expected the resource is deleted, however, a variable value had to be set during terraform destroy. Setting the value is unnecessary as it is not applied before deletion anyway and the goal was to destroy the existing resources in their current state. hence why the input prompt comes as a bit of a surprise.

In actual projects it might not be desired to set default values for certain variables. Similarly, a .tfvars file is not always necessary.

Making the user define a variable value during the deletion process which has effectively no use seems cumbersome.

@danieldreier is there any chance this behaviour will be changed any time soon?

I3urny avatar Aug 02 '21 14:08 I3urny

I have the same issue but i have to type the correct value to destroy the infrastructure on Terraform v1.0.5 (on linux_amd64 + provider registry.terraform.io/hashicorp/aws v3.56.0) . Here's a part of the Terraform main.tf file:

resource "aws_security_group" "SG_Ansible" {
  name        = "Ansible-brandonrodriguezc"
  description = "Ansible target apps"
  vpc_id      = data.aws_vpc.psl_vpc.id

  ingress {
    description      = "From ansible master to this new host"
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    cidr_blocks      = ["${var.ip}/32"]
    ipv6_cidr_blocks = ["::/0"]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
}

And a piece of the variable.tf file:

variable "ip"{
    description = "Ip of the ansible master to add it to the security group"
    type = string
}

When i try to destroy it, it asks for the ip variable and the input is incorrect it stops the destroy process:

[root@b7c1c904a293 TerraformTest]# terraform destroy
var.ip
  Ip of the current host to add it to the security group

  Enter a value: yes

module.Ansible-target.aws_security_group.SG_Ansible: Refreshing state... [id=sg-02b383a605894cb26]
╷
│ Error: "yes/32" is not a valid CIDR block: invalid CIDR address: yes/32
│
│   with module.Ansible-target.aws_security_group.SG_Ansible,
│   on .terraform/modules/Ansible-target/ASG-SG-LC/main.tf line 5, in resource "aws_security_group" "SG_Ansible":
│    5: resource "aws_security_group" "SG_Ansible" {
│
╵
╷
│ Error: "yes/32" is not a valid CIDR block: invalid CIDR address: yes/32
│
│   with module.Ansible-target.aws_security_group.SG_Ansible,
│   on .terraform/modules/Ansible-target/ASG-SG-LC/main.tf line 5, in resource "aws_security_group" "SG_Ansible":
│    5: resource "aws_security_group" "SG_Ansible" {
│
╵
[root@b7c1c904a293 TerraformTest]#

But if the input is correct it continues with the destroy process:

[root@b7c1c904a293 TerraformTest]# terraform destroy
var.ip
  Ip of the current host to add it to the security group

  Enter a value: 34.139.48.058            

module.Ansible-target.aws_security_group.SG_Ansible: Refreshing state... [id=sg-02b383a605894cb26]
module.Ansible-target.aws_launch_configuration.Ansible-brandonrodriguezc: Refreshing state... [id=terraform-20210827140741740900000001]
module.Ansible-target.aws_autoscaling_group.ASG-Ansible: Refreshing state... [id=ASG_Ansible_brandonrodriguezc]

The expected behavior is to destroy the infrastructure without asking the variables used in the apply process

BrandonRodriguezC avatar Aug 27 '21 14:08 BrandonRodriguezC

I have come across the same issue and it is March 2022 so it means this has not been resolved. It just does not make any sense for Terraform to ask us all the variables again when we are asking it to 'destroy'. I have a Azure VM template with five variables input and now I want to destroy the VM but it is asking me all the variables again and will not take 'Enter' or any other value.

`[ash@rhel8 azurevm]$ terraform destroy var.resource_group_name Resource Group name

Enter a value: ashredhatt

var.user_name Enter your username:

Enter a value:

var.user_password Enter your Password:

Enter a value:

var.vm_name Enter your VM name:

Enter a value:

........ ╷ │ Error: "name" must not be empty │ │ with azurerm_windows_virtual_machine.rg, │ on main.tf line 60, in resource "azurerm_windows_virtual_machine" "rg": │ 60: name = var.vm_name │ ╵ ╷ │ Error: expected "admin_username" to not be an empty string, got │ │ with azurerm_windows_virtual_machine.rg, │ on main.tf line 64, in resource "azurerm_windows_virtual_machine" "rg": │ 64: admin_username = var.user_name │ ╵ ╷ │ Error: Public Ip Address: (Name "_pip" / Resource Group "ashredhatt") was not found │ │ with data.azurerm_public_ip.rg, │ on main.tf line 83, in data "azurerm_public_ip" "rg": │ 83: data "azurerm_public_ip" "rg" { │ ╵ [ash@rhel8 azurevm]$ `

asharsidd avatar Mar 03 '22 00:03 asharsidd

I am also running into this issue.

ksalman avatar May 08 '22 23:05 ksalman

But if the input is correct it continues with the destroy process

is asking me all the variables again and will not take 'Enter' or any other value

Both of those examples of throwing errors are implemented as ValidateFunc within the respective providers for those properties and not directly related to the issue of being prompted at all.

You can see why it prompts for input from the help docs (it actually runs apply)

Usage: terraform [global options] destroy [options]

  Destroy Terraform-managed infrastructure.

  This command is a convenience alias for:
      terraform apply -destroy

Also note: #27681

OneCricketeer avatar May 27 '22 20:05 OneCricketeer

Same issue for me.

The best solution would be to be able to pass the plan as a destroy variable, something like this...

terraform plan -out test.plan

var.HostName
  Input desired hostname

  Enter a value: host1
..........  

terraform destroy test.plan

metalboz avatar Jun 15 '22 08:06 metalboz

Just hit the same behavior.

It's a bit weird to ask considering that the variable value doesn't matter.

LaurentDumont avatar Oct 10 '22 17:10 LaurentDumont

Also having this issue. Variables' values should not be asked for since they do not matter at the time of destroying

victorrgez avatar Nov 15 '22 18:11 victorrgez

still facing this issue with TF version 1.3.6

tmassoth avatar Dec 23 '22 21:12 tmassoth

still facing this issue with TF version 1.3.7

luis-fnogueira avatar Jan 31 '23 19:01 luis-fnogueira

still facing this issue with TF version 1.3.7

daxpate avatar Feb 28 '23 16:02 daxpate

still facing this issue with TF version 1.3.9

rubber-ant avatar Mar 05 '23 23:03 rubber-ant

still facing this issue with TF version 1.4.2

saymolet avatar Mar 28 '23 20:03 saymolet

Still an issue. Will this ever be resolved?

georgeollis avatar May 12 '23 10:05 georgeollis

Still an issue with TF version 1.4.6

shfletcher avatar May 19 '23 15:05 shfletcher

Still seems like an ongoing issue. I have defined a variable to take user input for a CIDR block as follows:

resource "aws_security_group" "test_sg" {
    name = "test_sg"
    description = "This allows SSH, HTTP and MySql"
    vpc_id = "${aws_vpc.test_vpc.id}"

    ingress {
        description = "SSH"
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["${var.ip_address}/32"]
    }
}

However, when trying to destroy, if I enter a blank value in the IP address input, the destruction fails:

var.ip_address
  Your ip address for adding to the security group

  Enter a value: 

var.owner
  Enter a value: 

var.project
  Enter a value: 

aws_vpc.test_vpc: Refreshing state... [id=vpc-078041a919c110583]
aws_internet_gateway.test_ig: Refreshing state... [id=igw-058c7d4e3352757aa]
╷
│ Error: "/32" is not a valid CIDR block: invalid CIDR address: /32
│ 
│   with aws_security_group.test_sg,
│   on sg.tf line 3, in resource "aws_security_group" "test_sg":
│    3: resource "aws_security_group" "test_sg" {
│ 

It will proceed if the correct IP address is mentioned. TF version 1.4.6

aiah7894 avatar Jun 09 '23 16:06 aiah7894

still an issue

dss010101 avatar Aug 06 '23 20:08 dss010101

Still an issue with Terraform v1.5.6

rmsys avatar Sep 01 '23 14:09 rmsys

Thanks for the update! This is likely to remain an issue until this specific issue is closed, no need to post these updates (until this issue is closed).

Please do 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. Thanks again for the feedback!

crw avatar Sep 07 '23 18:09 crw

To work around this, I add all of my input variables as output variables, with the names prepended by TF_VAR_. Then I can run eval $(terraform output | sed -nr '/TF_VAR_/ s/(TF_VAR_.*) = (.*)/export \1=\2/p') to set all the same input variables for the destroy. It's annoying that Terraform doesn't just retain this information automatically, though.

DrGerbil avatar Sep 13 '23 05:09 DrGerbil

Just run into this. As a hackish workaround, I use local-exec provisioners to save the inputs in an .auto.tfvars file at the apply stage and then auto-load and delete the file at the destroy stage.

resource "null_resource" "manage_inputs" {

  provisioner "local-exec" {
    command = <<-EOT
		printf "instances = %s\ncores = %s\ngigabytes = %s\n" "${var.instances}" "${var.cores}" "${var.gigabytes}" > vms.auto.tfvars
	EOT
    when = create
  }

  provisioner "local-exec" {
    command = "rm -f vms.auto.tfvars"
    when = destroy
  }

}

ArtemVakhitov avatar Oct 02 '24 12:10 ArtemVakhitov