github.com/tomaszheflik/terraform@v0.7.3-0.20160827060421-32f990b41594/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 // id is always computed, because we're always "creating a new resource" 51 diff.init() 52 diff.SetAttribute("id", &ResourceAttrDiff{ 53 Old: "", 54 NewComputed: true, 55 RequiresNew: true, 56 Type: DiffAttrOutput, 57 }) 58 } 59 60 err = ctx.Hook(func(h Hook) (HookAction, error) { 61 return h.PostDiff(n.Info, diff) 62 }) 63 if err != nil { 64 return nil, err 65 } 66 67 *n.Output = diff 68 69 if n.OutputState != nil { 70 state := &InstanceState{} 71 *n.OutputState = state 72 73 // Apply the diff to the returned state, so the state includes 74 // any attribute values that are not computed. 75 if !diff.Empty() && n.OutputState != nil { 76 *n.OutputState = state.MergeDiff(diff) 77 } 78 } 79 80 return nil, nil 81 } 82 83 // EvalReadDataApply is an EvalNode implementation that executes a data 84 // resource's ReadDataApply method to read data from the data source. 85 type EvalReadDataApply struct { 86 Provider *ResourceProvider 87 Output **InstanceState 88 Diff **InstanceDiff 89 Info *InstanceInfo 90 } 91 92 func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) { 93 // TODO: test 94 provider := *n.Provider 95 diff := *n.Diff 96 97 // If the diff is for *destroying* this resource then we'll 98 // just drop its state and move on, since data resources don't 99 // support an actual "destroy" action. 100 if diff != nil && diff.GetDestroy() { 101 if n.Output != nil { 102 *n.Output = nil 103 } 104 return nil, nil 105 } 106 107 // For the purpose of external hooks we present a data apply as a 108 // "Refresh" rather than an "Apply" because creating a data source 109 // is presented to users/callers as a "read" operation. 110 err := ctx.Hook(func(h Hook) (HookAction, error) { 111 // We don't have a state yet, so we'll just give the hook an 112 // empty one to work with. 113 return h.PreRefresh(n.Info, &InstanceState{}) 114 }) 115 if err != nil { 116 return nil, err 117 } 118 119 state, err := provider.ReadDataApply(n.Info, diff) 120 if err != nil { 121 return nil, fmt.Errorf("%s: %s", n.Info.Id, err) 122 } 123 124 err = ctx.Hook(func(h Hook) (HookAction, error) { 125 return h.PostRefresh(n.Info, state) 126 }) 127 if err != nil { 128 return nil, err 129 } 130 131 if n.Output != nil { 132 *n.Output = state 133 } 134 135 return nil, nil 136 }