hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.

Home Page:https://www.terraform.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Running an empty destroy with an interpolated output in module fails

dvishniakov opened this issue · comments

Seems like another scenario when TF fail to run destroy. Reproducible on empty setup even without creating resources.
Since it's reproducible without provider credentials, is it possible to add tests?
#17768 fixed code but didn't add any tests

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request

Note: this block was copy-pasted from terraform-provider-aws

Terraform Version

Affected: 
0.11.4, 0.11.5
0.11.6, 0.11.7 (output differs a little bit from 0.11.4, 0.11.5)

Terraform Configuration Files

main.tf

provider "aws" {
  region  = "us-east-1"
  version = "~> 1.14"
}
terraform {
  required_version = ">= 0.11.0"
}
module "cluster" {
  source = "./cluster"
}
output "main_cluster_output" {
  value = "${module.cluster.cluster_output}" # produces an error
}
output "main_app_output" {
  value = "${module.cluster.app_output}"
}

# The same, below - works

resource "aws_ecs_cluster" "default_cluster" {
  name = "cluster_name"
}
output "cluster_output" {
  value = {
    "cluster_id"   = "${aws_ecs_cluster.default_cluster.id}"
    "cluster_name" = "${aws_ecs_cluster.default_cluster.name}"
  }
}

cluster/cluster-main.tf

resource "aws_ecs_cluster" "default_cluster" {
  name = "cluster_name"
}
resource "aws_ecr_repository" "default_ecr" {
  name = "test-bug"
}
output "cluster_output" {
  value = {
    "cluster_id" = "${aws_ecs_cluster.default_cluster.id}"

    # "repository_url" = "${aws_ecr_repository.default_ecr.repository_url}" # if you uncomment this line, error from it hides default_cluster errors
    "cluster_name" = "${aws_ecs_cluster.default_cluster.name}"
  }
}
output "app_output" {
  value = {
    "repository_url" = "${aws_ecr_repository.default_ecr.repository_url}"
  }
}

Debug Output

https://gist.github.com/dvishniakov/58ab1fef3126665d85c63f13803b3b05

Expected Behavior

No error output, successful output, exit with code 0

Actual Behavior

Error: Error applying plan:

TF 0.11.4, 0.11.5,

3 error(s) occurred:

  • module.cluster.output.cluster_output: variable "default_cluster" is nil, but no error was reported
  • output.cluster_output: variable "default_cluster" is nil, but no error was reported
  • module.cluster.output.app_output: variable "default_ecr" is nil, but no error was reported

TF 0.11.6, 0.11.7

2 error(s) occurred:

  • module.cluster.output.cluster_output: variable "default_cluster" is nil, but no error was reported
  • module.cluster.output.app_output: variable "default_ecr" is nil, but no error was reported

Steps to Reproduce

  1. terraform init
  2. terraform plan -input=false --destroy -out=terraform.plan
  3. terraform apply -input=false terraform.plan

References

#17691, probably partially fixed by @jbardin in #17768

Have the same issue on v0.11.5:

resource "aws_subnet" "mysubnet" {
  vpc_id     = "${var.vpc_id}"
  cidr_block = "10.43.${var.cidr_range}.0/24"

  tags = {
    Name = "${var.tag}"
  }
}

output "subnet_id" {
  value = "${aws_subnet.mysubnet.id}"
}

Error occurs during destroy If apply was failed.
Does anyone have a workaround, I tried this:

output "subnet_id" {
  value = "${aws_subnet.mysubnet ? aws_subnet.mysubnet.id : ""}"
}

but it doesn't work with Error reading config for output subnet_id: aws_subnet.mysubnet: resource variables must be three parts: TYPE.NAME.ATTR in

Cool, after couple of hours I found the workaround:

Inspired by #16681 (comment)

We don't need several aws_subnet objects, but we can interpret it as an array with one element!

So it works:

resource "aws_subnet" "mysubnet" {
  count      = 1
  vpc_id     = "${var.vpc_id}"
  cidr_block = "10.43.${var.cidr_range}.0/24"

  tags = {
    Name = "${var.tag}"
  }
}

output "subnet_id" {
  value = "${element(concat(aws_instance.mysubnet.*.public_ip, list("")), 0)}"
}

Don't forget to fix references to this resources in another places in my case from "${aws_subnet. mysubnet.id}" to "${aws_subnet.mysubnet.0.id}"

I'm seeing this as well on 0.11.7 with:

* provider.archive: version = "~> 1.0"
* provider.aws: version = "~> 1.28"
* provider.consul: version = "~> 2.1"
* provider.datadog: version = "~> 1.0"
* provider.null: version = "~> 1.0"
* provider.template: version = "~> 1.0"

In my case the initial destroy failed after actually deleting everything; I'm left with an empty state file but every destroy fails with these errors for interpolated outputs:

* module.bento-githook-proxy.output.hook_url: Resource 'aws_api_gateway_rest_api.rest_api' does not have attribute 'id' for variable 'aws_api_gateway_rest_api.rest_api.id'
* module.bento_iam_role.output.ip_arn: variable "bento" is nil, but no error was reported
* module.bento_iam_role.output.arn: variable "bento" is nil, but no error was reported

@jantman have you tried TF_WARN_OUTPUT_ERRORS=1 terraform destroy?

+1 for fixing this issue. If a single issue occurs during our delete process our environment is left in a half destroyed yet undestroyable state. The TF_WARN_OUTPUT_ERRORS=1 fix works, but I feel it is a hack masking the underlying problem

The TF_WARN_OUTPUT_ERRORS variable does not see to work with 0.11.8 on Linux 64 bit Please refer this link as well https://github.com/hashicorp/terraform/pull/17768#issuecomment-417281234

I just found another use case related to that:

provider "random" {
  version = "= 2.0.0"
}

resource "random_id" "test_suffix" {
  byte_length = 2
}

module "some_awesome_module" {
  source = "../.."

  foo = "bar-${random_id.test_suffix.hex}"
}

I'm getting:

       * module.some_awesome_module.var.foo: variable "test_suffix" is nil, but no error was reported

TF_WARN_OUTPUT_ERRORS obviously not going to make any difference as in this case it has nothing to do with the output. Same applies to random_string. It is reproducible on both 0.11.8 and 0.11.3.

The issue was there for a while preventing implementing integration testing with kitchen-terraform and inspec, even for some basic stuff such as simple use case using random provider. cc @ncs-alane - maybe there some workaround can be done on the kitchen side?

Hey @llibicpep,

If you would like to open an issue against Kitchen-Terraform, we may be able to identity a workflow or configuration to avoid your particular problem.

commented

We have the same problem with Terraform v0.11.8 on Linux 64bit. The output looks a little bit different:

  • module.compute.output.service_endpoint: Resource 'aws_lb.ext-alb' does not have attribute 'dns_name' for variable 'aws_lb.ext-alb.dns_name'
  • module.compute.output.bastion_host_public_ip: Resource 'aws_instance.bastion_host' does not have attribute 'public_ip' for variable 'aws_instance.bastion_host.public_ip'

With TF_WARN_OUTPUT_ERRORS=1, the problem disappears but it should not happen in the first place IMHO.

Hello,

Any updates on this bug? It's quite a problem to not be able to destroy resources

This is still a problem with variables:

$ TF_WARN_OUTPUT_ERRORS=1 terraform destroy --auto-approve

Error: Error applying plan:

1 error(s) occurred:

* module.dcos.local.cluster_name: local.cluster_name: variable "id" is nil, but no error was reported

@bernadinm I overcame a very similar sounding problem in 0.11 using this approach:

locals {
  result = {
    command = ""
  }
  kubeadm_join_results = "${concat(data.external.kubeadm_join.*.result, list(local.result))}"
  kubeadm_join_command = "${lookup(local.kubeadm_join_results["0"], "command", "")}"
}

 output "kubeadm_join_command" {
  depends_on = ["null_resource.masters_provisioner"]
  value = "${local.kubeadm_join_command}"
 }

Full description here: https://groups.google.com/d/msg/terraform-tool/y9H4rAVOcLA/G5iftvErBwAJ

Hello! 🤖

This issue relates to an older version of Terraform that is no longer in active development, and because the area of Terraform it relates to has changed significantly since the issue was opened we suspect that the issue is either fixed or that the circumstances around it have changed enough that we'd need an updated issue report in order to reproduce and address it.

If you're still seeing this or a similar issue in the latest version of Terraform, please do feel free to open a new bug report! Please be sure to include all of the information requested in the template, even if it might seem redundant with the information already shared in this issue, because the internal details relating to this problem are likely to be different in the current version of Terraform.

Thanks!

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.