github.com/gettyimages/terraform@v0.7.6-0.20161219132226-dc052c5707a3/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. We use some older
    41  	// code for this that we've used for a long time.
    42  	var stateDeps []string
    43  	{
    44  		oldN := &graphNodeExpandedResource{Resource: n.Config}
    45  		stateDeps = oldN.StateDependencies()
    46  	}
    47  
    48  	// Eval info is different depending on what kind of resource this is
    49  	switch n.Config.Mode {
    50  	case config.ManagedResourceMode:
    51  		return n.evalTreeManagedResource(
    52  			stateId, info, resource, stateDeps,
    53  		)
    54  	case config.DataResourceMode:
    55  		return n.evalTreeDataResource(
    56  			stateId, info, resource, stateDeps)
    57  	default:
    58  		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
    59  	}
    60  }
    61  
    62  func (n *NodePlannableResourceInstance) evalTreeDataResource(
    63  	stateId string, info *InstanceInfo,
    64  	resource *Resource, stateDeps []string) EvalNode {
    65  	var provider ResourceProvider
    66  	var config *ResourceConfig
    67  	var diff *InstanceDiff
    68  	var state *InstanceState
    69  
    70  	return &EvalSequence{
    71  		Nodes: []EvalNode{
    72  			&EvalReadState{
    73  				Name:   stateId,
    74  				Output: &state,
    75  			},
    76  
    77  			// We need to re-interpolate the config here because some
    78  			// of the attributes may have become computed during
    79  			// earlier planning, due to other resources having
    80  			// "requires new resource" diffs.
    81  			&EvalInterpolate{
    82  				Config:   n.Config.RawConfig.Copy(),
    83  				Resource: resource,
    84  				Output:   &config,
    85  			},
    86  
    87  			&EvalIf{
    88  				If: func(ctx EvalContext) (bool, error) {
    89  					computed := config.ComputedKeys != nil && len(config.ComputedKeys) > 0
    90  
    91  					// If the configuration is complete and we
    92  					// already have a state then we don't need to
    93  					// do any further work during apply, because we
    94  					// already populated the state during refresh.
    95  					if !computed && state != nil {
    96  						return true, EvalEarlyExitError{}
    97  					}
    98  
    99  					return true, nil
   100  				},
   101  				Then: EvalNoop{},
   102  			},
   103  
   104  			&EvalGetProvider{
   105  				Name:   n.ProvidedBy()[0],
   106  				Output: &provider,
   107  			},
   108  
   109  			&EvalReadDataDiff{
   110  				Info:        info,
   111  				Config:      &config,
   112  				Provider:    &provider,
   113  				Output:      &diff,
   114  				OutputState: &state,
   115  			},
   116  
   117  			&EvalWriteState{
   118  				Name:         stateId,
   119  				ResourceType: n.Config.Type,
   120  				Provider:     n.Config.Provider,
   121  				Dependencies: stateDeps,
   122  				State:        &state,
   123  			},
   124  
   125  			&EvalWriteDiff{
   126  				Name: stateId,
   127  				Diff: &diff,
   128  			},
   129  		},
   130  	}
   131  }
   132  
   133  func (n *NodePlannableResourceInstance) evalTreeManagedResource(
   134  	stateId string, info *InstanceInfo,
   135  	resource *Resource, stateDeps []string) EvalNode {
   136  	// Declare a bunch of variables that are used for state during
   137  	// evaluation. Most of this are written to by-address below.
   138  	var provider ResourceProvider
   139  	var diff *InstanceDiff
   140  	var state *InstanceState
   141  	var resourceConfig *ResourceConfig
   142  
   143  	return &EvalSequence{
   144  		Nodes: []EvalNode{
   145  			&EvalInterpolate{
   146  				Config:   n.Config.RawConfig.Copy(),
   147  				Resource: resource,
   148  				Output:   &resourceConfig,
   149  			},
   150  			&EvalGetProvider{
   151  				Name:   n.ProvidedBy()[0],
   152  				Output: &provider,
   153  			},
   154  			// Re-run validation to catch any errors we missed, e.g. type
   155  			// mismatches on computed values.
   156  			&EvalValidateResource{
   157  				Provider:       &provider,
   158  				Config:         &resourceConfig,
   159  				ResourceName:   n.Config.Name,
   160  				ResourceType:   n.Config.Type,
   161  				ResourceMode:   n.Config.Mode,
   162  				IgnoreWarnings: true,
   163  			},
   164  			&EvalReadState{
   165  				Name:   stateId,
   166  				Output: &state,
   167  			},
   168  			&EvalDiff{
   169  				Name:        stateId,
   170  				Info:        info,
   171  				Config:      &resourceConfig,
   172  				Resource:    n.Config,
   173  				Provider:    &provider,
   174  				State:       &state,
   175  				OutputDiff:  &diff,
   176  				OutputState: &state,
   177  			},
   178  			&EvalCheckPreventDestroy{
   179  				Resource: n.Config,
   180  				Diff:     &diff,
   181  			},
   182  			&EvalWriteState{
   183  				Name:         stateId,
   184  				ResourceType: n.Config.Type,
   185  				Provider:     n.Config.Provider,
   186  				Dependencies: stateDeps,
   187  				State:        &state,
   188  			},
   189  			&EvalWriteDiff{
   190  				Name: stateId,
   191  				Diff: &diff,
   192  			},
   193  		},
   194  	}
   195  }