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  }