Merge pull request #9496 from hashicorp/b-apply-data
terraform: new apply resource node supports data sources
This commit is contained in:
commit
0fdedbd003
|
@ -508,6 +508,38 @@ func TestContext2Apply_destroyComputed(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestContext2Apply_dataBasic(t *testing.T) {
|
||||
m := testModule(t, "apply-data-basic")
|
||||
p := testProvider("null")
|
||||
p.ApplyFn = testApplyFn
|
||||
p.DiffFn = testDiffFn
|
||||
p.ReadDataApplyReturn = &InstanceState{ID: "yo"}
|
||||
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Module: m,
|
||||
Providers: map[string]ResourceProviderFactory{
|
||||
"null": testProviderFuncFixed(p),
|
||||
},
|
||||
})
|
||||
|
||||
if p, err := ctx.Plan(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
} else {
|
||||
t.Logf(p.String())
|
||||
}
|
||||
|
||||
state, err := ctx.Apply()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(state.String())
|
||||
expected := strings.TrimSpace(testTerraformApplyDataBasicStr)
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: \n%s", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Apply_destroyData(t *testing.T) {
|
||||
m := testModule(t, "apply-destroy-data-resource")
|
||||
p := testProvider("null")
|
||||
|
|
|
@ -2,6 +2,8 @@ package terraform
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/config"
|
||||
)
|
||||
|
||||
// NodeApplyableResource represents a resource that is "applyable":
|
||||
|
@ -49,6 +51,106 @@ func (n *NodeApplyableResource) EvalTree() EvalNode {
|
|||
stateDeps = oldN.StateDependencies()
|
||||
}
|
||||
|
||||
// Eval info is different depending on what kind of resource this is
|
||||
switch n.Config.Mode {
|
||||
case config.ManagedResourceMode:
|
||||
return n.evalTreeManagedResource(
|
||||
stateId, info, resource, stateDeps,
|
||||
)
|
||||
case config.DataResourceMode:
|
||||
return n.evalTreeDataResource(
|
||||
stateId, info, resource, stateDeps)
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
|
||||
}
|
||||
}
|
||||
|
||||
func (n *NodeApplyableResource) evalTreeDataResource(
|
||||
stateId string, info *InstanceInfo,
|
||||
resource *Resource, stateDeps []string) EvalNode {
|
||||
var provider ResourceProvider
|
||||
var config *ResourceConfig
|
||||
var diff *InstanceDiff
|
||||
var state *InstanceState
|
||||
|
||||
return &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
// Get the saved diff for apply
|
||||
&EvalReadDiff{
|
||||
Name: stateId,
|
||||
Diff: &diff,
|
||||
},
|
||||
|
||||
// Stop here if we don't actually have a diff
|
||||
&EvalIf{
|
||||
If: func(ctx EvalContext) (bool, error) {
|
||||
if diff == nil {
|
||||
return true, EvalEarlyExitError{}
|
||||
}
|
||||
|
||||
if diff.GetAttributesLen() == 0 {
|
||||
return true, EvalEarlyExitError{}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
},
|
||||
Then: EvalNoop{},
|
||||
},
|
||||
|
||||
// We need to re-interpolate the config here, rather than
|
||||
// just using the diff's values directly, because we've
|
||||
// potentially learned more variable values during the
|
||||
// apply pass that weren't known when the diff was produced.
|
||||
&EvalInterpolate{
|
||||
Config: n.Config.RawConfig.Copy(),
|
||||
Resource: resource,
|
||||
Output: &config,
|
||||
},
|
||||
|
||||
&EvalGetProvider{
|
||||
Name: n.ProvidedBy()[0],
|
||||
Output: &provider,
|
||||
},
|
||||
|
||||
// Make a new diff with our newly-interpolated config.
|
||||
&EvalReadDataDiff{
|
||||
Info: info,
|
||||
Config: &config,
|
||||
Previous: &diff,
|
||||
Provider: &provider,
|
||||
Output: &diff,
|
||||
},
|
||||
|
||||
&EvalReadDataApply{
|
||||
Info: info,
|
||||
Diff: &diff,
|
||||
Provider: &provider,
|
||||
Output: &state,
|
||||
},
|
||||
|
||||
&EvalWriteState{
|
||||
Name: stateId,
|
||||
ResourceType: n.Config.Type,
|
||||
Provider: n.Config.Provider,
|
||||
Dependencies: stateDeps,
|
||||
State: &state,
|
||||
},
|
||||
|
||||
// Clear the diff now that we've applied it, so
|
||||
// later nodes won't see a diff that's now a no-op.
|
||||
&EvalWriteDiff{
|
||||
Name: stateId,
|
||||
Diff: nil,
|
||||
},
|
||||
|
||||
&EvalUpdateStateHook{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (n *NodeApplyableResource) evalTreeManagedResource(
|
||||
stateId string, info *InstanceInfo,
|
||||
resource *Resource, stateDeps []string) EvalNode {
|
||||
// Declare a bunch of variables that are used for state during
|
||||
// evaluation. Most of this are written to by-address below.
|
||||
var provider ResourceProvider
|
||||
|
|
|
@ -25,13 +25,13 @@ func TestMain(m *testing.M) {
|
|||
// Experimental features
|
||||
xNewApply := flag.Bool("Xnew-apply", false, "Experiment: new apply graph")
|
||||
|
||||
// Normal features
|
||||
shadow := flag.Bool("shadow", true, "Enable shadow graph")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
// Setup experimental features
|
||||
X_newApply = *xNewApply
|
||||
if X_newApply {
|
||||
println("Xnew-apply enabled")
|
||||
}
|
||||
|
||||
if testing.Verbose() {
|
||||
// if we're verbose, use the logging requested by TF_LOG
|
||||
|
@ -48,7 +48,7 @@ func TestMain(m *testing.M) {
|
|||
contextTestDeepCopyOnPlan = true
|
||||
|
||||
// Shadow the new graphs
|
||||
contextTestShadow = true
|
||||
contextTestShadow = *shadow
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
@ -257,6 +257,11 @@ aws_instance.foo:
|
|||
type = aws_instance
|
||||
`
|
||||
|
||||
const testTerraformApplyDataBasicStr = `
|
||||
data.null_data_source.testing:
|
||||
ID = yo
|
||||
`
|
||||
|
||||
const testTerraformApplyRefCountStr = `
|
||||
aws_instance.bar:
|
||||
ID = foo
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
data "null_data_source" "testing" {}
|
Loading…
Reference in New Issue