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 panics on object with key types list(map()) and optional(string) in defaults #29942

Closed dmikalova closed 2 years ago

dmikalova commented 3 years ago

Terraform Version

Terraform v1.0.11
on linux_amd64
+ provider registry.terraform.io/digitalocean/digitalocean v2.15.0
+ provider registry.terraform.io/gitlabhq/gitlab v3.7.0
+ provider registry.terraform.io/hashicorp/kubernetes v2.6.1
+ provider registry.terraform.io/hashicorp/random v3.1.0

Terraform Configuration Files

variable "conf" {
...
    webhooks = object({
      middlewares = list(map(string))
      subdomain   = optional(string)
    })
  })
}

locals {
  conf = merge(
    defaults(var.conf, {
      webhooks = {
        # middlewares = "test"
        subdomain = "webhooks"
      }
  }))
}

Note that in webhooks, subdomain is optional and middlewares is type list(map(string) and is not optional. If subdomain is provided in defaults, but not middlewares, a panic results. If middlewares is provided in defaults, or the type for middlewares is string, then no panic occurs.

Expected Behavior

Defaults should fill the value for subdomain.

Actual Behavior

An error occurs:

│ Error: Error in function call
│ 
│   on main.tf line 4, in locals:
│    4:     defaults(var.conf, {
│    5:       webhooks = {
│    6:         # middlewares = "test"
│    7:         subdomain = "webhooks"
│    8:       }
│    9:       working_dir = "$(workspaces.${local.labels.git_repo_workspace}.path)/$(params.${local.labels.context_path})"
│   10:   }))
│     ├────────────────
│     │ local.labels.context_path is "context-path"
│     │ local.labels.git_repo_workspace is "git-repo-workspace"
│     │ var.conf is object with 9 attributes
│ 
│ Call to function "defaults" failed: panic in function implementation:
│ string required
│ goroutine 779 [running]:
│ runtime/debug.Stack(0xc0011d1360, 0x22ad1a0, 0xc0011a12c0)
│       /usr/local/go/src/runtime/debug/stack.go:24 +0x9f
│ github.com/zclconf/go-cty/cty/function.errorForPanic(...)
│       /home/circleci/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/function/error.go:44
│ github.com/zclconf/go-cty/cty/function.Function.Call.func1(0xc0011d3320,
│ 0xc0011d3340)
│       /home/circleci/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/function/function.go:291
│ +0x93
│ panic(0x22ad1a0, 0xc0011a12c0)
│       /usr/local/go/src/runtime/panic.go:965 +0x1b9
│ github.com/hashicorp/terraform/internal/lang/funcs.defaultsApply(0x2bb58b8,
│ 0xc000052469, 0x0, 0x0, 0x2bb5928, 0xc00144dd30, 0x0, 0x0, 0x0, 0x772c46,
│ ...)
│       /home/circleci/project/project/internal/lang/funcs/defaults.go:92 +0x16a5
│ github.com/hashicorp/terraform/internal/lang/funcs.defaultsApply(0x2bb5960,
│ 0xc00144dcd0, 0x2384620, 0xc001568480, 0x2bb5928, 0xc00144dd30, 0x0, 0x0,
│ 0xc001568480, 0xc000052469, ...)
│       /home/circleci/project/project/internal/lang/funcs/defaults.go:154 +0xd2e
│ github.com/hashicorp/terraform/internal/lang/funcs.defaultsApply(0x2bb5928,
│ 0xc00144dd30, 0x2262f20, 0xc000ba8840, 0x2bb5928, 0xc00144dd30, 0x0, 0x0,
│ 0x2262f20, 0xc000ba8840, ...)
│       /home/circleci/project/project/internal/lang/funcs/defaults.go:168 +0x1085
│ github.com/hashicorp/terraform/internal/lang/funcs.defaultsApply(0x2bb5998,
│ 0xc00144dd40, 0x2384620, 0xc0015685a0, 0x2bb5998, 0xc00144de40, 0x2384620,
│ 0xc001568ab0, 0x2384620, 0xc001568ab0, ...)
│       /home/circleci/project/project/internal/lang/funcs/defaults.go:115 +0x57c
│ github.com/hashicorp/terraform/internal/lang/funcs.defaultsApply(0x2bb5998,
│ 0xc00144dd50, 0x2384620, 0xc001568600, 0x2bb5998, 0xc00144de80, 0x2384620,
│ 0xc001568b10, 0x0, 0xc0011d3120, ...)
│       /home/circleci/project/project/internal/lang/funcs/defaults.go:115 +0x57c
│ github.com/hashicorp/terraform/internal/lang/funcs.glob..func31(0xc001767300,
│ 0x2, 0x2, 0x2bb5998, 0xc00144dd50, 0xc0011a0e50, 0x2384620, 0xc001569680,
│ 0xc0015696e0, 0x40da01, ...)
│       /home/circleci/project/project/internal/lang/funcs/defaults.go:65 +0xb3
│ github.com/zclconf/go-cty/cty/function.Function.Call(0xc00019ee40,
│ 0xc001767300, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
│       /home/circleci/go/pkg/mod/github.com/zclconf/go-cty@v1.10.0/cty/function/function.go:295
│ +0x4a7
│ github.com/hashicorp/hcl/v2/hclsyntax.(*FunctionCallExpr).Value(0xc0005fa000,
│ 0xc000ba8648, 0x0, 0xc000f988e0, 0x0, 0x0, 0xbda768e100000000,
│ 0xc001188ce0, 0x0)
│       /home/circleci/go/pkg/mod/github.com/hashicorp/hcl/v2@v2.10.1/hclsyntax/expression.go:442
│ +0xff6
│ github.com/hashicorp/hcl/v2/hclsyntax.(*FunctionCallExpr).Value(0xc0005fa0f0,
│ 0xc000ba8648, 0x0, 0xc001189800, 0x1, 0x1, 0x0, 0x0, 0x0)
│       /home/circleci/go/pkg/mod/github.com/hashicorp/hcl/v2@v2.10.1/hclsyntax/expression.go:408
│ +0x2902
│ github.com/hashicorp/terraform/internal/lang.(*Scope).EvalExpr(0xc0015cbbd0,
│ 0x2bb4620, 0xc0005fa0f0, 0x2bb58f0, 0x3c95d18, 0x0, 0x0, 0x0, 0x0, 0x0,
│ ...)
│       /home/circleci/project/project/internal/lang/eval.go:171 +0x1bc
│ github.com/hashicorp/terraform/internal/terraform.(*BuiltinEvalContext).EvaluateExpr(0xc0003b2700,
│ 0x2bb4620, 0xc0005fa0f0, 0x2bb58f0, 0x3c95d18, 0x0, 0x0, 0x0,
│ 0xffffffffffffffff, 0x0, ...)
│       /home/circleci/project/project/internal/terraform/eval_context_builtin.go:281
│ +0xbb
│ github.com/hashicorp/terraform/internal/terraform.(*NodeLocal).Execute(0xc0002da5d0,
│ 0x2be7180, 0xc0003b2700, 0xc0000ac002, 0xc000eddce8, 0x40bb05, 0x23cfa20)
│       /home/circleci/project/project/internal/terraform/node_local.go:153 +0x67d
│ github.com/hashicorp/terraform/internal/terraform.(*ContextGraphWalker).Execute(0xc001a44000,
│ 0x2be7180, 0xc0003b2700, 0x7ffb6fe84f98, 0xc0002da5d0, 0x0, 0x0, 0x0)
│       /home/circleci/project/project/internal/terraform/graph_walk_context.go:129
│ +0xbf
│ github.com/hashicorp/terraform/internal/terraform.(*Graph).walk.func1(0x2551ba0,
│ 0xc0002da5d0, 0x0, 0x0, 0x0)
│       /home/circleci/project/project/internal/terraform/graph.go:59 +0xbd3
│ github.com/hashicorp/terraform/internal/dag.(*Walker).walkVertex(0xc000b06300,
│ 0x2551ba0, 0xc0002da5d0, 0xc000998040)
│       /home/circleci/project/project/internal/dag/walk.go:381 +0x288
│ created by github.com/hashicorp/terraform/internal/dag.(*Walker).Update
│       /home/circleci/project/project/internal/dag/walk.go:304 +0x1246
│ .
╵
ERRO[0004] 1 error occurred:
        * exit status 1

Steps to Reproduce

I haven't tested a minimal reproduction, but you should be able to use the above. Here's the full config as well as the calling terragrunt module.

korinne commented 2 years ago

Hi, we recently released the Terraform v1.3 alpha, which includes the ability to mark object type attributes as optional and set default values.

I'm following up with issues that have provided feedback on the previous experiment, and wanted to invite you all to try the alpha and provide any feedback on this updated design. You can learn more/add comments here. Thank you so much in advance, and hope you like the feature!

apparentlymart commented 2 years ago

Hello again! Thanks for the bug report.

The final incarnation of the optional attributes feature does not include this defaults function at all, and instead the facility to choose default values is included in the main type constraint syntax. The partial example shown in the issue comment could therefore now be rewritten like this:

variable "conf" {
...
    webhooks = object({
      middlewares = list(map(string))
      subdomain   = optional(string, "webhooks")
    })
  })
}

The built-in default value handling is implemented in a different way to the defaults function and so it doesn't include the codepath that crashed here. If anyone sees something similar to this with the final version of the feature, please open a new issue to describe it because we'll need to start over with a new reproduction case against the new codepath.

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.