github.com/ricardclau/terraform@v0.6.17-0.20160519222547-283e3ae6b5a9/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 17 func (n *EvalReadDataDiff) Eval(ctx EvalContext) (interface{}, error) { 18 // TODO: test 19 provider := *n.Provider 20 config := *n.Config 21 22 err := ctx.Hook(func(h Hook) (HookAction, error) { 23 return h.PreDiff(n.Info, nil) 24 }) 25 if err != nil { 26 return nil, err 27 } 28 29 diff, err := provider.ReadDataDiff(n.Info, config) 30 if err != nil { 31 return nil, err 32 } 33 if diff == nil { 34 diff = new(InstanceDiff) 35 } 36 37 // id is always computed, because we're always "creating a new resource" 38 diff.init() 39 diff.Attributes["id"] = &ResourceAttrDiff{ 40 Old: "", 41 NewComputed: true, 42 RequiresNew: true, 43 Type: DiffAttrOutput, 44 } 45 46 err = ctx.Hook(func(h Hook) (HookAction, error) { 47 return h.PostDiff(n.Info, diff) 48 }) 49 if err != nil { 50 return nil, err 51 } 52 53 *n.Output = diff 54 55 if n.OutputState != nil { 56 state := &InstanceState{} 57 *n.OutputState = state 58 59 // Apply the diff to the returned state, so the state includes 60 // any attribute values that are not computed. 61 if !diff.Empty() && n.OutputState != nil { 62 *n.OutputState = state.MergeDiff(diff) 63 } 64 } 65 66 return nil, nil 67 } 68 69 // EvalReadDataApply is an EvalNode implementation that executes a data 70 // resource's ReadDataApply method to read data from the data source. 71 type EvalReadDataApply struct { 72 Provider *ResourceProvider 73 Output **InstanceState 74 Diff **InstanceDiff 75 Info *InstanceInfo 76 } 77 78 func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) { 79 // TODO: test 80 provider := *n.Provider 81 diff := *n.Diff 82 83 // If the diff is for *destroying* this resource then we'll 84 // just drop its state and move on, since data resources don't 85 // support an actual "destroy" action. 86 if diff.Destroy { 87 if n.Output != nil { 88 *n.Output = nil 89 } 90 return nil, nil 91 } 92 93 // For the purpose of external hooks we present a data apply as a 94 // "Refresh" rather than an "Apply" because creating a data source 95 // is presented to users/callers as a "read" operation. 96 err := ctx.Hook(func(h Hook) (HookAction, error) { 97 // We don't have a state yet, so we'll just give the hook an 98 // empty one to work with. 99 return h.PreRefresh(n.Info, &InstanceState{}) 100 }) 101 if err != nil { 102 return nil, err 103 } 104 105 state, err := provider.ReadDataApply(n.Info, diff) 106 if err != nil { 107 return nil, fmt.Errorf("%s: %s", n.Info.Id, err) 108 } 109 110 err = ctx.Hook(func(h Hook) (HookAction, error) { 111 return h.PostRefresh(n.Info, state) 112 }) 113 if err != nil { 114 return nil, err 115 } 116 117 if n.Output != nil { 118 *n.Output = state 119 } 120 121 return nil, nil 122 }