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.
https://www.terraform.io/
Other
42.74k stars 9.56k forks source link

Terraform crash while creating plan #31510

Closed jim-leary closed 2 years ago

jim-leary commented 2 years ago

Terraform Version

Terraform v1.2.5
on darwin_amd64
+ provider registry.terraform.io/cloudflare/cloudflare v3.19.0
+ provider registry.terraform.io/gavinbunney/kubectl v1.14.0
+ provider registry.terraform.io/hashicorp/aws v4.23.0
+ provider registry.terraform.io/hashicorp/cloudinit v2.2.0
+ provider registry.terraform.io/hashicorp/github v4.27.1
+ provider registry.terraform.io/hashicorp/helm v2.6.0
+ provider registry.terraform.io/hashicorp/kubernetes v2.12.1
+ provider registry.terraform.io/hashicorp/random v3.3.2
+ provider registry.terraform.io/hashicorp/tls v3.4.0
+ provider registry.terraform.io/petoju/mysql v3.0.17

Terraform Configuration Files

 terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"

    }
    mysql = {
      source = "petoju/mysql"
      version = "~> 3.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.11"
    }
    kubectl = {
      source = "gavinbunney/kubectl"
      version = "~> 1.14"
    }
    cloudflare = {
      source = "cloudflare/cloudflare"
      version = "~> 3.18"
    }
  }
}
...

Debug Output

Expected Behavior

Actual Behavior

Steps to Reproduce

Additional Context

References

jim-leary commented 2 years ago

This was working correctly all day, then around 16:00 EDST I started getting plan errors. There were no changes to the configuration or code at all.

jim-leary commented 2 years ago

terraform_debug.log.gz

jbardin commented 2 years ago

Hi @jim-leary,

Thanks for reporting the issue. The stack trace from the crash is here:

github.com/zclconf/go-cty/cty.Type.AttributeTypes(...)
        /Users/distiller/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/object_type.go:187
github.com/zclconf/go-cty/cty/convert.unifyObjectTypesToMap({0xc00231b480, 0x2, 0x3870f00?}, 0x1)
        /Users/distiller/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/convert/unify.go:368 +0x579
github.com/zclconf/go-cty/cty/convert.unifyTupleTypesToList({0xc00231b480, 0x2, 0x2}, 0x1)
        /Users/distiller/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/convert/unify.go:487 +0x40a
github.com/zclconf/go-cty/cty/convert.unifyTupleTypes({0xc00231b480?, 0x2, 0x2}, 0x1, 0x0?)
        /Users/distiller/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/convert/unify.go:418 +0x6b9
github.com/zclconf/go-cty/cty/convert.unify({0xc00231b480?, 0x2, 0x2}, 0x1)
        /Users/distiller/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/convert/unify.go:85 +0x41e
github.com/zclconf/go-cty/cty/convert.UnifyUnsafe(...)
        /Users/distiller/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/convert/public.go:82
github.com/hashicorp/hcl/v2/hclsyntax.(*ConditionalExpr).Value(0xc00029d9d0, 0xc001ee7080)
        /Users/distiller/go/pkg/mod/github.com/hashicorp/hcl/v2@v2.12.0/hclsyntax/expression.go:610 +0x2ab
github.com/hashicorp/terraform/internal/lang.(*Scope).EvalExpr(0xc00055c7e0, {0x386faa8?, 0xc00029d9d0}, {{0x3870ec8?, 0x4c53230?}})
        /Users/distiller/project/project/internal/lang/eval.go:171 +0x148
github.com/hashicorp/terraform/internal/terraform.(*BuiltinEvalContext).EvaluateExpr(0x386faa8?, {0x386faa8, 0xc00029d9d0}, {{0x3870ec8?, 0x4c53230?}}, {0x0?, 0x0?})
        /Users/distiller/project/project/internal/terraform/eval_context_builtin.go:282 +0xc5
github.com/hashicorp/terraform/internal/terraform.(*NodeLocal).Execute(0x0?, {0x387f0e0, 0xc00207e540}, 0x60?)
        /Users/distiller/project/project/internal/terraform/node_local.go:153 +0x576

Can you supply a minimal example that causes the same crash so we can reproduce the issue?

jim-leary commented 2 years ago

I am able to reproduce the error with some simple code - it's rather interesting:

# local-module for test of crash
# Jim Leary
# local-module/main.tf

variable "lifecycle_rules" {
  description = "additional list of lifecycle rules maps"
  type        = any
  default     = {}
}

locals {

  default_lifecycle_rules = {
      id      = "default"
      enabled = true
      transition = [
        {
          days          = 1825
          storage_class = "GLACIER"
        }
      ]
      expiration = {
        days = 2555
      }
      noncurrent_version_expiration = {
        newer_noncurrent_versions = 3
        days = 3
      }
    }

  # This code will induce the crash
  all_lifecycle_rules = length(var.lifecycle_rules) >  0 ? [local.default_lifecycle_rules, var.lifecycle_rules] : [local.default_lifecycle_rules]

}

resource "null_resource" "test" {

    provisioner "local-exec" {
    command = "echo module local-module"
  }
}

When my root process calls the module above, it is not passing any variables and allowing the default values to be used. The variable "lifecycle_rules" is set to type any, and the default value is {}. This will cause the crash. Changing the variable type to map eliminates the crash. The key here is the use of a variable. Using locals will not cause a crash. Hope this helps.

jbardin commented 2 years ago

Thanks @jim-leary,

This looks like something which will be fixed with the upstream patch here: https://github.com/zclconf/go-cty/pull/126. In this case however "fixed" only refers to not panicking, the given expression is still going to return an error, at least for now.

The problem is that the Terraform language is not able to find a unified type which can be used for the complete conditional expression. It would be more robust if you define a strict type for lifecycle_rules, so that expressions which use that value don't end up changing types between runs, possibly even becoming entirely invalid, based on the value being used.

jim-leary commented 2 years ago

Thanks - the original "any" designation was a bug on my part; however, not having Terraform panic and cause state-locks would be a big help.

apparentlymart commented 2 years ago

The upstream library change that @jbardin mentioned was included in one of the v1.2 patch releases and now in the v1.3 series, so this should now be a normal error explaining the problem instead of a panic. Therefore I'm going to close this.

If you see something which seems similar to this, please open a new issue for it so we can repeat the reproduction and debugging process against the updated code. (The upstream changes have probably invalidated the stack trace we collected above.) Thanks!

github-actions[bot] commented 2 years ago

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.