mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-09 07:05:33 -06:00
In Terraform 0.11 and earlier we just silently ignored undeclared variables in -var-file and the automatically-loaded .tfvars files. This was a bad user experience for anyone who made a typo in a variable name and got no feedback about it, so we made this an error for 0.12. However, several users are now relying on the silent-ignore behavior for automation scenarios where they pass the same .tfvars file to all configurations in their organization and expect Terraform to ignore any settings that are not relevant to a specific configuration. We never intentionally supported that, but we don't want to immediately break that workflow during 0.12 upgrade. As a compromise, then, we'll make this a warning for v0.12.0 that contains a deprecation notice suggesting to move to using environment variables for this "cross-configuration variables" use-case. We don't produce errors for undeclared variables in environment variables, even though that potentially causes the same UX annoyance as ignoring them in vars files, because environment variables are assumed to live in the user's session and this it would be very inconvenient to have to unset such variables when moving between directories. Their "ambientness" makes them a better fit for these automatically-assigned general variable values that may or may not be used by a particular configuration. This can revert to being an error in a future major release, after users have had the opportunity to migrate their automation solutions over to use environment variables. We don't seem to have any tests covering this specific situation right now. That isn't ideal, but this change is so straightforward that it would be relatively expensive to build new targeted test cases for it and so I instead just hand-tested that it is indeed now producing a warning where we were previously producing an error. Hopefully if there is any more substantial work done on this codepath in future that will be our prompt to add some unit tests for this.
93 lines
3.8 KiB
Go
93 lines
3.8 KiB
Go
package backend
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/hcl2/hcl"
|
|
"github.com/hashicorp/terraform/configs"
|
|
"github.com/hashicorp/terraform/terraform"
|
|
"github.com/hashicorp/terraform/tfdiags"
|
|
)
|
|
|
|
// UnparsedVariableValue represents a variable value provided by the caller
|
|
// whose parsing must be deferred until configuration is available.
|
|
//
|
|
// This exists to allow processing of variable-setting arguments (e.g. in the
|
|
// command package) to be separated from parsing (in the backend package).
|
|
type UnparsedVariableValue interface {
|
|
// ParseVariableValue information in the provided variable configuration
|
|
// to parse (if necessary) and return the variable value encapsulated in
|
|
// the receiver.
|
|
//
|
|
// If error diagnostics are returned, the resulting value may be invalid
|
|
// or incomplete.
|
|
ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics)
|
|
}
|
|
|
|
func ParseVariableValues(vv map[string]UnparsedVariableValue, decls map[string]*configs.Variable) (terraform.InputValues, tfdiags.Diagnostics) {
|
|
var diags tfdiags.Diagnostics
|
|
ret := make(terraform.InputValues, len(vv))
|
|
|
|
for name, rv := range vv {
|
|
var mode configs.VariableParsingMode
|
|
config, declared := decls[name]
|
|
if declared {
|
|
mode = config.ParsingMode
|
|
} else {
|
|
mode = configs.VariableParseLiteral
|
|
}
|
|
|
|
val, valDiags := rv.ParseVariableValue(mode)
|
|
diags = diags.Append(valDiags)
|
|
if valDiags.HasErrors() {
|
|
continue
|
|
}
|
|
|
|
if !declared {
|
|
switch val.SourceType {
|
|
case terraform.ValueFromConfig, terraform.ValueFromAutoFile, terraform.ValueFromNamedFile:
|
|
// These source types have source ranges, so we can produce
|
|
// a nice error message with good context.
|
|
//
|
|
// This one is a warning for now because there is an existing
|
|
// pattern of providing a file containing the superset of
|
|
// variables across all configurations in an organization. This
|
|
// is deprecated in v0.12.0 because it's more important to give
|
|
// feedback to users who make typos. Those using this approach
|
|
// should migrate to using environment variables instead before
|
|
// this becomes an error in a future major release.
|
|
diags = diags.Append(&hcl.Diagnostic{
|
|
Severity: hcl.DiagWarning,
|
|
Summary: "Value for undeclared variable",
|
|
Detail: fmt.Sprintf("The root module does not declare a variable named %q. To use this value, add a \"variable\" block to the configuration.\n\nUsing a variables file to set an undeclared variable is deprecated and will become an error in a future release. If you wish to provide certain \"global\" settings to all configurations in your organization, use TF_VAR_... environment variables to set these instead.", name),
|
|
Subject: val.SourceRange.ToHCL().Ptr(),
|
|
})
|
|
case terraform.ValueFromEnvVar:
|
|
// We allow and ignore undeclared names for environment
|
|
// variables, because users will often set these globally
|
|
// when they are used across many (but not necessarily all)
|
|
// configurations.
|
|
case terraform.ValueFromCLIArg:
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Value for undeclared variable",
|
|
fmt.Sprintf("A variable named %q was assigned on the command line, but the root module does not declare a variable of that name. To use this value, add a \"variable\" block to the configuration.", name),
|
|
))
|
|
default:
|
|
// For all other source types we are more vague, but other situations
|
|
// don't generally crop up at this layer in practice.
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Value for undeclared variable",
|
|
fmt.Sprintf("A variable named %q was assigned a value, but the root module does not declare a variable of that name. To use this value, add a \"variable\" block to the configuration.", name),
|
|
))
|
|
}
|
|
continue
|
|
}
|
|
|
|
ret[name] = val
|
|
}
|
|
|
|
return ret, diags
|
|
}
|