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  }