6 "github.com/hashicorp/terraform/plans"
7 "github.com/hashicorp/terraform/providers"
8 "github.com/hashicorp/terraform/states"
10 "github.com/hashicorp/terraform/addrs"
11 "github.com/zclconf/go-cty/cty"
14 // NodePlannableResourceInstance represents a _single_ resource
15 // instance that is plannable. This means this represents a single
16 // count index, for example.
17 type NodePlannableResourceInstance struct {
18 *NodeAbstractResourceInstance
19 ForceCreateBeforeDestroy bool
23 _ GraphNodeSubPath = (*NodePlannableResourceInstance)(nil)
24 _ GraphNodeReferenceable = (*NodePlannableResourceInstance)(nil)
25 _ GraphNodeReferencer = (*NodePlannableResourceInstance)(nil)
26 _ GraphNodeResource = (*NodePlannableResourceInstance)(nil)
27 _ GraphNodeResourceInstance = (*NodePlannableResourceInstance)(nil)
28 _ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstance)(nil)
29 _ GraphNodeAttachResourceState = (*NodePlannableResourceInstance)(nil)
30 _ GraphNodeEvalable = (*NodePlannableResourceInstance)(nil)
34 func (n *NodePlannableResourceInstance) EvalTree() EvalNode {
35 addr := n.ResourceInstanceAddr()
37 // Eval info is different depending on what kind of resource this is
38 switch addr.Resource.Resource.Mode {
39 case addrs.ManagedResourceMode:
40 return n.evalTreeManagedResource(addr)
41 case addrs.DataResourceMode:
42 return n.evalTreeDataResource(addr)
44 panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
48 func (n *NodePlannableResourceInstance) evalTreeDataResource(addr addrs.AbsResourceInstance) EvalNode {
50 var provider providers.Interface
51 var providerSchema *ProviderSchema
52 var change *plans.ResourceInstanceChange
53 var state *states.ResourceInstanceObject
54 var configVal cty.Value
59 Addr: n.ResolvedProvider,
61 Schema: &providerSchema,
67 ProviderSchema: &providerSchema,
72 // If we already have a non-planned state then we already dealt
73 // with this during the refresh walk and so we have nothing to do
76 If: func(ctx EvalContext) (bool, error) {
79 // Check and see if any of our dependencies have changes.
80 changes := ctx.Changes()
81 for _, d := range n.StateReferences() {
82 ri, ok := d.(addrs.ResourceInstance)
86 change := changes.GetResourceInstanceChange(ri.Absolute(ctx.Path()), states.CurrentGen)
87 if change != nil && change.Action != plans.NoOp {
93 refreshed := state != nil && state.Status != states.ObjectPlanned
95 // If there are no dependency changes, and it's not a forced
96 // read because we there was no Refresh, then we don't need
97 // to re-read. If any dependencies have changes, it means
98 // our config may also have changes and we need to Read the
100 if !depChanges && refreshed {
101 return false, EvalEarlyExitError{}
108 &EvalValidateSelfRef{
110 Config: config.Config,
111 ProviderSchema: &providerSchema,
117 Dependencies: n.StateReferences(),
119 ProviderAddr: n.ResolvedProvider,
120 ProviderSchema: &providerSchema,
121 ForcePlanRead: true, // _always_ produce a Read change, even if the config seems ready
122 OutputChange: &change,
123 OutputValue: &configVal,
129 ProviderAddr: n.ResolvedProvider,
130 ProviderSchema: &providerSchema,
136 ProviderSchema: &providerSchema,
143 func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsResourceInstance) EvalNode {
145 var provider providers.Interface
146 var providerSchema *ProviderSchema
147 var change *plans.ResourceInstanceChange
148 var state *states.ResourceInstanceObject
150 return &EvalSequence{
153 Addr: n.ResolvedProvider,
155 Schema: &providerSchema,
161 ProviderSchema: &providerSchema,
166 &EvalValidateSelfRef{
168 Config: config.Config,
169 ProviderSchema: &providerSchema,
175 CreateBeforeDestroy: n.ForceCreateBeforeDestroy,
177 ProviderAddr: n.ResolvedProvider,
178 ProviderSchema: &providerSchema,
180 OutputChange: &change,
183 &EvalCheckPreventDestroy{
190 ProviderAddr: n.ResolvedProvider,
192 ProviderSchema: &providerSchema,
196 ProviderSchema: &providerSchema,