backend/remote: Only load variables if we're going to use them
Some commands don't use variables at all or use them in a way that doesn't require them to all be fully valid and consistent. For those, we don't want to fetch variable values from the remote system and try to validate them because that's wasteful and likely to cause unnecessary error messages. Furthermore, the variables endpoint in Terraform Cloud and Enterprise only works for personal access tokens, so it's important that we don't assume we can _always_ use it. If we do, then we'll see problems when commands are run inside Terraform Cloud and Enterprise remote execution contexts, where the variables map always comes back as empty.
This commit is contained in:
parent
a8d01e3940
commit
b10f058cbb
|
@ -9,9 +9,11 @@ import (
|
||||||
tfe "github.com/hashicorp/go-tfe"
|
tfe "github.com/hashicorp/go-tfe"
|
||||||
"github.com/hashicorp/terraform/backend"
|
"github.com/hashicorp/terraform/backend"
|
||||||
"github.com/hashicorp/terraform/command/clistate"
|
"github.com/hashicorp/terraform/command/clistate"
|
||||||
|
"github.com/hashicorp/terraform/configs"
|
||||||
"github.com/hashicorp/terraform/states/statemgr"
|
"github.com/hashicorp/terraform/states/statemgr"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/hashicorp/terraform/tfdiags"
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Context implements backend.Enhanced.
|
// Context implements backend.Enhanced.
|
||||||
|
@ -88,6 +90,13 @@ func (b *Remote) Context(op *backend.Operation) (*terraform.Context, statemgr.Fu
|
||||||
return nil, nil, diags
|
return nil, nil, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if op.AllowUnsetVariables {
|
||||||
|
// If we're not going to use the variables in an operation we'll be
|
||||||
|
// more lax about them, stubbing out any unset ones as unknown.
|
||||||
|
// This gives us enough information to produce a consistent context,
|
||||||
|
// but not enough information to run a real operation (plan, apply, etc)
|
||||||
|
opts.Variables = stubAllVariables(op.Variables, config.Module.Variables)
|
||||||
|
} else {
|
||||||
if tfeVariables != nil {
|
if tfeVariables != nil {
|
||||||
if op.Variables == nil {
|
if op.Variables == nil {
|
||||||
op.Variables = make(map[string]backend.UnparsedVariableValue)
|
op.Variables = make(map[string]backend.UnparsedVariableValue)
|
||||||
|
@ -111,6 +120,7 @@ func (b *Remote) Context(op *backend.Operation) (*terraform.Context, statemgr.Fu
|
||||||
}
|
}
|
||||||
opts.Variables = variables
|
opts.Variables = variables
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tfCtx, ctxDiags := terraform.NewContext(&opts)
|
tfCtx, ctxDiags := terraform.NewContext(&opts)
|
||||||
diags = diags.Append(ctxDiags)
|
diags = diags.Append(ctxDiags)
|
||||||
|
@ -119,3 +129,30 @@ func (b *Remote) Context(op *backend.Operation) (*terraform.Context, statemgr.Fu
|
||||||
|
|
||||||
return tfCtx, stateMgr, diags
|
return tfCtx, stateMgr, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stubAllVariables(vv map[string]backend.UnparsedVariableValue, decls map[string]*configs.Variable) terraform.InputValues {
|
||||||
|
ret := make(terraform.InputValues, len(decls))
|
||||||
|
|
||||||
|
for name, cfg := range decls {
|
||||||
|
raw, exists := vv[name]
|
||||||
|
if !exists {
|
||||||
|
ret[name] = &terraform.InputValue{
|
||||||
|
Value: cty.UnknownVal(cfg.Type),
|
||||||
|
SourceType: terraform.ValueFromConfig,
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val, diags := raw.ParseVariableValue(cfg.ParsingMode)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
ret[name] = &terraform.InputValue{
|
||||||
|
Value: cty.UnknownVal(cfg.Type),
|
||||||
|
SourceType: terraform.ValueFromConfig,
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret[name] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue