opentofu/terraform/eval_provider.go
Martin Atkins 39a83b2fd1 core: fix test for buildProviderConfig
This was incorrectly comparing a cty.Value to an hcl.Body. Now we decode
the body first so we can compare two of cty.Value.

Also includes a fix to a stale comment in buildProviderConfig that was no
longer accurate.
2018-10-16 18:48:28 -07:00

154 lines
4.6 KiB
Go

package terraform
import (
"fmt"
"github.com/hashicorp/hcl2/hcl"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/tfdiags"
)
func buildProviderConfig(ctx EvalContext, addr addrs.ProviderConfig, body hcl.Body) hcl.Body {
// If we have an Input configuration set, then merge that in
if input := ctx.ProviderInput(addr); input != nil {
// "input" is a map of the subset of config values that were known
// during the input walk, set by EvalInputProvider. Note that
// in particular it does *not* include attributes that had
// computed values at input time.
inputBody := configs.SynthBody("<input prompt>", input)
body = configs.MergeBodies(body, inputBody)
}
return body
}
// EvalConfigProvider is an EvalNode implementation that configures
// a provider that is already initialized and retrieved.
type EvalConfigProvider struct {
Addr addrs.ProviderConfig
Provider *ResourceProvider
Config *configs.Provider
}
func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) {
if n.Provider == nil {
return nil, fmt.Errorf("EvalConfigProvider Provider is nil")
}
if n.Config == nil {
return nil, nil
}
var diags tfdiags.Diagnostics
provider := *n.Provider
config := n.Config
if config == nil {
// If we have no explicit configuration, just write an empty
// configuration into the provider.
configDiags := ctx.ConfigureProvider(n.Addr, cty.EmptyObjectVal)
return nil, configDiags.ErrWithWarnings()
}
schema, err := provider.GetSchema(&ProviderSchemaRequest{})
if err != nil {
diags = diags.Append(err)
return nil, diags.NonFatalErr()
}
if schema == nil {
return nil, fmt.Errorf("schema not available for %s", n.Addr)
}
configSchema := schema.Provider
configBody := buildProviderConfig(ctx, n.Addr, config.Config)
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, addrs.NoKey)
diags = diags.Append(evalDiags)
if evalDiags.HasErrors() {
return nil, diags.NonFatalErr()
}
configDiags := ctx.ConfigureProvider(n.Addr, configVal)
configDiags = configDiags.InConfigBody(configBody)
return nil, configDiags.ErrWithWarnings()
}
// EvalInitProvider is an EvalNode implementation that initializes a provider
// and returns nothing. The provider can be retrieved again with the
// EvalGetProvider node.
type EvalInitProvider struct {
TypeName string
Addr addrs.ProviderConfig
}
func (n *EvalInitProvider) Eval(ctx EvalContext) (interface{}, error) {
return ctx.InitProvider(n.TypeName, n.Addr)
}
// EvalCloseProvider is an EvalNode implementation that closes provider
// connections that aren't needed anymore.
type EvalCloseProvider struct {
Addr addrs.ProviderConfig
}
func (n *EvalCloseProvider) Eval(ctx EvalContext) (interface{}, error) {
ctx.CloseProvider(n.Addr)
return nil, nil
}
// EvalGetProvider is an EvalNode implementation that retrieves an already
// initialized provider instance for the given name.
//
// Unlike most eval nodes, this takes an _absolute_ provider configuration,
// because providers can be passed into and inherited between modules.
// Resource nodes must therefore know the absolute path of the provider they
// will use, which is usually accomplished by implementing
// interface GraphNodeProviderConsumer.
type EvalGetProvider struct {
Addr addrs.AbsProviderConfig
Output *ResourceProvider
// If non-nil, Schema will be updated after eval to refer to the
// schema of the provider.
Schema **ProviderSchema
}
func (n *EvalGetProvider) Eval(ctx EvalContext) (interface{}, error) {
result := ctx.Provider(n.Addr)
if result == nil {
return nil, fmt.Errorf("provider %s not initialized", n.Addr)
}
if n.Output != nil {
*n.Output = result
}
if n.Schema != nil {
*n.Schema = ctx.ProviderSchema(n.Addr)
}
return nil, nil
}
// EvalInputProvider is an EvalNode implementation that asks for input
// for the given provider configurations.
type EvalInputProvider struct {
Addr addrs.ProviderConfig
Provider *ResourceProvider
Config *configs.Provider
}
func (n *EvalInputProvider) Eval(ctx EvalContext) (interface{}, error) {
// This is currently disabled. It used to interact with a provider method
// called Input, allowing the provider to capture input interactively
// itself, but once re-implemented we'll have this instead use the
// provider's configuration schema to automatically infer what we need
// to prompt for.
var diags tfdiags.Diagnostics
diags = diags.Append(tfdiags.SimpleWarning(fmt.Sprintf("%s: provider input is temporarily disabled", n.Addr)))
return nil, diags.ErrWithWarnings()
}