github.com/brandonstevens/terraform@v0.9.6-0.20170512224929-5367f2607e16/terraform/node_resource_plan_instance.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/terraform/config"
     7  )
     8  
     9  // NodePlannableResourceInstance represents a _single_ resource
    10  // instance that is plannable. This means this represents a single
    11  // count index, for example.
    12  type NodePlannableResourceInstance struct {
    13  	*NodeAbstractResource
    14  }
    15  
    16  // GraphNodeEvalable
    17  func (n *NodePlannableResourceInstance) EvalTree() EvalNode {
    18  	addr := n.NodeAbstractResource.Addr
    19  
    20  	// stateId is the ID to put into the state
    21  	stateId := addr.stateId()
    22  
    23  	// Build the instance info. More of this will be populated during eval
    24  	info := &InstanceInfo{
    25  		Id:         stateId,
    26  		Type:       addr.Type,
    27  		ModulePath: normalizeModulePath(addr.Path),
    28  	}
    29  
    30  	// Build the resource for eval
    31  	resource := &Resource{
    32  		Name:       addr.Name,
    33  		Type:       addr.Type,
    34  		CountIndex: addr.Index,
    35  	}
    36  	if resource.CountIndex < 0 {
    37  		resource.CountIndex = 0
    38  	}
    39  
    40  	// Determine the dependencies for the state.
    41  	stateDeps := n.StateReferences()
    42  
    43  	// Eval info is different depending on what kind of resource this is
    44  	switch n.Config.Mode {
    45  	case config.ManagedResourceMode:
    46  		return n.evalTreeManagedResource(
    47  			stateId, info, resource, stateDeps,
    48  		)
    49  	case config.DataResourceMode:
    50  		return n.evalTreeDataResource(
    51  			stateId, info, resource, stateDeps)
    52  	default:
    53  		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
    54  	}
    55  }
    56  
    57  func (n *NodePlannableResourceInstance) evalTreeDataResource(
    58  	stateId string, info *InstanceInfo,
    59  	resource *Resource, stateDeps []string) EvalNode {
    60  	var provider ResourceProvider
    61  	var config *ResourceConfig
    62  	var diff *InstanceDiff
    63  	var state *InstanceState
    64  
    65  	return &EvalSequence{
    66  		Nodes: []EvalNode{
    67  			&EvalReadState{
    68  				Name:   stateId,
    69  				Output: &state,
    70  			},
    71  
    72  			// We need to re-interpolate the config here because some
    73  			// of the attributes may have become computed during
    74  			// earlier planning, due to other resources having
    75  			// "requires new resource" diffs.
    76  			&EvalInterpolate{
    77  				Config:   n.Config.RawConfig.Copy(),
    78  				Resource: resource,
    79  				Output:   &config,
    80  			},
    81  
    82  			&EvalIf{
    83  				If: func(ctx EvalContext) (bool, error) {
    84  					computed := config.ComputedKeys != nil && len(config.ComputedKeys) > 0
    85  
    86  					// If the configuration is complete and we
    87  					// already have a state then we don't need to
    88  					// do any further work during apply, because we
    89  					// already populated the state during refresh.
    90  					if !computed && state != nil {
    91  						return true, EvalEarlyExitError{}
    92  					}
    93  
    94  					return true, nil
    95  				},
    96  				Then: EvalNoop{},
    97  			},
    98  
    99  			&EvalGetProvider{
   100  				Name:   n.ProvidedBy()[0],
   101  				Output: &provider,
   102  			},
   103  
   104  			&EvalReadDataDiff{
   105  				Info:        info,
   106  				Config:      &config,
   107  				Provider:    &provider,
   108  				Output:      &diff,
   109  				OutputState: &state,
   110  			},
   111  
   112  			&EvalWriteState{
   113  				Name:         stateId,
   114  				ResourceType: n.Config.Type,
   115  				Provider:     n.Config.Provider,
   116  				Dependencies: stateDeps,
   117  				State:        &state,
   118  			},
   119  
   120  			&EvalWriteDiff{
   121  				Name: stateId,
   122  				Diff: &diff,
   123  			},
   124  		},
   125  	}
   126  }
   127  
   128  func (n *NodePlannableResourceInstance) evalTreeManagedResource(
   129  	stateId string, info *InstanceInfo,
   130  	resource *Resource, stateDeps []string) EvalNode {
   131  	// Declare a bunch of variables that are used for state during
   132  	// evaluation. Most of this are written to by-address below.
   133  	var provider ResourceProvider
   134  	var diff *InstanceDiff
   135  	var state *InstanceState
   136  	var resourceConfig *ResourceConfig
   137  
   138  	return &EvalSequence{
   139  		Nodes: []EvalNode{
   140  			&EvalInterpolate{
   141  				Config:   n.Config.RawConfig.Copy(),
   142  				Resource: resource,
   143  				Output:   &resourceConfig,
   144  			},
   145  			&EvalGetProvider{
   146  				Name:   n.ProvidedBy()[0],
   147  				Output: &provider,
   148  			},
   149  			// Re-run validation to catch any errors we missed, e.g. type
   150  			// mismatches on computed values.
   151  			&EvalValidateResource{
   152  				Provider:       &provider,
   153  				Config:         &resourceConfig,
   154  				ResourceName:   n.Config.Name,
   155  				ResourceType:   n.Config.Type,
   156  				ResourceMode:   n.Config.Mode,
   157  				IgnoreWarnings: true,
   158  			},
   159  			&EvalReadState{
   160  				Name:   stateId,
   161  				Output: &state,
   162  			},
   163  			&EvalDiff{
   164  				Name:        stateId,
   165  				Info:        info,
   166  				Config:      &resourceConfig,
   167  				Resource:    n.Config,
   168  				Provider:    &provider,
   169  				State:       &state,
   170  				OutputDiff:  &diff,
   171  				OutputState: &state,
   172  			},
   173  			&EvalCheckPreventDestroy{
   174  				Resource: n.Config,
   175  				Diff:     &diff,
   176  			},
   177  			&EvalWriteState{
   178  				Name:         stateId,
   179  				ResourceType: n.Config.Type,
   180  				Provider:     n.Config.Provider,
   181  				Dependencies: stateDeps,
   182  				State:        &state,
   183  			},
   184  			&EvalWriteDiff{
   185  				Name: stateId,
   186  				Diff: &diff,
   187  			},
   188  		},
   189  	}
   190  }