github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/terraform/eval_read_data.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 ) 6 7 // EvalReadDataDiff is an EvalNode implementation that executes a data 8 // resource's ReadDataDiff method to discover what attributes it exports. 9 type EvalReadDataDiff struct { 10 Provider *ResourceProvider 11 Output **InstanceDiff 12 OutputState **InstanceState 13 Config **ResourceConfig 14 Info *InstanceInfo 15 16 // Set Previous when re-evaluating diff during apply, to ensure that 17 // the "Destroy" flag is preserved. 18 Previous **InstanceDiff 19 } 20 21 func (n *EvalReadDataDiff) Eval(ctx EvalContext) (interface{}, error) { 22 // TODO: test 23 24 err := ctx.Hook(func(h Hook) (HookAction, error) { 25 return h.PreDiff(n.Info, nil) 26 }) 27 if err != nil { 28 return nil, err 29 } 30 31 var diff *InstanceDiff 32 33 if n.Previous != nil && *n.Previous != nil && (*n.Previous).GetDestroy() { 34 // If we're re-diffing for a diff that was already planning to 35 // destroy, then we'll just continue with that plan. 36 diff = &InstanceDiff{Destroy: true} 37 } else { 38 provider := *n.Provider 39 config := *n.Config 40 41 var err error 42 diff, err = provider.ReadDataDiff(n.Info, config) 43 if err != nil { 44 return nil, err 45 } 46 if diff == nil { 47 diff = new(InstanceDiff) 48 } 49 50 // if id isn't explicitly set then it's always computed, because we're 51 // always "creating a new resource". 52 diff.init() 53 if _, ok := diff.Attributes["id"]; !ok { 54 diff.SetAttribute("id", &ResourceAttrDiff{ 55 Old: "", 56 NewComputed: true, 57 RequiresNew: true, 58 Type: DiffAttrOutput, 59 }) 60 } 61 } 62 63 err = ctx.Hook(func(h Hook) (HookAction, error) { 64 return h.PostDiff(n.Info, diff) 65 }) 66 if err != nil { 67 return nil, err 68 } 69 70 *n.Output = diff 71 72 if n.OutputState != nil { 73 state := &InstanceState{} 74 *n.OutputState = state 75 76 // Apply the diff to the returned state, so the state includes 77 // any attribute values that are not computed. 78 if !diff.Empty() && n.OutputState != nil { 79 *n.OutputState = state.MergeDiff(diff) 80 } 81 } 82 83 return nil, nil 84 } 85 86 // EvalReadDataApply is an EvalNode implementation that executes a data 87 // resource's ReadDataApply method to read data from the data source. 88 type EvalReadDataApply struct { 89 Provider *ResourceProvider 90 Output **InstanceState 91 Diff **InstanceDiff 92 Info *InstanceInfo 93 } 94 95 func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) { 96 // TODO: test 97 provider := *n.Provider 98 diff := *n.Diff 99 100 // If the diff is for *destroying* this resource then we'll 101 // just drop its state and move on, since data resources don't 102 // support an actual "destroy" action. 103 if diff != nil && diff.GetDestroy() { 104 if n.Output != nil { 105 *n.Output = nil 106 } 107 return nil, nil 108 } 109 110 // For the purpose of external hooks we present a data apply as a 111 // "Refresh" rather than an "Apply" because creating a data source 112 // is presented to users/callers as a "read" operation. 113 err := ctx.Hook(func(h Hook) (HookAction, error) { 114 // We don't have a state yet, so we'll just give the hook an 115 // empty one to work with. 116 return h.PreRefresh(n.Info, &InstanceState{}) 117 }) 118 if err != nil { 119 return nil, err 120 } 121 122 state, err := provider.ReadDataApply(n.Info, diff) 123 if err != nil { 124 return nil, fmt.Errorf("%s: %s", n.Info.Id, err) 125 } 126 127 err = ctx.Hook(func(h Hook) (HookAction, error) { 128 return h.PostRefresh(n.Info, state) 129 }) 130 if err != nil { 131 return nil, err 132 } 133 134 if n.Output != nil { 135 *n.Output = state 136 } 137 138 return nil, nil 139 }