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
|
|
}
|