core: Remove machinery for the "input" walk

Provider input is now longer handled with a graph walk, so the code
related to the input graph and walk are no longer needed.

For now the Input method is retained on the ResourceProvider interface,
but it will never be called. Subsequent work to revamp the provider API
will remove this method.
This commit is contained in:
Martin Atkins 2018-06-01 10:29:55 -07:00
parent aa07f34dbe
commit f14369e7fb
11 changed files with 11 additions and 174 deletions

View File

@ -270,9 +270,6 @@ func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, tfdiags.
Validate: opts.Validate,
}).Build(addrs.RootModuleInstance)
case GraphTypeInput:
// The input graph is just a slightly modified plan graph
fallthrough
case GraphTypeValidate:
// The validate graph is just a slightly modified plan graph
fallthrough
@ -290,8 +287,6 @@ func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, tfdiags.
// Some special cases for other graph types shared with plan currently
var b GraphBuilder = p
switch typ {
case GraphTypeInput:
b = InputGraphBuilder(p)
case GraphTypeValidate:
b = ValidateGraphBuilder(p)
}

View File

@ -14,7 +14,6 @@ const (
GraphTypePlan
GraphTypePlanDestroy
GraphTypeApply
GraphTypeInput
GraphTypeValidate
GraphTypeEval // only visits in-memory elements such as variables, locals, and outputs.
)
@ -24,7 +23,6 @@ const (
// graph types.
var GraphTypeMap = map[string]GraphType{
"apply": GraphTypeApply,
"input": GraphTypeInput,
"plan": GraphTypePlan,
"plan-destroy": GraphTypePlanDestroy,
"refresh": GraphTypeRefresh,

View File

@ -142,30 +142,3 @@ func (n *EvalGetProvider) Eval(ctx EvalContext) (interface{}, error) {
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
diag := &hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Provider input is temporarily disabled",
Detail: fmt.Sprintf("Skipped gathering input for %s because the input step is currently disabled pending a change to the provider API.", n.Addr),
}
if n.Config != nil {
diag.Subject = n.Config.DeclRange.Ptr()
}
diags = diags.Append(diag)
return nil, diags.ErrWithWarnings()
}

View File

@ -1,14 +1,12 @@
package terraform
import (
"reflect"
"testing"
"github.com/hashicorp/hcl2/hcldec"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/configschema"
"github.com/hashicorp/terraform/configs"
)
@ -159,64 +157,3 @@ func TestEvalGetProvider(t *testing.T) {
t.Fatalf("wrong provider address %s", ctx.ProviderAddr)
}
}
func TestEvalInputProvider(t *testing.T) {
var provider ResourceProvider = &MockResourceProvider{
InputFn: func(ui UIInput, c *ResourceConfig) (*ResourceConfig, error) {
if c.Config["mock_config"] != "mock" {
t.Fatalf("original config not passed to provider.Input")
}
rawConfig, err := config.NewRawConfig(map[string]interface{}{
"set_by_input": "input",
})
if err != nil {
return nil, err
}
config := NewResourceConfig(rawConfig)
config.ComputedKeys = []string{"computed"} // fake computed key
return config, nil
},
}
ctx := &MockEvalContext{ProviderProvider: provider}
config := &configs.Provider{
Name: "foo",
Config: configs.SynthBody("synth", map[string]cty.Value{
"mock_config": cty.StringVal("mock"),
"set_in_config": cty.StringVal("input"),
}),
}
n := &EvalInputProvider{
Addr: addrs.ProviderConfig{Type: "foo"},
Provider: &provider,
Config: config,
}
result, err := n.Eval(ctx)
if err != nil {
t.Fatalf("Eval failed: %s", err)
}
if result != nil {
t.Fatalf("Eval returned non-nil result %#v", result)
}
if !ctx.SetProviderInputCalled {
t.Fatalf("ctx.SetProviderInput wasn't called")
}
if got, want := ctx.SetProviderInputAddr.String(), "provider.mock"; got != want {
t.Errorf("wrong provider name %q; want %q", got, want)
}
inputCfg := ctx.SetProviderInputValues
// we should only have the value that was set during Input
want := map[string]cty.Value{
"set_by_input": cty.StringVal("input"),
}
if !reflect.DeepEqual(inputCfg, want) {
t.Errorf("got incorrect input config:\n%#v\nwant:\n%#v", inputCfg, want)
}
}

View File

@ -21,18 +21,13 @@ func ProviderEvalTree(n *NodeApplyableProvider, config *configs.Provider) EvalNo
// Input stuff
seq = append(seq, &EvalOpFilter{
Ops: []walkOperation{walkInput, walkImport},
Ops: []walkOperation{walkImport},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalGetProvider{
Addr: addr,
Output: &provider,
},
&EvalInputProvider{
Addr: relAddr,
Provider: &provider,
Config: config,
},
},
},
})

View File

@ -1,27 +0,0 @@
package terraform
import (
"github.com/hashicorp/terraform/dag"
)
// InputGraphBuilder creates the graph for the input operation.
//
// Unlike other graph builders, this is a function since it currently modifies
// and is based on the PlanGraphBuilder. The PlanGraphBuilder passed in will be
// modified and should not be used for any other operations.
func InputGraphBuilder(p *PlanGraphBuilder) GraphBuilder {
// We're going to customize the concrete functions
p.CustomConcrete = true
// Set the provider to the normal provider. This will ask for input.
p.ConcreteProvider = func(a *NodeAbstractProvider) dag.Vertex {
return &NodeApplyableProvider{
NodeAbstractProvider: a,
}
}
// We purposely don't set any more concrete fields since the remainder
// should be no-ops.
return p
}

View File

@ -7,7 +7,6 @@ type walkOperation byte
const (
walkInvalid walkOperation = iota
walkInput
walkApply
walkPlan
walkPlanDestroy

View File

@ -199,13 +199,13 @@ func (i *Interpolater) valueResourceVar(
}
if variable == nil {
// During the input walk we tolerate missing variables because
// During the refresh walk we tolerate missing variables because
// we haven't yet had a chance to refresh state, so dynamic data may
// not yet be complete.
// If it truly is missing, we'll catch it on a later walk.
// This applies only to graph nodes that interpolate during the
// config walk, e.g. providers.
if i.Operation == walkInput || i.Operation == walkRefresh {
// refresh walk, e.g. providers.
if i.Operation == walkRefresh {
result[n] = unknownVariable()
return nil
}
@ -526,10 +526,7 @@ MISSING:
//
// For a Destroy, we're also fine with computed values, since our goal is
// only to get destroy nodes for existing resources.
//
// For an input walk, computed values are okay to return because we're only
// looking for missing variables to prompt the user for.
if i.Operation == walkRefresh || i.Operation == walkPlanDestroy || i.Operation == walkInput {
if i.Operation == walkRefresh || i.Operation == walkPlanDestroy {
return &unknownVariable, nil
}
@ -549,13 +546,6 @@ func (i *Interpolater) computeResourceMultiVariable(
unknownVariable := unknownVariable()
// If we're only looking for input, we don't need to expand a
// multi-variable. This prevents us from encountering things that should be
// known but aren't because the state has yet to be refreshed.
if i.Operation == walkInput {
return &unknownVariable, nil
}
// Get the information about this resource variable, and verify
// that it exists and such.
module, cr, err := i.resourceVariableInfo(scope, v)
@ -637,7 +627,7 @@ func (i *Interpolater) computeResourceMultiVariable(
//
// For an input walk, computed values are okay to return because we're only
// looking for missing variables to prompt the user for.
if i.Operation == walkRefresh || i.Operation == walkPlanDestroy || i.Operation == walkDestroy || i.Operation == walkInput {
if i.Operation == walkRefresh || i.Operation == walkPlanDestroy || i.Operation == walkDestroy {
return &unknownVariable, nil
}

View File

@ -121,17 +121,6 @@ func (n *NodeApplyableModuleVariable) EvalTree() EvalNode {
IgnoreDiagnostics: false,
},
},
&EvalOpFilter{
Ops: []walkOperation{walkInput},
Node: &EvalModuleCallArgument{
Addr: n.Addr.Variable,
Config: n.Config,
Expr: n.Expr,
Values: vals,
IgnoreDiagnostics: true,
},
},
&EvalSetModuleCallArguments{
Module: call,

View File

@ -115,17 +115,6 @@ func (n *NodeApplyableOutput) References() []*addrs.Reference {
func (n *NodeApplyableOutput) EvalTree() EvalNode {
return &EvalSequence{
Nodes: []EvalNode{
&EvalOpFilter{
// Don't let interpolation errors stop Input, since it happens
// before Refresh.
Ops: []walkOperation{walkInput},
Node: &EvalWriteOutput{
Addr: n.Addr.OutputValue,
Sensitive: n.Config.Sensitive,
Expr: n.Config.Expr,
ContinueOnErr: true,
},
},
&EvalOpFilter{
Ops: []walkOperation{walkRefresh, walkPlan, walkApply, walkValidate, walkDestroy, walkPlanDestroy},
Node: &EvalWriteOutput{

View File

@ -30,13 +30,12 @@ type ResourceProvider interface {
// resource or data source has the SchemaAvailable flag set.
GetSchema(*ProviderSchemaRequest) (*ProviderSchema, error)
// Input is called to ask the provider to ask the user for input
// for completing the configuration if necesarry.
// Input was used prior to v0.12 to ask the provider to prompt the user
// for input to complete the configuration.
//
// This may or may not be called, so resource provider writers shouldn't
// rely on this being available to set some default values for validate
// later. Example of a situation where this wouldn't be called is if
// the user is not using a TTY.
// From v0.12 onwards this method is never called because Terraform Core
// is able to handle the necessary input logic itself based on the
// schema returned from GetSchema.
Input(UIInput, *ResourceConfig) (*ResourceConfig, error)
// Validate is called once at the beginning with the raw configuration