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