github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/terraform/node_resource_plan_instance.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 6 "github.com/hashicorp/terraform/config" 7 ) 8 9 // NodePlannableResourceInstance represents a _single_ resource 10 // instance that is plannable. This means this represents a single 11 // count index, for example. 12 type NodePlannableResourceInstance struct { 13 *NodeAbstractResource 14 } 15 16 // GraphNodeEvalable 17 func (n *NodePlannableResourceInstance) EvalTree() EvalNode { 18 addr := n.NodeAbstractResource.Addr 19 20 // stateId is the ID to put into the state 21 stateId := addr.stateId() 22 23 // Build the instance info. More of this will be populated during eval 24 info := &InstanceInfo{ 25 Id: stateId, 26 Type: addr.Type, 27 ModulePath: normalizeModulePath(addr.Path), 28 } 29 30 // Build the resource for eval 31 resource := &Resource{ 32 Name: addr.Name, 33 Type: addr.Type, 34 CountIndex: addr.Index, 35 } 36 if resource.CountIndex < 0 { 37 resource.CountIndex = 0 38 } 39 40 // Determine the dependencies for the state. We use some older 41 // code for this that we've used for a long time. 42 var stateDeps []string 43 { 44 oldN := &graphNodeExpandedResource{Resource: n.Config} 45 stateDeps = oldN.StateDependencies() 46 } 47 48 // Eval info is different depending on what kind of resource this is 49 switch n.Config.Mode { 50 case config.ManagedResourceMode: 51 return n.evalTreeManagedResource( 52 stateId, info, resource, stateDeps, 53 ) 54 case config.DataResourceMode: 55 return n.evalTreeDataResource( 56 stateId, info, resource, stateDeps) 57 default: 58 panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) 59 } 60 } 61 62 func (n *NodePlannableResourceInstance) evalTreeDataResource( 63 stateId string, info *InstanceInfo, 64 resource *Resource, stateDeps []string) EvalNode { 65 var provider ResourceProvider 66 var config *ResourceConfig 67 var diff *InstanceDiff 68 var state *InstanceState 69 70 return &EvalSequence{ 71 Nodes: []EvalNode{ 72 &EvalReadState{ 73 Name: stateId, 74 Output: &state, 75 }, 76 77 // We need to re-interpolate the config here because some 78 // of the attributes may have become computed during 79 // earlier planning, due to other resources having 80 // "requires new resource" diffs. 81 &EvalInterpolate{ 82 Config: n.Config.RawConfig.Copy(), 83 Resource: resource, 84 Output: &config, 85 }, 86 87 &EvalIf{ 88 If: func(ctx EvalContext) (bool, error) { 89 computed := config.ComputedKeys != nil && len(config.ComputedKeys) > 0 90 91 // If the configuration is complete and we 92 // already have a state then we don't need to 93 // do any further work during apply, because we 94 // already populated the state during refresh. 95 if !computed && state != nil { 96 return true, EvalEarlyExitError{} 97 } 98 99 return true, nil 100 }, 101 Then: EvalNoop{}, 102 }, 103 104 &EvalGetProvider{ 105 Name: n.ProvidedBy()[0], 106 Output: &provider, 107 }, 108 109 &EvalReadDataDiff{ 110 Info: info, 111 Config: &config, 112 Provider: &provider, 113 Output: &diff, 114 OutputState: &state, 115 }, 116 117 &EvalWriteState{ 118 Name: stateId, 119 ResourceType: n.Config.Type, 120 Provider: n.Config.Provider, 121 Dependencies: stateDeps, 122 State: &state, 123 }, 124 125 &EvalWriteDiff{ 126 Name: stateId, 127 Diff: &diff, 128 }, 129 }, 130 } 131 } 132 133 func (n *NodePlannableResourceInstance) evalTreeManagedResource( 134 stateId string, info *InstanceInfo, 135 resource *Resource, stateDeps []string) EvalNode { 136 // Declare a bunch of variables that are used for state during 137 // evaluation. Most of this are written to by-address below. 138 var provider ResourceProvider 139 var diff *InstanceDiff 140 var state *InstanceState 141 var resourceConfig *ResourceConfig 142 143 return &EvalSequence{ 144 Nodes: []EvalNode{ 145 &EvalInterpolate{ 146 Config: n.Config.RawConfig.Copy(), 147 Resource: resource, 148 Output: &resourceConfig, 149 }, 150 &EvalGetProvider{ 151 Name: n.ProvidedBy()[0], 152 Output: &provider, 153 }, 154 // Re-run validation to catch any errors we missed, e.g. type 155 // mismatches on computed values. 156 &EvalValidateResource{ 157 Provider: &provider, 158 Config: &resourceConfig, 159 ResourceName: n.Config.Name, 160 ResourceType: n.Config.Type, 161 ResourceMode: n.Config.Mode, 162 IgnoreWarnings: true, 163 }, 164 &EvalReadState{ 165 Name: stateId, 166 Output: &state, 167 }, 168 &EvalDiff{ 169 Name: stateId, 170 Info: info, 171 Config: &resourceConfig, 172 Resource: n.Config, 173 Provider: &provider, 174 State: &state, 175 OutputDiff: &diff, 176 OutputState: &state, 177 }, 178 &EvalCheckPreventDestroy{ 179 Resource: n.Config, 180 Diff: &diff, 181 }, 182 &EvalWriteState{ 183 Name: stateId, 184 ResourceType: n.Config.Type, 185 Provider: n.Config.Provider, 186 Dependencies: stateDeps, 187 State: &state, 188 }, 189 &EvalWriteDiff{ 190 Name: stateId, 191 Diff: &diff, 192 }, 193 }, 194 } 195 }